主题
2.6 显示模块
显示模块用来给设备做一块屏:把温度、频率、运行状态这些数字组织成现场人员看得懂、按得动的画面——第一行「送风温度 26.5℃」,第三行「运行模式 停止」,第四行按进去就是「参数设置」。
本节分三部分来讲:先说明如何从零做出一页可用的画面(2.6.2,按步骤约十分钟),再逐个给出各功能块的入口(2.6.3~2.6.7,每个块的端子、为什么这么设计都写在它自己那一页),最后说明现场人员拿到屏之后的操作——怎么翻页、怎么改值、密码怎么拦人(2.6.9~2.6.11)。
先说清楚现在能用到哪一步
上位机这一侧是完整的:能画、能校验、能生成 JSON、能下发,还有「显示模拟器」按真实屏逐点画出屏上效果——本页所有屏面图都出自它,无需连接屏幕也能先行验证。 设备端只保存这份显示程序,不负责渲染,画面真正亮起来要靠接上的文本显示器(屏)。带屏的设备型号与配套固件发布后,本节会补真屏的安装与操作说明。
2.6.1 先认清四层结构
| 层 | 用什么块 | 数量限制 |
|---|---|---|
| 显示主循环 | 「HMI显示主循环」 | 全画布只能 1 个,块上没有任何参数 |
| 页 | 「HMI一般页」「HMI子页」 | 主页 + 子页合计最多 20 页 |
| 行 | 每页的 行1 ~ 行4 四个端子 | 每页固定 4 行,留空的行不显示 |
| 行内容 | 菜单行 / 普通文本 / 枚举文本列表 / 子页 | 接在行端子上(取寄存器不算行内容,它只接在菜单行或枚举块的「值」端子上) |
屏是 128×64 点,4 行、每行 16 个字符位:数字和字母占 1 位,汉字占 2 位,所以一行最多 8 个汉字。写「冷冻水供水温度」是 8 个字正好占满,后面再接数值就必然被截掉——这类问题无需逐字核对字数,「排版体检」会直接报出来(见 2.6.10)。
左侧工具箱的 HMI 分类自带几条提示标签,就是这四层结构的口诀,照着放不会错:
- 「整个画布放 1 个「HMI显示主循环」(零参数)」
- 「── 放进「HMI显示主循环」里 ──」(一般页、子页)
- 「── HMI显示界面保护 = 页上的「密码等级」(逐页) ──」
- 「── 行内容(接在 行1~行4 端子上)──」(菜单行、普通文本)
- 「── 「值」端子上用:取(只读) / 设(屏上可改) ──」(取寄存器)
2.6.2 动手做第一页:把送风温度显示出来
目标
- 一页「主控台」,第一行显示
送风温度 26℃ - 温度实测值在 D100
- 全程不写一行代码,做完在「显示模拟器」里当场看到屏
逻辑原理:屏上的每一行都是「名称 + 数值 + 单位」三段拼的,名称和单位是固定文字,数值来自一个寄存器。所以这一页需要一个主循环、一个页、一个菜单行、两个文本、一个取寄存器,共 5 个块。
搭建步骤
在设备详情页点 「逻辑编程」 打开编辑器。

从左侧 HMI 分类把 「HMI显示主循环」 拖到画布上。它只有一个空口子,没有参数——刷新周期、镜像地址这类都不用在程序里设,屏自己按 1 秒轮询。
把 「HMI一般页」 拖进那个口子里,点块上的页名改成
主控台,密码等级保持0。把 「HMI菜单行显示」 拖到页的 行1 端子上。这时块上能看到三个并排的端子:文本 / 值 / 其他。
行1 的 「文本」 接一个 「HMI普通文本显示」,字符串填
送风温度——这是行名称。「值」 接一个 「取寄存器」(也在 HMI 分类里),选
D、地址填100,模式保持 「取(只读)」。「其他」 再接一个 「HMI普通文本显示」,字符串填
℃——这是单位。点编辑器下方 「显示模拟」 标签:屏上第一行就该出现
送风温度 0℃(没接在线设备时数值全是 0),第一行整行反白,因为光标停在它上面。
搭好后画布应该长这样(这一页之外还多做了三行,正好是 2.6.8 完整示例的样子):

验证效果
- 选中一台在线设备(模拟器也行),「显示模拟」面板顶部的「没接设备·屏上数值全为 0」会消失,屏上的数值变成设备实时值。
- 在上位机的寄存器操作里把 D100 写成
26,等一秒,屏上应该变成送风温度 26℃。 - 再写成
265,屏上显示送风温度 265℃——屏不会替您除以 10。想让 265 显示成 26.5,要在主程序里用线性变换把 D100 换算成带小数的值(或直接用浮点寄存器 DF),再把换算结果接到「值」上。
改改看
- 想再加一行频率:再拖一个菜单行到 行2,名称填
风机频率、值接 D101、单位填Hz。 - 想让现场人员能在屏上改这个值:把「值」上那个取寄存器改成 「设(屏上可改)」,规矩写在 HMI菜单行显示 那一页。
- 一行放不下:名称缩短,或把单位并进名称(
送风温度(℃))。
2.6.3 HMI显示主循环
整个显示部分的入口,块面上一个参数都没有,只有一个放页的口子。
→ 详解(刷新周期去哪了、为什么全画布只能 1 个):ddc_display_loop
2.6.4 一般页与子页
两个块的端子完全一样:页名 + 密码等级 + 行1~行4。区别只在放的位置——一般页接在显示主循环里,子页接在上级页的某一行上,表示「这一行按进去就是这一页」。
→ 详解:页名规矩、密码等级怎么拦人、行上能接什么 —— ddc_page 一般页; 子页按页名跳转、孤岛页、行首箭头为什么撤掉 —— ddc_subpage 子页
2.6.5 HMI菜单行显示:一行是怎么拼出来的
最常用的块:文本(行名)+ 值(数值)+ 其他(单位或枚举列表)三段拼出一行。
→ 详解(三个端子各接什么、小数位为什么是自动的、这一行在屏上能不能改):ddc_menu_row
2.6.6 HMI普通文本显示
块上只有一个「字符串」框,输出一段固定文字。
→ 详解(当行名 / 当单位 / 整行提示语三种接法、按 16 字符位截断):ddc_text
2.6.7 HMI枚举文本列表显示
把一个数字翻成现场看得懂的话——寄存器里存 0、1、2,屏上显示「停止」「运行」「故障」。
→ 详解(序号从 0 开始这一易错点、项数与文字框怎么对齐、屏上切项怎么配):ddc_enum_text
三项以上的枚举不能绑位元件
枚举的「值」接在 X / Y / M / L 这类位软元件上时最多只有 2 项:位只有 0 和 1,选第 3 项要发 2,设备只会存成 1,屏上那一项永远选不到。要显示「停止 / 运行 / 故障」三态,把状态字放 D 一类的字寄存器,或者把枚举裁到 2 项。排版体检会直接把这条报出来。
2.6.8 完整示例:主控台 + 一个带密码的子页
做完之后的屏面(出自上位机的显示模拟器):

四行分别是:
HMI显示主循环
└─ HMI一般页:页「主控台」 密码等级 0
├─ 行1 菜单行:文本「送风温度」 值 ←取(只读) D100 其他「℃」
├─ 行2 菜单行:文本「风机频率」 值 ←取(只读) D101 其他「Hz」
├─ 行3 菜单行:文本「运行模式」 值 ←取(只读) D102 其他 ←枚举列表(停止|运行,值接 D102)
└─ 行4 HMI子页:页「参数设置」 密码等级 2 ← 这一行按确定进子页子页「参数设置」自己带四行,这里只用第一行放一个可改的设定值:
HMI子页:页「参数设置」 密码等级 2
└─ 行1 菜单行:文本「送风设定」 值 ←设(屏上可改) D103 其他「℃」
行2 ~ 行4 留空(屏上不显示)生成的 JSON 节选(点「生成 JSON」得到,右侧面板同时显示「校验通过」):
json
{
"version": 1, "name": "主控台", "scan_ms": 200, "lines": [],
"display_loop": { "pages": [
{ "name": "主控台", "pwd_level": 0, "rows": [
{ "op": "menu_row", "rw": 0,
"text": { "op": "text", "value": "送风温度" },
"other": { "op": "text", "value": "℃" },
"args": [ { "op": "ref", "device": "D", "addr": 100 } ] },
{ "op": "menu_row", "rw": 0,
"text": { "op": "text", "value": "运行模式" },
"other": { "op": "enum_text", "items": ["停止", "运行"],
"args": [ { "op": "ref", "device": "D", "addr": 102 } ] },
"args": [ { "op": "ref", "device": "D", "addr": 102 } ] },
{ "op": "subpage", "page": "参数设置" }
] },
{ "name": "参数设置", "pwd_level": 2, "rows": [
{ "op": "menu_row", "rw": 1,
"text": { "op": "text", "value": "送风设定" },
"other": { "op": "text", "value": "℃" },
"args": [ { "op": "ref", "device": "D", "addr": 103 } ] },
null, null, null
] }
] }
}对着这份 JSON 能读出四条规矩:
rows固定四格,不用的行是null——屏上那一格就不显示。- 子页在上级页里只有
{"op":"subpage","page":"参数设置"}:按页名跳转,不按第几页。插页、删页都不会让跳转指错地方。 "pwd_level": 2表示"参数设置"这页要 2 级权限。"rw"是算出来的:上面那份 JSON 里,前三行是0(只读),子页那行是1(可改),差别就在取寄存器块选的是「取(只读)」还是「设(屏上可改)」。
进子页之后的屏面:

2.6.9 现场人员拿到屏之后怎么操作
无需连接屏幕也能先行验证:编辑器下方点 「显示模拟」,它按真实屏逐点画(12864 只有"点亮/不亮"两态、没有灰度)。

| 面板上的东西 | 对应现场 |
|---|---|
| 屏面 | 光标所在行整行反白(真屏没有灰度,反白就是两个色态互换) |
| ↑上/加、↓下/减、确定/进入、返回 | 就是屏上那四个键 |
| 适应 1×/2×/4× | 放大倍率自动取偶数倍,没有手选按钮:把左栏拖宽或面板加高,倍率自己跳档(奇数倍摊不到整数像素,字边会发糊) |
| 权限 Lv.0 / 密码 1 级 / 密码 2 级 / 退出登录 | 模拟现场人员升、降权限,用来验证密码等级拦不拦得住 |
| 送显值 105B / 2页 | 这份显示要占多少字节、几页 |
| 寄存器监视 | 本页引用到的软元件和它们的设备实时值(没接设备时是 —) |
| 排版体检 | 见 2.6.10 |
三个典型动作:
翻页看别的行:按 ↓,反白整行往下走一格。
改一个可改的值(可写的行在页上会标出来,告诉您按确定能改):
按键 发生什么 确定 进入改值,个位开始闪(半秒一亮一灭) ↑ / ↓ 只改当前闪动的那一位,不进位;改的过程中新值先显示出来 确定 认位,闪动往左移一位(个位 → 十位 → 百位…) 确定 最后一位认完就落值,写回那个寄存器 返回 放弃,回到原值 枚举行不按位改:按确定后直接 ↑↓ 切项(值那一段整段反白闪动),确定落值。 改值同样鉴权——本页的密码等级被抬高而现场人员权限不够时,按确定会提示「改不了」并说清要几级。
进子页:光标停在「参数设置」按确定。等级不够会当场拦下:

提示原文是「进不去:这个页面的密码等级是 Lv.2,当前权限 Lv.0。先在 Setting 页输入相应等级密码。」——这句话就是给现场人员的操作指引。
升到 2 级后再按确定,就进到子页了(见 2.6.8 最后那张图)。
屏上没数不是坏了
面板顶部写着「没接设备·屏上数值全为 0」,是因为没选中在线设备。选中设备后这里就是实时值,改完值当场能看到回读。
2.6.10 排版体检:先把能在电脑上发现的问题发现掉
「生成 JSON」不只生成,还会校验,右侧「JSON / 问题」面板列出问题,点一条直接定位到画布上出问题的块。显示部分常见的几类:
| 类型 | 举例 |
|---|---|
| 一行放不下 | 名称 8 个汉字 + 数值 + 单位,超过 16 字符位会被截 |
| 页名问题 | 重名、空名、首页名字太长 |
| 导航问题 | 子页没有任何一行引用它(孤岛页,现场永远进不去);子页指向的页名不存在 |
| 接错/没接 | 枚举行没接「值」(恒显第 1 项);枚举超过 2 项却绑在位元件上(第 3 项永远选不到);行端子上接了不能当行内容的块 |
| 越界 | 寄存器地址超出该区范围 |

2.6.11 下发
显示页面跟着 DDC 程序一起下发:点「下发设备」,写入的就是那份 ddc.json(逻辑 + 显示一个文件),写入后设备自动重启生效,不会改动梯形图和 main.lua。
多台设备刷同一份画面,用命令行批量:见 11.5 批量写 DDC 程序。
2.6.12 做不出来时对照这几句
| 报的话(原文) | 意思 | 怎么改 |
|---|---|---|
显示最多 20 页(主页面+子页面合计),当前 21 页 | 页数超了 | 合并页面,或不常用的参数并到同一页分页显示 |
页名不能为空(子页按页名寻址跳转目标) / 子页块缺少页名 | 页名没填 | 每页填一个看得懂、不重名的页名 |
菜单行显示块需要 1 个值输入(「其他」接枚举列表时可省) | 菜单行的「值」空着 | 给「值」接待显示的寄存器或算式 |
枚举文本列表要有 1~8 项文本 | 项数和文字框对不上 | 项数填几,就把几格文字填上(1~8 项) |
枚举文本列表要接 1 个「值」——屏上按它选第几项,不接就恒显示第 1 项 | 枚举块没接「值」 | 给枚举块自己的「值」端子接上状态寄存器 |
这一行是可写的,但「其他」里那个枚举块的「值」不是单个「取寄存器」块,屏上没有写回落点 | 想可写,但落点是个算式 | 把枚举块的「值」换成单个取寄存器,并选「设(屏上可改)」 |
未知的显示行内容类型 … | 行端子上接了不能当行内容的块 | 行上只放 2.6.1 表里那几种块 |
扫描周期必须 >= 10 毫秒 | 主循环周期填太小 | 改到 10 毫秒以上 |
寄存器地址越界: … 允许范围 0~… | 地址超出该寄存器区 | D 0~7999;DD/DF 0~7998(各占两格 D);M 0~7679;X/Y 八进制 0~377;T 0~511;C 0~255 |
| 屏上这一行改不了(没报错) | 「值」的落点不是可写的单个寄存器 | 把那个取寄存器块改成「设(屏上可改)」,重新生成 JSON |
| 屏上数字和预期差 10 倍 | 屏不做缩放 | 在主程序里用线性变换换算好再接进来(见 2.6.2 的验证步骤 3) |
学完这一节,您已经能给设备做出一套带密码保护的多页画面。接下来可以:
- 把显示的值先算好再显示:2.4 计算类功能块(线性变换、限值)
- 状态量翻成文字:2.3 逻辑类功能块(比较、启停)
- 整份程序下发与生效:3.1 下发与设备端运行