从 DGUS 到 HMIS:串口屏协议的演进与废弃

Babel36acl 嵌入式实战 无~ 7 次阅读 预计阅读时间: 9 分钟 发布于 1 天前 最后更新于 1 小时前 1885 字


架构演进 协议设计

DGUS 串口屏协议封装:在一个协处理引擎里的权衡

串口屏(DGUS/迪文)曾是 USART1 的默认协议。从 V1.1 开始,它已完全被 HMIS(HMI Session Protocol)取代。本文记录这次协议演进的原因、改动范围和迁移经验。

HMIS 协议帧格式见博文 542。本文不再重复协议细节,只聚焦"为什么弃用 DGUS"和"迁移中踩的坑"。

为什么放弃 DGUS

DGUS 变量协议的核心是 VP 地址模型:固件向屏的指定地址写数据,屏显示该地址的内容。HMI 上位机通过抓取屏的通信来间接获取设备信息。这个模式存在三个根本问题:

  1. 两套协议栈— HMI 同时维护 USART3 20B 帧和 USART1 DGUS 5A A5
  2. 三处耦合— 参数地址、HMI 配置、固件参数定义各存一份,新增参数要改三处
  3. 无会话管理— 无 SEQ 序号、无心跳、无能力声明,断线后无法自动恢复
// HMIS 帧格式(详细见博文 542)
| SOF(2) | VER(1) | TYPE(1) | SEQ(2) | CMD(1) | FLAGS(1) | LEN(2) | PAYLOAD(N) | CRC16(2) |
| 55 AA  |  0x01  | 0x01    | 小端   | 0x30   |  0x00    |  0+..  |  0..128B   | Modbus   |

协处理引擎设计

我们在 Service 层做了一个专门处理 DGUS 帧的模块 packer_dbus(文件名来自历史兼容,实际处理 DGUS 协议):

// 初始化
void packer_dbus_init(void);

// 每周期轮询 — 读取 USART1 数据流,解析 5A A5 帧
void packer_dbus_task_once(void);

// 日志推送 — 将格式化文本封装为 DGUS 0x82 帧写入屏的文本区
void packer_dbus_log_send(uint8_t level, const char *text, uint16_t len);

轮询处理器的职责

packer_dbus_task_once() 每周期做三件事:

1. 从 USART1 接收缓冲读取字节流
2. 查找帧头 5A A5,提取完整帧
3. 按命令分发:

   0x83 (屏主动上报) — 通常是触摸按键事件
      → 映射到操作 (如"保存参数"→ packer_runtime_config_save())

   0x82 (上位机/屏写参数)
      → 解析目标 VP 地址 → 映射到参数 ID
      → packer_runtime_config_write(id, value)

   0x81 (读参数请求)
      → 查参数表 → 封装 0x82 回复帧 → USART1 发送

日志推送路径

BSP 日志模块 bsp_log 是一个纯格式化层,不关心输出到哪里。它的输出通过回调函数分发给多个后端:

// bsp_log 输出 → 回调函数 →
//   ├── USART1: packer_dbus_log_send() → DGUS 5A A5 帧 → 屏显
//   ├── HMI 端口 B: 同一 USART1 线路收到 → HMI 日志面板
//   └── (未来) RingBuffer / SD 卡日志

// 日志帧格式:
// 5A A5 + Length + 0x82 + VP地址(0x3000) + 日志文本
// 日志写入 DGUS 预设的文本显示区 VP 0x3000~0x301F

与 HMI 端口 B 共存

发送者 帧特征 下位机响应
DGUS 屏触摸 5A A5 + 0x83 上报 解析执行
HMI 端口 B 5A A5 + 0x82 写参数 解析执行
下位机推送 5A A5 + 0x82 日志帧 —(屏显 + HMI 接收)

三者在同一物理线路上通过帧头(5A A5)和前导码区分。HMI 端口 B 只监听不冲突——它不主动发帧时不会干扰 DGUS 屏和下位机的正常通信。

两个设计权衡

1. 轮询 vs 中断

packer_dbus_task_once() 由 ProtoTask(优先级 AboveNormal,50ms 周期)中的协议分发调用,而非独立的 USART1 接收中断。

为什么不是中断?DGUS 帧是低速的(9600 波特),一帧最长约 20 字节,传输约 20ms。50ms 的轮询周期足够捕获完整帧,且避免了中断上下文做帧解析的复杂性。

2. 参数 ID 映射表

DGUS 端的 VP 地址(0x3000 等)和下位机的参数 ID(RCFG_ID_xxx)之间通过一张映射表关联:

static const struct {
    uint16_t vp_addr;       // DGUS 端的变量地址
    rcfg_id_t param_id;     // 下位机参数 ID
    uint8_t  rw;           // 读/写权限
} s_vp_map[] = {
    {0x1000, RCFG_ID_SPEED_BAG_OUT_HZ,       2}, // 读写
    {0x1002, RCFG_ID_SPEED_TEAR_OFF_HZ,      2},
    {0x1010, RCFG_ID_POWER_ON_DELAY_MS,      2},
};

这个映射表是 DGUS 协议封装的核心——它把"屏端的地址"和"固件端的参数 ID"解耦。换屏时只需改映射表,不动业务逻辑。

此作者没有提供个人介绍。
最后更新于 2026-05-30