512 lines
15 KiB
C
512 lines
15 KiB
C
/* 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 <stdint.h>
|
||
#include <stdio.h>
|
||
#include "screen.h"
|
||
#include <string.h>
|
||
#include <sys/_intsup.h>
|
||
|
||
/* 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 */
|
||
|