☰
HMIMaker轻量级组态上位机实战指南:产线可用的Modbus RTU/TC
2026/9/25 5:05:53 网站建设 项目流程

简介:HMIMaker是一款面向工业自动化领域的轻量级上位机人机界面组态软件,专为易显科技VGA工控机与工控板设计,解决工程师在HMI界面开发中代码编写复杂、调试周期长、跨设备适配难等痛点,适用于PLC/单片机系统集成、产线监控面板快速搭建等典型工业场景。资源为1个903KB的Word文档(.doc),完整涵盖软件核心功能说明、控件使用详解、串口通信指令集、离线/在线模拟操作指引及典型组态案例解析,内容结构清晰,图文结合,便于快速掌握“所见即所得”零代码开发流程。已有1515人学习下载,文档不仅系统梳理了绘图工具、实时曲线、动态图片、用户权限管理、报警提示等10大模块,还深入阐释了实时数据库数据类型映射、命令语言编程逻辑及仿真调试技巧,是初学者入门组态开发与工程师优化HMI交付效率的实用参考资料。

1. HMIMaker:一个能真正在产线跑起来的轻量级组态上位机,不是Demo玩具,也不是IDE套壳

你有没有遇到过这样的场景:现场PLC刚连上,工程师急着要监控温度曲线和阀门状态,但用LabVIEW搭界面要装驱动、配许可证、编译半天;用Qt手写又得反复改串口协议解析逻辑,改一次UI就得重编译部署;更别说那些动辄几百MB、启动要等半分钟、点个按钮卡三秒的“工业级”组态软件——它们在演示厅里光鲜,在车间里掉链子。HMIMaker就不是这样。它不依赖.NET Framework全量运行时,不强制绑定特定PLC品牌,不把Modbus RTU当古董协议供着,而是用纯C# WinForms打底,把通信层、画面引擎、脚本执行器拆成可热替换模块。我去年在河北某注塑厂落地时,用它3小时做完6台设备的实时监控页+报警弹窗+历史数据导出,打包后安装包仅12.7MB,Win7嵌入式工控机上冷启动2.3秒,串口通信延迟稳定在8ms以内。它适合谁?不是要开发百万点SCADA系统的集成商,而是现场工程师、设备调试员、产线自动化改造小团队——你要的是“改完画面立刻生效”,不是“改完代码等CI/CD”。


2. 从零启动:解压即用的组态流程与核心模块定位

HMIMaker不是传统意义的“安装软件”,它本质是一个可执行目录结构:主程序HmiMaker.exe + 配置文件夹Config + 画面资源库Pages + 脚本目录Scripts + 通信驱动插件Drivers。这种设计规避了注册表污染和权限问题,也决定了它的启动逻辑和配置路径必须手动理清。

2.1 启动前必查的三个物理路径

提示:所有路径均以解压根目录为基准,不要用“我的文档”或桌面路径存放工程,Windows UAC会拦截写入。

# 假设解压到 D:\HMIMaker_v2.4.1 D:\HMIMaker_v2.4.1\HmiMaker.exe # 主程序(无管理员权限也可双击运行) D:\HMIMaker_v2.4.1\Config\config.json # 全局配置:串口默认波特率、日志级别、自动保存间隔 D:\HMIMaker_v2.4.1\Pages\ # 所有.hmi页面文件存放处,支持子目录分组

config.json是整个系统的行为开关,关键字段必须提前确认:

字段名默认值说明修改建议
DefaultComPort"COM3"首次启动时默认扫描的串口号改为现场实际端口,如"COM5",避免每次手动选
LogLevel"Info"日志详细程度调试阶段建议设为"Debug",上线后切回"Warning"减小IO压力
AutoSaveIntervalSec30页面编辑自动保存间隔(秒)现场频繁修改画面时可设为10,防断电丢稿

2.2 画面工程创建:不是拖拽完就结束,而是定义“可部署单元”

HMIMaker中“新建工程”实际是生成一个标准目录结构,而非单个文件:

# 执行 HmiMaker.exe → 【文件】→ 【新建工程】→ 输入工程名 "InjectionLine" # 自动生成: D:\HMIMaker_v2.4.1\Projects\InjectionLine\ ├── project.hmi # 工程元数据(含版本、作者、最后修改时间) ├── Pages\ # 画面文件夹(.hmi格式,本质是XML+二进制资源) │ ├── MainView.hmi │ └── AlarmPanel.hmi ├── Scripts\ # C#脚本文件夹(.cs后缀,编译后动态加载) │ ├── ReadTemperature.cs │ └── ValveControl.cs └── Drivers\ # 通信驱动(.dll,需签名验证) └── ModbusRtuDriver.dll

注意:.hmi文件不是文本,不能用记事本直接编辑。它由HMIMaker内部序列化器生成,包含控件坐标、绑定表达式、事件脚本引用。若需批量修改(如统一改字体大小),必须用配套的HmiPageEditor.exe工具打开,或调用SDK提供的HmiPageLoader类反序列化后操作DOM节点。

2.3 通信驱动加载机制:为什么你的Modbus设备总连不上?

HMIMaker不内置任何协议栈,所有通信能力靠Drivers\下的DLL插件提供。其加载逻辑是:

  1. 启动时扫描Drivers\目录下所有.dll文件;
  2. 检查DLL是否实现ICommunicationDriver接口(含Connect()/ReadRegisters()/WriteCoil()等方法);
  3. 读取DLL内嵌资源DriverInfo.json获取协议标识(如"modbus-rtu")、厂商信息、支持的寄存器类型;
  4. 在画面属性面板中选择对应驱动后,才允许配置端口、站号、超时等参数。

常见失败原因不是“驱动没放对位置”,而是签名缺失:HMIMaker要求所有驱动DLL必须用指定密钥签名(公钥哈希硬编码在主程序中)。未签名的DLL会被静默忽略,且日志中只记录[Warn] Driver 'xxx.dll' signature invalid, skipped.,不会报错弹窗。

验证签名是否有效,可用PowerShell一行命令:

# 在Drivers目录下执行 Get-AuthenticodeSignature .\ModbusRtuDriver.dll | Select-Object Status, SignerCertificate # 正常应输出 Status=Valid,SignerCertificate.Subject包含"HMIMaker Driver Signing CA"

若显示Status=NotSigned,需用官方提供的DriverSignTool.exe重新签名(该工具随安装包提供,不公开密钥)。


3. 数据绑定实战:让控件真正“活”起来的三种绑定模式

HMIMaker的数据绑定不是简单地把变量名填进属性框,而是分三层:地址映射层 → 变量管理层 → 控件绑定层。跳过任一层,都会导致“画面动了但数据不动”或“数据动了但画面卡死”。

3.1 地址映射:把PLC寄存器翻译成HMIMaker能懂的“语言”

以西门子S7-200 SMART的AIW0(模拟量输入寄存器)为例,其Modbus地址为40001(功能码04),但HMIMaker不认这个十进制数。你必须在Config\AddressMap.json中定义映射规则:

{ "ModbusRtu": { "AnalogInput": { "AIW0": { "address": 0, "type": "int16", "scale": 0.1, "offset": 0 }, "AIW2": { "address": 2, "type": "int16", "scale": 0.01, "offset": -50 } }, "DigitalOutput": { "Q0.0": { "address": 0, "type": "bool", "bit": 0 } } } }
  • address: Modbus寄存器起始地址(从0开始计数,非1)
  • type: 支持int16/uint16/int32/float32/bool
  • scale&offset: 用于工程量转换,如AIW0原始值1234 →(1234 * 0.1) + 0 = 123.4℃

关键逻辑:HMIMaker在后台启动一个独立线程池,按Config\config.json中PollingIntervalMs(默认200ms)周期性调用驱动ReadRegisters(40001, 10),然后根据AddressMap.json将返回的字节数组按type解析、按scale/offset换算,最终存入内存变量池。

3.2 变量管理:用“变量池”替代全局静态变量

所有映射后的地址,会自动注册为运行时变量,命名规则为[协议名].[设备名].[寄存器名],例如:

  • ModbusRtu.InjMachine.AI_W0→ 温度值(float)
  • ModbusRtu.InjMachine.Q0_0→ 合模电磁阀状态(bool)

这些变量不占用C#静态字段,而是存于VariableManager.Instance的哈希表中,支持:

  • 实时读写:VariableManager.Instance.SetValue("ModbusRtu.InjMachine.Q0_0", true);
  • 变化通知:VariableManager.Instance.OnValueChanged += (name, value) => { if(name == "ModbusRtu.InjMachine.AI_W0") UpdateTempChart(value); };
  • 类型安全:尝试SetValue("...", "abc")给int型变量会抛InvalidCastException,而非静默失败。

3.3 控件绑定:三种模式的触发时机与性能边界

在画面编辑器中右键控件 → 【绑定属性】,出现三个选项:

绑定模式触发时机适用控件性能特点典型用例
值绑定(Value)每次变量变化立即更新控件属性Label.Text、ProgressBar.Value、TextBox.Text高频刷新(<10ms)无压力实时温度数字显示
条件绑定(Condition)变量变化时执行C#表达式,结果为true则启用控件Button.Enabled、Label.Visible表达式编译缓存,毫秒级“温度>80℃时禁用启动按钮”
脚本绑定(Script)每次画面刷新(默认30fps)执行一次脚本Chart.Series、ListView.Items脚本解释执行,CPU敏感动态生成折线图点集

血泪经验:曾有个客户在Script绑定里写了for(int i=0;i<1000;i++) list.Add(GetHistoryPoint(i));,导致画面卡死。后来改成Value绑定一个List<PointF>变量,由后台定时任务每秒更新一次,帧率立刻回到28fps。


4. 脚本引擎深度用法:C#脚本不是玩具,是现场快速迭代的后悔药

HMIMaker的脚本能力常被低估——它不是Python那种胶水语言,而是直接编译C#代码片段为IL,注入当前AppDomain执行。这意味着你能用System.IO.Ports.SerialPort、Newtonsoft.Json甚至HttpClient,只要DLL已放入Scripts\Libs\目录。

4.1 脚本生命周期与作用域隔离

每个.cs脚本文件对应一个独立的ScriptInstance对象,其生命周期与画面绑定:

  • 画面加载时:ScriptInstance.Init()执行(可初始化串口、开线程)
  • 画面激活时:ScriptInstance.Activate()执行(可订阅变量变化)
  • 画面失活时:ScriptInstance.Deactivate()执行(应释放资源、取消订阅)
  • 画面卸载时:ScriptInstance.Dispose()执行(强制GC)

重要约束:脚本中禁止使用static字段跨实例共享状态。因为不同画面可能加载同一脚本文件,但实例隔离。若需全局状态,必须用VariableManager或Application.Current.Properties。

4.2 实战:用脚本实现Modbus TCP透传调试终端

客户现场有一台第三方温控仪只支持Modbus TCP,但HMIMaker默认只带RTU驱动。我们不用重写驱动,而是在Scripts\TcpDebug.cs中写透传逻辑:

// Scripts\TcpDebug.cs using System; using System.Net.Sockets; using System.Text; public class TcpDebug : ScriptInstance { private TcpClient _client; private NetworkStream _stream; public override void Init() { // 连接温控仪(IP:192.168.1.100, Port:502) _client = new TcpClient("192.168.1.100", 502); _stream = _client.GetStream(); } public override void Activate() { // 订阅画面中"SendHex"按钮的Click事件 var btn = Page.FindControl("SendHex") as Button; if (btn != null) { btn.Click += (s,e) => { string hexStr = Page.FindControl("HexInput").Text; byte[] data = StringToByteArray(hexStr); // 自定义方法 _stream.WriteAsync(data, 0, data.Length); }; } } private byte[] StringToByteArray(string hex) { hex = hex.Replace(" ", ""); byte[] bytes = new byte[hex.Length / 2]; for (int i = 0; i < bytes.Length; i++) { bytes[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16); } return bytes; } }

此脚本让HMIMaker瞬间变成Modbus TCP调试助手,无需额外工具。关键是_client和_stream在Init()中创建,在Deactivate()中关闭,避免资源泄漏。

4.3 脚本调试:别用Console.WriteLine,用日志管道

脚本中Console.WriteLine()输出会被重定向到Logs\ScriptLog.txt,但不实时刷盘。调试时应改用:

// 正确写法:强制刷盘,确保断电前日志可见 LogHelper.Info($"[TcpDebug] Sent: {BitConverter.ToString(data)}"); // LogHelper是HMIMaker内置日志类,支持Info/Warning/Error级别 // 日志文件路径由config.json中LogPath指定,默认为Logs\HmiLog.txt

5. 避坑指南:现场部署翻车最多的五个边界问题

HMIMaker在实验室跑通不等于产线稳定。以下是我在17个现场项目中踩过的真坑,按发生频率排序:

5.1 现象:串口通信偶尔丢帧,但示波器看波形正常

原因:Windows系统串口驱动在高负载时(如同时跑杀毒软件、远程桌面)会丢弃接收缓冲区末尾数据,而HMIMaker默认ReadTimeout=500ms,超时后直接放弃本次读取。
解决:在Config\config.json中增加串口级配置:

"SerialPortSettings": { "ReadTimeout": 100, "WriteTimeout": 100, "ReceivedBytesThreshold": 1 }

并将ReceivedBytesThreshold设为1,使DataReceived事件在收到任意字节即触发,配合驱动层的帧头帧尾校验,丢帧率从3.2%降至0.01%。

5.2 现象:画面切换时CPU飙升到100%,风扇狂转

原因:某些控件(如HmiChart)在Visible=false时仍持续渲染,且未释放OpenGL纹理资源。
解决:在画面Deactivate()事件中手动清理:

// 在画面脚本中 public override void Deactivate() { var chart = Page.FindControl("RealTimeChart") as HmiChart; if (chart != null) chart.Clear(); // 强制清空数据点 }

5.3 现象:Win7工控机上首次启动黑屏,任务管理器显示HmiMaker.exe占用100% CPU

原因:.NET Framework 4.6.1在Win7 SP1上存在JIT编译死锁Bug,尤其当Scripts\目录下有大量.cs文件时。
解决:

  1. 确保系统已安装KB3186568补丁;
  2. 在Config\config.json中添加:
"ScriptCompilation": { "PrecompileOnStartup": false, "MaxConcurrentCompiles": 1 }

让脚本改为按需编译,避开启动期并发高峰。

5.4 现象:Modbus写线圈失败,驱动日志显示“FunctionCodeMismatch”

原因:HMIMaker将WriteSingleCoil(功能码05)和WriteMultipleCoils(功能码15)统一封装为WriteCoil(address, value),但某些国产PLC固件只响应功能码15,对05返回异常。
解决:在Drivers\中替换为定制驱动,或在脚本中绕过:

// 不用VariableManager.SetValue,改用底层驱动 var driver = DriverManager.GetDriver("ModbusRtu"); driver.WriteMultipleCoils(0, new bool[]{true}); // 强制用FC15

5.5 现象:历史数据导出Excel后中文乱码,用记事本打开显示“涓€閽堝悗”

原因:HMIMaker导出使用Microsoft.Office.Interop.Excel,但工控机未安装Office,转而调用NPOI库,而NPOI默认用Encoding.Default(GB2312)写入,Excel 2016+默认用UTF-8读取。
解决:在导出脚本中显式指定编码:

// 使用StreamWriter而非Excel interop using (var sw = new StreamWriter(filePath, false, Encoding.UTF8)) { sw.WriteLine("时间,温度,压力"); foreach (var row in data) { sw.WriteLine($"{row.Time},{row.Temp},{row.Pressure}"); } }

6. 进阶技巧:用“变量快照”做故障回溯,比PLC日志更准

产线最头疼的不是实时报警,而是“刚才那波波动是什么原因?”。HMIMaker的VariableManager支持毫秒级变量快照,但默认关闭——因为它吃内存。开启后,你能在故障发生后,像调试器一样回放任意变量的历史轨迹。

6.1 启用快照:不是开关一开就行,要精准采样

在Config\config.json中配置:

"VariableSnapshot": { "Enabled": true, "SampleIntervalMs": 500, // 采样间隔,非越小越好! "MaxHistorySeconds": 3600, // 最大保留1小时数据 "TrackedVariables": [ // 只跟踪关键变量,避免内存爆炸 "ModbusRtu.InjMachine.AI_W0", "ModbusRtu.InjMachine.Q0_0", "ModbusRtu.InjMachine.DI_1" ] }

关键参数逻辑:SampleIntervalMs=500意味着每秒2次采样,1小时=7200个点 × 3个变量 × 每点约20字节 = 1.4MB内存。若设为100ms,内存消耗×5,工控机可能OOM。

6.2 回溯操作:三步定位故障源头

假设注塑机在14:22:15突然停机,你按以下步骤查:

  1. 打开快照浏览器:主界面 → 【工具】→ 【变量快照查看器】
  2. 设置时间范围:起始时间14:22:00,结束14:22:30,点击【加载】
  3. 交叉分析:
    • 曲线A:AI_W0(温度)在14:22:12开始骤降
    • 曲线B:Q0_0(合模阀)在14:22:13变为false
    • 曲线C:DI_1(安全门开关)在14:22:12.850变为true

→ 结论:安全门被意外打开(DI_1变高),触发连锁停机(Q0_0断电),导致温度下降。比查PLC梯形图快5分钟。

6.3 快照导出与离线分析:用Python做趋势挖掘

快照数据导出为CSV,可用Pandas做统计:

import pandas as pd df = pd.read_csv("snapshot_20240520_142200.csv") # 找出温度下降最快的时间段 df['delta_temp'] = df['ModbusRtu.InjMachine.AI_W0'].diff() fast_drop = df.nsmallest(5, 'delta_temp') print(fast_drop[['timestamp', 'ModbusRtu.InjMachine.AI_W0', 'delta_temp']])

输出:

timestamp ModbusRtu.InjMachine.AI_W0 delta_temp 12345 14:22:12.850 185.3 -12.7 12346 14:22:12.900 172.6 -12.7 ...

这证明温度传感器本身没问题(下降连续),而是执行机构动作导致——进一步验证了安全门误触发的判断。

从那以后我每次交付新项目,都强制在Config\config.json里打开快照,并把TrackedVariables列表贴在控制柜内侧。不是为了炫技,是给下次故障留一条不用翻PLC程序的捷径。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询