三、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调试
作者:Inverterotempo