首先感谢论坛的这次团购,让我们可以使用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
将原有的arduino程序移植过来,如下:
- #include "mbed.h"
- #define false 0
- #define true 1
- Ticker tick;
- DigitalOut led1(LED1);
- //DigitalOut led2(PTA13);
- AnalogIn pulsepin(A0);//analog input pin
- Serial pc(SERIAL_TX, SERIAL_RX);//USB TO SERIAL
- // these variables are volatile because they are used during the shorterrupt service routine!
- volatile short BPM; // used to hold the pulse rate
- volatile short Signal; // holds the incoming raw data
- volatile short IBI = 600; // holds the time between beats, must be seeded!
- volatile char Pulse = false; // true when pulse wave is high, false when it's low
- volatile char QS = false; // becomes true when Arduoino finds a beat.
- volatile short rate[10]; // array to hold last ten IBI values
- volatile unsigned long sampleCounter = 0; // used to determine pulse timing
- volatile unsigned long lastBeatTime = 0; // used to find IBI
- volatile short P =512; // used to find peak in pulse wave, seeded
- volatile short T = 512; // used to find trough in pulse wave, seeded
- volatile short thresh = 512; // used to find instant moment of heart beat, seeded
- volatile short amp = 100; // used to hold amplitude of pulse waveform, seeded
- volatile char firstBeat = true; // used to seed rate array so we startup with reasonable BPM
- volatile char secondBeat = false; // used to seed rate array so we startup with reasonable BPM
- //void ledFadeToBeat()
- //{
- // fadeRate -= 15; // set LED fade value
- // fadeRate = constrain(fadeRate,0,255); // keep LED fade value from going shorto negative numbers!
- // analogWrite(fadePin,fadeRate); // fade LED
- //}
- void timer_isr(void)
- {
- //cli(); // disable shorterrupts while we do this
-
- Signal = pulsepin.read_u16()>>6; // read the Pulse Sensor
- sampleCounter += 2; // keep track of the time in mS with this variable
- short N = sampleCounter - lastBeatTime; // monitor the time since the last beat to avoid noise
- // find the peak and trough of the pulse wave
- if(Signal < thresh && N > (IBI/5)*3) { // avoid dichrotic noise by waiting 3/5 of last IBI
- if (Signal < T) { // T is the trough
- T = Signal; // keep track of lowest poshort in pulse wave
- }
- }
- if(Signal > thresh && Signal > P) { // thresh condition helps avoid noise
- P = Signal; // P is the peak
- } // keep track of highest poshort in pulse wave
- // NOW IT'S TIME TO LOOK FOR THE HEART BEAT
- // signal surges up in value every time there is a pulse
- if (N > 250) { // avoid high frequency noise
- if ( (Signal > thresh) && (Pulse == false) && (N > (IBI/5)*3) ) {
- Pulse = true; // set the Pulse flag when we think there is a pulse
- led1=1; // turn on pin 13 LED
- IBI = sampleCounter - lastBeatTime; // measure time between beats in mS
- lastBeatTime = sampleCounter; // keep track of time for next pulse
- if(secondBeat) { // if this is the second beat, if secondBeat == TRUE
- secondBeat = false; // clear secondBeat flag
- for(short i=0; i<=9; i++) { // seed the running total to get a realisitic BPM at startup
- rate[i] = IBI;
- }
- }
- if(firstBeat) { // if it's the first time we found a beat, if firstBeat == TRUE
- firstBeat = false; // clear firstBeat flag
- secondBeat = true; // set the second beat flag
- //sei(); // enable shorterrupts again
- return; // IBI value is unreliable so discard it
- }
- // keep a running total of the last 10 IBI values
- unsigned short runningTotal = 0; // clear the runningTotal variable
- for(short i=0; i<=8; i++) { // shift data in the rate array
- rate[i] = rate[i+1]; // and drop the oldest IBI value
- runningTotal += rate[i]; // add up the 9 oldest IBI values
- }
- rate[9] = IBI; // add the latest IBI to the rate array
- runningTotal += rate[9]; // add the latest IBI to runningTotal
- runningTotal /= 10; // average the last 10 IBI values
- BPM = 60000/runningTotal; // how many beats can fit shorto a minute? that's BPM!
- QS = true; // set Quantified Self flag
- // QS FLAG IS NOT CLEARED INSIDE THIS ISR
- }
- }
- if (Signal < thresh && Pulse == true) { // when the values are going down, the beat is over
- led1=0; // turn off pin 13 LED
- Pulse = false; // reset the Pulse flag so we can do it again
- amp = P - T; // get amplitude of the pulse wave
- thresh = amp/2 + T; // set thresh at 50% of the amplitude
- P = thresh; // reset these for next time
- T = thresh;
- }
- if (N > 2500) { // if 2.5 seconds go by without a beat
- thresh = 512; // set thresh default
- P = 512; // set P default
- T = 512; // set T default
- lastBeatTime = sampleCounter; // bring the lastBeatTime up to date
- firstBeat = true; // set these to avoid noise
- secondBeat = false; // when we get the heartbeat back
- }
- //sei(); // enable shorterrupts when youre done!
- }
- void sendDataToProcessing(char symbol, short data )
- {
- pc.putc(symbol); // symbol prefix tells Processing what type of data is coming
- pc.printf("%d\r\n", data); // the data to send culminating in a carriage return
- }
- int main()
- {
- pc.baud(115200); // we agree to talk fast!
- tick.attach_us(&timer_isr,2000); // sets up to read Pulse Sensor signal every 2mS
- while(1) {
- sendDataToProcessing('S', Signal); // send Processing the raw Pulse Sensor data
- if (QS == true) { // Quantified Self flag is true when arduino finds a heartbeat
- //fadeRate = 255; // Set 'fadeRate' Variable to 255 to fade LED with pulse
- sendDataToProcessing('B',BPM); // send heart rate with a 'B' prefix
- sendDataToProcessing('Q',IBI); // send time between beats with a 'Q' prefix
- QS = false; // reset the Quantified Self flag for next time
- }
- //ledFadeToBeat();
- wait(0.02); // take a break
- }
- }
MBED平台下载程序很简单,只需要将编译产生的文件拖进开发板在电脑上显示的U盘空间中就可以了。
程序中以500hz频率进行AD采集,将数据滤波处理后通过串口发送到电脑上,同时板子上的LD2小灯会跟随心跳频率闪烁。
上位机软件采用开源软件processing,程序可以在pulsesensor官网下载得到。直接运行后可以看到采集到脉搏波形和心率数值。
最后附上演示视频:
可以看到心率值可以正常读取。下一步准备加上OLED模块显示心率数值。