当前位置: 首页 > news >正文

【双MCU项目复盘与优化】02 -自定义串口通信协议

摘要:本文复盘了V3智控面板双MCU间自定义串口协议的固定长度、扩展性差等不足,并规划了V4的帧头+长度+类型码+载荷+校验+帧尾的可扩展协议框架

  • 往期连接:【双MCU项目复盘与优化】01 - 总体架构与调度逻辑 - 临祁 - 博客园

1. V3 串口协议复盘

1.1 协议内容

  • 以下是具体的协议内容
帧头 类型码 数据 1 数据 2 数据 3 数据 4 数据 5 数据 6 校验 帧尾
CD 系统状态:01 系统空闲:00
系统工作:01
00 00 00 00 00 —— FA
CD 继电器 1:03 关闭:00
开启:01
人体:02
超时时间:0~60 分钟 00 00 00 00 —— FA
CD 继电器 2:04 关闭:00
开启:01
人体:02
超时时间:0~60 分钟 00 00 00 00 —— FA
CD 灯光:05 关闭:00
开启:01
人体:02
超时时间:
0~60 分钟
亮度值:0~100 00 00 00 —— FA
CD 传感器:02 温度:
低八位
温度:
高八位
湿度:
低八位
湿度:
高八位
流明:
低八位
流明:
高八位
—— FA
  • 可见,V3 采用了固定字长的帧格式,格式为“帧头+数据+校验+帧尾
    • 校验字节在构建数据帧时使用 XOR 实时计算,此处用 “——” 占位
  • 修改配置时,STM32F103 会接收数据帧,然后解析并修改配置,然后把最新的配置打包成同样的数据帧回传给 ESP32-S3

1.2 分析不足

  • V3 协议在设计上满足了基本的数据交换需求,但随着项目迭代,以下问题逐渐暴露:
    1. 扩展性差:协议采用固定位置、固定含义的字段,添加新功能(如 NFC 卡号列表)需要重新定义帧结构,无法平滑升级。
    2. 带宽利用率低:每一帧固定为 7 个数据字节(数据1~数据7),但实际有效载荷往往只有 2~3 字节。例如配置继电器时,只有类型码、模式、超时三个有效字节,其余 4 字节填 0x00,浪费率接近 60%
  • 这些问题共同指向一个结论:V3 协议只能用于当前有限功能,V4 必须彻底重构

2. V4 串口协议规划

  • 参考资料:【第33期】协议设计:帧头、帧尾与转义(Stuffing)

基本结构:帧头+长度+类型码+载荷+校验值+帧尾

  • 串口协议的解析顺序:接收方先查找帧头,然后读取长度 Len,接着读取 Len 字节载荷,再读 1 字节 XOR 校验和,最后读 1 字节帧尾用于可选验证。帧尾不参与定位,仅作完整性检查。

2.1 确定帧头帧尾

  • 在开始规划具体内容之前,可以先把帧头和帧尾确定下来,这里采用固定值,并且 ESP32-S3 发送的帧头帧尾和 STM32 发送的不一样
  • 我这里确定为以下这四个值。帧头帧尾可以随意分配(因为长度字段已存在,接收方按长度解析,不依赖帧尾定位,故不需要转义):
发送方 接收方 帧头 帧尾
ESP32-S3 STM32 0xBC 0x3A
STM32 ESP32-S3 0xCE 0x9D

2.2 结合场景规划类型码、载荷

  • 在开始之前,可以先约定一下类型码的分配规则,这样可以便于调试和扩展
    • 类型码高半字节 0xE 表示 ESP32 发出的指令,0xF 表示 STM32 发出的响应或数据,

2.2.1 配置场景

① 灯光、继电器 1/2 配置
  • ESP32-S3 会对 STM32 发送关于灯光、继电器 1/2 的配置参数,而 STM32 会根据接收到的配置参数修改硬件状态。在 STM32 修改完状态之后,最好给 ESP32 报告一下。
  • 所以可以这样设计(长度指的是载荷的字节数)
发送方 帧头 Head 长度 Len 类型码 Type 载荷 Payload XOR 帧尾 Tail 含义
ESP32-S3 0xBC 3 0xE1 uint8_t mode = 0 关闭 / 1 开启 / 2 人体检测;
uint8_t tout = 人体检测模式的超时时间(分钟);
uint8_t value = 亮度值(百分比);
—— 0x3A 配置 Light
0xBC 2 0xE2 uint8_t mode = 0 关闭 / 1 开启 / 2 人体检测;
uint8_t tout = 人体检测模式的超时时间(分钟);
—— 0x3A 配置 Relay1
0xBC 2 0xE3 uint8_t mode = 0 关闭 / 1 开启 / 2 人体检测;
uint8_t tout = 人体检测模式的超时时间(分钟);
—— 0x3A 配置 Relay2
STM32 0xCE 0 0xF1 —— 0x9D Light 配置成功
0xCE 0 0xF2 —— 0x9D Relay1 配置成功
0xCE 0 0xF3 —— 0x9D Relay2 配置成功
0xCE 0 0xF4 —— 0x9D Light 配置失败
0xCE 0 0xF5 —— 0x9D Relay1 配置失败
0xCE 0 0xF6 —— 0x9D Relay2 配置失败
  • 其中,XOR暂时留空,只需要知道是校验值即可
  • 另外,如果要更保险一定,可以选择在 STM32 发送“配置成功”消息时,可以在载荷里面把配置参数也一起回传,这样 ESP32 可以检验是否真的配置成功了。目前这个项目我觉得数据量不大,就不使用回传了。
② NFC 卡配置
  • 由于我们终端有需要有增加卡、删除卡的功能。
  • 我们需要定义一个增卡的配置消息,而 STM32 收到后就会读取当前识别到的卡号并且添加到已有的卡号列表,然后我们可以返回一个增卡成功的消息,并且把拿到的卡号也一并回传给 ESP32-S3 方便保存。当然,对应的增卡失败要有。
  • 同时,删卡的配置消息也需要有,STM32 收到后就会读取当前识别到的卡号,然后在已经有的卡号列表里面把它删除掉,然后我们可以返回一个删卡成功的消息,并且把删除的卡号也一并回传给 ESP32-S3 方便删除。对应的删卡失败也必不可少。
  • 由于需要在 ESP32-S3 保存卡号列表,而 STM32 内部不做掉电保存,于是必须在开机的时候,给 STM32 发送具体的卡号列表,所以还需要一个初始化卡号列表消息,以及对应的回复消息
发送方 帧头 Head 长度 Len 类型码 Type 载荷 Payload XOR 帧尾 Tail 含义
ESP32-S3 0xBC 2 + num*4 0xE4 uint8_t capacity:卡号列表最大容量
uint8_t num:当前卡 ID 数量
uint32_t nfc_card_id[num]
—— 0x3A 初始化 STM32 内部的卡号列表
0xBC 0 0xE5 —— 0x3A 增加卡
0xBC 0 0xE6 —— 0x3A 删除卡
STM32 0xCE 0 0xF7 —— 0x9D 初始化卡号列表失败
0xCE 0 0xF8 —— 0x9D 初始化卡号列表成功
0xCE 0 0xF9 —— 0x9D 增加卡失败
0xCE 1 0xFA 增加的卡号 —— 0x9D 增加卡成功
0xCE 0 0xFB —— 0x9D 删除卡失败
0xCE 1 0xFC 删除的卡号 —— 0x9D 删除卡成功

2.2.2 传感器数据场景

  • 由于终端需要显示室内的温湿度数据,以及屏幕自适应亮度需要知道环境光照,而传感器这种硬件基本由 STM32 进行驱动,所以,我们还需要设计关于传感器数据的协议部分。
  • 温度(Temp)
    • 室内温度通常只需要显示 3 位数即可,即两位整数和一位小数,范围大概在 5.0~32.0 之间,而串口通信一般数据是整数的,所以我们最好对温度数据进行定点化再通过串口发送。
    • 这里选择 10 为定点化倍数,如 25.6 定点化之后就是 256,可以用 uint16_t 来存储并发送,接收之后再进行去定点化即可获得 25.6
  • 湿度(Humi)
    • 室内湿度是百分比,范围是 0~100,一般显示无小数即可
    • 所以可以用 uint8_t 来存储并发送,无需定点化
  • 光照(Lux)
    • 光照的数据大小一般与环境光传感器的增益、积分时间等参数有关,目前不确定,可以先决定使用 uint16_t 来存储并发送,如果后续知道光照的值在 0~255 内,可以改为使用 uint8_t
  • 所以内容可以设置如下:
发送方 帧头 Head 长度 Len 类型码 Type 载荷 Payload XOR 帧尾 Tail 含义
STM32 0xCE 5 0xFD uint16_t temp:温度
uint8_t humi:湿度
uint16_t lux:光照
—— 0x9D 发送温度、湿度、光照
  • 由于传感器数据仅需最新值,所以为了减少冗余,无需应答设计,STM32 周期性发送、ESP32 保留最后有效值即可,而不是等待确认。

2.3 选择校验和算法

  • 除了硬件自带的奇偶检验之外,我们还应该给自己协议设计选择一个专属于协议的校验和算法
  • 可以选择异或校验(XOR)、累加和校验(Checksum)、CRC 校验(CRC-8/16/32)
  • 这里,我选择最简单的 XOR 检验,因为数据量小、通信环境良好(同一块板子内部或短距离),且后续会配合串口本身的硬件校验,所以够用
  • XOR 会对帧头、长度、类型码、载荷所有字节进行异或,结果放在 CRC 字段

2.4 大小端问题

  • 在之前的协议内容设计中,载荷里面出现了变量类型:uint16_t 和 uint32_t
  • 而这就涉及到大小端的问题,例如:uint32_t val = 0x12345678,在存储中的情况就是:
    • 小端:78 56 34 12
    • 大端:12 34 56 78
  • 所以,我们还需要约定好在协议里面 uint16_t 和 uint32_t 是使用大端还是小端
  • 如果是小端,例如 uint16_t 的变量, 串口则会先发送低八位再发送高八位,大端则相反
  • STM32 和 ESP32-S3,两者均为小端模式,但协议约定通常使用大端传输,于是本协议同样使用大端模式
  • 发送多字节整数时,先发送高位字节(MSB),后发送低位字节(LSB);接收方需按相同顺序重组。

2.5 收尾

  • 协议内容汇总
发送方 帧头 Head 长度 Len(载荷字节数) 类型码 Type 载荷 Payload XOR 帧尾 Tail 含义
ESP32-S3 0xBC 3 0xE1 uint8_t mode = 0 关闭 / 1 开启 / 2 人体检测;
uint8_t tout = 人体检测模式的超时时间(分钟);
uint8_t value = 亮度值(百分比);
—— 0x3A 配置 Light
0xBC 2 0xE2 uint8_t mode = 0 关闭 / 1 开启 / 2 人体检测;
uint8_t tout = 人体检测模式的超时时间(分钟);
—— 0x3A 配置 Relay1
0xBC 2 0xE3 uint8_t mode = 0 关闭 / 1 开启 / 2 人体检测;
uint8_t tout = 人体检测模式的超时时间(分钟);
—— 0x3A 配置 Relay2
0xBC 2 + num*4 0xE4 uint8_t capacity:卡号列表最大容量
uint8_t num:当前卡 ID 数量
uint32_t nfc_card_id[num]
—— 0x3A 初始化 STM32 内部的卡号列表
0xBC 0 0xE5 —— 0x3A 增加卡
0xBC 0 0xE6 —— 0x3A 删除卡
STM32 0xCE 0 0xF1 —— 0x9D Light 配置成功
0xCE 0 0xF2 —— 0x9D Relay1 配置成功
0xCE 0 0xF3 —— 0x9D Relay2 配置成功
0xCE 0 0xF4 —— 0x9D Light 配置失败
0xCE 0 0xF5 —— 0x9D Relay1 配置失败
0xCE 0 0xF6 —— 0x9D Relay2 配置失败
0xCE 0 0xF7 —— 0x9D 初始化卡号列表失败
0xCE 0 0xF8 —— 0x9D 初始化卡号列表成功
0xCE 0 0xF9 —— 0x9D 增加卡失败
0xCE 1 0xFA 增加的卡号 —— 0x9D 增加卡成功
0xCE 0 0xFB —— 0x9D 删除卡失败
0xCE 1 0xFC 删除的卡号 —— 0x9D 删除卡成功
0xCE 5 0xFD uint16_t temp:温度
uint8_t humi:湿度
uint16_t lux:光照
—— 0x9D 发送温度、湿度、光照

另外,由于本项目使用电路板,MCU 间串口线路短、电磁环境良好,误码率极低,所以本协议的帧头、帧尾、类型码的分配随意,不是某些约定俗成的固定值。如果希望协议健壮些,可以考虑是否是载荷里面的高概率数字,并引入转义。如果还希望更健壮,还进一步结合通信原理来进行编码。

http://www.jsqmd.com/news/1013995/

相关文章:

  • MPC8280内存控制器与L2缓存接口设计详解
  • 从DCNv1到v3:手把手带你用MMDetection/YOLO跑通可变形卷积的完整训练流程
  • 戴森球计划8000+工厂蓝图:从新手到大师的终极生产力指南
  • 40公斤寄什么物流便宜?40公斤寄大件物流,哪个最便宜? - 快递物流资讯
  • 如何为Windows 11 LTSC系统恢复微软商店:完整安装指南
  • Agent 记忆压缩:如何降低向量库成本
  • AI智能体安全深度实战:微软7种原生故障模式全解析 供应链攻击/目标劫持/MCP滥用攻防原理与企业级防御SOP落地
  • Product Hunt 每日热榜 | 2026-06-14
  • 2026年6月最新版南通正规房屋漏水防水补漏维修口碑名单:创维修缮机构等5家深度测评 - 一修哥咨询
  • Agent 能力评估 CheckList:你的智能体准备好上线了吗?
  • 从零到一:Awesome-Dify-Workflow如何让你5分钟构建AI工作流
  • 2026年6月最新版六盘水正规房屋漏水防水补漏维修口碑名单:创维修缮机构等5家深度测评 - 一修哥咨询
  • 微信小程序逆向工程核心技术解析:深入理解wxappUnpacker的架构突破与安全价值
  • 影刀RPA新手教程_键盘操作与快捷键模拟的完整指南
  • 2026年西安赛格购物卡回收平台多维度排行TOP榜:三大正规回收平台深度横评 - 鼎鼎收礼品卡回收
  • 深入解析MPC7450的60x总线协议:地址流水线与分离事务设计
  • wxapkg-convertor深度解析:微信小程序反编译技术终极指南
  • OBS高级计时器插件:5个简单步骤实现专业直播时间管理
  • 从PyTorch/TensorFlow需求反推:Ubuntu上CUDA和cuDNN版本到底该怎么选?
  • AgentBench评测结果深度解读:GPT-4领先,但开源模型在哪些场景下‘翻车’了?
  • 如何永久保存微信聊天记录:你的数字记忆保险箱终极指南
  • CVE-2026-5027全链路攻防深度剖析:Langflow未认证远程代码执行漏洞原理、在野利用与AI低代码安全体系建设
  • 3分钟解决TranslucentTB的Microsoft.VCLibs.140.00缺失错误:完整配置指南
  • 11-GIL不是性能杀手(上)-CPU密集vsIO密集的实测对比
  • 2026年温州企业IP打造浙视传媒战略级内容全案解析 - 资讯速览
  • 2026年实用降AIGC网站:亲测AI率从90%降至4%的省心方案
  • 2026年6月最新版龙岩正规房屋漏水防水补漏维修口碑名单:创维修缮机构等5家深度测评 - 一修哥咨询
  • 从Latte到StreamingT2V:一文看懂开源视频生成模型的演进与选型指南
  • OpenCore Legacy Patcher:让旧款Mac重获新生的智能兼容方案
  • MPC8280并行I/O端口配置详解:从寄存器原理到嵌入式工程实践