/* USER CODE BEGIN Header */ /** ****************************************************************************** * File Name : freertos.c * Description : Code for freertos applications ****************************************************************************** * @attention * * Copyright (c) 2026 STMicroelectronics. * All rights reserved. * * This software is licensed under terms that can be found in the LICENSE file * in the root directory of this software component. * If no LICENSE file comes with this software, it is provided AS-IS. * ****************************************************************************** */ /* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "FreeRTOS.h" #include "task.h" #include "main.h" #include "cmsis_os.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "usart.h" #include "adc.h" #include "tim.h" #include "motor_driver.h" #include "elog.h" #include #include #include "screen.h" #include #include /* USER CODE END Includes */ /* Private typedef -----------------------------------------------------------*/ /* USER CODE BEGIN PTD */ /* USER CODE END PTD */ /* Private define ------------------------------------------------------------*/ /* USER CODE BEGIN PD */ /* USER CODE END PD */ /* Private macro -------------------------------------------------------------*/ /* USER CODE BEGIN PM */ #ifdef __GNUC__ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif PUTCHAR_PROTOTYPE { HAL_UART_Transmit(&huart5, (uint8_t *) &ch, 1, HAL_MAX_DELAY); return ch; } /* USER CODE END PM */ /* Private variables ---------------------------------------------------------*/ /* USER CODE BEGIN Variables */ /* 按键状态位: bit0..bit3 分别对应 M__KEY, M__KEYC7, HOT_KEY, TIME_KEY, 为1表示按下 */ volatile uint8_t key_state = 0; volatile uint8_t key_state_prev = 0; /* 上一次的按键状态,用于检测按键变化 */ /* 设备状态标志:0表示关闭,1表示打开 */ static uint8_t hot_state = 0; /* HOT 设备状态 */ static uint8_t time_state = 0; /* TIME_KEY 时间状态 */ /* USER CODE END Variables */ /* Definitions for defaultTask */ osThreadId_t defaultTaskHandle; const osThreadAttr_t defaultTask_attributes = { .name = "defaultTask", .stack_size = 128 * 4, .priority = (osPriority_t) osPriorityNormal, }; /* Definitions for KeyTask */ osThreadId_t KeyTaskHandle; const osThreadAttr_t KeyTask_attributes = { .name = "KeyTask", .stack_size = 512 * 4, .priority = (osPriority_t) osPriorityRealtime, }; /* Definitions for Sensor_Task */ osThreadId_t Sensor_TaskHandle; const osThreadAttr_t Sensor_Task_attributes = { .name = "Sensor_Task", .stack_size = 512 * 4, .priority = (osPriority_t) osPriorityHigh7, }; /* Definitions for Temp_Task */ osThreadId_t Temp_TaskHandle; const osThreadAttr_t Temp_Task_attributes = { .name = "Temp_Task", .stack_size = 256 * 4, .priority = (osPriority_t) osPriorityNormal, }; /* Definitions for Motor_Task */ osThreadId_t Motor_TaskHandle; const osThreadAttr_t Motor_Task_attributes = { .name = "Motor_Task", .stack_size = 512 * 4, .priority = (osPriority_t) osPriorityNormal1, }; /* Definitions for Screen_Tsak */ osThreadId_t Screen_TsakHandle; const osThreadAttr_t Screen_Tsak_attributes = { .name = "Screen_Tsak", .stack_size = 1024 * 4, .priority = (osPriority_t) osPriorityNormal, }; /* Private function prototypes -----------------------------------------------*/ /* USER CODE BEGIN FunctionPrototypes */ /* USER CODE END FunctionPrototypes */ void StartDefaultTask(void *argument); void Key(void *argument); void Sensor(void *argument); void Temp(void *argument); void Motor(void *argument); void Screen(void *argument); void MX_FREERTOS_Init(void); /* (MISRA C 2004 rule 8.1) */ /** * @brief FreeRTOS initialization * @param None * @retval None */ void MX_FREERTOS_Init(void) { /* USER CODE BEGIN Init */ easylogger_init(); /* 初始化 EasyLogger */ __enable_irq(); //开启全局中断 elog_i("task_init", "任务初始!"); /* USER CODE END Init */ /* USER CODE BEGIN RTOS_MUTEX */ /* add mutexes, ... */ /* USER CODE END RTOS_MUTEX */ /* USER CODE BEGIN RTOS_SEMAPHORES */ /* add semaphores, ... */ /* USER CODE END RTOS_SEMAPHORES */ /* USER CODE BEGIN RTOS_TIMERS */ /* start timers, add new ones, ... */ /* USER CODE END RTOS_TIMERS */ /* USER CODE BEGIN RTOS_QUEUES */ /* add queues, ... */ /* USER CODE END RTOS_QUEUES */ /* Create the thread(s) */ /* creation of defaultTask */ defaultTaskHandle = osThreadNew(StartDefaultTask, NULL, &defaultTask_attributes); /* creation of KeyTask */ KeyTaskHandle = osThreadNew(Key, NULL, &KeyTask_attributes); /* creation of Sensor_Task */ Sensor_TaskHandle = osThreadNew(Sensor, NULL, &Sensor_Task_attributes); /* creation of Temp_Task */ Temp_TaskHandle = osThreadNew(Temp, NULL, &Temp_Task_attributes); /* creation of Motor_Task */ Motor_TaskHandle = osThreadNew(Motor, NULL, &Motor_Task_attributes); /* creation of Screen_Tsak */ Screen_TsakHandle = osThreadNew(Screen, NULL, &Screen_Tsak_attributes); /* USER CODE BEGIN RTOS_THREADS */ /* add threads, ... */ /* USER CODE END RTOS_THREADS */ /* USER CODE BEGIN RTOS_EVENTS */ /* add events, ... */ /* USER CODE END RTOS_EVENTS */ } /* USER CODE BEGIN Header_StartDefaultTask */ /** * @brief Function implementing the defaultTask thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_StartDefaultTask */ void StartDefaultTask(void *argument) { /* USER CODE BEGIN StartDefaultTask */ // 初始化命令 uint8_t init_cmd1[] = {0x7E, 0xFF, 0x06, 0x06, 0x00, 0x00, 0x1E, 0xFE, 0xD7, 0xEF}; // 开启声音 uint8_t init_cmd2[] = {0x7E, 0xFF, 0x06, 0x09, 0x00, 0x00, 0x02, 0xFE, 0xF0, 0xEF}; // 指定播放设备为TF卡 // 定义测试指令数据 uint8_t test_cmd[] = {0x7E, 0xFF, 0x06, 0x12, 0x00, 0x00, 0x01, 0xFE, 0xE8, 0xEF}; // 先让模块稳定 osDelay(2000); // 初始化:先发送开启声音指令,再发送指定播放设备指令 HAL_UART_Transmit(&huart3, init_cmd1, sizeof(init_cmd1), 1000); osDelay(1500); // 重要:等待模块响应 HAL_UART_Transmit(&huart3, init_cmd2, sizeof(init_cmd2), 1000); osDelay(1500); // 重要:等待初始化完成 /* Infinite loop */ for(;;) { // 直接整包发送测试指令 HAL_UART_Transmit(&huart3, test_cmd, sizeof(test_cmd), 1000); // 把发送的数据打印出来 //elog_d("mp3_cmd","发送测试指令: %02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", test_cmd[0], test_cmd[1], test_cmd[2], test_cmd[3], test_cmd[4], test_cmd[5], test_cmd[6], test_cmd[7], test_cmd[8], test_cmd[9]); // 可选:等待发送完成 // while(__HAL_UART_GET_FLAG(&huart3, UART_FLAG_TC) == RESET); HAL_GPIO_TogglePin(RUN_LED_GPIO_Port, RUN_LED_Pin); osDelay(1000); // 延时1秒 } /* USER CODE END StartDefaultTask */ } /* USER CODE BEGIN Header_Key */ /** * @brief Function implementing the KeyTask thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_Key */ void Key(void *argument) { /* USER CODE BEGIN Key */ /* 防抖轮询实现四个低电平有效按键检测 */ GPIO_TypeDef* key_ports[4] = {M__KEY_GPIO_Port, M__KEYC7_GPIO_Port, HOT_KEY_GPIO_Port, TIME_KEY_GPIO_Port}; const uint16_t key_pins[4] = {M__KEY_Pin, M__KEYC7_Pin, HOT_KEY_Pin, TIME_KEY_Pin}; uint8_t press_count[4] = {0}; uint8_t release_count[4] = {0}; uint8_t pressed[4] = {0}; const uint8_t THRESH = 3; /* 3 * 10ms = 30ms 防抖 */ for(;;) { for (int i = 0; i < 4; i++) { GPIO_PinState level = HAL_GPIO_ReadPin(key_ports[i], key_pins[i]); if (level == GPIO_PIN_RESET) { /* 低电平有效 */ press_count[i]++; release_count[i] = 0; if (!pressed[i] && press_count[i] >= THRESH) { pressed[i] = 1; key_state |= (1 << i); /* bit0..3 分别对应四个按键按下状态 */ } } else { release_count[i]++; press_count[i] = 0; if (pressed[i] && release_count[i] >= THRESH) { pressed[i] = 0; key_state &= ~(1 << i); } } } osDelay(10); /* 10ms 轮询间隔 */ } /* USER CODE END Key */ } /* USER CODE BEGIN Header_Sensor */ /** * @brief Function implementing the Sensor_Task thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_Sensor */ void Sensor(void *argument) { /* USER CODE BEGIN Sensor */ /* 按键处理任务 - 按键状态切换控制 */ /* Infinite loop */ for(;;) { /* 检测新按下的按键 */ uint8_t key_pressed = key_state & ~key_state_prev; key_state_prev = key_state; /* ===== M__KEY (bit0) 控制 ===== */ if (key_pressed & (1 << 0)) { /* M__KEY 按下:加档(提高转速) */ elog_i("Key", "M__KEY按下 - 加档"); if (Motor_GetGear() == 0) { Motor_StartupBoost(); } else { Motor_GearUp(); } } /* ===== M__KEYC7 (bit1) 控制 ===== */ if (key_pressed & (1 << 1)) { /* M__KEYC7 按下:降档(降低转速) */ elog_i("Key", "M__KEYC7按下 - 降档"); Motor_GearDown(); } /* ===== HOT_KEY (bit2) 控制 ===== */ if (key_pressed & (1 << 2)) { /* HOT_KEY 按下:切换热功能 */ hot_state = !hot_state; HAL_GPIO_WritePin(HOT_GPIO_Port, HOT_Pin, hot_state ? GPIO_PIN_SET : GPIO_PIN_RESET); } /* ===== TIME_KEY (bit3) 控制 ===== */ if (key_pressed & (1 << 3)) { /* TIME_KEY 按下:切换定时 */ time_state = !time_state; if (time_state) { // TODO: 添加定时启动逻辑 } else { // TODO: 添加定时关闭逻辑 } } osDelay(20); /* 20ms 检查一次按键状态 */ } /* USER CODE END Sensor */ } /* USER CODE BEGIN Header_Temp */ /** * @brief Function implementing the Temp_Task thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_Temp */ void Temp(void *argument) { /* USER CODE BEGIN Temp */ #ifdef ENABLE_TEMP_SENSOR /* ADC采集参数 */ uint32_t adc_raw = 0; /* ADC原始值 */ uint32_t adc_sum = 0; /* 累加和(用于平均) */ uint16_t sample_count = 32; /* 采样次数 */ float voltage = 0.0f; /* 转换后的电压 */ float temperature = 0.0f; /* 转换后的温度 */ /* 电路参数 */ const float VREF = 3.3f; /* 参考电压 */ /* 一阶低通滤波器 */ float adc_filtered = 0.0f; /* 滤波后的ADC值 */ const float FILTER_ALPHA = 0.1f; /* 滤波系数 */ /* NTC 10K 3950参数 */ const float NTC_B_VALUE = 3950.0f; /* NTC B值 */ const float NTC_R0 = 10000.0f; /* 25°C时电阻10K */ const float NTC_T0 = 298.15f; /* 25°C对应的绝对温度(K) */ const float R_FIXED = 10000.0f; /* 分压电阻10K */ /* ADC校准 */ HAL_ADCEx_Calibration_Start(&hadc1); /* 预热:先采集几次丢弃,稳定ADC */ for (uint16_t i = 0; i < 10; i++) { HAL_ADC_Start(&hadc1); HAL_ADC_PollForConversion(&hadc1, 100); HAL_ADC_GetValue(&hadc1); HAL_ADC_Stop(&hadc1); osDelay(10); } /* Infinite loop */ for(;;) { /* 采集多次求平均,提高精度 */ adc_sum = 0; for (uint16_t i = 0; i < sample_count; i++) { HAL_ADC_Start(&hadc1); if (HAL_ADC_PollForConversion(&hadc1, 100) == HAL_OK) { adc_sum += HAL_ADC_GetValue(&hadc1); } HAL_ADC_Stop(&hadc1); osDelay(20); } /* 计算平均值 */ adc_raw = adc_sum / sample_count; /* 一阶低通滤波 */ if (adc_filtered == 0.0f) { adc_filtered = (float)adc_raw; } else { adc_filtered = FILTER_ALPHA * (float)adc_raw + (1.0f - FILTER_ALPHA) * adc_filtered; } adc_raw = (uint32_t)(adc_filtered + 0.5f); /* 转换为电压 */ voltage = ((float)adc_raw / 4095.0f) * VREF; /* ==================== NTC 10K 3950 温度计算 ==================== * 电路:3.3V ──[10K固定电阻]──┬── PA0 (ADC) * │ * [NTC 10K] * │ * GND * * Steinhart-Hart简化方程: * 1/T = 1/T0 + (1/B) * ln(R/R0) */ { /* 计算NTC电阻值 */ float ntc_resistance = R_FIXED * voltage / (VREF - voltage); /* Steinhart-Hart方程计算温度(K) */ float steinhart = logf(ntc_resistance / NTC_R0) / NTC_B_VALUE + 1.0f / NTC_T0; temperature = 1.0f / steinhart - 273.15f; /* 转换为摄氏度 */ elog_i("Temp", "ADC:%lu 电压:%.3fV NTC:%.1fΩ 温度:%.1f°C", adc_raw, voltage, ntc_resistance, temperature); } osDelay(1000); } #else /* 温度传感器未启用,任务空转 */ elog_i("Temp", "温度传感器未启用,等待NTC改装..."); for(;;) { osDelay(5000); elog_i("Temp", "温度传感器未启用,等待NTC改装..."); } #endif /* ENABLE_TEMP_SENSOR */ /* USER CODE END Temp */ } /* USER CODE BEGIN Header_Motor */ /** * @brief Function implementing the Motor_Task thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_Motor */ void Motor(void *argument) { /* USER CODE BEGIN Motor */ /* 电机驱动初始化 */ Motor_Init(); /* Infinite loop */ for(;;) { /* 电机任务主要功能: * - 监控电机状态(超温保护、过流保护等) * - 定期打印状态信息 * - 响应紧急停止信号 */ /* 每1秒打印一次电机状态 */ uint8_t current_gear = Motor_GetGear(); elog_i("Motor", "当前档位: %u (0=停止,1=低,2=中,3=高)", current_gear); osDelay(1000); } /* USER CODE END Motor */ } /* USER CODE BEGIN Header_Screen */ /** * @brief Function implementing the Screen_Tsak thread. * @param argument: Not used * @retval None */ /* USER CODE END Header_Screen */ void Screen(void *argument) { /* USER CODE BEGIN Screen */ char buf[100]; sprintf(buf, "CLR(1);\r\n"); //HAL_UART_Transmit(&huart1, (uint8_t *)buf, strlen(buf), HAL_MAX_DELAY); /* Infinite loop */ for(;;) { HAL_UART_Transmit(&huart1, (uint8_t *)buf, strlen(buf), HAL_MAX_DELAY); osDelay(2000); } /* USER CODE END Screen */ } /* Private application code --------------------------------------------------*/ /* USER CODE BEGIN Application */ /* USER CODE END Application */