目录
一、介绍
二、传感器原理
1.接线图
2.引脚描述
3.工作原理:光电容积法原理
4.工作原理:心率采样数据处理算法
三、程序设计
main.c文件
adcx.h文件
adc.c文件
四、实验效果
五、资料获取
项目分享
一、介绍
PulseSensor传感器是一种基于光学原理的心率传感器,可以通过测量心脏跳动时的血液流动情况来检测心率。它由一个LED和一个光敏元件组成,LED发出的光线透过皮肤照射到血液中,光敏元件接收反射回来的光线,然后将光信号转换为电信号,从而测量出心率。
以下是土壤湿度传感器的参数:
供电电压
DC:3.3~5V
检测信号类型
光反射信号(PPG)
输出信号类型
模拟信号
LED峰值波长
515nm(绿光)
信号放大倍数
330倍
输出信号范围
0~VCC
电流大小
~4ma
哔哩哔哩视频
PulseSensor心率传感器详解(STM32)
(资料分享见文末)
二、传感器原理
1.接线图
传感器只有三个引脚,分别为信号输出 S 脚 、电源正极 VCC 以及电源负极 GND,供电电压为 3.3V - 5V,可通过杜邦线与开发板连接。上电后, 传感器会不断从 S 脚输出采集到的电压模拟值。
2.引脚描述
引脚名称
描述
S
脉搏信号输出
+
5V(或3.3V)电源输入
-
GND地
3.工作原理:光电容积法原理
光电容积法的基本原理是利用人体组织在血管搏动时造成透光率不同来进行脉搏测量的。光源一般采用对动脉血有选择性的特定波长的发光二极管(515nm的绿光)。当光束透过人体外周血管,由于动脉搏动充血容积变化导致这束光的透过光率发生改变,此时由光电变换器接收人体组织反射的光线,转变为电信号并将其放大和输出。由于脉搏是随心脏的搏动而周期性变化的信号,动脉血管容积也周期性变化,因此光电变换器的电信号变化周期就是脉搏率。
4.工作原理:心率采样数据处理算法
测量相邻两次脉搏的时间间隔,再用一分钟除以这个间隔得出心率。
IBI: 相邻两次脉搏的时间间隔(单位:ms),BPM:心率,一分钟内的心跳次数且:BPM = 60 / IBI。我们的最终目的就是要求出 IBI 的值,并通过 IBI 计算出实时心率。其核心操作在于识别一个脉搏信号
①选取阈值
首先动态计算出参考阈值,然后用用阈值对信号判定、识别一个波峰
② 计算特征点
选取信号上升到振幅的一半作为特征点,我们可以捕获这个特征点作为一个有效脉搏的标志,然后计算 IBI
三、程序设计
1.使用STM32F103C8T6读取PulseSensor心率传感器采集的数据
2.将读取得到的温湿度数据同时在OLED上显示
PulseSensor
PA0
OLED_SCL
PB11
OLED_SDA
PB10
串口
串口1
main.c文件
#include "stm32f10x.h"
#include "led.h"
#include "usart.h"
#include "delay.h"
#include "oled.h"
#include "adcx.h"
#include "timer.h"
/*****************辰哥单片机设计******************
STM32
* 项目 : PulseSensor心率传感器实验
* 版本 : V1.0
* 日期 : 2024.8.19
* MCU : STM32F103C8T6
* 接口 : 参看ADCX.h
* BILIBILI : 辰哥单片机设计
* CSDN : 辰哥单片机设计
* 作者 : 辰哥
**********************BEGIN***********************/
extern _Bool Timer_Flag ; //时间到 标准位
extern _Bool update_flag; //更新标志变量
//要写入到STM32 FLASH的字符串数组
u8 TEXT_Buffer[]={"0000000"};
#define SIZE sizeof(TEXT_Buffer) //数组长度
//#define FLASH_SAVE_ADDR 0X08020000 //设置FLASH 保存地址(必须为偶数,且其值要大于本代码所占用FLASH的大小+0X08000000)
#define FLASH_SAVE_ADDR 0X0800f400 //设置FLASH 保存地址(必须为偶数,且其值要大于本代码所占用FLASH的大小+0X08000000)
int main(void)
{
unsigned char p[16]=" ";
u8 datatemp[SIZE];
_Bool Heart_OK = 0; //读取到正确心率标志位
unsigned char Heart = 0; //心率值
SystemInit();//配置系统时钟为72M
delay_init(72);
LED_Init();
LED_On();
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_3);//设置中断优先级分组为组3:2位抢占优先级,2位响应优先级
USART1_Config();//串口初始化
OLED_Init();
printf("Start \n");
delay_ms(1000);
//显示“血氧:”
OLED_ShowChinese(0,0,0,16,1);
OLED_ShowChinese(16,0,1,16,1);
OLED_ShowChar(32,0,':',16,1);
ADCx_Init();
TIM3_Int_Init(1999,71); //定时2ms中断
TIM2_Int_Init(199,7199); //10Khz的计数频率,计数到500为20ms
// while (1)
// {
// LED_Toggle();
// printf("光照强度: %d\r\n",light);
//
// OLED_ShowNum(80,0,light,3,16,1);
// delay_ms(500);
// }
while(1)
{
if(Timer_Flag==1) //500ms到 读取数据
{
Timer_Flag = 0; //清除标志
TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE ); //使能指定的TIM3中断,允许更新中断
TIM_ITConfig(TIM3,TIM_IT_Update,DISABLE ); //使能指定的TIM3中断,允许更新中断
delay_ms(500);
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能指定的TIM3中断,允许更新中断
TIM_Cmd(TIM2, ENABLE); //使能TIMx
if (QS == true) //读取到了心率信号
{
QS = false; //清除标志 等待下一次读取
if(BPM>HEART_MIN_ERROR&&BPM { Heart_OK = 1; //标志位置一 Heart = BPM; //心率传递给Heart } else { Heart_OK = 0; //标志位清零 Heart = 0; //设置为0 } } } delay_ms(20); if(Heart_OK==1) //读取到正确心率 { OLED_ShowNum(40,0,Heart,3,16,1); } else { OLED_ShowString(32,0,":---r/min",16,1); } } } adcx.h文件 #ifndef _ADCX_H_ #define _ADCX_H_ #include "stm32f10x.h" // Device header /*****************辰哥单片机设计****************** STM32 * 项目 : PulseSensor心率传感器实验 * 版本 : V1.0 * 日期 : 2024.8.19 * MCU : STM32F103C8T6 * 接口 : 参看ADCX.h * BILIBILI : 辰哥单片机设计 * CSDN : 辰哥单片机设计 * 作者 : 辰哥 **********************BEGIN***********************/ // ADC 编号选择 // 可以是 ADC1/2/3 #define ADCx ADC1 #define ADC_CLK RCC_APB2Periph_ADC1 #define PulseSensor_GPIO_CLK RCC_APB2Periph_GPIOA #define PulseSensor_GPIO_PORT GPIOA #define PulseSensor_GPIO_PIN GPIO_Pin_0 void ADCx_Init(void); u16 Get_Adc(u8 ch); u16 Get_Adc_Average(u8 ch,u8 times); #endif adc.c文件 #include "adcx.h" #include "delay.h" /*****************辰哥单片机设计****************** STM32 * 项目 : PulseSensor心率传感器实验 * 版本 : V1.0 * 日期 : 2024.8.19 * MCU : STM32F103C8T6 * 接口 : 参看ADCX.h * BILIBILI : 辰哥单片机设计 * CSDN : 辰哥单片机设计 * 作者 : 辰哥 **********************BEGIN***********************/ //初始化ADC //这里我们仅以规则通道为例 //我们默认将开启通道0~3 void ADCx_Init(void) { ADC_InitTypeDef ADC_InitStructure; GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(PulseSensor_GPIO_CLK|ADC_CLK,ENABLE); RCC_ADCCLKConfig(RCC_PCLK2_Div6); //PA0 GPIO_InitStructure.GPIO_Pin=PulseSensor_GPIO_PIN; GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN; GPIO_Init(PulseSensor_GPIO_PORT,& GPIO_InitStructure); ADC_DeInit(ADCx); ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:ADCx和ADC2工作在独立模式 ADC_InitStructure.ADC_ScanConvMode = DISABLE; //模数转换工作在单通道模式 ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //模数转换工作在单次转换模式 //ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T3_TRGO;//选择TIM3作为外部触发源 ADC_InitStructure.ADC_DataAlign= ADC_DataAlign_Right; //ADC数据右对齐 ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的ADC通道的数目 ADC_Init(ADCx, &ADC_InitStructure); ADC_ExternalTrigConvCmd(ADCx,ENABLE);//采用外部触发 ADC_RegularChannelConfig(ADCx, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5);//adc转换时间21us ADC_Cmd(ADCx, ENABLE); ADC_ResetCalibration(ADCx); //复位校准 while(ADC_GetResetCalibrationStatus(ADCx)); //等待校准结束,校准结束状态为RESET ADC_StartCalibration(ADCx); //AD校准 while(ADC_GetCalibrationStatus(ADCx)); //等待校准结束 } //获得ADC值 //ch:通道值 0~3 u16 Get_Adc(u8 ch) { //设置指定ADC的规则组通道,一个序列,采样时间 ADC_RegularChannelConfig(ADCx, ch, 1, ADC_SampleTime_239Cycles5 ); //ADCx,ADC通道,采样时间为239.5周期 ADC_SoftwareStartConvCmd(ADCx, ENABLE); //使能指定的ADCx的软件转换启动功能 while(!ADC_GetFlagStatus(ADCx, ADC_FLAG_EOC ));//等待转换结束 return ADC_GetConversionValue(ADCx); //返回最近一次ADCx规则组的转换结果 } u16 Get_Adc_Average(u8 ch,u8 times) { u32 temp_val=0; u8 t; for(t=0;t { temp_val+=Get_Adc(ch); delay_ms(5); } return temp_val/times; } 四、实验效果 五、资料获取 项目分享