查看: 34806|回复: 16

[7月赛] 【开源盛世】基于onenet的心率定位手环

  [复制链接]

1

主题

18

帖子

41

积分

新手上路

Rank: 1

积分
41
发表于 2017-7-5 11:33:34 | 显示全部楼层 |阅读模式
本帖最后由 胥豪 于 2017-7-25 20:52 编辑

参赛类别】:开源盛世
【正文】
自从参加互联网+这个比赛,对互联网产生了浓厚的兴趣。由于自己的专业是工业上面的自动控制,对互联网控制这方面的知识比较欠缺,学习过程效率低走了许多弯路,但是功夫不负有心人,经过不知多少日夜奋战,当室友睡得正香我还在实验室调试。在onenet的支持下我成功的做出了我的互联网+作品。多的都不说了只有技术人员能懂其中的不容易
下面来介绍一下作品组成部分:
       手环分为四部分:,北斗+GPS定位,采用中国的北斗比美国的GPS精度更高尽量降低误差;,GSM用于设备与onenet通信和基站定位,即使在没有卫星信号的情况下也可以定位;,stm32c8t6主控,高达72M主频,保证能快速处理各项数据但是我降低了频率,其中的原因后面再说先卖个关子:心率检测,由于学生党经济条件有限用了某宝比较便宜的光电反射式心率模块,实际使用过程检测数据还是比较准确的。


基本原理及基本:

      1. 北斗+GPS定位,通过串口发送到单片机,单片机简析串口收到的数据,通过简单的算法之后算出大致经纬度;2.单片机AD检测心率模块模拟量输出,通过一系列算法得出心率;3.数据整合打包通过GSM上传至onenet之后再调用地图纠偏在地图上显示原始的坐标位置。


下面是最激动的制作过程:

1,先用模块搭建一个简易测试平台,写出代码的大致结构。


这是用模块搭建的测试

这是用模块搭建的测试


2,有了前面的基础就开始设计电路,原理图到PCB。   现在想想还是很不错的哈
QQ截图20170725202116.jpg QQ截图20170725202247.jpg


3,拿到心率模块了,先上示波器看看波形,哈哈怎么有种医院心点图的感觉。

心率波形,有没有种医院做心电图的感觉

心率波形,有没有种医院做心电图的感觉


4,打样回来的PCB,看着上面的0603有点蛋疼啊。

打回来的样板

打回来的样板



废话不多说开始焊接


IMG_20170610_203948.jpg

全部0603贴片,手动贴片贴的美滋滋

全部0603贴片,手动贴片贴的美滋滋

设计上面的失误,忘了留串口还好留了SWD。

设计上面的失误,忘了留串口还好留了SWD。


经过一上午的努力终于焊接好了,由于串口被占用只能用SW模式下载程序了

串口被占用了只好用ST-Link下载代码

串口被占用了只好用ST-Link下载代码




完全焊接好之后

完全焊接好之后



下面来回答前面买的关子,为什么要降频呢?
答:说实话STM32功耗真的好高,不适合做穿戴设备主控。前期没有想到功耗问题现在想换MSP430但是板子都打样回来了,学生党穷舍不得在打一次,也不能浪费这个板子就将就用吧,办法都是人想出来的STM32有那么多低功耗模式但是都是休眠了。不能及时处理MC20过来的数据,只有选择降频运行来降低功耗。说这么多还不如来点实际的来看看怎么 降低频率

只需要把#define SYSCLK_FREQ_72MHz  72000000   这段注释掉
取消     # define SYSCLK_FREQ_24MHz  24000000   的注释就行
QQ截图20170725204636.jpg

本来想用3D打印一个外壳的,结构有点复杂暂时没有画出来就先不打印外壳了。先去学学UG,等画出来在来跟新。部分调试过程在后面回复帖子里面有。













pcb文件.rar

493.18 KB, 下载次数: 2639

原理图.rar

164.27 KB, 下载次数: 2625

经过长时间的调试,最终确定硬件方面没有问题

源代码.rar

2.02 MB, 下载次数: 2608

代码有点bug后面还在修复

回复

举报

0

主题

4

帖子

12

积分

新手上路

Rank: 1

积分
12
发表于 2019-3-30 09:53:25 | 显示全部楼层
82****@qq.com 发表于 2018-10-6 20:40
请问一下地图纠偏是怎么做的呢?谢谢

这是之前的账号  手机号没用了 无法登陆,地图纠偏是ONENET自己就处理了的,我们只需要把GPS的信息转换成度分秒格式上传就好了

0

主题

1

帖子

5

积分

新手上路

Rank: 1

积分
5
发表于 2018-10-6 20:40:17 | 显示全部楼层
请问一下地图纠偏是怎么做的呢?谢谢

0

主题

2

帖子

3

积分

新手上路

Rank: 1

积分
3
发表于 2018-5-15 16:52:04 | 显示全部楼层
楼主 我们能加QQ详聊么 ;我自己也在做 有问题想咨询你 我QQ543407156

0

主题

1

帖子

6

积分

新手上路

Rank: 1

积分
6
发表于 2017-7-10 16:13:01 | 显示全部楼层
以前经常去川教踢球,楼主是遂宁人么?

14

主题

94

帖子

289

积分

中级会员

Rank: 3Rank: 3

积分
289
发表于 2017-7-6 10:42:33 | 显示全部楼层
多谢分享,开发过程的描述可以再详细点,期待后期继续跟新

94

主题

570

帖子

2182

积分

金牌会员

Rank: 5Rank: 5

积分
2182
发表于 2017-7-5 13:55:01 | 显示全部楼层
不错不错,期待楼主做出更多有意思的东西跟我们分享
1、OneNET交流群6:887624121
该群目前非常活跃,欢迎大家参与进来,交流,讨论,答疑,解惑~~

1

主题

18

帖子

41

积分

新手上路

Rank: 1

积分
41
 楼主| 发表于 2017-7-7 10:32:31 | 显示全部楼层
先在开发板上面搭建一个测试品台,测试一下心率模块
IMG_20170620_001141.jpg

1

主题

18

帖子

41

积分

新手上路

Rank: 1

积分
41
 楼主| 发表于 2017-7-7 10:26:22 | 显示全部楼层
liuyi618 发表于 2017-7-6 10:42
多谢分享,开发过程的描述可以再详细点,期待后期继续跟新

后期会贴出关键代码

1

主题

18

帖子

41

积分

新手上路

Rank: 1

积分
41
 楼主| 发表于 2017-7-11 20:56:24 | 显示全部楼层
healthcare 发表于 2017-7-11 17:54
大哥,能不能把你的工程发我。我想好好参考一下。对这方面学的时间不长,太差。谢谢啦。或者我买也行,总之 ...

不知道你是要pcb工程还是源代码,源代码的话还没有写完还在不断完善中。。。

0

主题

1

帖子

2

积分

新手上路

Rank: 1

积分
2
发表于 2017-7-11 10:10:46 | 显示全部楼层
好东西,希望楼主开源

1

主题

18

帖子

41

积分

新手上路

Rank: 1

积分
41
 楼主| 发表于 2017-7-7 14:22:05 | 显示全部楼层
检测的心率值通过串口打印输出  
QQ截图20170707141951.jpg

1

主题

18

帖子

41

积分

新手上路

Rank: 1

积分
41
 楼主| 发表于 2017-7-7 14:26:57 | 显示全部楼层
本帖最后由 胥豪 于 2017-7-7 14:28 编辑
  1. void TIM3_IRQHandler()
  2. {
  3.         unsigned int runningTotal;
  4.         unsigned char i;
  5.          TIM_ClearFlag(TIM3,TIM_FLAG_Update);                 

  6.     ADC_SoftwareStartConvCmd(ADC1, ENABLE);
  7. //          while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
  8.                 Signal=ADC_GetConversionValue(ADC1);                                         // read the Pulse Senso
  9.                 sampleCounter += 2;                         // keep track of the time in mS with this variable
  10.                 Num = sampleCounter - lastBeatTime;       // monitor the time since the last beat to avoid noise
  11. //                HAL_ADC_Start(&hadc1);                                                                        //restart ADC conversion
  12.    ADC_ResetCalibration(ADC1);

  13.                 //  find the peak and trough of the pulse wave
  14.   if(Signal < thresh && Num > (IBI/5)*3){       // avoid dichrotic noise by waiting 3/5 of last IBI
  15.     if (Signal < T){                        // T is the trough
  16.       T = Signal;                         // keep track of lowest point in pulse wave
  17.     }
  18.   }

  19.   if(Signal > thresh && Signal > P){          // thresh condition helps avoid noise
  20.     P = Signal;                             // P is the peak
  21.   }                                        // keep track of highest point in pulse wave

  22.   //  NOW IT'S TIME TO LOOK FOR THE HEART BEAT
  23.   // signal surges up in value every time there is a pulse
  24.   if (Num > 250){                                   // avoid high frequency noise
  25.     if ( (Signal > thresh) && (Pulse == false) && (Num > (IBI/5)*3) ){        
  26.       Pulse = true;                               // set the Pulse flag when we think there is a pulse
  27.       GPIO_ResetBits(GPIOE,LED2);                // turn on pin 13 LED
  28.       IBI = sampleCounter - lastBeatTime;         // measure time between beats in mS
  29.       lastBeatTime = sampleCounter;               // keep track of time for next pulse

  30.       if(secondBeat){                        // if this is the second beat, if secondBeat == TRUE
  31.         secondBeat = false;                  // clear secondBeat flag
  32.         for(i=0; i<=9; i++){             // seed the running total to get a realisitic BPM at startup
  33.           rate[i] = IBI;                     
  34.         }
  35.       }

  36.       if(firstBeat){                         // if it's the first time we found a beat, if firstBeat == TRUE
  37.         firstBeat = false;                   // clear firstBeat flag
  38.         secondBeat = true;                   // set the second beat flag
  39. //       sei();                               // enable interrupts again
  40.         return;                              // IBI value is unreliable so discard it
  41.       }   


  42.       // keep a running total of the last 10 IBI values
  43.       runningTotal = 0;                  // clear the runningTotal variable   

  44.       for(i=0; i<=8; i++){                // shift data in the rate array
  45.         rate[i] = rate[i+1];                  // and drop the oldest IBI value
  46.         runningTotal += rate[i];              // add up the 9 oldest IBI values
  47.       }

  48.       rate[9] = IBI;                          // add the latest IBI to the rate array
  49.       runningTotal += rate[9];                // add the latest IBI to runningTotal
  50.       runningTotal /= 10;                     // average the last 10 IBI values
  51.       BPM = 60000/runningTotal;               // how many beats can fit into a minute? that's BPM!
  52.                         if(BPM>200)BPM=200;                        
  53.                         if(BPM<30)BPM=30;                              
  54.                         sprintf(tstr,"%d",BPM);
  55.       QS = true;                              // set Quantified Self flag
  56.       // QS FLAG IS NOT CLEARED INSIDE THIS ISR
  57.     }                       
  58.   }

  59.   if (Signal < thresh && Pulse == true){   // when the values are going down, the beat is over
  60.      GPIO_SetBits(GPIOE,LED2);            // turn off pin 13 LED
  61.     Pulse = false;                         // reset the Pulse flag so we can do it again
  62.     amp = P - T;                           // get amplitude of the pulse wave
  63.     thresh = amp/2 + T;                    // set thresh at 50% of the amplitude
  64.     P = thresh;                            // reset these for next time
  65.     T = thresh;
  66.   }

  67.   if (Num > 2500){                           // if 2.5 seconds go by without a beat
  68.     thresh = 512;                          // set thresh default
  69.     P = 512;                               // set P default
  70.     T = 512;                               // set T default
  71.     lastBeatTime = sampleCounter;          // bring the lastBeatTime up to date        
  72.     firstBeat = true;                      // set these to avoid noise
  73.     secondBeat = false;                    // when we get the heartbeat back
  74.   }

  75. }
复制代码

1

主题

18

帖子

41

积分

新手上路

Rank: 1

积分
41
 楼主| 发表于 2017-7-7 14:29:45 | 显示全部楼层

2ms中断一次检测心率模块AD电压值,计算其心率值。

1

主题

18

帖子

41

积分

新手上路

Rank: 1

积分
41
 楼主| 发表于 2017-7-9 14:39:37 | 显示全部楼层
本帖最后由 胥豪 于 2017-7-21 08:55 编辑

解析GPS数据,提取位置信息,移动速度,心率。打包上传onenet平台。
  1. void parseGpsBuffer()
  2. {
  3.         char *subString;
  4.         char *subStringNext;
  5.         char i = 0;
  6.         if (Save_Data.isGetData)
  7.         {
  8.                 Save_Data.isGetData = false;
  9.                 printf("**************\r\n");
  10.                 printf(Save_Data.GPS_Buffer);


  11.                 for (i = 0 ; i <= 7 ; i++)
  12.                 {
  13.                         if (i == 0)
  14.                         {
  15.                                 if ((subString = strstr(Save_Data.GPS_Buffer, ",")) == NULL)
  16.                                         errorLog(1);        //½âÎö´íÎó
  17.                         }
  18.                         else
  19.                         {
  20.                                 subString++;
  21.                                 if ((subStringNext = strstr(subString, ",")) != NULL)
  22.                                 {
  23.                                         char usefullBuffer[2];
  24.                                         switch(i)
  25.                                         {
  26.                                                 case 1:memcpy(Save_Data.UTCTime, subString, subStringNext - subString);break;        
  27.                                                 case 2:memcpy(usefullBuffer, subString, subStringNext - subString);break;            
  28.                                                 case 3:memcpy(Save_Data.latitude, subString, subStringNext - subString);break;        
  29.                                                 case 4:memcpy(Save_Data.N_S, subString, subStringNext - subString);break;            
  30.                                                 case 5:memcpy(Save_Data.longitude, subString, subStringNext - subString);break;        
  31.                                                 case 6:memcpy(Save_Data.E_W, subString, subStringNext - subString);break;         
  32.                                                 case 7:memcpy(Save_Data.Speed, subString, subStringNext - subString);break;
  33.                                                 default:break;
  34.                                         }

  35.                                         subString = subStringNext;
  36.                                         Save_Data.isParseData = true;
  37.                                         if(usefullBuffer[0] == 'A')
  38.                                                 Save_Data.isUsefull = true;
  39.                                         else if(usefullBuffer[0] == 'V')
  40.                                                 Save_Data.isUsefull = false;

  41.                                 }
  42.                                 else
  43.                                 {
  44.                                         errorLog(2);
  45.                                 }
  46.                         }


  47.                 }
  48.         }
  49. }
复制代码
GPS解析部分源码。


上传onenet源码,串口1与GPS模块通信,并发送调试信息到电脑串口,串口2与GSM通信上传数据。


  1. void OneNet()
  2. {
  3.         char i;
  4.         double j,k;
  5.         Speed1=atof(Save_Data.Speed);
  6.         
  7.         if (sendCommand("AT+CIPSTART=TCP,183.230.40.33,80\r\n","CONNECT", 30000, 10) == Success);
  8.         else errorLog(4);
  9.         delay_ms(10);

  10.         if (sendCommand("AT+CIPSEND\r\n",">", 1000, 10) == Success);
  11.         else errorLog(4);
  12.         delay_ms(10);
  13.         
  14.         j=longitudeToOnenetFormat(Save_Data.longitude);        //ת»»×ø±ê
  15.         k=latitudeToOnenetFormat(Save_Data.latitude);
  16. //        sprintf(test,"{\"datastreams\":[{\"id\":\"location\",\"datapoints\":[{\"value\":{\"lon\":%0.10f,\"lat\":%0.10f}}]}]}",j,k);
  17.         sprintf(test,"{\"location\":{\"lon\":%0.10f,\"lat\":%0.10f},\"xinlv\":\"%d\",\"sudu\":\"%0.2f\"}",j,k,BPM,Speed1);
  18.         i=strlen(test);
  19.         u2_printf("POST /devices/********/datapoints?type=3 HTTP/1.1\r\n");      //**符号为自己的设备ID
  20.         printf("POST /devices/*********/datapoints?type=3 HTTP/1.1\r\n");
  21.         u2_printf("api-key: *************************\r\n");                                     //这里的**是api-key
  22.         printf("api-key: ************************\r\n");        //UART1
  23.         u2_printf("Host: api.heclouds.com\r\n");
  24.         printf("Host: api.heclouds.com\r\n");                      //UART1
  25.         sprintf(tmp,"Content-Length: %d\r\n",i);
  26.         u2_printf(tmp);
  27.         printf(tmp);            //UART1
  28.         u2_printf("\r\n");
  29.         printf("\r\n");
  30.         u2_printf(test);
  31.         printf(test);                                               //UART1
  32.         u2_printf("\r\n");
  33.         printf("\r\n");                                            //UART1
  34.         USART_SendData(USART2,0x1a);
  35.         USART_SendData(USART1,0x1a);
  36.         delay_ms(1000);
  37.                                 if (strstr(USART2_RX_BUF, "OK\r\n") != NULL)
  38.                         {                                
  39.                                 printf("\r\n***************receive****************\r\n");
  40.                                 printf(USART2_RX_BUF);
  41.                                 USART2_CLR_Buf();
  42.                         }
  43.                         delay_ms(1000);
  44.                 if (sendCommand("AT+CIPCLOSE\r\n", "OK\r\n", 1500, 10) == Success);
  45.         else errorLog(5);
  46.         delay_ms(10);
  47.         
  48. }
复制代码


QQ截图20170709143002.jpg
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

快速回复 返回顶部 返回列表