干环保在线监测集成这些年我见过太多人栽在通讯这一环上。分析仪、采样器都调好了现场数据也正常了结果平台那边就是收不到数或者收到的报文解析不出来。查到最后问题基本都出在数采仪这一侧要么是HJ212报文格式不对要么是CRC校验算错了要么是4G模块的串口参数和触摸屏对不上。今天这篇就专门解决这个痛点手把手带你把MCGS触摸屏配合4G模块把HJ212报文稳稳地发到环保平台去。这套方案特别适合两类人看一类是做环保项目集成、现场运维的工程师手里有现成的MCGS触摸屏和4G DTU想省掉工控机那笔钱另一类是刚接触HJ212的初学者对报文结构、CRC算法一知半解想找一份能直接抄作业的完整示例。文章里我会把报文的每一个字节怎么来的、脚本每一行是干什么的、现场会踩哪些坑全部讲清楚保证你看完就能上手。1. 环保数采仪通讯为什么让人发愁先把HJ212报文的底细摸清楚1.1 HJ212不是“协议”而是“话术规范”很多人一听“HJ212协议”下意识就觉得要跑什么复杂的TCP/IP协议栈、要处理什么握手应答。实际上完全不是这样。HJ212全称是《污染物在线监控监测系统数据传输标准》它规定的不是网络怎么传而是数据长什么样子——设备往平台发数据的时候报文怎么组织、字段怎么命名、校验码怎么算。说白了它是一套“话术规范”只要你的设备能把符合格式的字符串发到平台的IP和端口上平台就认你。这就带来一个好消息你根本不需要懂网络编程只要能把一串字符从MCGS触摸屏的串口发出去再让4G模块把这串字符透传到环保平台的服务器上事情就成了。这也是为什么MCGS触摸屏能干这活的根本原因——它本质就是个带屏幕的嵌入式电脑有串口、有脚本、有定时器足够用来组报文、发数据。HJ212报文的基本骨架是这样的## 数据段长度 数据段 CRC校验码 \r\n拿一条最典型的实时数据上传报文举例##0139QN20250910103000000;ST31;CN2011;PW123456;MN001AEF01;CPdataTime20250910103000;COD12.5,1.08C1A\r\n拆开来看就非常清晰了部分内容说明起始符##固定两个井号平台靠它判断报文开始数据段长度0139从QN开始到结束的字符数4位十进制不足补0数据段QN...;ST31;...;CP...真正的业务数据由多个分号分隔的字段组成CRC校验码8C1A对数据段做CRC16校验4位十六进制结束符\r\n回车换行平台靠它判断报文结束数据段内部的字段也有一张标准表我列出最常用的几个字段含义示例QN请求时间戳格式yyyyMMddHHmmssSSS20250910103000000ST系统类型31代表在线监测31CN命令编码2011是实时数据上传2011PW访问密码123456MN设备唯一标识20位以内字符001AEF01CP数据区包裹dataTime20250910103000;COD12.5,1.01.2 常见的发愁点格式、校验、时序我做过的项目里90%的通讯问题都出在下面这几个地方。数据段长度算错。长度指的是从QN开始一直到结束的总字符数不包含##、不包含CRC码、不包含\r\n。很多人把这个长度算成了整个报文的长度平台一解析就报错。而且这个长度是用4位十进制表示的实际位数不够就在前面补0。比如长度是139个字符就要写成0139而不是139。脚本里最稳妥的做法是Right(0000 CStr(Len(dataStr)), 4)自动补零。CRC校验码算错。HJ212用的CRC16算法多项式是0xA001初始值是0xFFFF计算范围是数据段从第一个字符到最后一个字符包含分号和。校验结果转成16进制后要低字节在前输出。举个例如果算出来的CRC值是0x1A8C写入报文的应该是8C1A。这个字节序问题特别坑很多人算法看起来对就是结果反了。结束符不完整。标准要求报文以\r\n结尾也就是回车(0x0D)加换行(0x0A)两个字符。有朋友图省事只发\n平台那边就可能把两条报文连在一起解析出现莫名其妙的乱码。还有人在字符串里直接写\r\n这两个字符结果发出去的是字母r和字母n而不是控制符。MCGS脚本里一定要用Chr(13) Chr(10)来构造。时序和心跳。环保平台通常要求设备主动上传而且要保持TCP长连接。如果数据上报间隔太长平台会判定设备离线。所以除了正常的数据报文还得定时发心跳报文命令编码CN1011这样平台才知道设备还活着。2. 方案选型为什么是MCGS触摸屏4G模块这套组合2.1 传统方案的痛点在没有MCGS触摸屏方案之前大家做数采仪通讯通常有三条路各有一堆毛病。工控机采集软件是最老派的做法优点是性能强、扩展性好缺点是成本高、功耗大、体积笨重。一个现场柜子里塞一台工控机几千块的成本不说风扇进灰、硬盘损坏、系统蓝屏一年到头得跑好几趟现场。很多环保站点都在比较偏远的地方跑一趟的交通和时间成本比设备本身还贵。单片机串口模块是另一个极端成本确实低但开发周期长。写协议解析、处理数据存储、画个简单的人机界面一套下来至少一两周。而且现场要改参数、看数据都没有界面调试全靠连电脑后期维护非常不方便。PLCHMI听起来合理但PLC本身不带HJ212这种自由协议处理能力很多中低端PLC连字符串拼接都费劲CRC计算更是难为它了。而且一台带以太网或者串口自由通讯的PLC价格也不便宜性价比不高。2.2 为什么MCGS触摸屏刚好合适MCGS触摸屏能解决这个问题靠的是三个优势叠加。第一是脚本能力。MCGS组态环境里有类VBS的脚本语言支持字符串拼接、位运算、定时器、自定义函数。这意味着CRC16算法可以在MCGS内部直接实现不需要外挂任何设备。第二是串口资源。主流型号都带至少两个串口RS232/RS485可以一个串口接分析仪采集数据另一个串口接4G模块发报文。第三是成本和人机界面。一台7寸MCGS屏市场价一千出头比工控机便宜一半还多而且现场的人能直接看到实时数据、通讯状态、报警信息维护人员排查问题一目了然。2.3 4G模块的使用方式选透传最省事4G模块市面上很多但用起来无非两种模式。AT指令模式模块通过串口接收AT指令比如ATTCPCONNECTIP,端口、ATTCPSEND数据。这种方式灵活但MCGS脚本里要写一堆AT指令的处理逻辑还要解析模块的返回麻烦且容易出错。除非你对成本极度敏感否则我不推荐在MCGS里用AT指令方式。透传模式DTU模式模块上电后自动连接平台服务器建立TCP长连接。之后串口收到什么字节就原封不动地往服务器发服务器发来什么字节也原封不动地往串口吐。对MCGS来说它根本感觉不到4G网络的存在就像直接往一根串口线上写数据一样。这极大简化了开发只需要在模块上用配置软件把服务器IP、端口设好剩下的就全是MCGS的事了。我个人强烈建议使用透传模式。选4G DTU模块时注意三个硬指标支持TCP Client、串口波特率范围覆盖你需要的速率、供电电压合适一般5V~36V直流都行。至于品牌大厂的有人物联网、移远、合宙都有对应产品按价格和供货选就行。2.4 整体数据链路这套方案组好之后的完整链路是这样的分析仪/数采仪(RS485) - MCGS触摸屏串口2 - MCGS脚本组包 - MCGS串口1 - 4G DTU - 环保平台MCGS扮演的角色是“翻译官”从分析仪拿到监测数据按照HJ212格式拼成报文再从另一个串口扔给4G模块。4G模块就是个“快递员”把报文原封不动地送到千里之外的平台上。链路中每一个环节都是低耦合的哪一段出了问题都容易定位。3. MCGS触摸屏端从零配置变量、串口和脚本准备3.1 先确认硬件接线和串口参数我用得比较多的是昆仑通态TPC7062系列7寸屏价格合适还带双串口。不同型号的串口定义略有差异但接线思路一样。从触摸屏背面的端子看COM1一般是RS232COM2是RS485。4G DTU模块通常提供RS232或者TTL接口我用的是RS232接口的DTU直接用三根线把触摸屏COM1连到DTU上触摸屏TX接DTU的RX触摸屏RX接DTU的TX然后两端共GND。先别急着插电接线检查三遍再上电串口通讯烧设备十有八九是接反了或者共地没做好。上电之后第一件事确认串口参数一致。触摸屏的COM1和4G模块的串口参数必须完全一样常见的是波特率9600、数据位8位、停止位1位、无校验简写就是9600,8,N,1。如果触摸屏设成9600DTU设成115200那两边的数据全是乱码平台收到的报文也完全不可用。3.2 建立工程与定义变量在电脑上打开MCGS组态环境我用的是嵌入版新建工程后先别急着画界面把数据变量定义清楚是后面所有脚本的基础。需要定义的变量大致有这几类变量名类型用途DataStr字符串缓存完整HJ212报文QN字符串请求时间戳MN字符串设备唯一标识COD数值COD监测值用于示例NH3N数值氨氮监测值CW数值废水流量示例因子SendOk开关型发送成功标志HeartbeatTimer数值心跳计时变量怎么发挥作用MCGS里脚本可以直接读写这些变量比如执行MN 001AEF01就把设备标识存进变量了。字符串变量在MCGS里很常用后面构造报文时直接用$符号拼接。有一点必须提醒MCGS变量名不能以数字开头也不能有中文最好全部用字母和数字避免脚本里引用的各种隐藏问题。3.3 配置设备窗口和串口发送通道在MCGS的“设备窗口”里我需要把串口通讯能力挂上去。操作路径通常是设备窗口 - 双击空白处 - 工具箱里找到“通用串口父设备” - 拖入设备列表 - 在属性里设置串口号COM1和串口参数9600,8,N,1。关键问题来了怎么让MCGS脚本主动把一段字符串通过串口发出去不同版本的MCGS函数名略有不同有的叫!SendStr有的叫!WriteComm还有的是通过设备对象写入实现。我用的版本支持在脚本里直接调用串口发送函数格式类似!SendStr(串口设备名, DataStr)第一次用的时候很容易卡在函数名上。我的建议是在MCGS的脚本编辑环境里按F1打开帮助搜索“串口”或者“Send”就能看到当前版本支持的准确函数名和参数格式。这个帮助文档平时不起眼遇到这种问题比问谁都管用。确认函数名之后发报文就只剩一条命令的事情。另外4G模块那边也要配置好用模块厂家提供的串口配置软件一般通过USB转串口连电脑把工作模式设为透传填上环保平台的服务器IP和端口设置心跳包间隔一般60秒到120秒。配置完后一定记得断电重启模块部分模块重启后才生效。3.4 用户窗口画一个简单的调试界面虽然本文重点在报文发送但我还是建议在MCGS里画一个最小可用的调试界面放两个元素就够一个“手动发送”按钮一个“最近发送状态”指示灯。按钮用来触发脚本手动发一条报文指示灯在SendOk变量为1时显示绿色。别看界面简陋现场调试能救命——工程师对着屏按一下按钮就知道通讯通不通不用开着电脑连串口。4. 核心代码实现在MCGS脚本里构造HJ212报文并发送4.1 报文构造的核心思路写脚本前先把流程在脑子里过一遍。构造一条实时数据上传报文CN2011需要五步取当前时间生成QN时间戳。拼接数据段从QN开始到CP...结束。计算数据段长度转成4位十进制。对数据段做CRC16校验结果转4位十六进制低字节在前。拼完整报文## 长度 数据段 CRC \r\n通过串口发送。每一步都不复杂难的是顺序不能错、字节不能少。我最开始写的时候就是漏了长度补零平台侧一直报“报文长度错误”排查了很久才意识到长度字段有问题。4.2 完整的MCGS脚本示例下面是一份可直接参考的MCGS脚本实现了CRC16计算和报文发送。注释我写得比较细方便对照。 自定义CRC16校验函数多项式0xA001初始值0xFFFF Function CRC16(s) Dim crc, i, j, ch crc HFFFF For i 1 To Len(s) ch Asc(Mid(s, i, 1)) crc crc Xor ch For j 1 To 8 If (crc And 1) Then crc (crc \ 2) And H7FFF crc crc Xor HA001 Else crc (crc \ 2) And H7FFF End If Next Next CRC16 crc End Function 构造并发送HJ212实时数据报文 Sub SendHJ212() Dim qn, st, cn, pw, mn, cp Dim dataStr, lenStr, crcVal, crcStr, fullStr 时间戳格式 yyyyMMddHHmmssSSS qn !TimeToStr(!Time, yyyyMMddHHmmss) 000 基础字段 st 31 cn 2011 pw 123456 mn 001AEF01 改成你设备的MN 数据区示例包含COD、氨氮、流量 cp dataTime !TimeToStr(!Time, yyyyMMddHHmmss) ; cp cp COD Str(!Format(!COD, 0.0)) ,1.0; cp cp NH3N Str(!Format(!NH3N, 0.000)) ,1.0; cp cp CW Str(!Format(!CW, 0.0)) ,1.0 拼接数据段 dataStr QN qn ;ST st ;CN cn ;PW pw dataStr dataStr ;MN mn ;CP cp 数据段长度4位十进制不足补0 lenStr Right(0000 CStr(Len(dataStr)), 4) CRC校验结果转十六进制低字节在前 crcVal CRC16(dataStr) crcStr Right(0000 Hex(crcVal), 4) crcStr Right(crcStr, 2) Left(crcStr, 2) 拼完整报文结束符用Chr(13) Chr(10) fullStr ## lenStr dataStr crcStr Chr(13) Chr(10) 发送到串口函数名以当前MCGS版本为准 !SendStr(串口设备名, fullStr) End Sub4.3 脚本里的几个关键细节这段脚本里的每个坑都是我用实际发送失败换来的教训。时间戳的格式。QN字段要求yyyyMMddHHmmssSSS也就是包含三位毫秒。有些平台对毫秒有要求有些可有可无。稳妥做法是每次都带上我示例里用 000补了3个0。dataTime字段不含毫秒用yyyyMMddHHmmss就够。数值字段的格式。CP区里的每个因子后面跟的,1.0第一个数是因子值第二个数是监测方法对应的系数或者标记不同因子这儿的写法有讲究。比如COD后面接,1.0有的平台要求,2.0。这里不能想当然必须对照环保平台那边的因子配置来填。我的习惯是先把平台下发数据或者别的设备上传的正常报文抓一份照着人家的格式写这比自己猜可靠得多。CRC函数的位运算。MCGS的脚本是类VBS语法整除用\按位与用And十六进制常数用H前缀。(crc \ 2) And H7FFF这一步是把crc右移一位并清掉最高位因为在VBS里没有直接的移位运算符得靠这种方式模拟。我见过有人图省事直接用crc crc / 2浮点数一顿操作下来CRC全乱了必须用整数除法。调用时机。发送函数写好后可以用三种方式触发手动按钮触发脚本里调用SendHJ212()、周期循环触发在“循环脚本”里设置周期比如60秒执行一次、事件触发当某个变量变化时执行。实操中我一般手动触发留一个按钮同时用循环脚本做周期上报。4.4 心跳报文的实现除了实时数据平台通常还要求定期发心跳来维持在线状态。心跳报文CN1011的结构简单很多不需要CP数据区Sub SendHeartbeat() Dim dataStr, lenStr, crcVal, crcStr, fullStr Dim qn qn !TimeToStr(!Time, yyyyMMddHHmmss) 000 dataStr QN qn ;ST31;CN1011;PW123456;MN001AEF01 lenStr Right(0000 CStr(Len(dataStr)), 4) crcVal CRC16(dataStr) crcStr Right(0000 Hex(crcVal), 4) crcStr Right(crcStr, 2) Left(crcStr, 2) fullStr ## lenStr dataStr crcStr Chr(13) Chr(10) !SendStr(串口设备名, fullStr) End Sub心跳的触发周期我一般设60秒到120秒太频繁平台可能判为干扰太慢又容易掉线。具体间隔按平台要求来通常平台侧会有参数说明。5. 联调现场实录与高频问题排查速查5.1 没有平台先自测串口调试助手是必须的工具写到这里你已经有了完整的脚本。但在真正对接环保平台之前我强烈建议先在本地把报文验证一遍别直接上平台否则错了连错误原因都不知道。方法很简单把触摸屏的COM口通过USB转RS232线接到电脑上电脑上开一个串口调试助手推荐SSCOM或者Vofa设置与触摸屏一样的波特率。然后在触摸屏上按“手动发送”按钮调试助手窗口里应该能看到完整报文。看到报文之后别急着高兴做一个关键动作把报文复制到HJ212在线解析工具里网上随便搜一个或者用环保平台自带的报文调试工具让工具帮你解析字段和校验CRC。HC212解析工具会明确告诉你报文格式对不对、CRC是否正确。这一步能过滤掉大部分低级错误。我之前遇到一个特别典型的情况串口调试助手显示报文内容完全正确但平台就是不收。后来发现是PC的串口助手软件界面显示的是ASCII字符但我把Chr(13) Chr(10)写成了字符串\r\n实际发出去的四个字符\、r、\、n平台自然不认。所以要特别留意报文结尾的十六进制值正常情况下应该是0D 0A而不是5C 72 5C 6E。5.2 平台连不上或收不到数的排查思路如果串口侧的报文没问题但平台仍然收不到问题十有八九出在4G链路上。排查顺序我已经形成了肌肉记忆按下面这个顺序走能省下大量时间。第一步查4G模块的网络状态。很多DTU有状态指示灯看拨号是否成功、TCP连接是否建立。有条件的用模块的配置软件连上去看当前网络注册状态和服务器连接状态。第二步检查SIM卡换一张在手机上确认能上网的卡试一下有的现场卡被运营商限了APN或者没开流量模块能注册到网络但数据传不出去。第三步核对服务器IP和端口这俩参数拼错一个字母都连不上别笑我见过把193.168.1.100这种IP填错成192.168.1.100的低级错误一查一个准。网络通路没问题但还是收不到数据那就要在DTU的配置软件里打开调试日志看看串口收到的原始数据是不是和调试助手里一样。这条链路里的数据是串行流动的MCGS串口 - DTU串口 - DTU网络 - 平台服务器。哪一段断了数据就停在哪一段。DTU日志能告诉你它到底有没有把数据发到网络侧。5.3 高频问题速查表我把这些年接触过的HJ212通讯高频问题整理成一张速查表现场排查对照着看就行问题现象可能原因解决办法平台收不到任何报文4G模块未拨号成功检查SIM卡、天线、APN参数报文被平台解析为“长度错误”数据段长度未补0或算错检查数据段Len计算逻辑平台提示“CRC校验错误”CRC字节序反了将CRC结果低字节放前平台提示“缺少结束符”\r\n写成了字符串用Chr(13) Chr(10)构造串口调试助手收到乱码MCGS串口和DTU波特率不一致统一改为9600,8,N,1定时上报间隔不准MCGS循环脚本周期设置不当检查循环脚本的周期配置断电重启后不上报启动时没有执行初始化脚本在启动脚本里调用一次发送函数平台显示设备离线心跳间隔太长调整心跳报文周期为60秒5.4 几条实战避坑笔记MN必须唯一且规整。MN是设备唯一标识相当于设备的身份证。同一个平台下每台设备的MN不能重复。有的项目图省事把MN设成默认值或者不填平台直接把设备当非法终端踢掉。而且MN一旦上线后尽量别改改了平台可能关联不上历史数据。多因子上报的分隔符。CP数据区里如果有多个因子因子之间用分号分隔。但同一个因子的多个参数比如COD值和量程上限之间用的是逗号。这个分号和逗号的区分特别容易搞混我见过有人把整个CP区都用分号平台解析到最后全乱了。监控平台对时间戳要求严格。如果MCGS的时钟不准确或者与平台时间差太多平台可能拒绝接收报文。项目交付时一定要校准MCGS的系统时间或者在MCGS里开启NTP校时功能。有的4G DTU也支持网络校时但MCGS本身时间快慢问题靠现场定期校准更现实。发送频率别太激进。实时数据上报间隔一般30秒到5分钟按项目合同要求来。有的工程师为了试机方便把循环脚本改成1秒发一次结果平台把设备判定为“异常高频上报”直接拉黑IP。测试阶段可以频繁发联调结束一定要改成正式的间隔。保留现场报文记录。在MCGS用户窗口放一个“最新发送报文”文本框把每次发送的fullStr存进去。这样现场维护的人只要看一眼屏就能把报文内容拍照发给后台分析效率提升很大。这个功能实现起来就一行脚本!StrSet(文本框, fullStr)但价值极高。写在最后的体会我在几个污水和废气在线监测项目里用了这套MCGS4G模块HJ212的方案最长的站点稳定运行了大半年没掉过链子。最让我省心的不是省了工控机的钱而是现场维护变得极其简单——触摸屏出问题直接换一块把工程灌进去接上线就能跑不用重新调外围设备4G模块出问题换一台重新配置几分钟搞定。这套组合的容错性和替换便利性是工控机方案完全比不上的。如果你也在折腾HJ212上报我的建议是先把报文这关吃透串口调试助手就是你最好的老师在本地把所有字节都验证清楚再上平台。也别害怕报错平台返回的错误码其实已经把问题告诉你了对照着速查表一步步排查这活没有想象中那么难。