Rust的匹配中的模式覆盖
2026/6/26 4:45:51
目录
一、VSCode
(1)App_receive_data.h
(2)App_receive_data.c
(3)App_freertos_task.c
(4)Com_config.h
(5)飞行状态机
(6)油门解锁状态机
二、可能遇到的问题
#ifndef __APP_RECEIVE_DATA__ #define __APP_RECEIVE_DATA__ #include "Int_SI24R1.h" #include "Com_config.h" // 定义帧头校验的值 #define FRAME_HEAD_CHECK_1 's' #define FRAME_HEAD_CHECK_2 'g' #define FRAME_HEAD_CHECK_3 'g' // 最大重试次数 #define MAX_RETRY_TIMES 10 /** * @brief 接收遥控器发送的遥控数据 => 解析为结构体 * * @return uint8_t 0:校验通过 是正常的数据 1:没收到数据 或者 校验失败 */ uint8_t App_receive_data(void); /** * @brief 处理连接状态的状态 * * @param res 上一次接收数据的返回值 */ void App_process_connect_state(uint8_t res); /** * @brief 处理飞机的飞行状态 * */ void App_process_flight_state(void); #endif // __APP_RECEIVE_DATA__#include "App_receive_data.h" extern Remote_Data remote_data; uint8_t rx_buff[TX_PLOAD_WIDTH] = {0}; // 遥控连接状态 extern Remote_State remote_state; // 飞行状态 extern Flight_State flight_state; // 油门解锁状态值 Thr_state thr_state = FREE; // MAX状态的进入时间 uint32_t max_enter_time = 0; // MIN状态的进入时间 uint32_t min_enter_time = 0; // 重试次数 uint8_t retry_count = 0; /** * @brief 接收遥控器发送的遥控数据 => 解析为结构体 * * @return uint8_t 0:校验通过 是正常的数据 1:没收到数据 或者 校验失败 */ uint8_t App_receive_data(void) { memset(rx_buff, 0, TX_PLOAD_WIDTH); Int_SI24R1_RxPacket(rx_buff); if (strlen((char *)rx_buff) == 0) { return 1; } // 1. 帧头校验 if (rx_buff[0] != FRAME_HEAD_CHECK_1 || rx_buff[1] != FRAME_HEAD_CHECK_2 || rx_buff[2] != FRAME_HEAD_CHECK_3) { return 1; } // 2. 帧尾校验 uint32_t sum = 0; uint32_t sum_receive = 0; for (uint8_t i = 0; i < 13; i++) { sum += rx_buff[i]; } // 高位在前 sum_receive = rx_buff[13] << 24 | rx_buff[14] << 16 | rx_buff[15] << 8 | rx_buff[16]; if (sum != sum_receive) { return 1; } // 3. 保存数据 remote_data.thr = (rx_buff[3] << 8) | rx_buff[4]; remote_data.yaw = (rx_buff[5] << 8) | rx_buff[6]; remote_data.pit = (rx_buff[7] << 8) | rx_buff[8]; remote_data.rol = (rx_buff[9] << 8) | rx_buff[10]; remote_data.shutdown = rx_buff[11]; remote_data.fix_height = rx_buff[12]; debug_printf(":%d,%d,%d,%d,%d,%d\n", remote_data.thr, remote_data.yaw, remote_data.pit, remote_data.rol, remote_data.shutdown, remote_data.fix_height); return 0; } /** * @brief 处理连接状态的状态 * * @param res 上一次接收数据的返回值 */ void App_process_connect_state(uint8_t res) { if (res == 0) { // 接收数据成功一次 即为连接成功 // 此处使用的全局变量 只有当前一个地方会修改 LED灯控任务当中是读取使用 remote_state = REMOTE_CONNECTED; retry_count = 0; } else if (res == 1) { // 接收数据失败 即为 retry_count++; if (retry_count >= MAX_RETRY_TIMES) { remote_state = REMOTE_DISCONNECTED; retry_count = 0; } } } /** * @brief 处理解锁逻辑 * * @return uint8_t 0: 解锁成功 1: 解锁失败 */ static uint8_t App_process_unlock(void) { // 1. 考虑安全问题 => 解锁完成的最终状态应该是油门为0 switch (thr_state) { case FREE: if (remote_data.thr >= 900) { // 2. 进入max状态 thr_state = MAX; // freeRTOS操作系统中以ms为单位计数的时间 max_enter_time = xTaskGetTickCount(); } break; case MAX: // 3. 持续的时间应该是离开的时间减去进入的时间 if (remote_data.thr < 900) { if (xTaskGetTickCount() - max_enter_time >= 1000) { // 4. 油门保持最高状态超过1s => 进入leave_max状态 thr_state = LEAVE_MAX; } else { // 5. 油门保持最高状态时间小于1s => 退回到free 重新解锁 thr_state = FREE; } } break; case LEAVE_MAX: if (remote_data.thr <= 100) { // 6. 油门回到0 进入min状态 thr_state = MIN; min_enter_time = xTaskGetTickCount(); } break; case MIN: // 7. 每次判断当前已经保持了多久 if (xTaskGetTickCount() - min_enter_time <= 1000) { // 还不够1s if (remote_data.thr > 100) { thr_state = FREE; } } else { // 已经保持够1s => 解锁完成 thr_state = UNLOCK; } break; case UNLOCK: /* code */ break; default: break; } if (thr_state == UNLOCK) { return 0; } return 1; } /** * @brief 处理飞机的飞行状态 * */ void App_process_flight_state(void) { // 使用状态机逻辑实现 // 1. 轮询调用判断当前所处的状态 switch (flight_state) { case IDLE: // 2. 只需要编写指向其他状态的代码即可 if (App_process_unlock() == 0) { flight_state = NORMAL; // 每一次解锁成功 需要将解锁状态重置 thr_state = FREE; } break; case NORMAL: // 3. 判断进入定高 if (remote_data.fix_height == 1) { flight_state = FIX_HEIGHT; remote_data.fix_height = 0; } // 4. 判断进入故障失联状态 if (remote_state == REMOTE_DISCONNECTED) { flight_state = FAIL; } break; case FIX_HEIGHT: // 5. 取消定高 if (remote_data.fix_height == 1) { flight_state = NORMAL; remote_data.fix_height = 0; } // 6. 判断故障 if (remote_state == REMOTE_DISCONNECTED) { flight_state = FAIL; } break; case FAIL: // 7.处理失联故障 缓慢停止电机 // TODO vTaskDelay(1); flight_state = IDLE; break; default: break; } }#include "App_freeRTOS_Task.h" // STM32F103C8T6 => SRAM 20k => 分配12K给操作系统 // 内存管理 => C语言中的结构体通常保存在堆中 不会自动垃圾回收 => 始终使用同一个结构体 不断循环使用 // 电机结构体 Motor_Struct left_top_motor = {.tim = &htim3, .channel = TIM_CHANNEL_1, .speed = 200}; Motor_Struct left_bottom_motor = {.tim = &htim4, .channel = TIM_CHANNEL_4, .speed = 200}; Motor_Struct right_top_motor = {.tim = &htim2, .channel = TIM_CHANNEL_2, .speed = 200}; Motor_Struct right_bottom_motor = {.tim = &htim1, .channel = TIM_CHANNEL_3, .speed = 200}; // LED结构体 LED_Struct left_top_led = {.port = LED1_GPIO_Port, .pin = LED1_Pin}; LED_Struct right_top_led = {.port = LED2_GPIO_Port, .pin = LED2_Pin}; LED_Struct right_bottom_led = {.port = LED3_GPIO_Port, .pin = LED3_Pin}; LED_Struct left_bottom_led = {.port = LED4_GPIO_Port, .pin = LED4_Pin}; // 表示当前连接状态 Remote_State remote_state = REMOTE_DISCONNECTED; // 表示当前的飞行状态 Flight_State flight_state = IDLE; // 扩展获取接收的遥控数据 Remote_Data remote_data = {0}; // 电源管理任务 void power_task(void *args); // 最小推荐填写128 => 128*4 = 512B #define POWER_TASK_STACK_SIZE 128 // 任务优先级 => 数值越小 优先级越小 => 最大4 => 不推荐使用最小优先级0 #define POWER_TASK_PRIORITY 4 TaskHandle_t power_task_handle; // 定义任务的周期 #define POWER_TASK_PERIOD 10000 // 飞行控制任务 void flight_task(void *args); #define FLIGHT_TASK_STACK_SIZE 128 #define FLIGHT_TASK_PRIORITY 3 TaskHandle_t flight_task_handle; #define FLIGHT_TASK_PERIOD 6 // LED任务 void led_task(void *args); #define LED_TASK_STACK_SIZE 128 #define LED_TASK_PRIORITY 1 TaskHandle_t led_task_handle; #define LED_TASK_PERIOD 100 // 通讯任务 void com_task(void *args); #define COM_TASK_STACK_SIZE 128 #define COM_TASK_PRIORITY 2 TaskHandle_t com_task_handle; // 任务周期 #define COM_TASK_PERIOD 6 /** * @brief 启动freeRTOS操作系统 * */ void App_freeRTOS_start(void) { // 1. 创建电源管理任务 xTaskCreate(power_task, "power_task", POWER_TASK_STACK_SIZE, NULL, POWER_TASK_PRIORITY, &power_task_handle); // 2. 创建飞行控制任务 xTaskCreate(flight_task, "flight_task", FLIGHT_TASK_STACK_SIZE, NULL, FLIGHT_TASK_PRIORITY, &flight_task_handle); // 3. 创建LED灯任务 xTaskCreate(led_task, "led_task", LED_TASK_STACK_SIZE, NULL, LED_TASK_PRIORITY, &led_task_handle); // 4. 创建通讯任务 xTaskCreate(com_task, "com_task", COM_TASK_STACK_SIZE, NULL, COM_TASK_PRIORITY, &com_task_handle); // 5. 启动调度器 vTaskStartScheduler(); } void power_task(void *args) { // 获取当前的基准时间 TickType_t xLastWakeTime = xTaskGetTickCount(); while (1) { // // 每10s执行一次 => 启动电源 避免自动关机 // vTaskDelayUntil(&xLastWakeTime, POWER_TASK_PERIOD); // // 启动电源 // Int_IP5305T_start(); // 使用直接任务通知的接收方法实现10s处理一次 // 一直等任务通知 直到收到通知res=1 或者 超时res=0 uint32_t res = ulTaskNotifyTake(pdTRUE, POWER_TASK_PERIOD); if (res != 0) { // 收到关机通知 Int_IP5305T_shutdown(); } else { // 不需要关机 => 正常执行启动 Int_IP5305T_start(); } } } void flight_task(void *args) { // 获取当前的基准时间 TickType_t xLastWakeTime = xTaskGetTickCount(); while (1) { // 1. 设置电机的转速 left_top_motor.speed = 400; // 2. 直接启动电机 // Int_motor_start(&left_top_motor); // Int_motor_start(&right_bottom_motor); vTaskDelayUntil(&xLastWakeTime, FLIGHT_TASK_PERIOD); } } void led_task(void *args) { // 获取当前的基准时间 TickType_t xLastWakeTime = xTaskGetTickCount(); uint8_t count = 0; while (1) { count++; // 前两个灯表示连接状态 // 1. 判断当前连接状态 if (remote_state == REMOTE_CONNECTED) { // 点亮前两个灯 Int_led_turn_on(&left_top_led); Int_led_turn_on(&right_top_led); } else if (remote_state == REMOTE_DISCONNECTED) { // 关掉前两个灯 Int_led_turn_off(&left_top_led); Int_led_turn_off(&right_top_led); } // 后两个灯表示飞行状态 // 2. 判断当前飞行状态 if (flight_state == IDLE) { // 灯慢闪烁 => 500ms亮 500ms灭 if (count % 5 == 0) { // 循环5次 一次是100ms 5次等于500ms Int_led_toggle(&left_bottom_led); Int_led_toggle(&right_bottom_led); } } else if (flight_state == NORMAL) { // 灯快闪 => 200ms亮 200ms灭 if (count % 2 == 0) { // 循环2次 一次是100ms 2次等于200ms Int_led_toggle(&left_bottom_led); Int_led_toggle(&right_bottom_led); } } else if (flight_state == FIX_HEIGHT) { // 后两个灯常量 Int_led_turn_on(&left_bottom_led); Int_led_turn_on(&right_bottom_led); } else if (flight_state == FAIL) { // 后两个灯灭 Int_led_turn_off(&left_bottom_led); Int_led_turn_off(&right_bottom_led); } // 将count计数重置 if (count == 10) { count = 0; } vTaskDelayUntil(&xLastWakeTime, LED_TASK_PERIOD); } } void com_task(void *args) { // 获取当前的基准时间 TickType_t xLastWakeTime = xTaskGetTickCount(); while (1) { // 1. 接收数据 uint8_t res = App_receive_data(); // 2. 根据接收数据的返回值 处理当前飞机的连接状态 App_process_connect_state(res); // 3. 处理关机命令 if (remote_data.shutdown == 1) { // 使用Int_IP5305T_shutdown 关机 功能可以实现 但是项目结构比较奇怪 // Int_IP5305T_shutdown(); // 使用freeRTOS直接任务通知 => 通知电源任务 => 执行关机 xTaskNotifyGive(power_task_handle); } // 4. 处理飞机的飞行状态 App_process_flight_state(); // 6ms执行一次 接收数据的时间间隔应该等于发送数据的时间间隔 vTaskDelayUntil(&xLastWakeTime, COM_TASK_PERIOD); } }#ifndef _COM_CONFIG_H #define _COM_CONFIG_H #include "main.h" // 连接状态 typedef enum { REMOTE_CONNECTED = 0, REMOTE_DISCONNECTED, }Remote_State; // 飞行状态 typedef enum { IDLE = 0, NORMAL, FIX_HEIGHT, FAIL, }Flight_State; // 油门解锁状态 typedef enum { FREE = 0, MAX, LEAVE_MAX, MIN, UNLOCK, } Thr_state; typedef struct { int16_t thr; int16_t yaw; int16_t pit; int16_t rol; uint8_t shutdown; // 1: 关闭 0: 不关机 uint8_t fix_height; // 1. 切换定高和不定高 0: 不切换 } Remote_Data; #endif // !_COM_CONFIG_H在飞控失联/故障的情况下,小灯没有熄灭,是因为油门解锁状态没有设为FREE