《嵌入式通讯协议栈实战》 3 通讯帧设计

第 3 篇:UART 协议设计------定义你自己的通讯协议


1. 帧格式设计

复制代码
┌──────┬──────┬──────┬──────┬──────┬──────┬──────┐
│ 帧头  │ 地址 │ 命令  │ 长度  │ 数据  │ CRC16 │ 帧尾  │
│ 2字节 │ 1字节│ 1字节 │ 1字节 │ N字节 │ 2字节 │ 1字节 │
│ 0xA5 │      │      │      │      │       │ 0x5A │
│ 0x5A │      │      │      │      │       │       │
└──────┴──────┴──────┴──────┴──────┴──────┴──────┘

2. 转义机制(SLIP 协议)

如果数据中恰好出现了 0xA5 或 0x5A,需要转义:

c 复制代码
#define FRAME_START  0xA5
#define FRAME_END    0x5A
#define ESCAPE_CHAR  0x7D

void slip_encode(uint8_t *in, int len, uint8_t *out, int *out_len) {
    for (int i = 0; i < len; i++) {
        if (in[i] == FRAME_START || in[i] == FRAME_END || in[i] == ESCAPE_CHAR) {
            out[(*out_len)++] = ESCAPE_CHAR;
        }
        out[(*out_len)++] = in[i];
    }
}

3. CRC16 校验

c 复制代码
uint16_t crc16_modbus(const uint8_t *data, int len) {
    uint16_t crc = 0xFFFF;
    for (int i = 0; i < len; i++) {
        crc ^= data[i];
        for (int j = 0; j < 8; j++) {
            if (crc & 1) crc = (crc >> 1) ^ 0xA001;
            else         crc >>= 1;
        }
    }
    return crc;
}

4. 逐字节解析状态机

c 复制代码
typedef enum { STATE_IDLE, STATE_HEAD1, STATE_HEAD2, STATE_ADDR,
               STATE_CMD, STATE_LEN, STATE_DATA, STATE_CRC1,
               STATE_CRC2, STATE_TAIL } proto_state_t;

void proto_parse_byte(proto_state_t *s, uint8_t byte) {
    switch (*s) {
        case STATE_IDLE:
            if (byte == 0xA5) *s = STATE_HEAD2; break;
        case STATE_HEAD2:
            *s = (byte == 0x5A) ? STATE_ADDR : STATE_IDLE; break;
        case STATE_ADDR:  frame.addr = byte; *s = STATE_CMD; break;
        // ... 依此类推
    }
}

状态机逐字节解析,不依赖于 DMA 缓冲区的起始位置------即使帧丢失也能自动恢复同步。


下一篇:I2C------主从模式的硬件与软件实现

相关推荐
做前端的娜娜子1 小时前
移动端上拉加载与下拉刷新实现方案
前端·面试·掘金·金石计划
程序员爱钓鱼2 小时前
Go 布尔类型 bool 详解
后端·面试·go
程序员爱钓鱼2 小时前
Rust Clone详解:深拷贝、复制成本与正确使用方式
后端·面试·rust
程序员-Benothing2 小时前
MySQL 的存储引擎有哪些?它们之间有什么区别?
后端·mysql·面试·职场和发展
艾莉丝努力练剑2 小时前
Mac 远程桌面体验:6 个工具的 macOS 适配情况整理
linux·运维·服务器·macos·面试
天才测试猿11 小时前
2026软件测试面试八股文(含答案+文档)
自动化测试·软件测试·python·功能测试·测试工具·面试·职场和发展
kyriewen15 小时前
我重写了自己用了两年的防抖节流Hook——发现里面藏着3个隐藏bug
前端·javascript·面试
spter。18 小时前
AI 面试相同请求为什么会重复调用,如何解决
人工智能·面试·职场和发展
众人皆醒我独醉18 小时前
Ray Serve:把 LLM 推理当"分布式 Actor"调度——不是 Kubernetes,是 Python 原生
面试·llm·ai编程