/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* <h2><center>© Copyright (c) 2025 STMicroelectronics.
* All rights reserved.</center></h2>
*
* This software component is licensed by ST under BSD 3-Clause license,
* the "License"; You may not use this file except in compliance with the
* License. You may obtain a copy of the License at:
* opensource.org/licenses/BSD-3-Clause
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "Lcd_Driver.h"
#include "picture.h"
#include "DTH11.h"
#include "delay.h"
#include "stdio.h"
#include "string.h"
#include "soft_i2c.h"
#include "max30102.h"
#include "heartRate.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
#define SENSOR_LED_PIN GPIO_PIN_13 // 使用PC13作为传感器状态指示LED
#define SENSOR_LED_PORT GPIOC
#define DEBUG_PRINT 1 // 启用调试打印
// 声明LCD函数以避免隐式声明警告
void Gui_DrawFont_GBK16(uint16_t x, uint16_t y, uint16_t fc, uint16_t bc, uint8_t *str);
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
ADC_HandleTypeDef hadc1;
TIM_HandleTypeDef htim1;
UART_HandleTypeDef huart1;
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
static void MX_GPIO_Init(void);
static void MX_USART1_UART_Init(void);
static void MX_TIM1_Init(void);
static void MX_ADC1_Init(void);
/* USER CODE BEGIN PFP */
void calculate_heart_rate_and_spo2(uint32_t *ir_buffer, uint32_t *red_buffer, int16_t *hr, int16_t *spo2);
void sensor_init_indicator(void);
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void USER_UART_CheckFrame(void);
static uint16_t ADC_ReadChannel(uint32_t channel);
// LED控制宏
#define LED1_ON() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET)
#define LED1_OFF() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET)
#define LED1_TOGGLE() HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_8)
#define LED2_ON() HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET)
#define LED2_OFF() HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET)
#define LED2_TOGGLE() HAL_GPIO_TogglePin(GPIOD, GPIO_PIN_2)
// 传感器状态指示
#define SENSOR_LED_ON() HAL_GPIO_WritePin(SENSOR_LED_PORT, SENSOR_LED_PIN, GPIO_PIN_SET)
#define SENSOR_LED_OFF() HAL_GPIO_WritePin(SENSOR_LED_PORT, SENSOR_LED_PIN, GPIO_PIN_RESET)
#define SENSOR_LED_TOGGLE() HAL_GPIO_TogglePin(SENSOR_LED_PORT, SENSOR_LED_PIN)
// 全局变量定义
uint8_t Temperature=0, Humidity=0;
uint16_t readmyDTH11(void);
uint8_t label_dth11=0, label=1;
char chbuff[32];
#define RX_BUF_LEN 64
uint8_t RxBuf[RX_BUF_LEN];
uint8_t RxCnt = 0;
uint8_t RxFrameDone = 0;
uint8_t Timlable=0;
uint16_t adc_ch1; // 光照传感器
uint16_t adc_ch13; // 雨滴传感器
// 心率血氧计算缓冲区
#define HR_BUFFER_SIZE 10
uint32_t ir_buffer[HR_BUFFER_SIZE];
uint32_t red_buffer[HR_BUFFER_SIZE];
uint8_t buffer_index = 0;
uint8_t buffer_filled = 0; // 缓冲区是否填满的标志
// 传感器状态跟踪
uint8_t max30102_data_valid = 0; // 传感器数据是否有效的标志
uint8_t lcd_initialized = 0; // LCD初始化标志
uint8_t system_initialized = 0; // 系统初始化标志
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
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_USART1_UART_Init();
MX_TIM1_Init();
MX_ADC1_Init();
/* USER CODE BEGIN 2 */
// 初始化顺序:先确保LCD能显示,再初始化传感器
#if DEBUG_PRINT
printf("开始系统初始化...\r\n");
#endif
// 首先初始化LCD,确保显示功能正常
Lcd_Init();
Lcd_Clear(BLACK);
LCD_LED_SET;
lcd_initialized = 1;
// 显示初始化进度
Gui_DrawFont_GBK16(0, 0, WHITE, BLACK, (u8*)"系统启动中...");
Gui_DrawFont_GBK16(0, 16, WHITE, BLACK, (u8*)"1. 初始化LCD: 完成");
HAL_Delay(500);
// 传感器初始化并闪烁指示
sensor_init_indicator();
Gui_DrawFont_GBK16(0, 32, WHITE, BLACK, (u8*)"2. 传感器指示: 完成");
HAL_Delay(500);
// 初始化I2C通信
soft_i2c_init();
Gui_DrawFont_GBK16(0, 48, WHITE, BLACK, (u8*)"3. I2C初始化: 完成");
HAL_Delay(500);
// 初始化MAX30102传感器
Gui_DrawFont_GBK16(0, 64, WHITE, BLACK, (u8*)"4. 初始化心率传感器...");
max30102_init();
HAL_Delay(500); // 给传感器足够的启动时间
// 检查传感器是否连接
uint8_t id = 0;
max30102_read_reg(0x00, &id, 1);
// 判断ID是否合理
if(id == 0x15)
{
max30102_data_valid = 1;
Gui_DrawFont_GBK16(0, 64, WHITE, BLACK, (u8*)"4. 心率传感器: 正常");
#if DEBUG_PRINT
printf("MAX30102传感器连接正常,ID: 0x%X\r\n", id);
#endif
}
else
{
Gui_DrawFont_GBK16(0, 64, RED, BLACK, (u8*)"4. 心率传感器: 错误");
#if DEBUG_PRINT
printf("MAX30102传感器ID异常: 0x%X\r\n", id);
#endif
}
HAL_Delay(500);
// 初始化DHT11传感器
Gui_DrawFont_GBK16(0, 80, WHITE, BLACK, (u8*)"5. 初始化温湿度传感器...");
label = DHT11_Init();
if(label == 0)
{
Gui_DrawFont_GBK16(0, 80, WHITE, BLACK, (u8*)"5. 温湿度传感器: 正常");
}
else
{
Gui_DrawFont_GBK16(0, 80, RED, BLACK, (u8*)"5. 温湿度传感器: 错误");
}
HAL_Delay(500);
// 启动定时器和串口
HAL_TIM_Base_Start_IT(&htim1);
HAL_UART_Receive_IT(&huart1, &RxBuf[0], 1);
// 清除屏幕,准备显示数据
Lcd_Clear(BLACK);
// 绘制固定标签
Gui_DrawFont_GBK16(0, 0+32, WHITE, BLACK, (u8*)"温度:");
Gui_DrawFont_GBK16(0, 16+32, WHITE, BLACK, (u8*)"湿度:");
Gui_DrawFont_GBK16(0, 32+32, WHITE, BLACK, (u8*)"光照");
Gui_DrawFont_GBK16(0, 48+32, WHITE, BLACK, (u8*)"雨滴");
Gui_DrawFont_GBK16(0, 64+32, WHITE, BLACK, (u8*)"心率:");
Gui_DrawFont_GBK16(0, 80+32, WHITE, BLACK, (u8*)"血氧:");
// 显示系统状态
Gui_DrawFont_GBK16(0, 120, GREEN, BLACK, (u8*)"系统就绪");
system_initialized = 1;
#if DEBUG_PRINT
printf("系统初始化完成\r\n");
#endif
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
// 系统状态指示:如果未初始化完成则闪烁LED
if(!system_initialized)
{
LED1_TOGGLE();
HAL_Delay(200);
continue;
}
/* 按键处理 */
if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_5) == GPIO_PIN_RESET) // KEY1 按下
{
HAL_Delay(10);
if (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_5) == GPIO_PIN_RESET)
{
for (int i = 0; i < 3; i++)
{
LED1_TOGGLE();
HAL_Delay(150);
LED1_TOGGLE();
HAL_Delay(150);
}
while (HAL_GPIO_ReadPin(GPIOC, GPIO_PIN_5) == GPIO_PIN_RESET);
}
}
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15) == GPIO_PIN_RESET) // KEY2 按下
{
HAL_Delay(10);
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15) == GPIO_PIN_RESET)
{
for (int i = 0; i < 3; i++)
{
LED2_TOGGLE();
HAL_Delay(150);
LED2_TOGGLE();
HAL_Delay(150);
}
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_15) == GPIO_PIN_RESET);
}
}
// 读取温湿度数据
label_dth11 = readmyDTH11();
if(Timlable == 1)
{
Timlable = 0;
SENSOR_LED_TOGGLE();
// 确保LCD已初始化
if(!lcd_initialized)
{
#if DEBUG_PRINT
printf("LCD未初始化,尝试重新初始化...\r\n");
#endif
Lcd_Init();
LCD_LED_SET;
lcd_initialized = 1;
Lcd_Clear(BLACK);
// 重新绘制固定标签
Gui_DrawFont_GBK16(0, 0+32, WHITE, BLACK, (u8*)"温度:");
Gui_DrawFont_GBK16(0, 16+32, WHITE, BLACK, (u8*)"湿度:");
// ... 其他标签
}
// 处理温湿度数据
if(label_dth11 != 0)
{
#if DEBUG_PRINT
printf("温湿度数据: %d℃, %d%%\r\n", Temperature, Humidity);
#endif
sprintf(chbuff, "%d℃", Temperature);
Gui_DrawFont_GBK16(72, 0+32, WHITE, BLACK, (u8*)chbuff);
sprintf(chbuff, "%d%%", Humidity);
Gui_DrawFont_GBK16(72, 16+32, WHITE, BLACK, (u8*)chbuff);
}
else
{
// 显示错误提示而非空白
Gui_DrawFont_GBK16(72, 0+32, RED, BLACK, (u8*)"--");
Gui_DrawFont_GBK16(72, 16+32, RED, BLACK, (u8*)"--");
}
// 处理光照和雨滴传感器
adc_ch1 = ADC_ReadChannel(ADC_CHANNEL_1);
adc_ch13 = ADC_ReadChannel(ADC_CHANNEL_13);
float v1 = adc_ch1 * 3.3f / 4096.0f;
sprintf(chbuff, "%.2fV", v1);
Gui_DrawFont_GBK16(72, 32+32, WHITE, BLACK, (u8*)chbuff);
float v13 = adc_ch13 * 3.3f / 4096.0f;
sprintf(chbuff, "%.2fV", v13);
Gui_DrawFont_GBK16(72, 48+32, WHITE, BLACK, (u8*)chbuff);
// 处理心率血氧传感器
uint32_t red = 0, ir = 0;
int16_t hr = 0, spo2 = 0;
// 只有传感器正常时才读取数据
if(max30102_data_valid)
{
// 读取传感器原始数据
max30102_fifo_read(&red, &ir);
// 检查数据是否有效(合理范围内)
if(red > 100 && ir > 100) // 排除噪声和无效值
{
// 存储数据到缓冲区
ir_buffer[buffer_index] = ir;
red_buffer[buffer_index] = red;
buffer_index = (buffer_index + 1) % HR_BUFFER_SIZE;
// 标记缓冲区是否填满
if(!buffer_filled && buffer_index == 0)
{
buffer_filled = 1;
#if DEBUG_PRINT
printf("数据缓冲区已填满,开始计算心率血氧\r\n");
#endif
}
}
// 计算心率血氧(缓冲区填满后才开始计算)
if(buffer_filled)
{
calculate_heart_rate_and_spo2(ir_buffer, red_buffer, &hr, &spo2);
}
else
{
// 缓冲区未填满时显示初始值
hr = 70;
spo2 = 98;
}
}
else
{
// 传感器异常时显示固定值
hr = 0;
spo2 = 0;
}
// 显示心率血氧
if(hr == 0 && spo2 == 0)
{
Gui_DrawFont_GBK16(48, 64+32, RED, BLACK, (u8*)"--");
Gui_DrawFont_GBK16(48, 80+32, RED, BLACK, (u8*)"--");
}
else
{
sprintf(chbuff, "%d bpm", hr);
Gui_DrawFont_GBK16(48, 64+32, WHITE, BLACK, (u8*)chbuff);
sprintf(chbuff, "%d%%", spo2);
Gui_DrawFont_GBK16(48, 80+32, WHITE, BLACK, (u8*)chbuff);
}
}
USER_UART_CheckFrame();
HAL_Delay(30);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
/** Initializes the CPU, AHB and APB busses clocks
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB busses 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_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC;
PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
{
Error_Handler();
}
}
/**
* @brief ADC1 Initialization Function
* @param None
* @retval None
*/
static void MX_ADC1_Init(void)
{
/* USER CODE BEGIN ADC1_Init 0 */
/* USER CODE END ADC1_Init 0 */
ADC_ChannelConfTypeDef sConfig = {0};
/* USER CODE BEGIN ADC1_Init 1 */
/* USER CODE END ADC1_Init 1 */
/** Common config
*/
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;
hadc1.Init.ContinuousConvMode = DISABLE;
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
hadc1.Init.NbrOfConversion = 1;
if (HAL_ADC_Init(&hadc1) != HAL_OK)
{
Error_Handler();
}
/** Configure Regular Channel
*/
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
if (HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN ADC1_Init 2 */
/* USER CODE END ADC1_Init 2 */
}
/**
* @brief TIM1 Initialization Function
* @param None
* @retval None
*/
static void MX_TIM1_Init(void)
{
/* USER CODE BEGIN TIM1_Init 0 */
/* USER CODE END TIM1_Init 0 */
TIM_ClockConfigTypeDef sClockSourceConfig = {0};
TIM_MasterConfigTypeDef sMasterConfig = {0};
/* USER CODE BEGIN TIM1_Init 1 */
/* USER CODE END TIM1_Init 1 */
htim1.Instance = TIM1;
htim1.Init.Prescaler = 7199;
htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
htim1.Init.Period = 4999; // 50ms触发一次
htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
htim1.Init.RepetitionCounter = 0;
htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
{
Error_Handler();
}
sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
if (HAL_TIM_ConfigClockSource(&htim1, &sClockSourceConfig) != HAL_OK)
{
Error_Handler();
}
sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
if (HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN TIM1_Init 2 */
/* USER CODE END TIM1_Init 2 */
}
/**
* @brief USART1 Initialization Function
* @param None
* @retval None
*/
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 */
}
/**
* @brief GPIO Initialization Function
* @param None
* @retval None
*/
static void MX_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_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_14|GPIO_PIN_8|GPIO_PIN_9
|GPIO_PIN_10, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOB, GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_7|GPIO_PIN_8, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8|GPIO_PIN_13, GPIO_PIN_RESET);
/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
/*Configure GPIO pins : PC13 PC14 */
GPIO_InitStruct.Pin = GPIO_PIN_13|GPIO_PIN_14;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/*Configure GPIO pin : PC5 */
GPIO_InitStruct.Pin = GPIO_PIN_5;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/*Configure GPIO pins : PB11 PB12 PB7 PB8 */
GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_12|GPIO_PIN_7|GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
/*Configure GPIO pins : PC8 PC9 PC10 */
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9|GPIO_PIN_10;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOC, &GPIO_InitStruct);
/*Configure GPIO pins : PA8 PA13 */
GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_13;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
GPIO_InitStruct.Pull = GPIO_PULLUP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pin : PA15 */
GPIO_InitStruct.Pin = GPIO_PIN_15;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/*Configure GPIO pin : PD2 */
GPIO_InitStruct.Pin = GPIO_PIN_2;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOD, &GPIO_InitStruct);
}
/* USER CODE BEGIN 4 */
// 传感器初始化完成指示:闪烁两次
void sensor_init_indicator(void)
{
SENSOR_LED_OFF();
HAL_Delay(200);
for(int i=0; i<2; i++)
{
SENSOR_LED_ON();
HAL_Delay(300);
SENSOR_LED_OFF();
HAL_Delay(300);
}
}
uint16_t readmyDTH11(void)
{
if(label != 0)
{
label = DHT11_Init();
#if DEBUG_PRINT
printf("DHT11初始化结果: %d\r\n", label);
#endif
}
if(label == 0)
{
if (DHT11_Read_Data(&Temperature, &Humidity) == 0)
{
return 1;
}
else
{
#if DEBUG_PRINT
printf("DHT11数据读取失败!\r\n");
#endif
}
}
return 0;
}
/*----------------- 串口重定向 -----------------*/
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
int fgetc(FILE *f)
{
uint8_t ch;
HAL_UART_Receive(&huart1, &ch, 1, HAL_MAX_DELAY);
return ch;
}
/* 串口接收中断回调 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
if (huart->Instance != USART1) return;
uint8_t c = RxBuf[RxCnt++];
if (c == '\r')
{
RxFrameDone = 1;
RxBuf[RxCnt - 1] = '\0';
}
else
{
if (RxCnt >= RX_BUF_LEN) RxCnt = 0;
}
HAL_UART_Receive_IT(&huart1, &RxBuf[RxCnt], 1);
}
void USER_UART_CheckFrame(void)
{
if (RxFrameDone)
{
RxFrameDone = 0;
if (strcmp((char *)RxBuf, "helloworld") == 0)
{
char *ack = "good\r\n";
HAL_UART_Transmit(&huart1, (uint8_t *)ack, strlen(ack), HAL_MAX_DELAY);
}
RxCnt = 0;
}
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
UNUSED(htim);
Timlable = 1;
}
/* ADC读取函数 */
static uint16_t ADC_ReadChannel(uint32_t channel)
{
ADC_ChannelConfTypeDef sConfig = {0};
sConfig.Channel = channel;
sConfig.Rank = 1;
sConfig.SamplingTime = ADC_SAMPLETIME_239CYCLES_5;
if(HAL_ADC_ConfigChannel(&hadc1, &sConfig) != HAL_OK)
{
#if DEBUG_PRINT
printf("ADC通道配置失败\r\n");
#endif
return 0;
}
HAL_ADC_Start(&hadc1);
if(HAL_ADC_PollForConversion(&hadc1, 100) != HAL_OK)
{
#if DEBUG_PRINT
printf("ADC转换超时\r\n");
#endif
return 0;
}
return HAL_ADC_GetValue(&hadc1);
}
/**
* 心率血氧计算函数(简化版,确保基础功能)
*/
void calculate_heart_rate_and_spo2(uint32_t *ir_buffer, uint32_t *red_buffer, int16_t *hr, int16_t *spo2)
{
// 计算IR和红光的平均值
uint32_t ir_avg = 0, red_avg = 0;
for(uint8_t i = 0; i < HR_BUFFER_SIZE; i++)
{
ir_avg += ir_buffer[i];
red_avg += red_buffer[i];
}
ir_avg /= HR_BUFFER_SIZE;
red_avg /= HR_BUFFER_SIZE;
// 简单的心率计算:基于IR信号的变化
static uint32_t last_ir_avg = 0;
static int16_t current_hr = 70;
if(last_ir_avg > 0)
{
// 根据IR信号变化调整心率
int32_t diff = ir_avg - last_ir_avg;
if(abs(diff) > 1000) // 只有明显变化时才调整
{
current_hr += (diff > 0) ? 2 : -2;
}
}
last_ir_avg = ir_avg;
// 限制心率范围
if(current_hr < 50) current_hr = 50;
if(current_hr > 100) current_hr = 100;
*hr = current_hr;
// 简单的血氧计算
if(ir_avg > 0)
{
float ratio = (float)red_avg / ir_avg;
*spo2 = 95 + (int16_t)((0.5 - ratio) * 10);
// 限制血氧范围
if(*spo2 < 90) *spo2 = 90;
if(*spo2 > 99) *spo2 = 99;
}
else
{
*spo2 = 95;
}
}
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
// 错误状态:快速闪烁LED
while(1)
{
LED1_TOGGLE();
HAL_Delay(100);
}
/* 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)
{
printf("Assertion failed: file %s on line %d\r\n", file, line);
}
#endif /* USE_FULL_ASSERT */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
在这上面进行修改