欢迎光临
我们一直在努力

【嵌入式外设精学】Day10|校验与协议帧:和、CRC、帧头长度

【嵌入式外设精学】Day10|校验与协议帧:和、CRC、帧头长度

今天解决:有校验为什么还会执行错命令?帧该怎么设计?


目录

  • 问题 2. 原理 3. 代码 4. 误区 5. 自测 6. 答案

  • 1. 问题

    • 串口收对了字节却解错业务
    • 校验过了但动作错乱

    2. 原理

    2.1 两层“校验”

    层例子作用
    硬件帧 8N1 起止位 保证一个字节能收
    协议帧 帧头、长度、命令、数据、校验 保证一段消息完整、正确

    2.2 校验能力差别(直觉)

    方法说明
    奇偶 只查 1 的个数,很弱
    累加和/异或 能挡不少错,交换、抵消类错误可能漏
    CRC 抗突发错误强,推荐

    2.3 为什么还要帧头和长度

    • 帧头:从字节流里认出“一条消息开始”
    • 长度:知道这条收到哪结束,并防止乱值导致缓冲区爆掉
    • 校验:整条对不对

    三件套缺一不可。


    3. 代码示例

    #include <stdint.h>
    #include <stdbool.h>

    #define FRAME_HDR 0xAAu
    #define FRAME_MAX 16u

    typedef struct {
    uint8_t hdr;
    uint8_t len;
    uint8_t cmd;
    uint8_t data[8];
    uint8_t sum;
    } frame_t;

    uint8_t sum_range(const uint8_t *p, uint32_t n)
    {
    uint8_t s = 0;
    while (n—) {
    s = (uint8_t)(s + *p++);
    }
    return s;
    }

    bool frame_valid(const frame_t *f)
    {
    /* 约定:sum 覆盖 hdr..data */
    uint8_t s = sum_range((const uint8_t *)f, (uint32_t)(2u + 1u + 8u));
    return (f->hdr == FRAME_HDR) && (s == f->sum);
    }

    简单 CRC8 示例(可替换为库函数):

    uint8_t crc8_calc(const uint8_t *d, uint32_t n)
    {
    uint8_t crc = 0x00u;
    uint32_t i;
    int b;
    for (i = 0; i < n; i++) {
    crc ^= d[i];
    for (b = 0; b < 8; b++) {
    crc = (crc & 0x80u) ? (uint8_t)((crc << 1) ^ 0x07u)
    : (uint8_t)(crc << 1);
    }
    }
    return crc;
    }


    4. 常见误区

    误区正解
    只有奇偶就够 协议里还要和/CRC
    校验过了就一定业务对 还要 cmd 合法、长度合法
    len 不设上限 错帧可能把缓冲写爆
    数据里可以随便出现帧头 要靠状态机+校验丢弃假峰

    5. 自测

  • 协议帧至少要有哪几样?
  • 为何不能只靠帧头?

  • 6. 答案

  • 帧头、长度(或定界)、负载语义、校验。
  • 数据里也会出现相同字节,必须结合长度推进和校验。

  • 作者:shuifanyu 标签:协议 CRC 校验和 串口

    赞(0)
    未经允许不得转载:171主机测评 » 【嵌入式外设精学】Day10|校验与协议帧:和、CRC、帧头长度
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址