三、STM32 Pulse sensor 心率脉搏检测

一、Pulse Sensor基本参数

供电电压:3.3~5V
检测信号类型:光反射信号(PPG)
输出信号类型:模拟信号
输出信号大小:0~Vcc
电流大小:~4ma(5v 下)

  传感器只有三个引脚,分别为信号输出 S 脚 、电源正极 VCC 以及电源负极 GND,供电电压为 3.3V - 5V,可通过杜邦线与开发板连接。上电后, 传感器会不断从 S 脚输出采集到的电压模拟值。需要注意的是,印有心形的一面才是与手指接触面,在测量时要避免接触布满元件的另一面,否则会影响信号准确性。

二、STM32CubeMX配置

S接ADC1_IN4

三、代码

appheart.h

#ifndef __APPHEART_H
#define __APPHEART_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

appheart.c

#include "appheart.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);
	 usPulse[ucPos++] = usData;  //±£´æ£¬¹²¼Æ128¸öµã
	 if (ucPos>=128)        //Íê³ÉÒ»Âֲɼ¯
	 {
		 ucPos = 0;
		 scaleData();           
		 calculatePulse(pulse, maxValue); 
	 }

//	 SIG = usData - 1500;    //使用Processing上位机打开
//	 printf("S%d\r\n",SIG);  //使用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);   //单纯串口调试打开
//	printf("B%d\r\n",*pulse);  //使用Processing上位机打开
//	printf("Q%d\r\n",IBI);     //使用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; //
} 

main.c(添加或修改)

/* USER CODE BEGIN Includes */
#include "stdio.h"
#include "oled.h"
#include "bmp.h"
#include "appheart.h"

extern uint16_t usPulse[128];  
extern uint8_t  ucPos;       
/* USER CODE END Includes */

int main(void)
{
  /* USER CODE BEGIN 1 */
  uint8_t i;
  uint8_t ucPulse = 0;   
  uint16_t usMaxValue = 0; 

  HAL_Init();
  SystemClock_Config();
  MX_GPIO_Init();
  MX_SPI1_Init();
  MX_I2C2_Init();
  MX_USART1_UART_Init();
  MX_ADC1_Init();

  /* USER CODE BEGIN 2 */
  OLED_Init();
  OLED_ColorTurn(0);
  OLED_DisplayTurn(0);
  OLED_Refresh();
  /* USER CODE END 2 */

  while (1)
  {
		HAL_GPIO_TogglePin(LED0_GPIO_Port, LED0_Pin);
		HAL_GPIO_TogglePin(LED1_GPIO_Port, LED1_Pin);
		
		HAL_ADC_Start(&hadc1);    //开启ADC1
        getPulse(&ucPulse, &usMaxValue);
        if(ucPos == 0)
        {
		   printf("心率:%d /分钟 \n",ucPulse);
     	}
	    HAL_Delay(20);
  }
}

四、串口调试

USART配置

在usart.c中添加

//添加头文件
/* USER CODE BEGIN 0 */
#include "stdio.h"
/* USER CODE END 0 */

//添加函数
/* USER CODE BEGIN 1 */
//struct __FILE
//{
//	int handle;
//};
//FILE __stdout;
//int fputc(int ch,FILE *f)
//{
//    while((USART1->SR & 0x40) == 0);
//	USART1->DR = (uint8_t)ch;
//    return ch;
//}

int fputc(int c,FILE *f)
{
    uint8_t ch[1]={c};
    HAL_UART_Transmit(&huart1,ch,1,0xFFFF);
    return c;
}
/* USER CODE END 1 */

输出

//appheart.c或main.c中自行输出
printf("BPM = %d SIG = %d\r\n\r\n",*pulse, *IBI);   //单纯串口调试打开

配置串口助手

五、Processing上位机

上位机通过解析串口接收到的数据进行心率图绘制、数据图形化显示。要想使用上位机查看心率。单片机串口发送的数据就必须符合上位机的解析格式。

//appheart.c中

//static void calculatePulse(uint8_t *pulse, uint16_t *maxValue) 中
printf("B%d\r\n",*pulse);  //使用Processing上位机打开
printf("Q%d\r\n",IBI);     //使用Processing上位机打开

//static void calculatePulse(uint8_t *pulse, uint16_t *maxValue) 中
printf("B%d\r\n",*pulse); //使用Processing上位机打开
printf("Q%d\r\n",IBI);    //使用Processing上位机打开

数据格式均为 ASCII 码,由于数据量较大,采用的波特率为 115200。其中包含三种数据:以「S」为前缀的,表示脉搏数据(脉象图的数值化表示);以「B」为前缀的,表示 BPM 数值(心率值);以「Q」为前缀的,表示 IBI 数值(相邻两个心跳之间的时间)。这三种数据通过串口发送给上位机 Processing 软件,就会在窗口中显示出来。其中 S 数据 20ms 发送一次,数据量大;B 和 Q 数据只有在检测到有效脉搏后,在每一次心跳后发送一次,数据量下。如下图:

 访问上位机的 Github 项目页面:WorldFamousElectronics/PulseSensor_Amped_Processing_Visualizer: Processing code for pulse wave visualization,点击 Clone or download 按钮下的 Download ZIP 即可下载上位机软件及其源码。

上位机是用 Processing 语言编写,不能直接打开,需要通过 Processing 运行环境加载运行。

从 Processing 官网下载对于版本的运行环境,地址:Download \ Processing.org

打开下载的 Processing 运行环境,点击右上角「文件」菜单的「打开」按钮,选择下载并解压后的上位机程序 PulseSensorAmpd_Processing_150.pde

点击运行按钮运行软件,即可看到上位机软件界面。把开发板上电连接电脑,在软件中选择对应的 COM 口,随后软件开始接收串口数据并显示。

 

六、OLED调试(移植u8g2后调试) 

STM32移植u8g2图形库(Pulse sensor和AHT10调试

  • 15
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值