4431|8

606

帖子

20

TA的资源

一粒金砂(高级)

楼主
 

EEWORLD DIY——我的健康手环(四) [复制链接]

本帖最后由 ketose 于 2017-11-20 15:26 编辑

      两周时间又过去了,今天在这里记录一下这两周所做的事情。上上篇我们已经把硬件全部弄就绪,这两周主要是软件部分。软件部分主要是1、实现LCD的驱动2、实现心跳数据测量
3、实现体温的测量
4、时钟表的实现
      我的健康手环显示部分使用Nokia5110,这比较老了,现在已经没有生产了,市面上能看到的基本上都是拆机的。不过使用起来挺简单了。它的主要特点是 1、单芯片 LCD 控制/驱动 2、48 行,84 列输出 3、显示数据 RAM 48*84 位,至于它的使用我这里也不多啰嗦了,有兴趣的朋友可以直接到网上搜索。我这里给出在STM32F103的驱动部分。

  1. /**
  2.   ******************************************************************************
  3.   * @file    lcd5110.c
  4.   * @author  sun xiao wu
  5.   * @version V1.0.0
  6.   * @date    2017/11/18
  7.   * @brief   NOKIA5110 LCD驱动文件
  8.   ******************************************************************************
  9.   */
  10. #include "stm32f10x.h"
  11. #include "LCD5110.h"
  12. #include "LCDFont.h"
  13. #include "delay.h"

  14. LCD_Output_Number lcd_output_number = LCD_write_shu;


  15. #define uchar unsigned char
  16. //-------------------------------------------------------------------
  17. //        Nokia5510指令集
  18. //  D7  D6  D5  D4  D3  D2  D1  D0
  19. //  0   0   1   0   0   PD  V   H
  20. //                      |   |   |_______1->扩展指令集  0->基本指令集
  21. //                      |   |___________1->垂直寻址    0->水平寻址
  22. //                      |_______________1->低功耗模式  0->正常模式
  23. //-------------------------------------------------------------------
  24. //        显示模式
  25. //  D7  D6  D5  D4  D3  D2  D1  D0
  26. //  0   0   0   0   1   D   0   E
  27. //                      |       |_______0    0    1    1
  28. //                      |_______________0    1    0    1
  29. //                                      白屏 正常 全显 反转
  30. //-------------------------------------------------------------------

  31. #ifdef HW_SPI
  32. void LCD_GPIO_init(void)
  33. {
  34.     GPIO_InitTypeDef GPIO_InitStructure;
  35.     SPI_InitTypeDef SPI_InitStructure;

  36.     RCC_APB2PeriphClockCmd(LCDRCC_CLK|RCC_APB2Periph_SPI1|RCC_APB2Periph_AFIO, ENABLE);                                 //激活GPIOA clock

  37.     GPIO_InitStructure.GPIO_Pin = LCD_RST|LCD_DC|LCD_BGL|LCD_CE;                          //设置GPIOB0、GPIOB1、GPIOB12
  38.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                                          //设置GPIO速度为10MHZ
  39.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                                          //设置以上三个GPIO为输出
  40.     GPIO_Init(LCD_CTRL_PORT, &GPIO_InitStructure);
  41.         /*硬件SPI*/
  42.     GPIO_InitStructure.GPIO_Pin = LCD_CLK|LCD_MOSI;
  43.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
  44.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  45.     GPIO_Init(LCD_CTRL_PORT, &GPIO_InitStructure);

  46.     //将以上设置参数写入
  47.         SPI_Cmd(SPI1, DISABLE);
  48.         SPI_StructInit(&SPI_InitStructure);
  49.     SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
  50.     SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
  51.     SPI_InitStructure.SPI_CRCPolynomial = 0x07;
  52.     SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
  53.     SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
  54.     SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge;
  55.     SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low;
  56.     SPI_InitStructure.SPI_Direction = SPI_Direction_1Line_Tx;
  57.     SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_256;
  58.     SPI_Init(SPI1,&SPI_InitStructure);
  59.         
  60.     SPI_Cmd(SPI1,ENABLE);
  61.     SPI_I2S_SendData(SPI1,0x0);
  62. }
  63. #else
  64. void LCD_GPIO_init(void)
  65. {
  66.     GPIO_InitTypeDef GPIO_InitStructure;

  67.     RCC_APB2PeriphClockCmd(LCDRCC_CLK|RCC_APB2Periph_AFIO, ENABLE);                                 //激活GPIOA clock
  68.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_SPI1,ENABLE);

  69.     GPIO_InitStructure.GPIO_Pin = LCD_RST|LCD_DC|LCD_BGL|LCD_CLK|LCD_MOSI|LCD_CE;          //设置GPIOB0、GPIOB1、GPIOB12
  70.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;                                          //设置GPIO速度为10MHZ
  71.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;                                          //设置以上三个GPIO为输出
  72.     GPIO_Init(LCD_CTRL_PORT, &GPIO_InitStructure);
  73. }
  74. #endif
  75. //---------------------------------------
  76. //名称: 使用SPI接口写数据到LCD
  77. //参数:dt:写入的数据 command: 1-数据/0-命令
  78. //作者:ketose
  79. //-----------------------------------------
  80. #ifdef HW_SPI
  81. void LCD_write_byte(unsigned char dt, unsigned char command)
  82. {
  83.     SCE_Low;
  84.     if(command)
  85.         DC_DAT;
  86.     else
  87.         DC_CMD;

  88.     SPI_I2S_SendData(SPI1,dt);
  89.         while(SPI_I2S_GetFlagStatus(SPI1,SPI_I2S_FLAG_TXE) == RESET);
  90. }
  91. #else
  92. void LCD_write_byte(unsigned char dt, unsigned char command)
  93. {
  94.     SCE_Low;
  95.     if(command)
  96.         DC_DAT;
  97.     else
  98.         DC_CMD;
  99.         
  100.     for(int i=0;i<8;i++)
  101.     {
  102.             if(dt&0x80)
  103.                     SDIN_High;
  104.             else
  105.                     SDIN_Low;
  106.             dt=dt<<1;
  107.             SCLK_Low;
  108.             SCLK_High;
  109.             SCLK_Low;
  110.     }
  111. }
  112. #endif
  113. //---------------------------------------
  114. //名称: 5110LCD初始化函数
  115. //作者:ketose
  116. //-----------------------------------------
  117. void LCD_init(void)
  118. {
  119.     SCE_High;
  120.     LCD_Set;
  121.     HAL_Delay_ms(10);
  122.     SCE_Low;
  123.     HAL_Delay_ms(100);
  124.     LCD_Set;
  125.     HAL_Delay_ms(10);
  126.     LCD_write_byte(0x21,LCD_CMD);//LCD功能设置:芯片活动,水平寻址,使用扩展指令
  127.     LCD_write_byte(0xC8,LCD_CMD);//设置VOP值,室温下的编程范围为3.00-10.68
  128.     //Vlcd=3.06+(VOP)*0.06,本例VOP为0B0101 0000为十进制的80,Vlcd=7.86V
  129.         LCD_write_byte(0X06,LCD_CMD);//温度校正
  130.         LCD_write_byte(0x13,LCD_CMD);//1:48
  131.     LCD_write_byte(0x20,LCD_CMD);//LCD功能设置:芯片活动,水平寻址,使用基本指令
  132.     LCD_write_byte(0x0C,LCD_CMD);//设定显示配置:普通模式
  133.     SCE_High;
  134. }
  135. //---------------------------------------
  136. //名称: 设置坐标函数
  137. //参数:X:0-83 Y:0-5
  138. //作者:ketose
  139. //-----------------------------------------
  140. void LCD_set_XY(unsigned char X, unsigned char Y)
  141. {
  142.     LCD_write_byte(0x40 | Y, LCD_CMD);// column
  143.     LCD_write_byte(0x80 | X, LCD_CMD);// row
  144.     SCE_High;
  145. }
  146. //---------------------------------------
  147. //名称: LCD清屏函数
  148. //作者:ketose
  149. //-----------------------------------------
  150. void LCD_clear(void)
  151. {
  152.     LCD_set_XY(0,0);
  153.     for(int t=0; t<6; t++)
  154.     {
  155.         for(int k=0; k<84; k++)
  156.         {
  157.             LCD_write_byte(0x00,LCD_DAT);
  158.         }
  159.     }
  160.     SCE_High;
  161. }
  162. //---------------------------------------
  163. //名称: 显示英文字符
  164. //参数:c:显示的字符在font6x8表格中的位置
  165. //作者:ketose
  166. //-----------------------------------------
  167. void LCD_write_char(unsigned char c)
  168. {
  169.     c -= 32;
  170.     for (int line=0; line<6; line++)
  171.         LCD_write_byte(font6x8[c][line], LCD_DAT);
  172. }
  173. //---------------------------------------
  174. //名称: 英文字符串显示函数
  175. //参数:*s:英文字符串指针 8*8点阵
  176. //作者:ketose
  177. //-----------------------------------------
  178. void LCD_write_String(unsigned char X,unsigned char Y,char *s)
  179. {
  180.     LCD_set_XY(X,Y);
  181.     while (*s)
  182.     {
  183.         LCD_write_char(*s);
  184.         s++;
  185.     }
  186. }
  187. //---------------------------------------
  188. //名称: 写一个字符到LCD函数(8*16点阵)
  189. //参数:row,page:写入字符的地址 c: 写入字符在shuzi表格中的位置
  190. //作者:ketose

  191. void LCD_write_shu(unsigned char row, unsigned char page,unsigned char c) //row:列 page:页 dd:字符
  192. {
  193.     LCD_set_XY(row*8, page);// 列,页
  194.     for(int i=0; i<8; i++)
  195.     {
  196.         LCD_write_byte(shuzi[c*16+i],LCD_DAT);
  197.     }

  198.     LCD_set_XY(row*8, page+1);// 列,页
  199.     for(int i=8; i<16; i++)
  200.     {
  201.         LCD_write_byte(shuzi[c*16+i],LCD_DAT);
  202.     }
  203.     SCE_High;
  204. }
  205. //---------------------------------------
  206. //名称: 写一个字符到LCD函数(8*16点阵)
  207. //参数:row,page:写入字符的地址 c: 写入字符在shuzi表格中的位置
  208. //作者:ketose

  209. void LCD_write_inverse_shu(unsigned char row, unsigned char page,unsigned char c) //row:列 page:页 dd:字符
  210. {
  211.     LCD_set_XY(row*8, page);// 列,页
  212.     for(int i=0; i<8; i++)
  213.     {
  214.         LCD_write_byte(~shuzi[c*16+i],LCD_DAT);
  215.     }

  216.     LCD_set_XY(row*8, page+1);// 列,页
  217.     for(int i=8; i<16; i++)
  218.     {
  219.         LCD_write_byte(~shuzi[c*16+i],LCD_DAT);
  220.     }
  221.     SCE_High;
  222. }
  223. //---------------------------------------
  224. //名称: 写一个字符到LCD函数(12*16点阵)
  225. //参数:row,page:写入字符的地址 c: 写入字符在shuzi表格中的位置
  226. //作者:ketose

  227. void LCD_write_digital(unsigned char row, unsigned char page,unsigned char c) //row:列 page:页 dd:字符
  228. {
  229.     LCD_set_XY(row*12, page);// 列,页
  230.     for(int i=0; i<12; i++)
  231.     {
  232.         LCD_write_byte(Digital[c*24+i],LCD_DAT);
  233.     }

  234.     LCD_set_XY(row*12, page+1);// 列,页
  235.     for(int i=12; i<24; i++)
  236.     {
  237.         LCD_write_byte(Digital[c*24+i],LCD_DAT);
  238.     }
  239.     SCE_High;
  240. }
  241. //---------------------------------------
  242. //名称: 写一个汉字到LCD函数 16*16
  243. //参数:x,y:写入汉字的地址 address: 写入汉字在han表格中的位置
  244. //作者:ketose
  245. //-----------------------------------------
  246. void LCD_write_hanzi(unsigned char row, unsigned char page,unsigned char c) //row:列 page:页 dd:字符
  247. {
  248.     LCD_set_XY(row*16, page);// 列,页
  249.     for(int i=0; i<16; i++)
  250.     {
  251.         LCD_write_byte(han[c*2][i],LCD_DAT);[/i]
  252.     }

  253.     LCD_set_XY(row*16, page+1);// 列,页
  254.     for(int i=0; i<16; i++)
  255.     {
  256.         LCD_write_byte(han[c*2+1],LCD_DAT);
  257.     }
  258.     SCE_High;
  259. }


复制代码

      显示部份有了,接下来就是最重要的体温和心跳部分的数据显示了。
体温用的是DS18B20,这个网上的资料也是分析的很透彻。我就不再把其它地方的资料再搬上来了。只接用代码说话吧。

  1. /**
  2.   ******************************************************************************
  3.   * @file    ds18b20.c
  4.   * @author  sun xiao wu
  5.   * @version V1.0.0
  6.   * @date    2017/11/09
  7.   * @brief   DS18B20温度传感器驱动文件
  8.   ******************************************************************************
  9.   */
  10.   
  11. #include "ds18b20.h"
  12. #include "delay.h"

  13. /**
  14. * @brief         复位DS18B20.
  15. * @note        单总线复位,总线主机拉低总线至少480us. 然后释放总线
  16. * @param[in]   none
  17. * @param[out]  none.  
  18. * @retval  none
  19. * @par 标识符
  20. *      保留
  21. * @par 其它
  22. *      无
  23. * @par 修改日志
  24. *      sun xiao wu于2017-11-01创建
  25. */
  26. void DS18B20_Rst(void)           
  27. {                 
  28.         DS18B20_IO_OUT();         //SET PA11 OUTPUT
  29.     DS18B20_DQ_OUT=0;         //拉低DQ
  30.     HAL_Delay_us(550);  //拉低550us
  31.     DS18B20_DQ_OUT=1;         //DQ=1
  32.         HAL_Delay_us(15);   //15US
  33. }

  34. /**
  35. * @brief         等待DS18B20的回应.
  36. * @note        在单总线复位后,检测总线上是否有60-240s 的低电平信号.
  37. * @param[in]   none
  38. * @param[out]  none.  
  39. * @retval  返回1:未检测到DS18B20的存在
  40. *                        返回0:存在
  41. * @par 标识符
  42. *      保留
  43. * @par 其它
  44. *      无
  45. * @par 修改日志
  46. *      sun xiao wu于2017-11-01创建
  47. */
  48. uint8_t DS18B20_Check(void)            
  49. {   
  50.         //重试次数
  51.         u8 retry=0;
  52.         
  53.         DS18B20_IO_IN();//SET PA11 INPUT         
  54.     while (DS18B20_DQ_IN && retry<200)
  55.         {
  56.                 retry++;
  57.                 HAL_Delay_us(1);
  58.         };         
  59.         if(retry>=200)
  60.                 return 1;
  61.         else
  62.                 retry=0;
  63.     while (!DS18B20_DQ_IN && retry<240)
  64.         {
  65.                 retry++;
  66.                 HAL_Delay_us(1);
  67.         };
  68.         if(retry>=240)
  69.                 return 1;            
  70.         return 0;
  71. }

  72. /**
  73. * @brief         从DS18B20读取一个bit位.
  74. *
  75. * @param[in]   none
  76. * @param[out]  none.  
  77. * @retval  返回1,0
  78. * @par 标识符
  79. *      保留
  80. * @par 其它
  81. *      无
  82. * @par 修改日志
  83. *      sun xiao wu于2017-11-01创建
  84. */
  85. uint8_t DS18B20_Read_Bit(void)                          // read one bit
  86. {
  87.     u8 data;
  88.         DS18B20_IO_OUT();//SET PA11 OUTPUT
  89.     DS18B20_DQ_OUT=0; //r拉低总线
  90.         HAL_Delay_us(2);
  91.     DS18B20_DQ_OUT=1; //释放总线
  92.         HAL_Delay_us(12);
  93.         DS18B20_IO_IN();//SET PA11 INPUT
  94.         if(DS18B20_DQ_IN)
  95.                 data=1;
  96.     else
  97.                 data=0;         
  98.     HAL_Delay_us(50);         //时隙持续时间的要求(至少60μs)         
  99.     return data;
  100. }

  101. /**
  102. * @brief         从DS18B20读取一个字节.
  103. *
  104. * @param[in]   none
  105. * @param[out]  none.  
  106. * @retval  返回了个字节数据
  107. * @par 标识符
  108. *      保留
  109. * @par 其它
  110. *      无
  111. * @par 修改日志
  112. *      sun xiao wu于2017-11-01创建
  113. */
  114. uint8_t DS18B20_Read_Byte(void)    // read one byte
  115. {        
  116.     u8 i,j,dat;
  117.     dat=0;
  118.         for (i=1;i<=8;i++)
  119.         {
  120.         j=DS18B20_Read_Bit();
  121.         dat=(j<<7)|(dat>>1);
  122.     }                                                   
  123.     return dat;
  124. }

  125. /**
  126. * @brief        写一个字节到DS18B20.
  127. *
  128. * @param[in]   dat 要写入的字节
  129. * @param[out]  none.  
  130. * @retval  none
  131. * @par 标识符
  132. *      保留
  133. * @par 其它
  134. *      无
  135. * @par 修改日志
  136. *      sun xiao wu于2017-11-01创建
  137. */
  138. void DS18B20_Write_Byte(uint8_t dat)     
  139. {            
  140.     u8 j;
  141.     u8 testb;
  142.         DS18B20_IO_OUT();//SET PA11 OUTPUT;
  143.     for (j=1;j<=8;j++)
  144.         {
  145.         testb=dat&0x01;
  146.         dat=dat>>1;
  147.         if (testb)
  148.         {
  149.             DS18B20_DQ_OUT=0;// Write 1
  150.             HAL_Delay_us(2);                           
  151.             DS18B20_DQ_OUT=1;
  152.             HAL_Delay_us(60);            
  153.         }
  154.         else
  155.         {
  156.             DS18B20_DQ_OUT=0;// Write 0
  157.             HAL_Delay_us(60);            
  158.             DS18B20_DQ_OUT=1;
  159.             HAL_Delay_us(2);                          
  160.         }
  161.     }
  162. }

  163. /**
  164. * @brief         启动DS18B20进行温度转换.
  165. *
  166. * @param[in]   none
  167. * @param[out]  none.  
  168. * @retval  none
  169. * @par 标识符
  170. *      保留
  171. * @par 其它
  172. *      无
  173. * @par 修改日志
  174. *      sun xiao wu于2017-11-01创建
  175. */
  176. void DS18B20_Start(void)// ds1820 start convert
  177. {                                                                  
  178.     DS18B20_Rst();           
  179.         DS18B20_Check();         
  180.     DS18B20_Write_Byte(0xcc);// skip rom
  181.     DS18B20_Write_Byte(0x44);// convert
  182. }
  183.   
  184. /**
  185. * @brief         初始化DS18B20的IO口 DQ 同时检测DS的存在.
  186. *
  187. * @param[in]   none
  188. * @param[out]  none.  
  189. * @retval  0:不存在
  190. *                         1:存在
  191. * @par 标识符
  192. *      保留
  193. * @par 其它
  194. *      无
  195. * @par 修改日志
  196. *      sun xiao wu于2017-11-01创建
  197. */
  198. uint8_t DS18B20_Init(void)
  199. {
  200.         GPIO_InitTypeDef gpio_1;
  201.         //RCC->APB2ENR|=1<<8;    //使能PORTG口时钟
  202.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  203.         

  204. //        GPIOA->CRH&=0XFFFF0FFF;//PORTA.11 推挽输出
  205. //        GPIOA->CRH|=0X00003000;
  206. //        GPIOA->ODR|=1<<11;      //输出1
  207.         gpio_1.GPIO_Mode = GPIO_Mode_Out_PP;
  208.         gpio_1.GPIO_Pin = GPIO_Pin_11;
  209.         gpio_1.GPIO_Speed = GPIO_Speed_2MHz;
  210.         
  211.         GPIO_Init(GPIOA,&gpio_1);
  212.         GPIO_SetBits(GPIOA,GPIO_Pin_11);
  213.         
  214.         DS18B20_Rst();
  215.         return DS18B20_Check();
  216. }  

  217. /**
  218. * @brief         从ds18b20得到温度值.
  219. * @note        精度:0.1C
  220. * @param[in]   none
  221. * @param[out]  none.  
  222. * @retval  温度值 (-550~1250)
  223. * @par 标识符
  224. *      保留
  225. * @par 其它
  226. *      无
  227. * @par 修改日志
  228. *      sun xiao wu于2017-11-01创建
  229. */
  230. float DS18B20_Get_Temp(void)
  231. {
  232.     uint8_t temp;
  233.     uint8_t TL,TH;
  234.         short tem;
  235.         float result;
  236.     DS18B20_Start ();                    // ds1820 start convert
  237.     DS18B20_Rst();
  238.     DS18B20_Check();         
  239.     DS18B20_Write_Byte(0xcc);// skip rom
  240.     DS18B20_Write_Byte(0xbe);// convert         
  241.         HAL_Delay_ms(750);
  242.     TL=DS18B20_Read_Byte(); // LSB   
  243.     TH=DS18B20_Read_Byte(); // MSB  
  244.                      
  245.     if(TH>7)
  246.     {
  247.         TH=~TH;
  248.         TL=~TL;
  249.         temp=0;//温度为负  
  250.     }else temp=1;//温度为正                    
  251.     tem=TH; //获得高八位
  252.     tem<<=8;   
  253.     tem+=TL;//获得底八位
  254.     result=(float)tem*0.0625;//转换     
  255.         if(temp)
  256.                 return result; //返回温度值
  257.         else
  258.                 return -result;   
  259. }

  260. /**************************************************************************************
  261. * 名    称: adjust_res
  262. * 功    能: 调整分辨率
  263. * 参    数: 分辨率值
  264. * 返 回 值: 无
  265. **************************************************************************************/  
  266.    
  267. void adjust_res(unsigned char res) ///res 分别等于 0x1f, 0x3f, 0x5f,0x7f温度读数分辨率分别对应  0.5, 0.25, 0.125,0.0625   
  268. {
  269.         DS18B20_Rst();                       //复位
  270.         DS18B20_Write_Byte(0xcc);              //跳过Rom
  271.         DS18B20_Write_Byte(0x4e);              //写暂存器
  272.         DS18B20_Write_Byte(0x02);              //写TH  
  273.         DS18B20_Write_Byte(0x01);              //写TL
  274.         DS18B20_Write_Byte(res);               //写结构寄存器
  275.         DS18B20_Rst();                       //复位
  276.         DS18B20_Write_Byte(0xcc);              //跳过Rom  
  277.         DS18B20_Write_Byte(0x48);              //把暂存器内容写到EPRam中
  278. }

复制代码

      接下来的部分就是心率的测量了,这部分看了SON1303的资料,觉得可以用外部中断上升沿下降沿和定时器可以解决问题,可是以测试的时候发现外部中断很不稳定,心跳有抖动。没办法用外部中断,所以想了个笨的办法,直接测高低电平的时间,这样即便是在高电平上有点小的抖动,也能很好的去抖动。代码了做了详细的注释,大这看就能看明白。
  1. /**
  2.   ******************************************************************************
  3.   * @file    son1303.c
  4.   * @author  sun xiao wu
  5.   * @version V1.0.0
  6.   * @date    2017/11/16
  7.   * @brief   心率传感器son1303驱动文件
  8.   ******************************************************************************
  9.   */
  10.   
  11. #include "son1303.h"

  12. HEARTRATE Hreat;        //心率
  13. uint32_t risingTimes = 0;        //高电平持续时间 ms
  14. uint32_t fallingTimes = 0;        //低电平持续时间 ms

  15. /**
  16. @brief:         SON1303的GPIO初始化,PB3开启心跳仪,PB4心跳输入
  17. @param:         None
  18. @return: None
  19. */
  20. void SON1303_GPIO_init(void)
  21. {
  22.     GPIO_InitTypeDef gpio_t;

  23.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);

  24.     gpio_t.GPIO_Pin = GPIO_Pin_3;
  25.     gpio_t.GPIO_Mode = GPIO_Mode_Out_PP;
  26.     gpio_t.GPIO_Speed = GPIO_Speed_10MHz;
  27.     GPIO_Init(GPIOB,&gpio_t);
  28.     GPIO_ResetBits(GPIOB,GPIO_Pin_3);

  29.     gpio_t.GPIO_Pin = GPIO_Pin_4;
  30.     gpio_t.GPIO_Mode = GPIO_Mode_IN_FLOATING;
  31.     gpio_t.GPIO_Speed = GPIO_Speed_10MHz;
  32.     GPIO_Init(GPIOB,&gpio_t);
  33. }
  34. /**
  35. @brief:         SON1303传感器初始化,PB4心跳输入
  36. @param:         None
  37. @return: None
  38. */
  39. void SON1303_init(void)
  40. {
  41.     NVIC_InitTypeDef nvic_1;
  42.     TIM_TimeBaseInitTypeDef tim_t;

  43.     RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);

  44.     /*心跳计时 TIM3 1000Hz 1ms*/
  45.     TIM_TimeBaseStructInit(&tim_t);
  46.     tim_t.TIM_CounterMode = TIM_CounterMode_Up;
  47.     tim_t.TIM_Period = 2000-1;
  48.     tim_t.TIM_ClockDivision = TIM_CKD_DIV1;
  49.     tim_t.TIM_Prescaler = 35;
  50.     TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE);
  51.     TIM_TimeBaseInit(TIM3,&tim_t);

  52.     nvic_1.NVIC_IRQChannel = TIM3_IRQn;
  53.     nvic_1.NVIC_IRQChannelPreemptionPriority = 0;
  54.     nvic_1.NVIC_IRQChannelSubPriority = 1;
  55.     nvic_1.NVIC_IRQChannelCmd = ENABLE;
  56.     NVIC_Init(&nvic_1);
  57. }
  58. /**
  59. @brief:         启动 SON1303传感器
  60. @param:         None
  61. @return: None
  62. */
  63. void SON1303_start(void)
  64. {
  65.     GPIO_SetBits(GPIOB,GPIO_Pin_3);
  66.     TIM_Cmd(TIM3,ENABLE);
  67. }
  68. /**
  69. @brief:         停止 SON1303传感器
  70. @param:         None
  71. @return: None
  72. */
  73. void SON1303_stop(void)
  74. {
  75.     GPIO_ResetBits(GPIOB,GPIO_Pin_3);
  76.     TIM_Cmd(TIM3,DISABLE);
  77. }
  78. /**
  79. @brief:         计算心率
  80. @param:         None
  81. @return: 心率
  82. */
  83. uint32_t CalcHeartRate(void)
  84. {
  85.     uint32_t result = 0;
  86.     uint32_t avg = 0;
  87.     if(Hreat.TestStable)
  88.     {
  89.                 avg = TESTCOUNT;
  90.                 int maxHeart = 0;
  91.                 int minHeart = 0;
  92.         for(int i=0; i<avg; i++)
  93.                 {
  94.                         maxHeart = maxHeart > Hreat.HeartRate[i] ? maxHeart : Hreat.HeartRate;[/i]
  95.                         minHeart = minHeart < Hreat.HeartRate ? minHeart : Hreat.HeartRate;
  96.             result += Hreat.HeartRate;
  97.                 }
  98.                 result = result - maxHeart - minHeart;
  99.                 avg = TESTCOUNT - 2;
  100.     }
  101.     else
  102.     {
  103.         avg = Hreat.TestTimes;
  104.         for(int i=0; i<avg; i++)
  105.             result += Hreat.HeartRate;
  106.     }
  107.     result = result / avg;
  108.     return result;
  109. }
  110. /**
  111. @brief:         配置PA2为ADC,检测是否配带,PA2
  112. @param:         None
  113. @return: None
  114. */
  115. void SON1303_ADC_init()
  116. {
  117.     GPIO_InitTypeDef gpio_t;
  118.     ADC_InitTypeDef adc_t;

  119.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE);
  120.     RCC_ADCCLKConfig(RCC_PCLK2_Div6);

  121.     gpio_t.GPIO_Pin = GPIO_Pin_2;
  122.     gpio_t.GPIO_Mode = GPIO_Mode_AIN;
  123.     GPIO_Init(GPIOA,&gpio_t);

  124.     ADC_DeInit(ADC1);
  125.     adc_t.ADC_Mode = ADC_Mode_Independent;
  126.     adc_t.ADC_ScanConvMode = DISABLE;
  127.     adc_t.ADC_ContinuousConvMode = DISABLE;
  128.     adc_t.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
  129.     adc_t.ADC_DataAlign = ADC_DataAlign_Right;
  130.     adc_t.ADC_NbrOfChannel = 1;
  131.     ADC_Init(ADC1,&adc_t);

  132.     ADC_Cmd(ADC1,ENABLE);
  133.     ADC_RegularChannelConfig(ADC1,ADC_Channel_2,1,ADC_SampleTime_239Cycles5);
  134.     ADC_ResetCalibration(ADC1);
  135.     while(ADC_GetResetCalibrationStatus(ADC1));
  136.     ADC_StartCalibration(ADC1);
  137.     while(ADC_GetCalibrationStatus(ADC1));
  138. }
  139. /**
  140. @brief:         检测是否配带
  141. @param:         None
  142. @return: 配带返回true
  143. */
  144. bool IsWeared(void)
  145. {
  146.     ADC_SoftwareStartConvCmd(ADC1,ENABLE);
  147.     while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC));
  148.     uint32_t adValue = ADC_GetConversionValue(ADC1);
  149.     return (adValue<0xD20);
  150. }

  151. void TIM3_IRQHandler(void)
  152. {
  153.         /*PB4 心跳输入*/
  154.     static uint8_t last_status = 0;

  155.     if(TIM_GetITStatus(TIM3,TIM_IT_Update) == SET)
  156.     {
  157.         if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_4) == Bit_SET)
  158.         {
  159.             /*上次状态是0,证明心跳了一次*/
  160.             if(last_status == 0)
  161.             {
  162.                 uint32_t sumTimes = risingTimes + fallingTimes;//心跳一次的总时间
  163.                 uint32_t tmp = 60000 / sumTimes;                                //一分钟是60000ms
  164.                 /**/
  165.                 if(tmp > 50 && tmp < 200)
  166.                 {
  167.                     if(Hreat.TestTimes >=TESTCOUNT)
  168.                     {
  169.                         Hreat.TestTimes = 0;
  170.                     }
  171.                     Hreat.HeartRate[Hreat.TestTimes] = tmp;
  172.                     Hreat.TestTimes++;
  173.                 }
  174.                 risingTimes = 0;
  175.             }
  176.             last_status = 1;
  177.             risingTimes++;//增加高电平的时间
  178.         }
  179.         else
  180.         {
  181.             if(last_status == 1)
  182.                 fallingTimes = 0;
  183.             last_status = 0;
  184.             fallingTimes++;//增加低电平的时间
  185.         }
  186.         TIM_ClearITPendingBit(TIM3,TIM_IT_Update);
  187.     }
  188. }
复制代码


接下来就是主程序文件。这个逻辑就简单很多。
  1. /**
  2.   ******************************************************************************
  3.   * @file    mainc.c
  4.   * @author  sun xiao wu
  5.   * @version V1.0.0
  6.   * @date    2017/11/06
  7.   * @brief   穿戴数据终端主程序文件
  8.   ******************************************************************************
  9.   */
  10.   
  11. #include "stm32f10x.h"                  // Device header
  12. #include "LCD5110.h"
  13. #include "ds18b20.h"
  14. #include "son1303.h"
  15. #include "delay.h"
  16. #include "rtc.h"
  17. #include "key.h"
  18. #include <stdio.h>
  19. #include <time.h>

  20. void Clock_Init(void);
  21. char printBuffer[16];

  22. extern LCD_Output_Number lcd_output_number;
  23. extern bool Key_Mode_Press;
  24. extern bool Key_Back_Press;
  25. extern bool Key_Up_Press;
  26. extern bool Key_Down_Press;
  27. extern enum KeySelect KeyValue;
  28. extern uint32_t LedDelay;

  29. extern bool bShowHeart;                //显示心跳和体温标记
  30. int ShowStatus=0;

  31. void GPIO_Configuration(void);
  32. void Show_time(void);
  33. void Show_Temperature(void);
  34. void Show_HeartRate(void);
  35. void Show_Logo(void);
  36. void Show_Power(void);

  37. int main()
  38. {
  39.     //时钟初始化
  40.     Clock_Init();
  41.     GPIO_Configuration();

  42.     RTC_init();
  43.     //延时初始化
  44.     HAL_Delay_Init();
  45.     //DS18B20初始化
  46.     DS18B20_Init();
  47.     //心率传感器初始化
  48.     SON1303_init();
  49.     SON1303_ADC_init();

  50.     //Nokia5110初始化
  51.     LCD_init();
  52.     LCD_clear();
  53.         

  54.     KEY_GPIO_init();
  55.     KEY_NVIC_init();

  56.     SON1303_start();
  57.         
  58.     for(;;)
  59.     {
  60.                 //交替显示心跳和体温
  61.                 if(bShowHeart)
  62.                 {
  63.                         if(ShowStatus == 1)
  64.                         {
  65.                                 /*如果是从显示体温界面转过来,则进行清屏,防止脱影*/
  66.                                 LCD_clear();
  67.                         }
  68.                         Show_HeartRate();
  69.                         ShowStatus = 0;
  70.                 }
  71.                 else
  72.                 {
  73.                         if(ShowStatus == 0)
  74.                         {
  75.                                 /*如果是从显示心跳界面转过来,则进行清屏,防止脱影*/
  76.                                 LCD_clear();
  77.                         }
  78.                         Show_Temperature();
  79.                         ShowStatus = 1;
  80.                 }
  81.                 //显示EEWORLD DIY
  82.                 Show_Logo();
  83.                 //显示电量
  84.                 Show_Power();
  85.                 //显示时间
  86.         Show_time();

  87.         HAL_Delay_ms(200);
  88.     }
  89. }

  90. /**
  91. @brief:         stm32芯片时钟初始化
  92. @param:         None
  93. @return: None
  94. */
  95. void Clock_Init(void)
  96. {
  97. //        RCC_DeInit();
  98. //        /* Enable HSE */
  99. //        RCC_HSEConfig(RCC_HSE_ON);
  100. //        /* Wait till HSE is ready and if Time out is reached exit */
  101. //        while(!RCC_WaitForHSEStartUp());


  102. //        /* Configure HCLK such as HCLK = SYSCLK */
  103. //        RCC_HCLKConfig(RCC_SYSCLK_Div1);
  104. //        /* Configure PCLK1 such as PCLK1 = HCLK/2 */
  105. //        RCC_PCLK1Config(RCC_HCLK_Div2);
  106. //        /* Configure PCLK2 such as PCLK2 = HCLK */
  107. //        RCC_PCLK2Config(RCC_HCLK_Div1);
  108. //
  109. //    FLASH_SetLatency(FLASH_Latency_2);
  110. //    FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
  111. //
  112. //        /* Set PLL clock output to 72MHz using HSE (8MHz) as entry clock */
  113. //        RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);
  114. //        /* Enable the PLL */
  115. //        RCC_PLLCmd(ENABLE);
  116. //        while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
  117. //
  118. //        /* Select the PLL as system clock source */
  119. //        RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
  120. //        while(RCC_GetSYSCLKSource() != 0x08);
  121. }

  122. /**
  123. @brief:         GPIO初始化
  124. @param:         None
  125. @return: None
  126. */
  127. void GPIO_Configuration(void)
  128. {
  129.     LCD_GPIO_init();
  130.     SON1303_GPIO_init();
  131. }
  132. /**
  133. @brief:         显示时间
  134. @param:         None
  135. @return: None
  136. */
  137. void Show_time(void)
  138. {
  139.     uint32_t t = RTC_GetCounter();
  140.     struct tm *ptm = localtime(&t);
  141.         if(LedDelay>0)
  142.                 BkLED_On;
  143.         else
  144.                 BkLED_Off;
  145.     if(Key_Mode_Press)
  146.     {
  147.         switch(KeyValue)
  148.         {
  149.         case Hour:
  150.             lcd_output_number = LCD_write_inverse_shu;
  151.             lcd_output_number(2,4,ptm->tm_hour/10);
  152.             lcd_output_number(3,4,ptm->tm_hour%10);
  153.             lcd_output_number = LCD_write_shu;
  154.             lcd_output_number(4,4,47);
  155.             lcd_output_number(5,4,ptm->tm_min/10);
  156.             lcd_output_number(6,4,ptm->tm_min%10);
  157.             lcd_output_number(7,4,47);
  158.             lcd_output_number(8,4,ptm->tm_sec/10);
  159.             lcd_output_number(9,4,ptm->tm_sec%10);
  160.             break;
  161.         case Minute:
  162.             lcd_output_number(2,4,ptm->tm_hour/10);                                                                                                                                                                                                      
  163.             lcd_output_number(3,4,ptm->tm_hour%10);
  164.             lcd_output_number(4,4,47);
  165.             lcd_output_number = LCD_write_inverse_shu;
  166.             lcd_output_number(5,4,ptm->tm_min/10);
  167.             lcd_output_number(6,4,ptm->tm_min%10);
  168.             lcd_output_number = LCD_write_shu;
  169.             lcd_output_number(7,4,47);
  170.             lcd_output_number(8,4,ptm->tm_sec/10);
  171.             lcd_output_number(9,4,ptm->tm_sec%10);
  172.             break;
  173.         case Second:
  174.             lcd_output_number(2,4,ptm->tm_hour/10);
  175.             lcd_output_number(3,4,ptm->tm_hour%10);
  176.             lcd_output_number(4,4,47);
  177.             lcd_output_number(5,4,ptm->tm_min/10);
  178.             lcd_output_number(6,4,ptm->tm_min%10);
  179.             lcd_output_number(7,4,47);
  180.             lcd_output_number = LCD_write_inverse_shu;
  181.             lcd_output_number(8,4,ptm->tm_sec/10);
  182.             lcd_output_number(9,4,ptm->tm_sec%10);
  183.             lcd_output_number = LCD_write_shu;
  184.             break;
  185.         }
  186.     }
  187.     else
  188.     {
  189.         LCD_write_shu(2,4,ptm->tm_hour/10);
  190.         LCD_write_shu(3,4,ptm->tm_hour%10);
  191.         LCD_write_shu(4,4,47);
  192.         LCD_write_shu(5,4,ptm->tm_min/10);
  193.         LCD_write_shu(6,4,ptm->tm_min%10);
  194.         LCD_write_shu(7,4,47);
  195.         LCD_write_shu(8,4,ptm->tm_sec/10);
  196.         LCD_write_shu(9,4,ptm->tm_sec%10);
  197.     }
  198.     //LCD_write_hanzi(0,4,0);
  199. }
  200. /**
  201. @brief:         显示温度
  202. @param:         None
  203. @return: None
  204. */
  205. void Show_Temperature(void)
  206. {
  207.     int temperature = (int)DS18B20_Get_Temp();
  208.         
  209.         LCD_write_hanzi(4,2,8);
  210.     int x = temperature / 10;
  211.         LCD_write_digital(2,2,x);
  212.     x = temperature % 10;
  213.         LCD_write_digital(3,2,x);
  214. }
  215. /**
  216. @brief:         显示心率
  217. @param:         None
  218. @return: None
  219. */
  220. void Show_HeartRate(void)
  221. {
  222.     uint32_t hr = CalcHeartRate();

  223.     LCD_write_hanzi(0,2,11);
  224.     int x = hr / 100;
  225.     LCD_write_digital(2,2,x);
  226.     x = (hr % 100) / 10;
  227.     LCD_write_digital(3,2,x);
  228.     x = hr % 10;
  229.     LCD_write_digital(4,2,x);
  230. }

  231. /**
  232. @brief:         显示LOGO
  233. @param:         None
  234. @return: None
  235. */
  236. void Show_Logo(void)
  237. {
  238.         LCD_write_String(0,0,"EEWORLD DIY");
  239. }

  240. /**
  241. @brief:         显示电量
  242. @param:         None
  243. @return: None
  244. */
  245. void Show_Power(void)
  246. {
  247.         //LCD_write_shu(0,1,48);
  248. }
复制代码

      按键部分,延时部分,RTC时间的代码我就不贴了,贴出来太多了。如果有人需要跟贴,我就把它们也贴出来。
      还有一部分工作没有完成,就是电量显示,和低功耗部分。这部分在后面会慢慢实现。
先看下目前完成的情况。




操作视频:
如果打不开,可以直接用这个地址看:http://v.youku.com/v_show/id_XMzE2OTQxNDg2OA==.html
这两天不知道怎么的,手上起了很多水泡,网上查了下是汗泡疹。大家有没有什么好的治疗办法分享一下,手上很多泡实在是很痒。


此内容由EEWORLD论坛网友ketose原创,如需转载或用于商业用途需征得作者同意并注明出处











最新回复

好东西,赞楼主  详情 回复 发表于 2017-11-21 16:54

赞赏

1

查看全部赞赏

点赞 关注
 

回复
举报

650

帖子

8

TA的资源

纯净的硅(初级)

沙发
 
楼主厉害
 
 

回复

406

帖子

1

TA的资源

一粒金砂(中级)

板凳
 
很不错
 
 
 

回复

9161

帖子

6

TA的资源

管理员

4
 
这个手环有点酷!

泡疹最好去皮肤科看下是什么引起的,一般的真菌除了外涂抗生素类软膏还要配合吃维生素类的药
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身

点评

谢谢了,视频能看到吗?  详情 回复 发表于 2017-11-20 15:27
真的么?麻麻的,我看了假皮肤科,医生瞟一眼,然后开了2支一样的药,说回去涂吧,就打发我走了~  详情 回复 发表于 2017-11-20 10:39
 
 
 

回复

1403

帖子

1

TA的资源

纯净的硅(中级)

5
 
eric_wang 发表于 2017-11-20 10:16
这个手环有点酷!

泡疹最好去皮肤科看下是什么引起的,一般的真菌除了外涂抗生素类软膏还要配合吃维生素 ...

真的么?麻麻的,我看了假皮肤科,医生瞟一眼,然后开了2支一样的药,说回去涂吧,就打发我走了~

点评

依据个体情况吧,你的没准就是轻微的问题,涂点药就能好的  详情 回复 发表于 2017-11-20 10:52
个人签名HELLO_WATER
 
 
 

回复

9161

帖子

6

TA的资源

管理员

6
 
shinykongcn 发表于 2017-11-20 10:39
真的么?麻麻的,我看了假皮肤科,医生瞟一眼,然后开了2支一样的药,说回去涂吧,就打发我走了 ...

依据个体情况吧,你的没准就是轻微的问题,涂点药就能好的
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
 
 
 

回复

606

帖子

20

TA的资源

一粒金砂(高级)

7
 
eric_wang 发表于 2017-11-20 10:16
这个手环有点酷!

泡疹最好去皮肤科看下是什么引起的,一般的真菌除了外涂抗生素类软膏还要配合吃维生素 ...

谢谢了,视频能看到吗?

点评

能 没问题  详情 回复 发表于 2017-11-20 15:33
 
 
 

回复

9161

帖子

6

TA的资源

管理员

8
 
ketose 发表于 2017-11-20 15:27
谢谢了,视频能看到吗?

能 没问题
加EE小助手好友,
入技术交流群
EE服务号
精彩活动e手掌握
EE订阅号
热门资讯e网打尽
聚焦汽车电子软硬件开发
认真关注技术本身
 
 
 

回复

1

帖子

0

TA的资源

一粒金砂(初级)

9
 
好东西,赞楼主
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表