From 93136756303b89c1e075a64e05d3fa0186d52ecf Mon Sep 17 00:00:00 2001 From: wangbeihong Date: Wed, 15 Apr 2026 00:06:45 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0RC522=E7=AB=99?= =?UTF-8?q?=E7=82=B9=E5=8C=B9=E9=85=8D=E9=80=BB=E8=BE=91=E5=8F=8A=E5=88=B0?= =?UTF-8?q?=E7=AB=99=E6=8F=90=E7=A4=BA=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Core/Bsp/bsp_rc522.c | 42 +++++++++++------------ Core/Bsp/protocol.c | 81 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 98 insertions(+), 25 deletions(-) diff --git a/Core/Bsp/bsp_rc522.c b/Core/Bsp/bsp_rc522.c index 68cf229..e3690b5 100644 --- a/Core/Bsp/bsp_rc522.c +++ b/Core/Bsp/bsp_rc522.c @@ -1,25 +1,4 @@ #include "bsp_rc522.h" -#include - -// 站点UID白名单(可扩展) -static const uint8_t g_station_1_uid[] = STATION_1_UID; -static const uint8_t g_station_2_uid[] = STATION_2_UID; - -station_id_t rc522_match_station(const uint8_t *uid, uint8_t uid_len) -{ - if (uid == NULL || uid_len == 0) return STATION_NONE; - // 匹配站点1 - if (uid_len == sizeof(g_station_1_uid) && memcmp(uid, g_station_1_uid, uid_len) == 0) { - return STATION_1; - } - // 匹配站点2 - if (uid_len == sizeof(g_station_2_uid) && memcmp(uid, g_station_2_uid, uid_len) == 0) { - return STATION_2; - } - // 可继续添加更多站点匹配 - return STATION_NONE; -} -#include "bsp_rc522.h" #include "spi.h" #include @@ -630,3 +609,24 @@ void rc522_irq_callback(uint16_t GPIO_Pin) g_irq_pending = 1U; } } + +/* 站点UID白名单(可扩展) */ +static const uint8_t g_station_1_uid[] = STATION_1_UID; +static const uint8_t g_station_2_uid[] = STATION_2_UID; + +station_id_t rc522_match_station(const uint8_t *uid, uint8_t uid_len) +{ + if (uid == NULL || uid_len == 0U) { + return STATION_NONE; + } + + if (uid_len == sizeof(g_station_1_uid) && memcmp(uid, g_station_1_uid, uid_len) == 0) { + return STATION_1; + } + + if (uid_len == sizeof(g_station_2_uid) && memcmp(uid, g_station_2_uid, uid_len) == 0) { + return STATION_2; + } + + return STATION_NONE; +} diff --git a/Core/Bsp/protocol.c b/Core/Bsp/protocol.c index 8e0c68f..4586a68 100644 --- a/Core/Bsp/protocol.c +++ b/Core/Bsp/protocol.c @@ -12,6 +12,8 @@ #include "bsp_hall.h" #include "bsp_pid.h" #include "bsp_uart.h" +#include "bsp_rc522.h" +#include "bsp_beep.h" #include "checksum.h" #include "cmsis_os.h" #include "elog.h" @@ -46,6 +48,10 @@ static float target_v_w = 0; // 原地旋转分量 static uint8_t car_running = 0; // 小车运行状态(1=运行,0=停止) static uint8_t car_speed_percent = 0; // 当前整体速度百分比(0~100) static uint16_t car_target_station = 0; // 目标站点编号 +static uint8_t car_target_reached = 0; // 到站锁存,避免重复触发 + +#define CAR_STATION_MIN ((uint16_t)STATION_1) +#define CAR_STATION_MAX ((uint16_t)STATION_2) /* 4个电机的 PID 控制器 */ static PID_TypeDef motor_pid[MOTOR_COUNT]; @@ -85,6 +91,46 @@ static void CarCtrl_StopAll(void) } } +/** + * @brief 到站蜂鸣提示 + * @param times 蜂鸣次数 + */ +static void CarCtrl_BeepTimes(uint8_t times) +{ + for (uint8_t i = 0; i < times; i++) { + BEEP_On(); + osDelay(120); + BEEP_Off(); + osDelay(120); + } +} + +/** + * @brief 运行期间检测是否到达目标站点 + */ +static void CarCtrl_CheckTargetStation(void) +{ + rc522_card_info_t card; + station_id_t station; + + if (car_running == 0U || car_target_reached != 0U || car_target_station == 0U) { + return; + } + + if (rc522_get_new_card(&card) == 0U) { + return; + } + + station = rc522_match_station(card.uid, card.uid_len); + if ((uint16_t)station == car_target_station) { + car_running = 0U; + car_target_reached = 1U; + CarCtrl_StopAll(); + elog_i(Protocol_TAG, "到达目标站点%u,停车并蜂鸣", car_target_station); + CarCtrl_BeepTimes(3U); + } +} + /** * @brief 按当前 car_speed_percent 设置所有电机速度 */ @@ -155,8 +201,8 @@ void CarCtrl_UpdateClosedLoop(void) const char* motor_names[] = {"LR", "LF", "RF", "RR"}; static uint32_t last_log_time = 0; if (HAL_GetTick() - last_log_time > 500) { - elog_d(Protocol_TAG, "M[%s] T:%.1f A:%.1f Pw:%d", - motor_names[i], target_rpms[i], actual_rpm, (int16_t)final_pwm); + elog_d(Protocol_TAG, "M[%s] T:%.1f A:%.1f Pw:%d", + motor_names[i], target_rpms[i], actual_rpm, (int16_t)final_pwm); if (i == MOTOR_COUNT - 1) last_log_time = HAL_GetTick(); } } @@ -184,11 +230,30 @@ static void CarCtrl_HandleCommand(const char *cmd_payload) // 启动/停止命令(仅作为自动循迹任务的启动/暂停信号,不直接控制电机) if (strncmp(cmd_payload, "ST", 2) == 0) { if (strcmp(arg + 1, "RUN") == 0) { + if (car_target_reached != 0U) { + car_running = 0U; + CarCtrl_StopAll(); + elog_w(Protocol_TAG, "已到达站点,请先重新设置目标站点 (GS:xxx) 之后再启动"); + CarCtrl_BeepTimes(2U); + return; + } + + if (car_target_station < CAR_STATION_MIN || car_target_station > CAR_STATION_MAX) { + car_running = 0U; + CarCtrl_StopAll(); + elog_w(Protocol_TAG, "未设置有效站点,拒绝启动。请先下发 GS:001 或 GS:002"); + CarCtrl_BeepTimes(2U); + return; + } + car_running = 1; + car_target_reached = 0; elog_i(Protocol_TAG, "小车自动循迹启动, speed=%u%%, station=%u", car_speed_percent, car_target_station); } else if (strcmp(arg + 1, "STOP") == 0) { car_running = 0; + car_target_reached = 0; + CarCtrl_StopAll(); elog_i(Protocol_TAG, "小车自动循迹暂停"); } else { elog_w(Protocol_TAG, "未知启动/停止命令: %s", cmd_payload); @@ -225,12 +290,17 @@ static void CarCtrl_HandleCommand(const char *cmd_payload) // 解析站点编号(0~999) if (sscanf(arg + 1, "%u", &station) == 1) { - if (station > 999U) { - station = 999U; + if (station < CAR_STATION_MIN || station > CAR_STATION_MAX) { + elog_w(Protocol_TAG, "站点%03u未配置,目前仅支持 %03u~%03u", station, + CAR_STATION_MIN, CAR_STATION_MAX); + CarCtrl_BeepTimes(2U); + return; } car_target_station = (uint16_t)station; + car_target_reached = 0; elog_i(Protocol_TAG, "设置目标站点: %03u", car_target_station); + CarCtrl_BeepTimes(1U); } else { elog_w(Protocol_TAG, "站点参数解析失败: %s", cmd_payload); } @@ -345,6 +415,9 @@ void CarCtrl_Task(void *argument) { CarCtrl_HandleCommand(cmd_payload); } + /* 1.1 运行中检查 RFID 是否到达目标站点 */ + CarCtrl_CheckTargetStation(); + /* 2. 执行 PID 闭环控制更新 */ CarCtrl_UpdateClosedLoop();