6431|2

217

帖子

0

TA的资源

一粒金砂(高级)

楼主
 

MAX32630FTHR板的学习(二):AD测量和心率传感器pulsesensor使用 [复制链接]

本帖最后由 anning865 于 2017-7-15 09:43 编辑

在上一篇中,已经使用了MBED平台点亮了MAX32630FTHR板自带的LED流水灯,初步摸清了该板的编译下载环境,接下来这篇主要讲MAX32630FTHR板上的ADC使用,以及采用了一款心率传感器pulsesensor来完成整个心率采集和显示功能。


ADC漫谈:在第一篇帖子中谈到,MAX32630这款芯片拥有强大的数据处理和储存能力,但相对应的ADC显得弱鸡了一些。该ADC类型是 Delta-Sigma,分辨率为10bit,最高时钟8MHz(采样率最高7.8ksps),外部输入通道只有4个,不支持DMA功能,这个配置与同类型绝大多数的ARM内核MCU相比都是相形见绌的。但是考虑到该芯片强大的数字接口和超小的封装后就可以发现,这款芯片真的是针对可穿戴设备和便携式设备来做的。在可穿戴设备领域,由于对功耗和体积的要求,绝大部分的传感器接口已经都是数字化了,而相应的模拟部分变得很少,可能最大的应用就是电池电压和电量监控了。所以MAX32630这款芯片可以明显感觉到其数字能力得到了强化而相应的模拟能力却进行了弱化,然而在可穿戴领域这样的模拟功能可以说是够用了,因此我们可以说这款芯片的市场定位是非常清晰而明确的,如果你非要将这款芯片用在数据采集领域,那就真的用错了地方。


实验背景介绍:这次使用我比较熟悉而且现成可用的心率传感器Pulsesensor来进行实验。

PulseSensor是一款用于脉搏心率测量、脉搏波形测量和HRV分析的光电反射式模拟传感器。将其佩戴于手指、耳垂等处,通过导线连接可将采集到的模拟信号传输给类似Arduino等单片机用来转换为数字信号,再通过单片机的简单计算后就可以得到心率数值,此外还可将脉搏波形通过串口上传到电脑显示波形。




图1:pulsesensor心率传感器


传感器的具体参数为:
电路板直径:16mm
电路板厚度:1.2mm
LED峰值波长:515nm
供电电压:3.3~5v
检测信号类型:光反射信号(PPG)
输出信号类型:模拟信号
信号放大倍数:330
输出信号大小:0~VCC
电流大小:~4ma(5v)



整个传感器一共就三个引脚,电源VCC,地GND和模拟输出S,所以在硬件上只需要连接到MAX32630的一个外部ADC接口就可以了。本来以为蛮简单的一个事情,实际在操作过程中还是遇到了一些“坑”。






实验过程:

坑1:MAX14690的电源输出

从MAX32630FTHR板的硬件原理图上可以看出J1的第2脚是输出3.3V的。从Pulsesensor的参数来看,输入电压可以是3.3~5V的,因此最开始决定就用板子上的3.3V来给心率传感器供电。但是在MBED上编写好相应的程序并下载进板子后,接上心率传感器,却发现传感器的绿灯LED不亮!经过测量后发现3.3V引脚没有电压输出,因此没有驱动传感器发光!





图2:MAX32630FTHR板引脚图(MBED平台)

翻看MAX32630FTHR板的原理图,发现此3.3v是由MAX14690电源管理芯片控制输出的。MAX14690芯片是一款很强大的电源管理IC,其除了可以进行锂电池充电管理和监控外,还可以实现5路电源输出,包括2路buck开关电源和3路LDO线性电源。其中J1的第2脚3.3V就是LDO3输出的,而且此电压是可通过I2C总线写入寄存器的方式调节的。所以如果上电后不对MAX14690进行相应寄存器的写入就无法得到相应的输出电压。



图3:MAX32630FTHR板原理图

幸运的是,在MBED平台上已经提供了MAX14690相应的库文件,被包含在了MAX32630FTHR库文件中,因此在建立工程的时候需要添加进来。并在主文件中添加“MAX32630FTHR pegasus(MAX32630FTHR::VIO_3V3);”。这样在初始化的时候,LDO3就会默认输出3.3v。







图4:MBED程序框架图

坑2:ADC的量程设置

解决了第一个问题,MAX32630FTHR板可以正常输出3.3V了。这时需要考虑心率传感器的输出需要接到ADC的哪个通道,而且AD的量程是否合适。根据随板子提供的引脚卡片图5(很奇怪此图和MBED网站上引脚图图4在AD部分不一致),AIN0~AIN3的量程是1.2V,同时AIN0和AIN1引脚还可以测量到5V电压,不过引脚号就变成AIN4和AIN5了。说实话只看这些信息还是让人摸不到头脑应该如何使用,只能再去翻翻芯片的使用手册了。



图5:MAX32630FTHR板引脚图(随板附带卡片)

根据芯片使用手册上的ADC内部结构图(图6)和AD使用说明(图7)可以看出来,该芯片只有四个外部ADC通道0~3,如果在不外接基准源的情况下,芯片ADC使用内部基准源1.2V,所以量程是到1.2V。但是通道4和5是将通道0和1的电压降低为1/5后再输入ADC进行测量的,所以在通道0和1可以承受5V电压的情况下(根据图8,AIN0和1可以承受5.5V),AIN4和AIN5的量程相当于扩大了,如果要测量0~5V范围内的信号需要在程序中使用AIN4或者AIN5来进行编程。此外还有一点要注意,根据图7的计算公式可以看到,AIN0~3的量程可以是0~1.2V(adc_scale==1)或者是0~0.6V(adc_scale==0 );而AIN4和5的量程是0~6V,虽然引脚AIN0最大只能承受5.5V,但是这时AD的转化结果1023代表6V,这点容易被忽略。



图6:ADC内部结构图


图7:AD使用说明


图8:ADC极限电气参数

综合上面的信息,如果使用3.3V给心率传感器供电,其输出电压最高可能到3.3V,那就必须使用AIN4或者AIN5来进行AD采样和转化。此外为了更好地对脉搏信号进行测量,发现可以使用板子上的另一个电源输出引脚VBUS(J3的第3脚)来对心率传感器进行供电,因为此引脚是USB电源引脚,电压稳定在5V左右。



最后的硬件连接方式为:
pulsesensor<->MAX32630FTHR板
S<->AIN4
VCC<->VBUS
GND<->GND


实验结果:

在MBED平台上移植并修改心率采集和计算的程序,并将脉搏波形通过串口以115200速率上传到PC端的Processing软件并显示。


下位机程序如下:
  1. #include "mbed.h"
  2. #include "max32630fthr.h"

  3. #define false 0
  4. #define true 1
  5. MAX32630FTHR pegasus(MAX32630FTHR::VIO_3V3);
  6. Ticker tick;
  7. DigitalOut led1(LED1);//led blinking with heart beat
  8. AnalogIn pulsepin(AIN_4);//analog input pin
  9. Serial pc(USBTX, USBRX);//USB TO SERIAL

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

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

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

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

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

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

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


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

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

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

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

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

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

  116.         //ledFadeToBeat();
  117.         wait(0.02);                             //  take a break
  118.     }
  119. }
复制代码

程序的主要思想:pulsesensor传感器根据返回的光强,输出脉搏的电压波形曲线。下位机采样电压曲线,并数字化后发送到上位机显示,同时下位机随时计算相邻两个脉搏波的峰值点的时间差并滤波,得到两次心跳之间的时间,即IBI数值;心率值BPM=60/IBI,就可以通过计算后得出。


通过串口输出数据主要有三类:“S”为前缀的,表示脉搏波电压数据(脉象图的数值化表示);以“B”为前缀的,表示BPM数值(心率值);以“Q”为前缀的,表示IBI数值(相邻两个心跳之间的时间)。下图(图9)是用串口调试软件截图得到的,可以看到三类数据。




图9:脉搏数据通过串口显示

此外,还可以使用开源的Processing上位机软件和程序对数据进行可视化显示,见下图(图10)



图10:processing显示的脉搏波形和心率数值

在MAX32630FTHR板上,还使用了LED1来显示用户的心跳情况,LED1的闪烁完全跟随用户的心跳,最终的实验效果可以看下面的实验视频:

查看本帖全部内容,请登录或者注册
点赞 关注
个人签名心率传感器:https://shop108071095.taobao.com
 

回复
举报

217

帖子

0

TA的资源

一粒金砂(高级)

沙发
 
不知道为何优酷视频播放不出来,我把地址放出来http://v.youku.com/v_show/id_XMj ... 0.0&from=s1.8-1-1.2
个人签名心率传感器:https://shop108071095.taobao.com
 
 

回复

217

帖子

0

TA的资源

一粒金砂(高级)

板凳
 
自己总结一下;
总结:
1.MAX32630的模拟功能较弱,数字功能较强,针对可穿戴领域进行了特别设计
2.板载的MAX14690电源管理芯片有5路可控电源输出,上电要调用库文件通过I2C总线写入寄存器,不然板上的3.3V没有输出
3.ADC的量程有多个范围可选,配置时需要注意
4.使用MAX32630FTHR板可以成功驱动心率传感器pulse sensor,得到心率数值和脉搏曲线
个人签名心率传感器:https://shop108071095.taobao.com
 
 
 

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

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条
【回帖赢京东卡】说说无线技术那些事儿
即日起—2月28日,参与回帖讨论都有机会赢取【30元京东卡】

查看 »

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

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

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

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

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