PulseSensor脉搏心率传感器 + u8g2 显示脉搏波形 (STM32 HAL库)

简介

PulseSensor 是一种光学心率传感器,通过检测心脏跳动时血液流动引起的光吸收变化来测量心率。它由一个 LED (发光二极管) 和一个光敏元件组成。LED 发出光线照射皮肤,光敏元件接收反射回来的光线,并将其转换为电信号。这个电信号经过处理后,可以用来计算心率。

我使用的是STM32F103C8T6  

这个传感器测量时找一下感觉,不要用力按压,因为是通过光电信号检测的,轻轻放上即可,然后注意有电阻电容的那面,不要摸!!!!

电压3.3V~5V
输出信号类型模拟信号
输入接口ADC1_IN7

 


效果展示

PulseSensor脉搏心率传感器 + u8g2 显示脉搏


cubemx配置

使能ADC_IN7 ,当然大家可以根据需要的引脚进行配置

注意改一下continuous conversion mode

还有时钟配置界面


 

代码分享 

画图函数

#define PULSE_BUFFER_SIZE 128
uint16_t pulse_data[PULSE_BUFFER_SIZE];
uint8_t pulse_index = 0; // 当前数据写入位置


// 缩放比例(调整为适应 1000-3000 的数据范围)
//因为ADC读取到的原始数值在0~3400左右,测量时的数值主要在1000~3000 所以可以缩小比例,看的更清楚。

#define PULSE_DATA_MIN 1000.0f // 数据的最小值
#define PULSE_DATA_MAX 3000.0f // 数据的最大值
#define PULSE_RANGE (PULSE_DATA_MAX - PULSE_DATA_MIN)
#define PULSE_SCALE_FACTOR (63.0f / PULSE_RANGE)


// 绘图偏移量
uint8_t offset = 0;
//把数组清空 不用也可以
void Pulse_Init()
{
    for (int i = 0; i < PULSE_BUFFER_SIZE; i++)
    {
        pulse_data[i] = 0;
    }
}



// 绘制脉搏图
//【u8g2_t *u8g2】:在外面调用时输入的结构体
//【pulse】输入的脉搏数值,不过这里没有做好,显示有问题,不可用,大家可以删掉
//【返回值int】可以外接一个flag,意思是数值到达2200~2500就返回一个1,可以配合蜂鸣器,达到蜂鸣器跟随心率“滴滴”的效果
int Pulse_Draw(u8g2_t *u8g2, uint8_t pulse)
{
    u8g2_ClearBuffer(u8g2);

    // 1. 采集数据 (简化示例,需要替换成你的 ADC 采集代码)
    uint16_t pulse_value = 0; // 存储当前的脉搏值
    uint16_t flag = 0;
    //  读取 ADC 值 (与之前的代码类似,这里简化)
    HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY);  // 等待转换完成
    pulse_value = HAL_ADC_GetValue(&hadc1);          // 获取 ADC 值
    if(pulse_value > 2200 &&pulse_value < 2500)
        flag = 1;
    else
        flag = 0;
    // 2. 将新数据添加到环形缓冲区
    pulse_data[pulse_index] = pulse_value;
    pulse_index = (pulse_index + 1) % PULSE_BUFFER_SIZE;

    // 3. 绘制脉搏图
    for (int i = 0; i < PULSE_BUFFER_SIZE - 1; i++)
    {
        // 计算数据索引
        uint8_t index1 = (pulse_index + i) % PULSE_BUFFER_SIZE;
        uint8_t index2 = (pulse_index + i + 1) % PULSE_BUFFER_SIZE;

        // 计算屏幕上的 x 和 y 坐标
        uint8_t x1 = i;
        float scaled_value1 = (float)pulse_data[index1];

        // 钳位,确保数据在范围内
        if (scaled_value1 < PULSE_DATA_MIN)
        {
            scaled_value1 = PULSE_DATA_MIN;
        }
        else if (scaled_value1 > PULSE_DATA_MAX)
        {
            scaled_value1 = PULSE_DATA_MAX;
        }
        //减去最小值,再缩放,不然最小值也在底部
        uint8_t y1 = 63 - (uint8_t)((scaled_value1 - PULSE_DATA_MIN) * PULSE_SCALE_FACTOR); // 反转Y轴
        uint8_t x2 = i + 1;

        float scaled_value2 = (float)pulse_data[index2];

        // 钳位,确保数据在范围内
        if (scaled_value2 < PULSE_DATA_MIN)
        {
            scaled_value2 = PULSE_DATA_MIN;
        }
        else if (scaled_value2 > PULSE_DATA_MAX)
        {
            scaled_value2 = PULSE_DATA_MAX;
        }

        uint8_t y2 = 63 - (uint8_t)((scaled_value2 - PULSE_DATA_MIN) * PULSE_SCALE_FACTOR);

        // 绘制线段
        u8g2_DrawLine(u8g2, x1, y1, x2, y2);
    }

    // 4. 显示数值
    char buffer[16]; // 足够存储 "Value: XXXX"
    sprintf(buffer, "Value: %u", pulse); // 格式化字符串
    u8g2_SetFont(u8g2, u8g2_font_wqy12_t_chinese2); // 设置字体 (根据你的需求调整)
    u8g2_DrawStr(u8g2, 0, 10, buffer); // 在 (0, 10) 位置显示数值字符串 (根据你的需求调整)

    u8g2_SendBuffer(u8g2);
    return flag;
}

 heart.c

里面有被注释掉的,配合上位机玩法的代码,可以来下面这个连接看,介绍的很棒,来自:

三、STM32 Pulse sensor 心率脉搏检测_心率监测系统stm32-CSDN博客

/*此代码来自其他博主*/
/*此代码来自其他博主*/
/*此代码来自其他博主*/
/**/
#include "heart.h"
#include "stdint.h"
#include "stdio.h"
 
uint8_t IBI;            
uint16_t usPulse[128];  
uint8_t  ucPos;         
 
void scaleData(void);
static void calculatePulse(uint8_t *pulse, uint16_t *maxValue);
uint16_t getArrayMax(uint16_t arr[], int size);
uint16_t getArrayMin(uint16_t arr[], int size); 
 
 void getPulse(uint8_t *pulse, uint16_t *maxValue)
 {
	 uint16_t usData,SIG;
	 *pulse = 0;
	 *maxValue = 0;
	 usData = HAL_ADC_GetValue(&hadc1);
//	 printf("S%d\r\n",usData);
	 usPulse[ucPos++] = usData;  //±£´æ£¬¹²¼Æ128¸öµã
	 if (ucPos>=128)        //Íê³ÉÒ»Âֲɼ¯
	 {
		 ucPos = 0;
		 scaleData();           
		 calculatePulse(pulse, maxValue); 
	 }
/////////////////////Processing上位机打开//////////////////////////
	 SIG = usData - 1500;    //使用Processing上位机打开
	 printf("S%d\r\n",SIG);  //使用Processing上位机打开
/////////////////////Processing上位机打开//////////////////////////
 }
 
 void scaleData()
 {
	 uint8_t i;
	 uint16_t usMax, usMin, usDelter;
	 usMax = getArrayMax(usPulse, 128);
	 usMin = getArrayMin(usPulse, 128);
	 usDelter = usMax - usMin;
	 if(usDelter<200)
	 {
		 for(i=0;i<128;i++)
		   usPulse[i] = usDelter/2;
	 }
	 else 
	 {
		 for(i=0;i<128;i++)
	     usPulse[i] = usDelter*(usPulse[i]-usMin)/usDelter;
	 } 
 }
 
 
static void calculatePulse(uint8_t *pulse, uint16_t *maxValue)
{
	uint8_t i, firstTime, secondTime;
	uint8_t PrePulse, Pulse, IBI;
	uint16_t usMax, usMin, usMid;
	
	usMax = getArrayMax(usPulse, 128);
	usMin = getArrayMin(usPulse, 128);
	usMid = (usMax + usMin)/2;
	*maxValue = usMax;
	firstTime = secondTime = 0;
	
	for(i=0;i<128;i++)
	{
		PrePulse = Pulse;
		Pulse = (usPulse[i]>usMid)?1:0;    
 
		if(PrePulse == 0 && Pulse == 1)
		{
			if(!firstTime) firstTime = i;
			if(firstTime && firstTime <i)
			{
				secondTime = i;
				break;      
			}
		}
	}
	if((secondTime - firstTime)>0)
	  {
	     IBI = (secondTime-firstTime)*HEART_PERIOD;  //IBI
	     *pulse = 60*1000/((secondTime-firstTime)*HEART_PERIOD);    //BPM                 //BPM
	  }
	else
		*pulse = 0;
 
	//printf("BPM = %d SIG = %d\r\n\r\n",*pulse, *IBI);   //单纯串口调试打开
/////////////////////Processing上位机打开//////////////////////////
	printf("B%d\r\n",*pulse);  //使用Processing上位机打开
	printf("Q%d\r\n",IBI);     //使用Processing上位机打开
/////////////////////Processing上位机打开//////////////////////////
}
 
 uint16_t getArrayMax(uint16_t arr[], int size) 
{
    if (size == 0) return 0; //
 
    uint16_t max = arr[0]; //
    for (int i = 1; i < size; i++) 
	  {
        if (arr[i] > max) 
				{
            max = arr[i]; //
        }
    }
    return max; //
}
 
uint16_t getArrayMin(uint16_t arr[], int size)
{
    if (size == 0) return 255; //
    uint16_t min = arr[0]; //
    for (int i = 1; i < size; i++)
   {
        if (arr[i] < min)
				{
            min = arr[i]; //
        }
    }
    return min; //
} 

  heart.h

#ifndef __HEART_H
#define __HEART_H



#include "adc.h"
#include "main.h"
 
#define HEART_PERIOD    20    
 
extern uint16_t usPulse[128];  
extern uint8_t  ucPos;         
 
void getPulse(uint8_t *pulse, uint16_t *maxValue);
 
#endif

调用方法

画图函数

//定义结构体,当然变量也可以,我用的freertos,结构体队列传输会方便一些。
typedef struct
{
    uint8_t Pulse;
    uint8_t usData;
} Pulse_Data_t;

Pulse_Data_t PulseData;
-----------------------------------------------

Pulse_Draw(&u8g2, PulseData.Pulse);
//20ms调用一次

 单纯的测量心率脉搏(主函数调用即可)

HAL_ADC_Start(&hadc1);    //开启ADC1
getPulse(&PulseData.Pulse, &usMaxValue);

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值