本帖最后由 qiao--- 于 2024-1-28 01:24 编辑
前言:
本次测评的是基于ADC用心率算法测出人体心率
参考文章:使用 PulseSensor 脉搏传感器测量心率之一:平台搭建_pulsesenneor-CSDN博客
我使用的心率传感器
1.测试ADC能正常检测到模拟量
1.1在msp.c文件中初始化引脚
这里我使用的的是ADC1,引脚用的是PA0
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
uint32_t i;
GPIO_InitTypeDef GPIO_Handle;
uint32_t ADC_Pin_Map[][3] =
{
{ ADC_CHANNEL_0_EN, (uint32_t)GPIOA, GPIO_PIN_0 },
// { ADC_CHANNEL_1_EN, (uint32_t)GPIOA, GPIO_PIN_1 },
// { ADC_CHANNEL_2_EN, (uint32_t)GPIOA, GPIO_PIN_2 },
// { ADC_CHANNEL_3_EN, (uint32_t)GPIOA, GPIO_PIN_3 },
// { ADC_CHANNEL_4_EN, (uint32_t)GPIOA, GPIO_PIN_4 },
// { ADC_CHANNEL_5_EN, (uint32_t)GPIOA, GPIO_PIN_5 },
// { ADC_CHANNEL_6_EN, (uint32_t)GPIOA, GPIO_PIN_6 },
// { ADC_CHANNEL_7_EN, (uint32_t)GPIOA, GPIO_PIN_7 },
// { ADC_CHANNEL_8_EN, (uint32_t)GPIOB, GPIO_PIN_0 },
// { ADC_CHANNEL_9_EN, (uint32_t)GPIOB, GPIO_PIN_1 },
// { ADC_CHANNEL_10_EN, (uint32_t)GPIOC, GPIO_PIN_0 },
// { ADC_CHANNEL_11_EN, (uint32_t)GPIOC, GPIO_PIN_1 },
// { ADC_CHANNEL_12_EN, (uint32_t)GPIOC, GPIO_PIN_2 },
// { ADC_CHANNEL_13_EN, (uint32_t)GPIOC, GPIO_PIN_3 },
// { ADC_CHANNEL_14_EN, (uint32_t)GPIOC, GPIO_PIN_4 },
// { ADC_CHANNEL_15_EN, (uint32_t)GPIOC, GPIO_PIN_5 },
{ 0xffffffff, 0 }, //结束标志
};
__HAL_RCC_GPIOA_CLK_ENABLE();
// __HAL_RCC_GPIOB_CLK_ENABLE();
// __HAL_RCC_GPIOC_CLK_ENABLE();
//Set gpio to analog.
for(i = 0; ADC_Pin_Map[i][0] != 0xffffffff; i++)
{
if(hadc->Init.ChannelEn & ADC_Pin_Map[i][0])
{
GPIO_Handle.Pin = ADC_Pin_Map[i][2];
GPIO_Handle.Mode = GPIO_MODE_ANALOG;
GPIO_Handle.Pull = GPIO_NOPULL;
HAL_GPIO_Init((GPIO_TypeDef *)ADC_Pin_Map[i][1], &GPIO_Handle);
}
}
/* Enable ADC Clock */
__HAL_RCC_ADC12_CLK_ENABLE();
/* Clear Pending Interrupt */
NVIC_ClearPendingIRQ(ADC12_IRQn);
/* Enable External Interrupt */
NVIC_EnableIRQ(ADC12_IRQn);
}
1.2硬件使能ADC
这里我新建了一个pulse.c文件,下面为ADC1的硬件初始化代码
ADC_HandleTypeDef ADC_Handle;
/******************************************************************************
* @brief : ADC Polling Mode Initialization.
* @param : none
* @return: none
******************************************************************************/
void ADC_Init_Polling_Nchannels(void)
{
ADC_ChannelConfTypeDef ADC_ChannelConf;
ADC_Handle.Init.ClockPrescaler = ADC_CLOCK_DIV16; //ADC_CLK分频选择
ADC_Handle.Init.Resolution = ADC_RESOLUTION_12B; //分辨率
ADC_Handle.Init.DataAlign = ADC_DATAALIGN_RIGHT; //数据对齐
ADC_Handle.Init.ConConvMode = DISABLE; //连续转换模式
ADC_Handle.Init.DiscontinuousConvMode = DISABLE; //间断模式
ADC_Handle.Init.NbrOfDiscConversion =1; //间断模式通道计数
ADC_Handle.Init.ExternalTrigConv = ADC_SOFTWARE_START; //触发模式:外部触发或软件触发
ADC_Handle.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;//外部触发边沿选择
ADC_Handle.Init.DMAMode = ADC_DMAMODE_DISABLE; //DMA选择
ADC_Handle.Init.OverMode = ADC_OVERMODE_DISABLE; //溢出时是否保留上次采样数据
ADC_Handle.Init.OverSampMode = ADC_OVERSAMPMODE_DISABLE;//过采样使能
ADC_Handle.Init.Oversampling.Ratio =ADC_OVERSAMPLING_RATIO_2;//过采样率
ADC_Handle.Init.Oversampling.RightBitShift =ADC_RIGHTBITSHIFT_2;//过采样移位系数
ADC_Handle.Init.Oversampling.TriggeredMode =0; //过采样触发模式
ADC_Handle.Init.AnalogWDGEn = ADC_ANALOGWDGEN_DISABLE; //模拟看门狗
ADC_Handle.Init.ChannelEn = ADC_CHANNEL_0_EN ;
ADC_Handle.Instance = ADC1;
HAL_ADC_Init(&ADC_Handle);
/* The total adc regular channels number */
ADC_Handle.ChannelNum = 1;
/* Add adc channels */
ADC_ChannelConf.Channel = ADC_CHANNEL_0;
ADC_ChannelConf.Sq = ADC_SEQUENCE_SQ1; //转换顺序
ADC_ChannelConf.Smp = ADC_SMP_CLOCK_320;//采样时间
ADC_ChannelConf.SingleDiff = ADC_SINGLE_ENDED; // ADC_DIFFERENTIAL_ENDED ; //单端/差分模式
//offset config
ADC_ChannelConf.OffsetNumber = ADC_OFFSET_NONE; //modeString[0].number; //ADC_OFFSET_NONE; //偏移通道选择
ADC_ChannelConf.Offset = 0; //偏移量
ADC_ChannelConf.OffsetSign = 0; //偏移计算方式
ADC_ChannelConf.OffsetSaturation = 0;//偏移结果格式选择
HAL_ADC_ConfigChannel(&ADC_Handle,&ADC_ChannelConf);
}
1.3.测试ADC功能
这里创建了一个测试函数,用于输出检测到我的心率传感器的模拟量
1.4测试结果
在主函数中调用,然后给开发板接上传感器并且上电,接线图
我们打开串口助手查看输出是否合理,如下图
输出正确,这样我们可以接着写心率的算法了。
2.心率算法
心率图如下
算法根据
算法大家可以去看看我前面提到的参考文章,总的来说就是算出两次脉搏跳动的时间,然后用60秒去除以这个时间来估算心率。
但是其实并没有那么简单,在这当中有两个关键点(也是难点):
- 怎么判断波峰---->阈值的选取。
- 怎么选取我们需要的特征点---->也就是怎么选取我们需要记录的时间点,进而计算这两个时间的差值,就是两次脉搏跳动的时间。
综上得出算法整体的框架如下:
- 缓存一个波形周期内的多次采样值,求出最大最小值,计算出振幅中间值作为信号判定阈值
- 通过把当前采样值和上一采样值与阈值作比较,寻找到「信号上升到振幅中间位置」的特征点,记录当前时间
- 寻找下一个特征点并记录时间,算出两个点的时间差值,即相邻两次脉搏的时间间隔 IBI
- 由 IBI 计算心率值 BPM
说干结干下面就是根据上方框架写出的算法
3.测试
接上心率模块后看看心率是否在正常范围内
IMG_8325
总结:这款ACM32单片机ADC的测量值挺准确,能够正常测出心率值。