MAX30102的STM32驱动程序

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>&copy; 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>&copy; 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

生成海报
点赞 0

Cn-Wang

我还没有学会写个人说明!

暂无评论

发表评论

相关推荐