3. 串口命令解析器
任务说明
实现一个串口命令解析器,接收形如 LED_ON、LED_OFF、PWM 128 的文本命令,解析后分发到对应处理函数。核心目标是让主程序只负责接收与分发,不包含具体业务逻辑,从而降低模块间耦合。
实现思路
采用命令表驱动方式:每个命令对应一个处理函数指针,解析器将命令字符串与命令表匹配后直接调用处理函数。新增命令时只需在表中增加一项,无需修改主循环或解析逻辑。
关键完整代码
#include <stdio.h>
#include <string.h>
#include <stdint.h>
/* 命令处理函数原型 */
typedef void (*cmd_handler_t)(const char *args);
/* 各命令的具体处理函数 */
static void led_on_handler(const char *args) {
printf("[执行] LED_ON, 参数: %s\n", args ? args : "(无)");
}
static void led_off_handler(const char *args) {
printf("[执行] LED_OFF, 参数: %s\n", args ? args : "(无)");
}
static void pwm_handler(const char *args) {
int duty = 0;
if (args && sscanf(args, "%d", &duty) == 1) {
printf("[执行] PWM 设置占空比: %d%%\n", duty);
} else {
printf("[错误] PWM 需要整数参数\n");
}
}
/* 命令表:命令名 + 处理函数 */
typedef struct {
const char *name;
cmd_handler_t handler;
} cmd_entry_t;
static const cmd_entry_t cmd_table[] = {
{"LED_ON", led_on_handler},
{"LED_OFF", led_off_handler},
{"PWM", pwm_handler},
};
#define CMD_TABLE_SIZE (sizeof(cmd_table) / sizeof(cmd_table[0]))
/* 解析并分发单条命令 */
static void parse_and_dispatch(char *line) {
/* 去除末尾换行/回车 */
line[strcspn(line, "\r\n")] = '\0';
/* 分离命令名与参数(空格分隔) */
char *cmd_name = strtok(line, " ");
char *args = strtok(NULL, ""); /* 剩余部分作为参数 */
if (cmd_name == NULL) return;
for (uint32_t i = 0; i < CMD_TABLE_SIZE; i++) {
if (strcmp(cmd_name, cmd_table[i].name) == 0) {
cmd_table[i].handler(args);
return;
}
}
printf("[错误] 未知命令: %s\n", cmd_name);
}
/* 模拟串口接收:从 stdin 逐行读取 */
int main(void) {
char line[128];
printf("串口命令解析器就绪,输入命令 (LED_ON / LED_OFF / PWM <数值>)\n");
while (fgets(line, sizeof(line), stdin)) {
parse_and_dispatch(line);
}
return 0;
}
编译与运行
gcc -o cmd_parser cmd_parser.c
./cmd_parser
验证方法
依次输入以下命令,观察输出是否符合预期:
- 输入
LED_ON→ 输出[执行] LED_ON, 参数: (无) - 输入
PWM 128→ 输出[执行] PWM 设置占空比: 128% - 输入
PWM abc→ 输出[错误] PWM 需要整数参数 - 输入
UNKNOWN→ 输出[错误] 未知命令: UNKNOWN
以上输出为代码逻辑直接推出的预期结果。若实际输出与之一致,说明解析与分发流程正确。
架构要点
- 主程序瘦身:
main()只负责读取行数据并调用parse_and_dispatch(),不包含任何命令业务逻辑。 - 低耦合扩展:新增命令时,只需编写处理函数并在
cmd_table中增加一项,解析器与主循环代码零修改。 - 参数透传:命令后的参数以字符串形式传给处理函数,由各函数自行解析,互不干扰。