很多工程师把串口屏当成"带触摸的显示器"来用,结果界面逻辑还是堆在单片机里。本文以迪文 DGUS 屏(K600+ 内核)为例,讲清变量驱动架构到底把哪些活搬到了屏幕上:13.BIN 触控文件与 14.BIN 显示变量文件怎么配、5 条串口指令怎么发、28K 字变量空间怎么规划、CRC16 帧校验怎么算,并给出一段可直接编译的 MCU 侧驱动代码。
结论先行:工业串口屏真正的价值不在"显示",而在于把界面从 MCU 代码里剥离出去——屏幕自己管 GUI,单片机只负责改数据。凡是把按钮位置、页面切换、数值格式都写进固件的项目,改一次界面就要重新编译、烧录、送检,代价极高。本文以迪文 DGUS 屏(基于 K600+ 内核)为样本,把变量驱动模型的三个文件、五条串口指令、两种存储空间、CRC16 帧校验与 Modbus RTU 主机模式一次讲透,并给出 MCU 侧可编译的驱动代码,适用于工业数据采集、RTU 远程终端与各类 物联网设备的人机界面开发。
先看两种做法的差别。传统做法是 MCU 直接驱动液晶,工程师要在固件里维护字库、坐标、页面状态机和触摸判定;变量驱动则把"怎么显示"下沉到屏幕内部的组态配置,MCU 与屏幕之间只剩一条数据通道。这两条路线的工程代价差别很大:
| 对比维度 | 传统 MCU 直接驱动液晶 | 变量驱动串口屏(DGUS) |
|---|---|---|
| 界面逻辑位置 | 固件内,随程序编译 | 屏幕内,由 PC 组态软件生成 |
| 改界面代价 | 改代码 → 重新编译 → 重新烧录 | 改配置 → SD 卡下载 13/14.BIN |
| MCU 侧工作 | 刷屏、字库、坐标、触摸判定全包 | 只读写变量地址 |
| 通信内容 | 图像/显存数据,数据量大 | 变量值,通常几个到几十个字节 |
| 变量空间 | 占用 MCU RAM | 屏幕侧 28K 字(56KB),不占 MCU RAM |
| 典型响应速度 | 取决于刷屏带宽 | 变量刷新最快 80ms 一个 DGUS 周期 |
要理解这套模型,记住一句话就够了:屏幕内部把 GUI 拆成一个个"控件",每个控件绑定一个变量地址,串口改写这个地址,控件显示就跟着变。举例来说,要在某个页面显示两位小数的温度值 25.00,只需两步:先用组态软件在页面上放一个"数据变量显示"控件,设好字体、颜色、单位、小数位数和数据源地址,通过 SD 卡把生成的 14.BIN 下载进屏;运行时 MCU 只需把温度值周期性地写到那个数据源地址即可,屏幕会自动按预设格式渲染。触摸录入同理,反向操作:MCU 定时读回录入变量的值。
DGUS 屏的"配置"全部通过 SD/SDHC 卡完成,卡里放三类文件:
把这两个 BIN 文件的分工记牢,开发流程就顺了:13.BIN 管输入,14.BIN 管输出。13.BIN 覆盖录入类交互,包括变量数据录入(0x00)、弹出菜单(0x01)、增量调节(0x02)、拖动调节(0x03)、RTC 设置(0x04)、按键值返回(0x05)、文本录入(0x06,分 ASCII 与 GBK 汉字)与硬件参数配置(0x07);14.BIN 覆盖显示类控件,分图标类(0x00~0x06,含动画图标、滑块刻度、位变量图标等)、文本类(数据变量 0x10、文本 0x11、RTC 0x12、HEX 变量 0x13)与图形类(实时曲线 0x20、基本图形 0x21、列表 0x22)。
工程上最容易踩的坑是:14.BIN 里变量的高字节写 0xFF 可以临时取消本条显示指令,这是做"显示开关"的官方手段,比改地址更省事。
DGUS 的串口协议非常克制——一共只有 5 条指令,因为屏幕的工作模式和 GUI 状态完全由数据变量控制,串口只需对变量和寄存器做读、写。数据帧固定由 5 个数据块组成:
| 数据块 | 1 | 2 | 3 | 4 | 5 |
|---|---|---|---|---|---|
| 定义 | 帧头 | 数据长度 | 指令 | 数据 | CRC 校验 |
| 字节数 | 2 | 1 | 1 | N | 2 |
| 说明 | 由 R3:RA 定义,出厂 5A A5 | 含指令+数据+校验 | 0x80~0x84 | 地址与数据 | 仅覆盖指令+数据 |
五条指令的功能与寻址方式如下。注意两种存储空间寻址单位不同,这是写代码时最容易出错的地方:
| 指令 | 功能 | 数据格式 | 寻址单位 |
|---|---|---|---|
| 0x80 | 写寄存器 | 寄存器地址(1B) + 写入数据 | 按字节,0x00~0xFF |
| 0x81 | 读寄存器 | 下发:地址 + 读取字节长度;应答:地址 + 长度 + 数据 | 按字节,0x00~0xFF |
| 0x82 | 写变量存储器 | 变量地址(2B) + 变量数据串 | 按字(Word),0x0000~0x6FFF |
| 0x83 | 读变量存储器 | 下发:地址 + 读取字长(0x00~0x7F);应答:地址 + 字长 + 数据 | 按字(Word),0x0000~0x6FFF |
| 0x84 | 写曲线缓冲区 | CH_Mode(1B) + DATA0…DATAn | 通道位图 + 16 位无符号数 |
以几个真实帧为例,方便直接对照调试。切换显示页面到第 5 页,是往寄存器 0x03(PIC_ID)写 0x0005;把背光调到 100%,是往寄存器 0x01(LED_NOW,范围 0x00~0x40)写 0x40:
切换页面到第5页 5A A5 06 80 03 00 05 19 E7
背光调至100% 5A A5 05 80 01 40 70 48
写VP 0x1000=2500 5A A5 07 82 10 00 09 C4 5F 1D
读VP 0x2000起4字 5A A5 06 83 20 00 04 29 A9
读寄存器0x00起16B 5A A5 05 81 00 10 20 24 <-- 数据手册原例
其中 5A A5 05 81 00 10 20 24 是数据手册中给出的原始示例,最后两字节 20 24 就是 CRC 校验值,本文后面用同一套算法复算过,结果一致——这一点很重要,说明校验范围确实只覆盖"指令+数据",不含帧头与长度字节。
新手最容易混淆的就是"寄存器"和"变量存储器"这两个词。它们在 DGUS 里是两块完全不同的空间:
| 空间 | 容量 | 寻址单位 | 用途 | 访问指令 |
|---|---|---|---|---|
| 寄存器 | 256 Byte(0x00~0xFF) | 字节 | 硬件操作的软件接口:亮度、页面切换、触摸状态、RTC、定时器、音乐播放 | 0x80 / 0x81 |
| 变量存储器 | 28K Word(56K Byte),0x0000~0x6FFF | 字(16bit) | GUI 变量数据存储,所有 13/14.BIN 控件的数据源 | 0x82 / 0x83 |
| 曲线缓冲区 | 8K Word,8 条曲线 | 16bit 无符号数 | 趋势图快速显示,数据均为 16 位无符号数 | 0x84 |
| 字库空间 | 0x40~0x7F 号字库,每个 128KW,最大 8MW(16MB) | 字 | 字库数据读取到变量存储器,也可作掉电保存区 | 寄存器 0x40~0x49 |
| 数据库空间 | 最大 480MW(960MB),字地址 0x00000000~0x1DFFFFFF | 字 | 历史数据记录,每 1Byte 占 2Byte 物理空间,单字库写寿命 10 万次 | 寄存器 0x56~0x5E |
常用的运行态寄存器值得单独列一下:0x01 是 LED 亮度(0x00~0x40);0x03 读为当前页面 ID、写为切换页面;0x05 是触摸标志,0x5A 表示触摸坐标有更新,用户读取后必须清零,否则触摸数据不再刷新;0x06 是触摸状态(0x01 第一次按下、0x03 一直按压、0x02 抬起);0x07 是 4 字节按压坐标;0x20 起 16 字节是 RTC(年月日星期时分秒 + 农历 + 天干地支 + 生肖);0xEE 写 0x5AA5 会让屏复位一次。
DGUS 的帧校验采用 ANSI CRC-16(生成多项式 X16+X15+X2+1,即 0x8005 反射形式 0xA001),初值 0xFFFF,低字节在前。是否启用由 R2.4(FCRC)决定,是否自动应答校验结果由 RC.3(CRC_ACK_EN)决定——启用应答后,屏幕会在校验完成时回一帧"帧头+02+原指令与数据+(0xFF 表示校验正确 / 0x00 表示错误)+CRC"。
下面这段代码把 CRC 计算和变量写入封装在一起,已在 8 位/32 位 MCU 上通用(不含串口收发底层):
#include <stdint.h>
/* ANSI CRC-16:多项式 0xA001(反射),初值 0xFFFF */
static uint16_t dgus_crc16(const uint8_t *p, uint16_t n)
{
uint16_t crc = 0xFFFF;
while (n--) {
crc ^= *p++;
for (uint8_t i = 0; i < 8; i++)
crc = (crc & 1) ? (crc >> 1) ^ 0xA001 : (crc >> 1);
}
return crc;
}
/* 向变量地址 vp 写入 len 个字(字按高字节在前排列) */
void dgus_write_vp(uint16_t vp, const uint16_t *w, uint8_t len)
{
uint8_t buf[8 + 128];
uint8_t n = 0;
uint16_t c;
buf[n++] = 0x5A; buf[n++] = 0xA5; /* 帧头 R3:RA */
buf[n++] = 3 + len * 2 + 2; /* 长度 = 指令+VP+数据+CRC */
buf[n++] = 0x82; /* 写变量存储器 */
buf[n++] = vp >> 8; buf[n++] = vp & 0xFF;
for (uint8_t i = 0; i < len; i++) {
buf[n++] = w[i] >> 8;
buf[n++] = w[i] & 0xFF;
}
c = dgus_crc16(&buf[3], 1 + 2 + len * 2); /* 校验不含帧头与长度 */
buf[n++] = c & 0xFF; /* 低字节在前 */
buf[n++] = c >> 8;
uart_send(buf, n);
}
用这段代码验证数据手册原例:对 81 00 10 三个字节求 CRC,得到 0x2420,低字节在前即 20 24,与手册完全一致。调试阶段建议先把 CRC 关掉(R2.4=0)跑通通信,再打开校验,否则一个字节顺序搞反就会表现为"屏幕毫无反应",很难定位。
这些参数全部写在 CONFIG.TXT 里,由 SD 卡一次性烧入,运行时不建议改动。它们是项目量产前必须确认的项:
| 寄存器 | 含义 | 关键取值与算法 |
|---|---|---|
| R0 | 屏幕物理分辨率 | 出厂已设好,配错直接导致显示异常 |
| R1 / R5 / R9 | 串口波特率 | R1=0x00~0x10 选 17 档固定波特率;R1=0x11 时由 R5:R9 = 6250000 / 波特率 决定。出厂 R1=7,即 115200bps |
| R3 : RA | 通信帧头 | 出厂 5A A5;多屏并联时用不同帧头当设备地址区分 |
| R2.7 / R2.6 | 显示方向(VDS / HDS) | 组合出 4 种显示方向 |
| R2.5 / R6 / R7 / R8 | 触摸屏控制背光 | R6 点亮亮度、R7 待机亮度、R8 点亮时长(单位 1.0s)。例:R6=40 R7=10 R8=1E,30 秒无操作降到 0x10 |
| R2.4 / RC.3 | CRC 校验 / 校验自动应答 | 同时置 1 才会自动回校验结果 |
| R2.1 / R2.0 | DGUS 周期(FRS1/FRS0) | 80 / 120 / 160 / 200ms 四档,周期越小响应越灵敏但处理能力越低;1024×768 建议 ≥120ms |
| RC.6 / RC.5 | 运行 DWIN OS / 触摸蜂鸣 | RC.6=1 运行 23.BIN 用户程序;RC.5=1 关闭触摸提示音 |
| RC.4 / RC.2 | 每页变量数 / 校准点数 | 64 或 128 变量模式(须与 PC 软件一致);3 点或 5 点校准 |
波特率那一项值得多看一眼:出厂 115200bps 在多数场合够用,若要频繁刷趋势图或传长文本,可按 R5:R9 = 6250000 / 目标波特率 自算。比如 10000bps 对应 R5:R9 = 625 = 0x0271,即 R5=0x02、R9=0x71。反过来,若屏幕偶发丢帧,先怀疑波特率误差而不是线材。
当系统里已有 Modbus 设备(PLC、仪表、变频器)时,可以让 DGUS 屏直接当 Modbus 主机,省掉一颗 MCU。迪文提供专用升级程序 DGUS_V63_MODBUS.BIN(对应 DGUS V6.3,支持 K600+ 内核),刷入后用户接口指令集变为 Modbus RTU 主机模式,不再支持标准 DGUS 指令集。其配置存放在 22.BIN 字库的 20KW~28KW 区间,最多支持 1023 条 Modbus 指令,每条指令的字段如下:
| 字段 | 变量地址 | 说明 |
|---|---|---|
| 启用标记 | 0x5000 | 写 0x5AA5 表示启用 Modbus 通信 |
| 保存 / 加载配置 | 0x5001:H / 0x5001:L | 写 0x5A 分别表示保存到 22 字库 / 从 22 字库加载 |
| 设备地址 | 0x5008L | 读写的 Modbus 从站地址 |
| 功能码 | 0x5009H | 读 / 写使用的 Modbus 指令 |
| 执行范围 | 0x500B | 4 字节规定发送方式;0x0000 表示所有页面下均执行 |
| 起始地址 | 0x500E | 本条指令在 Modbus 设备上的数据起始地址 |
支持的功能码与数据长度换算关系见下表。这里有一个必须记住的坑:Modbus 的位(线圈)变量按 LSB 定义,而 DGUS 按 MSB 定义,做位变量映射时要逐位翻转,否则读回来的状态整片错位。
| 功能码 | 功能 | 读写数据长度 | Modbus 起始地址含义 |
|---|---|---|---|
| 0x01 | 读取输入线圈状态 | 线圈个数 / 8 | 起始线圈位置 |
| 0x02 | 读取输入位变量状态 | 位变量个数 / 8 | 起始输出位置 |
| 0x03 | 读取保存寄存器 | 寄存器个数 × 2 | 保存寄存器首地址 |
| 0x04 | 读取输入寄存器 | 寄存器个数 × 2 | 输入寄存器首地址 |
| 0x05 / 0x06 | 强置单个线圈 / 预置单个寄存器 | 0x02 | 线圈 / 寄存器地址 |
| 0x0F / 0x10 | 强置多个线圈 / 预置多个寄存器 | 线圈数量 / 寄存器个数 × 2 | 起始线圈 / 寄存器首地址 |
| 0x11 | 读取从机标识 | 从机标识字节数 | 任意值 |
最后把工程上反复出现的问题归拢一下,都是文档里写得不显眼、但现场一定会遇到的:
变量驱动架构的本质是把"界面"从固件里搬进了屏幕,MCU 与屏之间只剩一条极简的数据通道——5 条指令、两种空间、一套 CRC16。掌握这套模型后,改界面不再需要动 MCU 代码,多语言、多页面、趋势图都变成组态工作。
落地时记住三句话:界面归屏幕,数据归 MCU;寄存器管硬件,变量存储器管显示;通信先跑通再开 CRC。本文基于《迪文 DGUS 屏用户开发指南》(Ver4.1)等资料整理优化。
沧州艾诺威电子 — 国家高新技术企业,20+项国家专利
嵌入式系统开发 · 物联网方案 · AI智能硬件 · 一站式交付
电话:13930711029 | 邮箱:tech@czinv.com | 24小时内响应