[原创] 【Nucleo心得】+脉搏心率监测实验

anning865   2014-10-10 22:37 楼主

首先感谢论坛的这次团购,让我们可以使用ST的Nucleo开发板来尽情发挥自己的设计。



       之前玩过ST的几块discovery板子,功能都很强大,板子上都有一些可以体现其芯片特色的外设设备。而这次拿到的Nucleo开发板的设计理念并不一样,其并没有扩展外设,而是将接口尽可能地自由发挥出来,留给了用户更大的自由度。其接口兼容arduino板子接口,而编程环境可以使用Mbed网上平台,风格十分类似arduino,因此玩过arduino的玩家可以很快上手mbed开发平台,将其原有的arduino设计轻松转移到Mbed平台。
之前已经在Mbed平台下玩过了KL25Z开发板,发现Mbed平台具有诸多优点,无需安装,驱动完备,程序可导出在keil等平台下调试。最近更是看到ARM公司对MBED的长远规划,感觉这个平台会极大推动物联网的发展,个人比较看好,认为有替代arduino等开源平台的潜力,是实现快速成型的好平台。其他的优点就不说了,希望大家有时间和精力可以好好了解。
       言归正传,本实验使用开源脉搏心率传感器Pulse sensor配合NUCLEO-L053R8开发板实现心率监测,并在电脑上显示脉搏曲线和心率数值。pulse sensor采集脉搏的原理是使用515nm波长的绿光照射人体皮肤,由于皮肤内的血液随心脏搏动而造成反射光也出现波动,从而探测到脉搏变化,通过记录相邻两个波峰之间的时间差来计算出心率数值。
先给出两个物品的图片:
开发板和传感器
传感器一共三个引脚:模拟输出,电源输入,地
按照下面将其连接到开发板上:
pulsesensor-NUCLEO-L053R8
VOUT       ->       A0
VCC         <-      3.3V
GND        <-      GND
3_副本.jpg
将原有的arduino程序移植过来,如下:
  1. #include "mbed.h"

  2. #define false 0
  3. #define true 1
  4. Ticker tick;
  5. DigitalOut led1(LED1);
  6. //DigitalOut led2(PTA13);
  7. AnalogIn pulsepin(A0);//analog input pin
  8. Serial pc(SERIAL_TX, SERIAL_RX);//USB TO SERIAL

  9. // these variables are volatile because they are used during the shorterrupt service routine!
  10. volatile short BPM;                   // used to hold the pulse rate
  11. volatile short Signal;                // holds the incoming raw data
  12. volatile short IBI = 600;             // holds the time between beats, must be seeded!
  13. volatile char Pulse = false;     // true when pulse wave is high, false when it's low
  14. volatile char QS = false;        // becomes true when Arduoino finds a beat.
  15. volatile short rate[10];                    // array to hold last ten IBI values
  16. volatile unsigned long sampleCounter = 0;          // used to determine pulse timing
  17. volatile unsigned long lastBeatTime = 0;           // used to find IBI
  18. volatile short P =512;                      // used to find peak in pulse wave, seeded
  19. volatile short T = 512;                     // used to find trough in pulse wave, seeded
  20. volatile short thresh = 512;                // used to find instant moment of heart beat, seeded
  21. volatile short amp = 100;                   // used to hold amplitude of pulse waveform, seeded
  22. volatile char firstBeat = true;        // used to seed rate array so we startup with reasonable BPM
  23. volatile char secondBeat = false;      // used to seed rate array so we startup with reasonable BPM

  24. //void ledFadeToBeat()
  25. //{
  26. //    fadeRate -= 15;                         //  set LED fade value
  27. //    fadeRate = constrain(fadeRate,0,255);   //  keep LED fade value from going shorto negative numbers!
  28. //    analogWrite(fadePin,fadeRate);          //  fade LED
  29. //}
  30. void timer_isr(void)
  31. {
  32.     //cli();                                      // disable shorterrupts while we do this
  33.    
  34.     Signal = pulsepin.read_u16()>>6;              // read the Pulse Sensor
  35.     sampleCounter += 2;                         // keep track of the time in mS with this variable
  36.     short N = sampleCounter - lastBeatTime;       // monitor the time since the last beat to avoid noise

  37.     //  find the peak and trough of the pulse wave
  38.     if(Signal < thresh && N > (IBI/5)*3) {      // avoid dichrotic noise by waiting 3/5 of last IBI
  39.         if (Signal < T) {                       // T is the trough
  40.             T = Signal;                         // keep track of lowest poshort in pulse wave
  41.         }
  42.     }

  43.     if(Signal > thresh && Signal > P) {         // thresh condition helps avoid noise
  44.         P = Signal;                             // P is the peak
  45.     }                                        // keep track of highest poshort in pulse wave

  46.     //  NOW IT'S TIME TO LOOK FOR THE HEART BEAT
  47.     // signal surges up in value every time there is a pulse
  48.     if (N > 250) {                                  // avoid high frequency noise
  49.         if ( (Signal > thresh) && (Pulse == false) && (N > (IBI/5)*3) ) {
  50.             Pulse = true;                               // set the Pulse flag when we think there is a pulse
  51.             led1=1;                // turn on pin 13 LED
  52.             IBI = sampleCounter - lastBeatTime;         // measure time between beats in mS
  53.             lastBeatTime = sampleCounter;               // keep track of time for next pulse

  54.             if(secondBeat) {                       // if this is the second beat, if secondBeat == TRUE
  55.                 secondBeat = false;                  // clear secondBeat flag
  56.                 for(short i=0; i<=9; i++) {            // seed the running total to get a realisitic BPM at startup
  57.                     rate[i] = IBI;
  58.                 }
  59.             }

  60.             if(firstBeat) {                        // if it's the first time we found a beat, if firstBeat == TRUE
  61.                 firstBeat = false;                   // clear firstBeat flag
  62.                 secondBeat = true;                   // set the second beat flag
  63.                 //sei();                               // enable shorterrupts again
  64.                 return;                              // IBI value is unreliable so discard it
  65.             }


  66.             // keep a running total of the last 10 IBI values
  67.             unsigned short runningTotal = 0;                  // clear the runningTotal variable

  68.             for(short i=0; i<=8; i++) {               // shift data in the rate array
  69.                 rate[i] = rate[i+1];                  // and drop the oldest IBI value
  70.                 runningTotal += rate[i];              // add up the 9 oldest IBI values
  71.             }

  72.             rate[9] = IBI;                          // add the latest IBI to the rate array
  73.             runningTotal += rate[9];                // add the latest IBI to runningTotal
  74.             runningTotal /= 10;                     // average the last 10 IBI values
  75.             BPM = 60000/runningTotal;               // how many beats can fit shorto a minute? that's BPM!
  76.             QS = true;                              // set Quantified Self flag
  77.             // QS FLAG IS NOT CLEARED INSIDE THIS ISR
  78.         }
  79.     }

  80.     if (Signal < thresh && Pulse == true) {  // when the values are going down, the beat is over
  81.         led1=0;            // turn off pin 13 LED
  82.         Pulse = false;                         // reset the Pulse flag so we can do it again
  83.         amp = P - T;                           // get amplitude of the pulse wave
  84.         thresh = amp/2 + T;                    // set thresh at 50% of the amplitude
  85.         P = thresh;                            // reset these for next time
  86.         T = thresh;
  87.     }

  88.     if (N > 2500) {                          // if 2.5 seconds go by without a beat
  89.         thresh = 512;                          // set thresh default
  90.         P = 512;                               // set P default
  91.         T = 512;                               // set T default
  92.         lastBeatTime = sampleCounter;          // bring the lastBeatTime up to date
  93.         firstBeat = true;                      // set these to avoid noise
  94.         secondBeat = false;                    // when we get the heartbeat back
  95.     }
  96.     //sei();                                   // enable shorterrupts when youre done!
  97. }

  98. void sendDataToProcessing(char symbol, short data )
  99. {
  100.     pc.putc(symbol);                // symbol prefix tells Processing what type of data is coming
  101.     pc.printf("%d\r\n", data);                // the data to send culminating in a carriage return
  102. }
  103. int main()
  104. {
  105.     pc.baud(115200);             // we agree to talk fast!
  106.     tick.attach_us(&timer_isr,2000);                 // sets up to read Pulse Sensor signal every 2mS
  107.     while(1) {
  108.         sendDataToProcessing('S', Signal);     // send Processing the raw Pulse Sensor data
  109.         if (QS == true) {                      // Quantified Self flag is true when arduino finds a heartbeat
  110.             //fadeRate = 255;                  // Set 'fadeRate' Variable to 255 to fade LED with pulse
  111.             sendDataToProcessing('B',BPM);   // send heart rate with a 'B' prefix
  112.             sendDataToProcessing('Q',IBI);   // send time between beats with a 'Q' prefix
  113.             QS = false;                      // reset the Quantified Self flag for next time
  114.         }

  115.         //ledFadeToBeat();
  116.         wait(0.02);                             //  take a break
  117.     }
  118. }
MBED平台下载程序很简单,只需要将编译产生的文件拖进开发板在电脑上显示的U盘空间中就可以了。
程序中以500hz频率进行AD采集,将数据滤波处理后通过串口发送到电脑上,同时板子上的LD2小灯会跟随心跳频率闪烁。
上位机软件采用开源软件processing,程序可以在pulsesensor官网下载得到。直接运行后可以看到采集到脉搏波形和心率数值。
2.JPG
最后附上演示视频:

可以看到心率值可以正常读取。下一步准备加上OLED模块显示心率数值。




心率传感器:https://shop108071095.taobao.com

回复评论 (24)

挺不错,这个上位机软件processing我去了解下
科技改变生活
点赞  2014-10-11 13:38
不错,感谢分享
点赞  2014-10-12 10:55
你好  请问一下 为什么 要 把 AD的采样值  右移 6位呢 ?
点赞  2015-1-21 12:36
引用: 守望刺客 发表于 2015-1-21 12:36
你好  请问一下 为什么 要 把 AD的采样值  右移 6位呢 ?



AD只需要10位精度就够了,所以只取了高10位
心率传感器:https://shop108071095.taobao.com
点赞  2015-1-21 13:44
这个不错
点赞  2015-1-23 13:09
不错,上位机软件
点赞  2015-1-23 13:34
感谢分享
点赞  2015-1-25 19:33
开发简单多了 相比官方库
点赞  2015-1-26 08:18
做的挺好呀。
专业电子方案/zigbee方案设计,毕业设计。QQ:1397905781
点赞  2015-1-26 17:57
MARK
点赞  2015-6-10 13:24
有没有人用STM32写过这个啊?我移植之后发现数据时好时坏,有时心率传感器根本检测不到,不知道是不是传感器本身的问题,程序还有待研究。求大神支招
点赞  2015-6-14 08:58
谢谢分享。。
点赞  2015-6-20 12:55
引用: hozin 发表于 2015-6-14 08:58
有没有人用STM32写过这个啊?我移植之后发现数据时好时坏,有时心率传感器根本检测不到,不知道是不是传感 ...

我用CUBE的库移植过,没问题的。注意AD需使用10位精度,其他的定时器和串口都配好就没什么难度了。
心率传感器:https://shop108071095.taobao.com
点赞  2015-6-24 19:33
引用: anning865 发表于 2015-6-24 19:33
我用CUBE的库移植过,没问题的。注意AD需使用10位精度,其他的定时器和串口都配好就没什么难度了。

你应该有STM32的例程吧?能不能发给我?1107899874@qq.com
点赞  2015-6-25 19:33
引用: hozin 发表于 2015-6-25 19:33
你应该有STM32的例程吧?能不能发给我?

不好意思,此例程不公开
心率传感器:https://shop108071095.taobao.com
点赞  2015-6-25 20:29
引用: anning865 发表于 2015-6-25 20:29
不好意思,此例程不公开

其实淘宝上有例程,买模块就给,主要我的是老师买的,不好意思麻烦他,不公开就算了,过些日子就都有啦,你还是自己留着吧
点赞  2015-7-6 11:28
你好,请问一下,有没有51系列的例程??有的话可否发一份给我,邮箱:1606525735@qq.com  谢谢
点赞  2015-11-17 18:16
不错
点赞  2016-3-9 22:06
请问楼主,sampleCounter += 这一句是什么意思?注释没有看太懂。另外请问Timer中断多长时间执行一次?谢谢!
点赞  2017-5-16 13:24
12下一页
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复