MAX30102的STM32驱动程序
效果演示:
CSDN演示专用 MAX30102
程序实现心率计算,心率波形显示,血氧计算。
下载文件中包含程序源码和PCB工程文件,PCB工程文件成品如演示视频,除基本功能外加入锂电池供电和充电功能。
源码过多,只展示了部分,全部源码下载链接:
CSDN:
https://download.csdn.net/download/qq_19534483/20368390
百度云:
链接:https://pan.baidu.com/s/1SFQCT1Nd2H6Dm05Rs2tHQA 提取码:hss2
github:
https://github.com/ahukl1/MAX30102.git
部分源码如下:
MAX30102.c:
int maxim_max30102_write_reg(uint8_t uch_addr, uint8_t uch_data){
HAL_I2C_Mem_Write(&hi2c1, I2C_WRITE_ADDR,uch_addr, I2C_MEMADD_SIZE_8BIT,&uch_data,1, 1000);
}
int maxim_max30102_reset()
{
maxim_max30102_write_reg(REG_MODE_CONFIG,0x40);
maxim_max30102_write_reg(REG_MODE_CONFIG,0x03);
maxim_max30102_write_reg(REG_INTR_ENABLE_1,0x40); // INTR setting
maxim_max30102_write_reg(REG_INTR_ENABLE_2,0x50);
maxim_max30102_write_reg(REG_FIFO_WR_PTR,0x00); //FIFO_WR_PTR[4:0]
maxim_max30102_write_reg(REG_OVF_COUNTER,0x00); //OVF_COUNTER[4:0]
maxim_max30102_write_reg(REG_FIFO_RD_PTR,0x00) ; //FIFO_RD_PTR[4:0]
maxim_max30102_write_reg(REG_FIFO_CONFIG,0x0f); //sample avg = 1, fifo rollover=false, fifo almost full = 17
maxim_max30102_write_reg(REG_MODE_CONFIG,0x03) ; //0x02 for Red only, 0x03 for SpO2 mode 0x07 multimode LED
maxim_max30102_write_reg(REG_SPO2_CONFIG,0x27); // SPO2_ADC range = 4096nA, SPO2 sample rate (100 Hz), LED pulseWidth (400uS)
maxim_max30102_write_reg(REG_LED1_PA,0x24) ; //Choose value for ~ 7mA for LED1
maxim_max30102_write_reg(REG_LED2_PA,0x24) ; // Choose value for ~ 7mA for LED2
maxim_max30102_write_reg(REG_PILOT_PA,0x7f) ; // Choose value for ~ 25mA for Pilot LED
maxim_max30102_write_reg(0x03,0x00);
maxim_max30102_write_reg(0x21,0x01);
}
MAX30102.h:
#define I2C_WRITE_ADDR 0xAE
#define I2C_READ_ADDR 0xAF
#include "main.h"
//register addresses
#define REG_INTR_STATUS_1 0x00
#define REG_INTR_STATUS_2 0x01
#define REG_INTR_ENABLE_1 0x02
#define REG_INTR_ENABLE_2 0x03
#define REG_FIFO_WR_PTR 0x04
#define REG_OVF_COUNTER 0x05
#define REG_FIFO_RD_PTR 0x06
#define REG_FIFO_DATA 0x07
#define REG_FIFO_CONFIG 0x08
#define REG_MODE_CONFIG 0x09
#define REG_SPO2_CONFIG 0x0A
#define REG_LED1_PA 0x0C
#define REG_LED2_PA 0x0D
#define REG_PILOT_PA 0x10
#define REG_MULTI_LED_CTRL1 0x11
#define REG_MULTI_LED_CTRL2 0x12
#define REG_TEMP_INTR 0x1F
#define REG_TEMP_FRAC 0x20
#define REG_TEMP_CONFIG 0x21
#define REG_PROX_INT_THRESH 0x30
#define REG_REV_ID 0xFE
#define REG_PART_ID 0xFF
extern I2C_HandleTypeDef hi2c1;
int maxim_max30102_reset();
#endif
oled.c:
struct oled_pot * start_pot[8];
void write(unsigned char data,int type){
switch(type)
{
case 0:HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);break;
case 1:HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);break;
}
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1,&data,1,1000);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
}
void OLED_WrCmd(uint8_t command){
write(command,0);
}
void OLED_WrData(uint8_t data){
write(data,1);
}
void OLED_Init(){
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_Delay(100);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
unsigned int a;
for(a=0;a<5000;a++);
OLED_WrCmd(0xAE);//--turn off oled panel
OLED_WrCmd(0x00);//---set low column address
OLED_WrCmd(0x10);//---set high column address
OLED_WrCmd(0x40);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
OLED_WrCmd(0xB0);
OLED_WrCmd(0x81);//--set contrast control register
OLED_WrCmd(0xFF); // Set SEG Output Current Brightness
OLED_WrCmd(0xa1);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
OLED_WrCmd(0xc8);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
OLED_WrCmd(0xa6);//--set normal display
OLED_WrCmd(0xa8);//--set multiplex ratio(1 to 64)
OLED_WrCmd(0x3f);//--1/64 duty``
OLED_WrCmd(0xd3);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
OLED_WrCmd(0x00);//-not offset
OLED_WrCmd(0xd5);//--set display clock divide ratio/oscillator frequency
OLED_WrCmd(0x80);//--set divide ratio, Set Clock as 100 Frames/Sec
OLED_WrCmd(0xd9);//--set pre-charge period
OLED_WrCmd(0xf1);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
OLED_WrCmd(0xda);//--set com pins hardware configuration
OLED_WrCmd(0x12);
OLED_WrCmd(0xdb);//--set vcomh
OLED_WrCmd(0x40);//Set VCOM Deselect Level
OLED_WrCmd(0x20);//-Set Page Addressing Mode (0x00/0x01/0x02)
OLED_WrCmd(0x02);//
OLED_WrCmd(0x8d);//--set Charge Pump enable/disable
OLED_WrCmd(0x14);//--set(0x10) disable
OLED_WrCmd(0xa4);// Disable Entire Display On (0xa4/0xa5)
OLED_WrCmd(0xa6);// Disable Inverse Display On (0xa6/a7)
OLED_WrCmd(0xaf);//--turn on oled panel
OLED_Clear();//OLED清屏
}
void OLED_Clear(void){
unsigned char i,n;
for(i=0; i<8; i++)
{
OLED_WrCmd(0xb0+i); //设置页地址(0~7)
OLED_WrCmd(0x00); //设置显示位置—列低地址
OLED_WrCmd(0x10); //设置显示位置—列高地址
for(n=0; n<128; n++) OLED_WrData(0x00); //写0x00到屏幕寄存器上
}
}
void OLED_Start(void){
unsigned char i,n;
for(i=0; i<8; i++)
{
OLED_WrCmd(0xb0+i); //设置页地址(0~7)
OLED_WrCmd(0x00); //设置显示位置—列低地址
OLED_WrCmd(0x10); //设置显示位置—列高地址
for(n=0; n<128; n++) OLED_WrData(start[i][n]); //写0x00到屏幕寄存器上
}
}
void OLED_Close_page(void){
unsigned char i,n;
for(i=0; i<8; i++)
{
OLED_WrCmd(0xb0+i); //设置页地址(0~7)
OLED_WrCmd(0x00); //设置显示位置—列低地址
OLED_WrCmd(0x10); //设置显示位置—列高地址
for(n=0; n<128; n++) OLED_WrData(close_img[i][n]); //写0x00到屏幕寄存器上
}
}
void OLED_page2(void){
unsigned char i,n;
for(i=0; i<8; i++)
{
OLED_WrCmd(0xb0+i); //设置页地址(0~7)
OLED_WrCmd(0x00); //设置显示位置—列低地址
OLED_WrCmd(0x10); //设置显示位置—列高地址
for(n=0; n<128; n++) OLED_WrData(page_2[i][n]); //写0x00到屏幕寄存器上
}
}
void OLED_SetPos(uint8_t x, uint8_t y){
WriteCmd(0xb0+y);
WriteCmd(((x&0xf0)>>4)|0x10);
WriteCmd(x&0x0f);
}
void OLED_DrawPoint(unsigned char x,unsigned char y)
{
unsigned char pos,bx,temp=0;
if(x>127||y>63)return;//超出范围了.
pos=7-y/8;
bx=y%8;
temp=1<<(7-bx);
OLED_SetPos(x,pos);
OLED_WrData(temp);
}
void OLED_ON(void){
WriteCmd(0X8D); //设置电荷泵
WriteCmd(0X14); //开启电荷泵
WriteCmd(0XAF); //OLED唤醒
}
void OLED_OFF(void){
WriteCmd(0X8D); //设置电荷泵
WriteCmd(0X10); //关闭电荷泵
WriteCmd(0XAE); //OLED休眠
}
void OLED_ShowChar(int x,int y,char txt[]){
int i,j;
y=y*8;
OLED_WrCmd(0xb0+2*x);
OLED_WrCmd(0x10|((0xf0&y)>>4));
OLED_WrCmd(0x00|(0x0f&y));
for(i=0;txt[i]!='\0';i++){
if(txt[i]-' '<0||txt[i]-' '>94) continue;
for(j=0;j<8;j++){
OLED_WrData(asc2_1206[txt[i]-' '][j]);
}
}
OLED_WrCmd(0xb0+2*x+1);
OLED_WrCmd(0x10|((0xf0&y)>>4));
OLED_WrCmd(0x00|(0x0f&y));
for(i=0;txt[i]!='\0';i++){
if(txt[i]-' '<0||txt[i]-' '>94) continue;
for(j=0;j<8;j++){
OLED_WrData(asc2_1206[txt[i]-' '][j+8]);
}
}
}
void OLED_ShowWord(int x,int y,int f){
int i,j;
y=y*8;
OLED_WrCmd(0xb0+2*x);
OLED_WrCmd(0x10|((0xf0&y)>>4));
OLED_WrCmd(0x00|(0x0f&y));
for(i=0;i<16;i++){
OLED_WrData(word[f][i]);
}
OLED_WrCmd(0xb0+2*x+1);
OLED_WrCmd(0x10|((0xf0&y)>>4));
OLED_WrCmd(0x00|(0x0f&y));
for(i=0;i<16;i++){
OLED_WrData(word[f][i+16]);
}
}
void OLED_ShowNum(int y,int x,int num)
{
int j;
x=x*8;
OLED_WrCmd(0xb0+2*y);
OLED_WrCmd(0x10|((0xf0&x)>>4));
OLED_WrCmd(0x00|(0x0f&x));
for(j=0;j<8;j++){
OLED_WrData(font_num[num][j]);
}
OLED_WrCmd(0xb0+2*y+1);
OLED_WrCmd(0x10|((0xf0&x)>>4));
OLED_WrCmd(0x00|(0x0f&x));
for(j=0;j<8;j++){
OLED_WrData(font_num[num][j+8]);
}
}
void OLED_ShowNums(int y,int x,int num,int len)
{
int i;
int dat;
dat=num;
for (i=0;i<len;i++){
OLED_ShowNum(y,x+len-i-1,dat%10);
dat=dat/10;
}
}
main.c:
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2021 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "cmsis_os.h"
#include "MAX30102.h"
#include "stdio.h"
#include "oled.h"
char data_save;
int heart;
int red_reg[200];
int led_reg[200];
int heart_reg;
char online=1;
int reg_num=0;
int reg_heart=1;
unsigned char pData[8];
float spo2;
int flag=3;
unsigned char char_show=0;
I2C_HandleTypeDef hi2c1;
SPI_HandleTypeDef hspi1;
UART_HandleTypeDef huart1;
osThreadId_t defaultTaskHandle;
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the USART */
huart1.Instance->DR = (uint8_t) ch;
/* Loop until the end of transmission */
while(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC) == RESET){}
return ch;
}
const osThreadAttr_t defaultTask_attributes = {
.name = "defaultTask",
.priority = (osPriority_t) osPriorityNormal,
.stack_size = 128 * 4
};
osThreadId_t myTask02Handle;
const osThreadAttr_t myTask02_attributes = {
.name = "myTask02",
.priority = (osPriority_t) osPriorityLow,
.stack_size = 128 * 6
};
osThreadId_t myTask03Handle;
const osThreadAttr_t myTask03_attributes = {
.name = "myTask03",
.priority = (osPriority_t) osPriorityLow,
.stack_size = 128 * 4
};
osThreadId_t myTask04Handle;
const osThreadAttr_t myTask04_attributes = {
.name = "myTask04",
.priority = (osPriority_t) osPriorityLow,
.stack_size = 128 * 4
};
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
static void MX_SPI1_Init(void);
static void MX_USART1_UART_Init(void);
void StartDefaultTask(void *argument);
void StartTask02(void *argument);
void StartTask03(void *argument);
void StartTask04(void *argument);
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_SPI1_Init();
MX_USART1_UART_Init();
OLED_Init();
osKernelInitialize();
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
myTask02Handle = osThreadNew(StartTask02, NULL, &myTask02_attributes);
myTask03Handle = osThreadNew(StartTask03, NULL, &myTask03_attributes);
myTask04Handle = osThreadNew(StartTask04, NULL, &myTask04_attributes);
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
/* USER CODE END RTOS_THREADS */
/* Start scheduler */
maxim_max30102_reset();
osKernelStart();
/* We should never get here as control is now taken by the scheduler */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL4;
RCC_OscInitStruct.PLL.PLLDIV = RCC_PLL_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
{
Error_Handler();
}
}
static void MX_I2C1_Init(void)
{
/* USER CODE BEGIN I2C1_Init 0 */
/* USER CODE END I2C1_Init 0 */
/* USER CODE BEGIN I2C1_Init 1 */
/* USER CODE END I2C1_Init 1 */
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C1_Init 2 */
/* USER CODE END I2C1_Init 2 */
}
static void MX_SPI1_Init(void)
{
/* USER CODE BEGIN SPI1_Init 0 */
/* USER CODE END SPI1_Init 0 */
/* USER CODE BEGIN SPI1_Init 1 */
/* USER CODE END SPI1_Init 1 */
/* SPI1 parameter configuration*/
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SPI1_Init 2 */
/* USER CODE END SPI1_Init 2 */
}
static void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
/*Configure GPIO pin : PC13 */
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
/*Configure GPIO pin : PC13 */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
/*Configure GPIO pin : PC13 */
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void StartDefaultTask(void *argument)
{
float r;
float red;
float led;
int red_last=0;
int led_last=0;
int cha=0;
int reg_num1=0;
int reg_num2=0;
int pot_i=0;
while (1)
{
HAL_I2C_Mem_Read(&hi2c1,I2C_READ_ADDR,REG_FIFO_DATA,I2C_MEMADD_SIZE_8BIT,(unsigned char *)pData,8,1000);
red=(red+(((pData[3]&0x03)<<16)|(pData[4]<<8)|(pData[5])))/2;
led=(led+(((pData[0]&0x03)<<16)|(pData[1]<<8)|(pData[2])))/2;
if(red>5000){ //判断采集状态
if(flag!=1) {OLED_Clear();flag=1;}
online=1;
cha=(cha+red-red_last)/2; //求导
if(cha<-10){data_save=data_save<<1|0;}
else data_save=data_save<<1|1;
r=red/led;
spo2=-45.060*r*r+30.354*r + 94.845;
if(pot_i<128){ //波形图显示
OLED_DrawPoint(++pot_i,25-cha/6);} //波形显示过大可把12调大,波形过小可调小12
else {
OLED_Clear();
pot_i=0;
}
}
else
{
if(flag!=0) {
OLED_Clear();
flag=0;
OLED_Clear();
pot_i=0;
data_save=0xff;
heart=0;
online=0;
reg_heart=0;
reg_num=0;
spo2=0;
}
OLED_ShowChar(1,2,"No FINGER!");
}
printf("a:%d,%d,%f,%f\n",cha,heart,red,spo2);
red_last=red;
maxim_max30102_write_reg(0x21,0x01);
vTaskDelay(10);
}
}
void StartTask02(void *argument)
{
while(1)
{
if(char_show==0){
OLED_ShowChar(3,0,"H:");
OLED_ShowNums(3,2,heart,3);
OLED_ShowChar(3,6,"Spo2:");
OLED_ShowNums(3,11,spo2,3);
vTaskDelay(10);
}
}
}
void StartTask03(void *argument)
{
int last;
int now;
int c;
int num=1;
while(1){
if((data_save&0xf0)==0x00)
{
now=HAL_GetTick();
if(now<last){c=(0xffffffff-last+now);}
else c=(now-last);
if(c>=300)
{
heart=60000/c;
last=now;
reg_heart=(reg_heart*reg_num+heart)/(reg_num+1);
if(reg_num==30){
heart_reg=reg_heart;
reg_num=0;
reg_heart=0;
}
else
reg_num++;
}
}
}
}
void StartTask04(void *argument)
{
for(;;)
{
osDelay(1);
}
}
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
源码过多,只展示了部分,全部源码下载链接:
https://download.csdn.net/download/qq_19534483/20368390
版权声明:本文为CSDN博主「Cn-Wang」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_19534483/article/details/118913979
MAX30102的STM32驱动程序
效果演示:
CSDN演示专用 MAX30102
程序实现心率计算,心率波形显示,血氧计算。
下载文件中包含程序源码和PCB工程文件,PCB工程文件成品如演示视频,除基本功能外加入锂电池供电和充电功能。
源码过多,只展示了部分,全部源码下载链接:
CSDN:
https://download.csdn.net/download/qq_19534483/20368390
百度云:
链接:https://pan.baidu.com/s/1SFQCT1Nd2H6Dm05Rs2tHQA 提取码:hss2
github:
https://github.com/ahukl1/MAX30102.git
部分源码如下:
MAX30102.c:
int maxim_max30102_write_reg(uint8_t uch_addr, uint8_t uch_data){
HAL_I2C_Mem_Write(&hi2c1, I2C_WRITE_ADDR,uch_addr, I2C_MEMADD_SIZE_8BIT,&uch_data,1, 1000);
}
int maxim_max30102_reset()
{
maxim_max30102_write_reg(REG_MODE_CONFIG,0x40);
maxim_max30102_write_reg(REG_MODE_CONFIG,0x03);
maxim_max30102_write_reg(REG_INTR_ENABLE_1,0x40); // INTR setting
maxim_max30102_write_reg(REG_INTR_ENABLE_2,0x50);
maxim_max30102_write_reg(REG_FIFO_WR_PTR,0x00); //FIFO_WR_PTR[4:0]
maxim_max30102_write_reg(REG_OVF_COUNTER,0x00); //OVF_COUNTER[4:0]
maxim_max30102_write_reg(REG_FIFO_RD_PTR,0x00) ; //FIFO_RD_PTR[4:0]
maxim_max30102_write_reg(REG_FIFO_CONFIG,0x0f); //sample avg = 1, fifo rollover=false, fifo almost full = 17
maxim_max30102_write_reg(REG_MODE_CONFIG,0x03) ; //0x02 for Red only, 0x03 for SpO2 mode 0x07 multimode LED
maxim_max30102_write_reg(REG_SPO2_CONFIG,0x27); // SPO2_ADC range = 4096nA, SPO2 sample rate (100 Hz), LED pulseWidth (400uS)
maxim_max30102_write_reg(REG_LED1_PA,0x24) ; //Choose value for ~ 7mA for LED1
maxim_max30102_write_reg(REG_LED2_PA,0x24) ; // Choose value for ~ 7mA for LED2
maxim_max30102_write_reg(REG_PILOT_PA,0x7f) ; // Choose value for ~ 25mA for Pilot LED
maxim_max30102_write_reg(0x03,0x00);
maxim_max30102_write_reg(0x21,0x01);
}
MAX30102.h:
#define I2C_WRITE_ADDR 0xAE
#define I2C_READ_ADDR 0xAF
#include "main.h"
//register addresses
#define REG_INTR_STATUS_1 0x00
#define REG_INTR_STATUS_2 0x01
#define REG_INTR_ENABLE_1 0x02
#define REG_INTR_ENABLE_2 0x03
#define REG_FIFO_WR_PTR 0x04
#define REG_OVF_COUNTER 0x05
#define REG_FIFO_RD_PTR 0x06
#define REG_FIFO_DATA 0x07
#define REG_FIFO_CONFIG 0x08
#define REG_MODE_CONFIG 0x09
#define REG_SPO2_CONFIG 0x0A
#define REG_LED1_PA 0x0C
#define REG_LED2_PA 0x0D
#define REG_PILOT_PA 0x10
#define REG_MULTI_LED_CTRL1 0x11
#define REG_MULTI_LED_CTRL2 0x12
#define REG_TEMP_INTR 0x1F
#define REG_TEMP_FRAC 0x20
#define REG_TEMP_CONFIG 0x21
#define REG_PROX_INT_THRESH 0x30
#define REG_REV_ID 0xFE
#define REG_PART_ID 0xFF
extern I2C_HandleTypeDef hi2c1;
int maxim_max30102_reset();
#endif
oled.c:
struct oled_pot * start_pot[8];
void write(unsigned char data,int type){
switch(type)
{
case 0:HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);break;
case 1:HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);break;
}
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET);
HAL_SPI_Transmit(&hspi1,&data,1,1000);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
}
void OLED_WrCmd(uint8_t command){
write(command,0);
}
void OLED_WrData(uint8_t data){
write(data,1);
}
void OLED_Init(){
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_Delay(100);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
unsigned int a;
for(a=0;a<5000;a++);
OLED_WrCmd(0xAE);//--turn off oled panel
OLED_WrCmd(0x00);//---set low column address
OLED_WrCmd(0x10);//---set high column address
OLED_WrCmd(0x40);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)
OLED_WrCmd(0xB0);
OLED_WrCmd(0x81);//--set contrast control register
OLED_WrCmd(0xFF); // Set SEG Output Current Brightness
OLED_WrCmd(0xa1);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常
OLED_WrCmd(0xc8);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常
OLED_WrCmd(0xa6);//--set normal display
OLED_WrCmd(0xa8);//--set multiplex ratio(1 to 64)
OLED_WrCmd(0x3f);//--1/64 duty``
OLED_WrCmd(0xd3);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)
OLED_WrCmd(0x00);//-not offset
OLED_WrCmd(0xd5);//--set display clock divide ratio/oscillator frequency
OLED_WrCmd(0x80);//--set divide ratio, Set Clock as 100 Frames/Sec
OLED_WrCmd(0xd9);//--set pre-charge period
OLED_WrCmd(0xf1);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock
OLED_WrCmd(0xda);//--set com pins hardware configuration
OLED_WrCmd(0x12);
OLED_WrCmd(0xdb);//--set vcomh
OLED_WrCmd(0x40);//Set VCOM Deselect Level
OLED_WrCmd(0x20);//-Set Page Addressing Mode (0x00/0x01/0x02)
OLED_WrCmd(0x02);//
OLED_WrCmd(0x8d);//--set Charge Pump enable/disable
OLED_WrCmd(0x14);//--set(0x10) disable
OLED_WrCmd(0xa4);// Disable Entire Display On (0xa4/0xa5)
OLED_WrCmd(0xa6);// Disable Inverse Display On (0xa6/a7)
OLED_WrCmd(0xaf);//--turn on oled panel
OLED_Clear();//OLED清屏
}
void OLED_Clear(void){
unsigned char i,n;
for(i=0; i<8; i++)
{
OLED_WrCmd(0xb0+i); //设置页地址(0~7)
OLED_WrCmd(0x00); //设置显示位置—列低地址
OLED_WrCmd(0x10); //设置显示位置—列高地址
for(n=0; n<128; n++) OLED_WrData(0x00); //写0x00到屏幕寄存器上
}
}
void OLED_Start(void){
unsigned char i,n;
for(i=0; i<8; i++)
{
OLED_WrCmd(0xb0+i); //设置页地址(0~7)
OLED_WrCmd(0x00); //设置显示位置—列低地址
OLED_WrCmd(0x10); //设置显示位置—列高地址
for(n=0; n<128; n++) OLED_WrData(start[i][n]); //写0x00到屏幕寄存器上
}
}
void OLED_Close_page(void){
unsigned char i,n;
for(i=0; i<8; i++)
{
OLED_WrCmd(0xb0+i); //设置页地址(0~7)
OLED_WrCmd(0x00); //设置显示位置—列低地址
OLED_WrCmd(0x10); //设置显示位置—列高地址
for(n=0; n<128; n++) OLED_WrData(close_img[i][n]); //写0x00到屏幕寄存器上
}
}
void OLED_page2(void){
unsigned char i,n;
for(i=0; i<8; i++)
{
OLED_WrCmd(0xb0+i); //设置页地址(0~7)
OLED_WrCmd(0x00); //设置显示位置—列低地址
OLED_WrCmd(0x10); //设置显示位置—列高地址
for(n=0; n<128; n++) OLED_WrData(page_2[i][n]); //写0x00到屏幕寄存器上
}
}
void OLED_SetPos(uint8_t x, uint8_t y){
WriteCmd(0xb0+y);
WriteCmd(((x&0xf0)>>4)|0x10);
WriteCmd(x&0x0f);
}
void OLED_DrawPoint(unsigned char x,unsigned char y)
{
unsigned char pos,bx,temp=0;
if(x>127||y>63)return;//超出范围了.
pos=7-y/8;
bx=y%8;
temp=1<<(7-bx);
OLED_SetPos(x,pos);
OLED_WrData(temp);
}
void OLED_ON(void){
WriteCmd(0X8D); //设置电荷泵
WriteCmd(0X14); //开启电荷泵
WriteCmd(0XAF); //OLED唤醒
}
void OLED_OFF(void){
WriteCmd(0X8D); //设置电荷泵
WriteCmd(0X10); //关闭电荷泵
WriteCmd(0XAE); //OLED休眠
}
void OLED_ShowChar(int x,int y,char txt[]){
int i,j;
y=y*8;
OLED_WrCmd(0xb0+2*x);
OLED_WrCmd(0x10|((0xf0&y)>>4));
OLED_WrCmd(0x00|(0x0f&y));
for(i=0;txt[i]!='\0';i++){
if(txt[i]-' '<0||txt[i]-' '>94) continue;
for(j=0;j<8;j++){
OLED_WrData(asc2_1206[txt[i]-' '][j]);
}
}
OLED_WrCmd(0xb0+2*x+1);
OLED_WrCmd(0x10|((0xf0&y)>>4));
OLED_WrCmd(0x00|(0x0f&y));
for(i=0;txt[i]!='\0';i++){
if(txt[i]-' '<0||txt[i]-' '>94) continue;
for(j=0;j<8;j++){
OLED_WrData(asc2_1206[txt[i]-' '][j+8]);
}
}
}
void OLED_ShowWord(int x,int y,int f){
int i,j;
y=y*8;
OLED_WrCmd(0xb0+2*x);
OLED_WrCmd(0x10|((0xf0&y)>>4));
OLED_WrCmd(0x00|(0x0f&y));
for(i=0;i<16;i++){
OLED_WrData(word[f][i]);
}
OLED_WrCmd(0xb0+2*x+1);
OLED_WrCmd(0x10|((0xf0&y)>>4));
OLED_WrCmd(0x00|(0x0f&y));
for(i=0;i<16;i++){
OLED_WrData(word[f][i+16]);
}
}
void OLED_ShowNum(int y,int x,int num)
{
int j;
x=x*8;
OLED_WrCmd(0xb0+2*y);
OLED_WrCmd(0x10|((0xf0&x)>>4));
OLED_WrCmd(0x00|(0x0f&x));
for(j=0;j<8;j++){
OLED_WrData(font_num[num][j]);
}
OLED_WrCmd(0xb0+2*y+1);
OLED_WrCmd(0x10|((0xf0&x)>>4));
OLED_WrCmd(0x00|(0x0f&x));
for(j=0;j<8;j++){
OLED_WrData(font_num[num][j+8]);
}
}
void OLED_ShowNums(int y,int x,int num,int len)
{
int i;
int dat;
dat=num;
for (i=0;i<len;i++){
OLED_ShowNum(y,x+len-i-1,dat%10);
dat=dat/10;
}
}
main.c:
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2021 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under Ultimate Liberty license
* SLA0044, the "License"; You may not use this file except in compliance with
* the License. You may obtain a copy of the License at:
* www.st.com/SLA0044
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "cmsis_os.h"
#include "MAX30102.h"
#include "stdio.h"
#include "oled.h"
char data_save;
int heart;
int red_reg[200];
int led_reg[200];
int heart_reg;
char online=1;
int reg_num=0;
int reg_heart=1;
unsigned char pData[8];
float spo2;
int flag=3;
unsigned char char_show=0;
I2C_HandleTypeDef hi2c1;
SPI_HandleTypeDef hspi1;
UART_HandleTypeDef huart1;
osThreadId_t defaultTaskHandle;
#ifdef __GNUC__
/* With GCC/RAISONANCE, small printf (option LD Linker->Libraries->Small printf
set to 'Yes') calls __io_putchar() */
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif /* __GNUC__ */
PUTCHAR_PROTOTYPE
{
/* Place your implementation of fputc here */
/* e.g. write a character to the USART */
huart1.Instance->DR = (uint8_t) ch;
/* Loop until the end of transmission */
while(__HAL_UART_GET_FLAG(&huart1, UART_FLAG_TC) == RESET){}
return ch;
}
const osThreadAttr_t defaultTask_attributes = {
.name = "defaultTask",
.priority = (osPriority_t) osPriorityNormal,
.stack_size = 128 * 4
};
osThreadId_t myTask02Handle;
const osThreadAttr_t myTask02_attributes = {
.name = "myTask02",
.priority = (osPriority_t) osPriorityLow,
.stack_size = 128 * 6
};
osThreadId_t myTask03Handle;
const osThreadAttr_t myTask03_attributes = {
.name = "myTask03",
.priority = (osPriority_t) osPriorityLow,
.stack_size = 128 * 4
};
osThreadId_t myTask04Handle;
const osThreadAttr_t myTask04_attributes = {
.name = "myTask04",
.priority = (osPriority_t) osPriorityLow,
.stack_size = 128 * 4
};
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_I2C1_Init(void);
static void MX_SPI1_Init(void);
static void MX_USART1_UART_Init(void);
void StartDefaultTask(void *argument);
void StartTask02(void *argument);
void StartTask03(void *argument);
void StartTask04(void *argument);
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C1_Init();
MX_SPI1_Init();
MX_USART1_UART_Init();
OLED_Init();
osKernelInitialize();
defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes);
myTask02Handle = osThreadNew(StartTask02, NULL, &myTask02_attributes);
myTask03Handle = osThreadNew(StartTask03, NULL, &myTask03_attributes);
myTask04Handle = osThreadNew(StartTask04, NULL, &myTask04_attributes);
/* USER CODE BEGIN RTOS_THREADS */
/* add threads, ... */
/* USER CODE END RTOS_THREADS */
/* Start scheduler */
maxim_max30102_reset();
osKernelStart();
/* We should never get here as control is now taken by the scheduler */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL4;
RCC_OscInitStruct.PLL.PLLDIV = RCC_PLL_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_1) != HAL_OK)
{
Error_Handler();
}
}
static void MX_I2C1_Init(void)
{
/* USER CODE BEGIN I2C1_Init 0 */
/* USER CODE END I2C1_Init 0 */
/* USER CODE BEGIN I2C1_Init 1 */
/* USER CODE END I2C1_Init 1 */
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 100000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN I2C1_Init 2 */
/* USER CODE END I2C1_Init 2 */
}
static void MX_SPI1_Init(void)
{
/* USER CODE BEGIN SPI1_Init 0 */
/* USER CODE END SPI1_Init 0 */
/* USER CODE BEGIN SPI1_Init 1 */
/* USER CODE END SPI1_Init 1 */
/* SPI1 parameter configuration*/
hspi1.Instance = SPI1;
hspi1.Init.Mode = SPI_MODE_MASTER;
hspi1.Init.Direction = SPI_DIRECTION_2LINES;
hspi1.Init.DataSize = SPI_DATASIZE_8BIT;
hspi1.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi1.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi1.Init.NSS = SPI_NSS_SOFT;
hspi1.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi1.Init.FirstBit = SPI_FIRSTBIT_MSB;
hspi1.Init.TIMode = SPI_TIMODE_DISABLE;
hspi1.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
hspi1.Init.CRCPolynomial = 10;
if (HAL_SPI_Init(&hspi1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN SPI1_Init 2 */
/* USER CODE END SPI1_Init 2 */
}
static void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
/*Configure GPIO pin : PC13 */
GPIO_InitStruct.Pin = GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
/*Configure GPIO pin : PC13 */
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
/*Configure GPIO pin : PC13 */
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
void StartDefaultTask(void *argument)
{
float r;
float red;
float led;
int red_last=0;
int led_last=0;
int cha=0;
int reg_num1=0;
int reg_num2=0;
int pot_i=0;
while (1)
{
HAL_I2C_Mem_Read(&hi2c1,I2C_READ_ADDR,REG_FIFO_DATA,I2C_MEMADD_SIZE_8BIT,(unsigned char *)pData,8,1000);
red=(red+(((pData[3]&0x03)<<16)|(pData[4]<<8)|(pData[5])))/2;
led=(led+(((pData[0]&0x03)<<16)|(pData[1]<<8)|(pData[2])))/2;
if(red>5000){ //判断采集状态
if(flag!=1) {OLED_Clear();flag=1;}
online=1;
cha=(cha+red-red_last)/2; //求导
if(cha<-10){data_save=data_save<<1|0;}
else data_save=data_save<<1|1;
r=red/led;
spo2=-45.060*r*r+30.354*r + 94.845;
if(pot_i<128){ //波形图显示
OLED_DrawPoint(++pot_i,25-cha/6);} //波形显示过大可把12调大,波形过小可调小12
else {
OLED_Clear();
pot_i=0;
}
}
else
{
if(flag!=0) {
OLED_Clear();
flag=0;
OLED_Clear();
pot_i=0;
data_save=0xff;
heart=0;
online=0;
reg_heart=0;
reg_num=0;
spo2=0;
}
OLED_ShowChar(1,2,"No FINGER!");
}
printf("a:%d,%d,%f,%f\n",cha,heart,red,spo2);
red_last=red;
maxim_max30102_write_reg(0x21,0x01);
vTaskDelay(10);
}
}
void StartTask02(void *argument)
{
while(1)
{
if(char_show==0){
OLED_ShowChar(3,0,"H:");
OLED_ShowNums(3,2,heart,3);
OLED_ShowChar(3,6,"Spo2:");
OLED_ShowNums(3,11,spo2,3);
vTaskDelay(10);
}
}
}
void StartTask03(void *argument)
{
int last;
int now;
int c;
int num=1;
while(1){
if((data_save&0xf0)==0x00)
{
now=HAL_GetTick();
if(now<last){c=(0xffffffff-last+now);}
else c=(now-last);
if(c>=300)
{
heart=60000/c;
last=now;
reg_heart=(reg_heart*reg_num+heart)/(reg_num+1);
if(reg_num==30){
heart_reg=reg_heart;
reg_num=0;
reg_heart=0;
}
else
reg_num++;
}
}
}
}
void StartTask04(void *argument)
{
for(;;)
{
osDelay(1);
}
}
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
tex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
源码过多,只展示了部分,全部源码下载链接:
https://download.csdn.net/download/qq_19534483/20368390
版权声明:本文为CSDN博主「Cn-Wang」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_19534483/article/details/118913979
暂无评论