万利LPC54102开发板的心率计Heartrate应用笔记例程移植分析
AN11608_Heart-rate Monitor using the Low Power LPC5410x演示了使用LPC54102和PulseSensorAMped!作为心率计的应用。
由于万里开发板的不同设置,以及没有PulseSensor传感器,需要做一定的修改移植,使用万利开发板上的AIN1作为模拟输入,电位器的来回旋转代表心跳的变化。
1、代码修改
由于万利开发板使用PIO1_4/AIN7作为电位器输入,因此在初始化代码中,做了如下修改:
其中在board.h中,取消了BOARD_NXP_LPCXPRESSO_54102的定义,而是重新定义了BOARD_MANLEY_LPC54102。
并在各个初始化代码中,增加了针对万利开发板的初始化代码。
#if defined(BOARD_NXP_LPCXPRESSO_54102)
/* SEQ_A enables channels 0, 3 and 4; Uses software trigger; doesn't use BURST */
#define ADC_SEQ_A_CONFIG \
TRIG_SOFT | /* Software trigger for SEQ_A */ \
TRIG_POL_POS | /* UM recommends this for S/W trigger */ \
MODE_EOS | /* Event generated after Sequence done */ \
ENABLE_CH(3) /* Associate channels 3 to SEQ_A */
#elif defined(BOARD_MANLEY_LPC54102)
#define ADC_SEQ_A_CONFIG \
TRIG_SOFT | /* Software trigger for SEQ_A */ \
TRIG_POL_POS | /* UM recommends this for S/W trigger */ \
MODE_EOS | /* Event generated after Sequence done */ \
ENABLE_CH(7) /* Associate channels 7 to SEQ_A */
#endif // #if defined(BOARD_xxx)
static void ADC_PinMuxSetup(void)
{
#if defined(BOARD_NXP_LPCXPRESSO_54102)
/* All pins to inactive, neither pull-up nor pull-down. */
Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 0, IOCON_MODE_INACT | IOCON_FUNC1 | IOCON_ANALOG_EN);
#elif defined(BOARD_MANLEY_LPC54102)
/* All pins to inactive, neither pull-up nor pull-down. */
Chip_IOCON_PinMuxSet(LPC_IOCON, 1, 4, IOCON_MODE_INACT | IOCON_FUNC1 | IOCON_ANALOG_EN);
#endif
}
2、运行
其余基本不变,下载后,将电位器来回旋转,可以看到串口输出了心跳数据。
3、代码分析
该应用基本采用CM4初始化后即进入休眠。
CM0+核初始化ADC、Timer之后,进入休眠。
每秒20次唤醒后,采样ADC,当采样过半时,调用Compute_Heartrate算法计算是否产生心跳以及心跳间隔IBI。当发现后即输出串口信息。
关键在于Compute_Heartrate算法,该算法采用PulseSensor官方的算法,基本是通过判断ADC模拟量发现峰值、过半点等运算。
- void Compute_Heartrate(void)
- {
- int i, N, Signal, runningTotal, current_sample = 0;
-
- while(current_sample < SAMPLE_FREQUENCY/2){
- Signal = temp_data[current_sample];
-
- /* Keep track of time in milliseconds with sampleCounter variable */
- sampleCounter = sampleCounter + 50;
-
- /* Monitor the time since last beat to avoid noise */
- N = sampleCounter - lastBeatTime;
- /* Find the peak and trough of the pulse wave, avoid dichrotic noise by waiting 3/5 of last IBI */
- if(Signal < thresh && N > (IBI/5)*3){
- if (Signal < T){
- /* Keep track of lowest point in pulse wave in the T variable */
- T = Signal;
- }
- }
-
- /* Use threshold condition to filter out noise, store peak in P */
- if(Signal > thresh && Signal > P){
- P = Signal;
- }
- /* Analyze the data to find heartbeat */
- if (N > 500){
- /* Avoid high frequency noise */
- if ( (Signal > thresh) && (Pulse == 0) && (N > (IBI/5)*3) ){
- Pulse = 1;
- IBI = sampleCounter - lastBeatTime;
- lastBeatTime = sampleCounter;
-
- if(secondBeat){
- secondBeat = 0;
- for(i=0; i<=9; i++){
- rate[i] = IBI;
- }
- }
- if(firstBeat){
- firstBeat = 0;
- secondBeat = 1;
- continue;
- }
- /* Keep a running total of the last 10 IBI values */
- runningTotal = 0;
- for(i=0; i<=8; i++){
- rate[i] = rate[i+1];
- runningTotal += rate[i];
- }
-
- /* Average the latest IBI values and calculate the BPM */
- rate[9] = IBI;
- runningTotal += rate[9];
- runningTotal /= 10;
- BPM = 60000/runningTotal;
- QS = 1;
- }
- }
- /* Once the beat is over, reset values */
- if (Signal < thresh && Pulse == 1){
- Pulse = 0;
- amp = P - T;
- thresh = amp/2 + T;
- P = thresh;
- T = thresh;
- }
- /* If we do not detect a heart beat in 2.5 seconds, reset all values */
- if (N > 2500){
- thresh = 2548;
- P = 2548;
- T = 2548;
- lastBeatTime = sampleCounter;
- firstBeat = 1;
- secondBeat = 0;
- }
- current_sample++;
- }
- }
复制代码