/* 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 "cmsis_os.h" #include "main.h" #include "task.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include "elog.h" #include "motor_driver.h" #include "screen.h" #include "tim.h" #include "usart.h" #include #include #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 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 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 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 */ Screen_Init(); // 初始化命令 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); elog_d("MP3", "发送的消息是:%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", init_cmd1[0], init_cmd1[1], init_cmd1[2], init_cmd1[3], init_cmd1[4], init_cmd1[5], init_cmd1[6], init_cmd1[7], init_cmd1[8], init_cmd1[9]); osDelay(1500); // 重要:等待模块响应 HAL_UART_Transmit(&huart3, init_cmd2, sizeof(init_cmd2), 1000); elog_d("MP3", "发送的消息是:%02X %02X %02X %02X %02X %02X %02X %02X %02X %02X", init_cmd2[0], init_cmd2[1], init_cmd2[2], init_cmd2[3], init_cmd2[4], init_cmd2[5], init_cmd2[6], init_cmd2[7], init_cmd2[8], init_cmd2[9]); 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(10000); // 延时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; elog_d("HOT", "加热的状态: %d", 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_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 */ // HAL_UART_Transmit(&huart1, (uint8_t *)buf, strlen(buf), HAL_MAX_DELAY); /* Infinite loop */ for (;;) { } /* USER CODE END Screen */ } /* Private application code --------------------------------------------------*/ /* USER CODE BEGIN Application */ /* USER CODE END Application */