diff --git a/Core/Bsp/protocol.c b/Core/Bsp/protocol.c index 5c44509..a094856 100644 --- a/Core/Bsp/protocol.c +++ b/Core/Bsp/protocol.c @@ -8,6 +8,7 @@ */ #include "protocol.h" +#include "bsp_motor.h" #include "bsp_uart.h" #include "checksum.h" #include "cmsis_os.h" @@ -19,6 +20,129 @@ /* 定义日志 TAG */ #define Protocol_TAG "Protocol" +/* 小车控制状态相关定义 */ +#define CAR_PWM_MAX 3599U // PWM最大值,对应100% + +static uint8_t car_running = 0; // 小车运行状态(1=运行,0=停止) +static uint8_t car_speed_percent = 0; // 当前整体速度百分比(0~100) +static uint16_t car_target_station = 0; // 目标站点编号 + +/** + * @brief 百分比转PWM值 + * @param percent 速度百分比(0~100) + * @return int16_t PWM占空比 + */ +static int16_t CarCtrl_PercentToPwm(uint8_t percent) +{ + if (percent > 100U) { + percent = 100U; + } + return (int16_t)((CAR_PWM_MAX * percent) / 100U); +} + +/** + * @brief 停止所有电机 + */ +static void CarCtrl_StopAll(void) +{ + motor_stop(MOTOR_1); + motor_stop(MOTOR_2); + motor_stop(MOTOR_3); + motor_stop(MOTOR_4); +} + +/** + * @brief 按当前 car_speed_percent 设置所有电机速度 + */ +static void CarCtrl_ApplySpeed(void) +{ + int16_t pwm = CarCtrl_PercentToPwm(car_speed_percent); + + motor_set_speed(MOTOR_1, pwm); + motor_set_speed(MOTOR_2, pwm); + motor_set_speed(MOTOR_3, pwm); + motor_set_speed(MOTOR_4, pwm); +} + +/** + * @brief 解析并执行协议命令 + * @param cmd_payload 队列传入的命令字符串(如 "ST:RUN"、"SP:080"、"GS:005") + */ +static void CarCtrl_HandleCommand(const char *cmd_payload) +{ + const char *arg = NULL; + + if (cmd_payload == NULL || cmd_payload[0] == '\0') { + return; + } + + // 查找冒号分隔符,分割命令类型和参数 + arg = strchr(cmd_payload, ':'); + if (arg == NULL) { + elog_w(Protocol_TAG, "未知控制指令: %s", cmd_payload); + return; + } + + // 启动/停止命令(仅作为自动循迹任务的启动/暂停信号,不直接控制电机) + if (strncmp(cmd_payload, "ST", 2) == 0) { + if (strcmp(arg + 1, "RUN") == 0) { + car_running = 1; + elog_i(Protocol_TAG, "小车自动循迹启动, speed=%u%%, station=%u", car_speed_percent, + car_target_station); + } else if (strcmp(arg + 1, "STOP") == 0) { + car_running = 0; + elog_i(Protocol_TAG, "小车自动循迹暂停"); + } else { + elog_w(Protocol_TAG, "未知启动/停止命令: %s", cmd_payload); + } + return; + } + + // 设置整体速度命令 + if (strncmp(cmd_payload, "SP", 2) == 0) { + unsigned int speed = 0; + + // 解析速度参数(百分比,0~100) + if (sscanf(arg + 1, "%u", &speed) == 1) { + if (speed > 100U) { + speed = 100U; + } + + car_speed_percent = (uint8_t)speed; + elog_i(Protocol_TAG, "设置整体速度: %u%%", car_speed_percent); + + // 如果当前处于运行状态,立即生效 + if (car_running != 0U) { + CarCtrl_ApplySpeed(); + } + } else { + elog_w(Protocol_TAG, "速度参数解析失败: %s", cmd_payload); + } + return; + } + + // 设置目标站点命令 + if (strncmp(cmd_payload, "GS", 2) == 0) { + unsigned int station = 0; + + // 解析站点编号(0~999) + if (sscanf(arg + 1, "%u", &station) == 1) { + if (station > 999U) { + station = 999U; + } + + car_target_station = (uint16_t)station; + elog_i(Protocol_TAG, "设置目标站点: %03u", car_target_station); + } else { + elog_w(Protocol_TAG, "站点参数解析失败: %s", cmd_payload); + } + return; + } + + // 未知命令类型 + elog_w(Protocol_TAG, "未支持的控制命令: %s", cmd_payload); +} + /* 引用在 freertos.c 中定义的消息队列句柄 */ extern osMessageQueueId_t CmdQueueHandle; /** @@ -110,7 +234,7 @@ void Protocol_HandleMessage(uint8_t *data, uint16_t len) { void CarCtrl_Task(void *argument) { /* USER CODE BEGIN CarCtrl_Task */ - char cmd_payload[16]; + char cmd_payload[16] = {0}; /* Infinite loop */ for (;;) { /* 从消息队列中获取数据,阻塞等待 */ @@ -118,7 +242,7 @@ void CarCtrl_Task(void *argument) { osOK) { elog_i(CarCtrlTask_TAG, "CarCtrl: Received command (ASCII: %s) from queue", cmd_payload); - /* 可以在这里添加根据 cmd_payload 控制小车的逻辑 */ + CarCtrl_HandleCommand(cmd_payload); } // osDelay(1); // osMessageQueueGet 已经是阻塞的,不需要额外的 osDelay } diff --git a/物流小车/app.exe b/物流小车/app.exe new file mode 100644 index 0000000..6b808b8 Binary files /dev/null and b/物流小车/app.exe differ diff --git a/物流小车/checksum.py b/物流小车/checksum.py new file mode 100644 index 0000000..b1625dc --- /dev/null +++ b/物流小车/checksum.py @@ -0,0 +1,72 @@ +""" +物流小车控制指令 - 校验和算法工具(交互式) + +用法: + python checksum.py # 启动交互模式,手动输入指令计算校验和 +""" + +import sys +import io + +if sys.platform == 'win32': + sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace') + sys.stderr = io.TextIOWrapper(sys.stderr.buffer, encoding='utf-8', errors='replace') + + +def calc_checksum(data: str) -> str: + """计算校验和:ASCII码求和 % 256 → 2位十六进制""" + total = sum(ord(c) for c in data) + return format(total % 256, '02X') + + +def print_ascii_detail(data: str): + """打印每个字符的 ASCII 码值""" + print(f"\n 原始字符串: {data}") + print(f" ASCII 码分解:") + + total = 0 + parts = [] + for c in data: + val = ord(c) + total += val + parts.append(f"'{c}'({val})") + + print(" " + " + ".join(parts)) + print(f" 总和 = {total}") + print(f" 取余 = {total} % 256 = {total % 256}") + print(f" 十六进制 = {calc_checksum(data)}") + + +def main(): + print("\n" + "=" * 55) + print(" 物流小车指令校验和工具(交互式)") + print(" 输入原始字符串,自动计算校验和并生成完整指令") + print(" 输入 q 退出") + print("=" * 55) + + while True: + print(f"\n{'─' * 55}") + raw = input("\n 请输入指令内容(如 LOGI:GS:001): ").strip() + + if raw.lower() in ('q', 'quit', 'exit'): + print("\n 再见!\n") + break + + if not raw: + continue + + # 如果用户输入的不是以 LOGI: 开头,自动拼接 + if not raw.upper().startswith('LOGI:'): + print(f"\n [提示] 检测到未包含帧头,已自动添加 LOGI:") + raw = 'LOGI:' + raw + + cs = calc_checksum(raw) + full_cmd = f"{raw}:{cs}#" + + # 显示计算过程 + print_ascii_detail(raw) + print(f"\n >>> 完整指令: {full_cmd}") + + +if __name__ == '__main__': + main() diff --git a/物流小车/esp_12f/TCPUDPDbg/config/lastsend.data b/物流小车/esp_12f/TCPUDPDbg/config/lastsend.data index 211494f..e69de29 100644 --- a/物流小车/esp_12f/TCPUDPDbg/config/lastsend.data +++ b/物流小车/esp_12f/TCPUDPDbg/config/lastsend.data @@ -1 +0,0 @@ -0hhh \ No newline at end of file