公司动态

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

📅 2026/8/8 8:46:55
《嵌入式通讯协议栈实战》 3 通讯帧设计
第 3 篇UART 协议设计——定义你自己的通讯协议1. 帧格式设计┌──────┬──────┬──────┬──────┬──────┬──────┬──────┐ │ 帧头 │ 地址 │ 命令 │ 长度 │ 数据 │ CRC16 │ 帧尾 │ │ 2字节 │ 1字节│ 1字节 │ 1字节 │ N字节 │ 2字节 │ 1字节 │ │ 0xA5 │ │ │ │ │ │ 0x5A │ │ 0x5A │ │ │ │ │ │ │ └──────┴──────┴──────┴──────┴──────┴──────┴──────┘2. 转义机制SLIP 协议如果数据中恰好出现了 0xA5 或 0x5A需要转义#defineFRAME_START0xA5#defineFRAME_END0x5A#defineESCAPE_CHAR0x7Dvoidslip_encode(uint8_t*in,intlen,uint8_t*out,int*out_len){for(inti0;ilen;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 校验uint16_tcrc16_modbus(constuint8_t*data,intlen){uint16_tcrc0xFFFF;for(inti0;ilen;i){crc^data[i];for(intj0;j8;j){if(crc1)crc(crc1)^0xA001;elsecrc1;}}returncrc;}4. 逐字节解析状态机typedefenum{STATE_IDLE,STATE_HEAD1,STATE_HEAD2,STATE_ADDR,STATE_CMD,STATE_LEN,STATE_DATA,STATE_CRC1,STATE_CRC2,STATE_TAIL}proto_state_t;voidproto_parse_byte(proto_state_t*s,uint8_tbyte){switch(*s){caseSTATE_IDLE:if(byte0xA5)*sSTATE_HEAD2;break;caseSTATE_HEAD2:*s(byte0x5A)?STATE_ADDR:STATE_IDLE;break;caseSTATE_ADDR:frame.addrbyte;*sSTATE_CMD;break;// ... 依此类推}}状态机逐字节解析不依赖于 DMA 缓冲区的起始位置——即使帧丢失也能自动恢复同步。下一篇I2C——主从模式的硬件与软件实现