McgsPro 通讯状态一直显示 6:一次 RS485 控制矩阵设备的完整排查实录

技术折腾 · · 墨言

最近这个项目的要求很直接:会议室那块昆仑通态触摸屏上,点一下按钮,就把指定的信号源切到指定的输出——也就是控制一台矩阵切换设备。屏这边走的是板上的 COM2(RS485,占用 7/8 针),两根线接到矩阵的 485 口上。

画面做完、工程下载到屏,满怀信心点下去——矩阵没反应。

我在画面上加了一个数值显示框,把设备的通讯状态通道接出来,屏幕上稳定显示一个数字:6。

接下来的两个小时,我一直在干一件错事:怀疑那两根线。A、B 是不是接反了?屏蔽层接没接?波特率对不对?把线拔下来量、调换顺序再试、换了个 USB 转 485 模块……全部无果。直到我老老实实去翻驱动帮助里那张状态码表,才发现问题根本不在线路上。

这篇文章就是这次排查的完整记录:6 这个数字到底在说什么、我怎么把问题从「线路」切到「命令」的、最后又是怎么写错的。文末那张排查清单可以直接拿到现场照着念。

先给结论

赶时间的话,记住这几条就够:

你看到的值官方含义该往哪一层查
0通讯正常—
1初始化失败 / 未收到确认帧物理层、参数层
2采集无数据返回物理层、参数层(地址/站号)
3采集数据校验错误参数层(校验位)、干扰
4设备命令读写操作失败命令层
5设备命令格式或参数错误命令层
6设备命令数据变量取值或赋值错误命令层 + 变量层(本文主角)
7 及以上收到的数据帧有问题 / 对端未准备好数据层、时序

关键判断:6 不等于「没连上」。 它的意思是链路已经通了、命令也已经发出去了,但是命令里用到的那个变量取不到值、或者值赋不进去。所以排查重心应该在脚本里的设备命令写法和实时数据库的变量定义上,而不是 A/B 线和波特率。

我这台最后的根因,就落在设备命令的写法上。

说明一下这张表的口径:昆仑通态各驱动帮助里,0~6 的含义基本一致,7 往上不同驱动写法会有差异(比如有的驱动 7 是「PLC 数据未准备好」,有的是「接收数据异常、解码错误」)。所以查的时候以你当前这个驱动自己的帮助为准,设备窗口里选中设备点「打开设备帮助」就能看到。

一、先把「通讯状态」这个数看对

在动手之前,有两件事必须先确认,否则你看到的可能根本不是你想看的那个数。

1. 通讯状态是设备的第一个通道。 昆仑通态的手册里写得很清楚:所有非板卡类设备(部分定制设备除外),第一个通道就是通讯通道,进入运行环境、驱动开始工作后,这个通道里返回的就是设备的通讯状态,0 为正常、非 0 为异常。

具体到串口数据收发这个驱动,它用的是固定通道,帮助里写死的三条是:

  • 通道 0:通讯状态标志
  • 通道 1:字符串通道
  • 通道 2:十六进制字符串通道

2. 我踩的第一个坑:盯错了设备。 我这台屏的设备窗口里挂了不止一个子设备——一路是 Modbus 相关,一路是串口收发。每个子设备都有自己的通讯状态通道,各自报各自的。我一开始在画面上看的那个变量,连的其实不是控制矩阵那一路。

确认方法很简单:在设备窗口里看清设备名,再到实时数据库里反查这个通道连的是哪个变量,最后确认画面上那个显示框绑的是不是同一个变量。别嫌麻烦,这一步能直接决定你后面两小时查的方向对不对。

3. 我踩的第二个坑:开着设备调试看状态。 手册里明确提示过——上位机运行时不要打开设备调试去查看设备状态,那样会导致通讯不正常。也就是说,你在调试状态下看到的那个非 0,可能是你自己看出来的。要观察真实状态,就把通讯状态通道接到画面上的显示框里,让屏自己跑。

二、怎么证明「线是通的」:把物理层和命令层切开

这是我这次最有用的一个动作。与其猜,不如设计一个能一锤定音的验证。

我用一个 USB 转 485 模块接到电脑上,然后:

  • 模块的 A 接屏的 A、B 接屏的 B(同名端对接,不是交叉);
  • 线路不稳定或距离稍长时把两端的地也接在一起(共地);
  • 电脑上开串口调试助手,参数设成和屏一致,冒充矩阵,看屏到底发出来了什么字节。

这里有个细节值得单独说:RS485 不能像 RS232 那样短接 2、3 脚做自发自收环回。 485 是差分信号,靠 A、B 两线之间的电压差传数据,把 A、B 短在一起什么也收不到。要做环回测试,得用两个转换器(或一个转换器的两个口)把 A-A、B-B 对起来,一端发、一端收。

结果:我在电脑侧的调试助手里清清楚楚看到了屏发出来的帧。

这一眼的价值极大——它一次性排掉了三件事:

  1. 屏的串口硬件是好的;
  2. 串口端口号(COM2)选对了;
  3. 波特率、数据位、停止位、校验位这些父设备参数,至少在”能发出去”这个层面是对的。

既然帧能发出来,1、2、3 这三个状态码基本可以划掉,问题必然在更上层。

顺带一提,如果连这一步都看不到帧,那就老老实实回头查物理层:万用表直流电压档量 A、B 之间的差分电压,屏在发数据时应该能看到电压跳变;距离长、节点多的时候考虑终端电阻;屏蔽层单端接地;485 线尽量远离变频器和伺服驱动器。

三、参数层:把「我以为对的」逐项核对一遍

即使帧能发出去,参数也值得再过一遍,尤其是容易被忽略的两项。

父设备(通用串口父设备)参数:

参数核对要点
串口端口号屏上 COM1 一般是 RS232(2/3/5 针),COM2 一般是 RS485(7/8 针),具体以你那款屏的手册为准
通信波特率与矩阵设备完全一致,别凭印象
数据位位数常见 8 位,个别设备是 7 位
停止位位数1 位还是 2 位,非常容易错
数据校验方式无校验 / 奇校验 / 偶校验,必须和对端一致

子设备(串口数据收发)参数里,最要命的是「协议类型」:

这个驱动有个协议类型选项,指定收发帧是十六进制还是 ASCII 码形式。如果你写的命令是 ASCII 明文指令,而这里选成了十六进制,那么驱动会拿你的字符串去当十六进制解析——解析失败,报出来的就是「取值或赋值错误」这一类。这是 6 号错误的近亲,而且表现得很像线路问题。

我的核对办法是对照法,很土但很有效:

  1. 先用电脑上的串口调试助手,把矩阵手册里那条指令原样发给矩阵,确认矩阵有回包、动作正常;
  2. 把同一条指令放进屏里发,用调试助手抓屏发出来的字节流;
  3. 两次的十六进制字节流逐字节比对。

只要这两串对得上,说明「屏要表达的意思」和「矩阵能听懂的话」是一致的,剩下的问题就只可能在命令本身怎么组织上。

四、命中:设备命令的写法

串口数据收发驱动的设备命令,帮助里给的标准格式长这样:

!SetDevice(设备0, 6, "Read(strData)")     ' 读串口数据,以字符串形式存放到 strData
!SetDevice(设备0, 6, "Write(strData)")    ' 把 strData 中的值写入串口

我这次的问题,就出在这一行的写法上。把驱动帮助里的示例和自己脚本里的句子逐字对照后,总结出四个最容易栽的坑:

坑具体表现为什么阴险
中文标点括号、引号、逗号写成了全角中文符号脚本不报错,命令解析直接失败
通道号乱填SetDevice 的第二个参数按自己理解改成了 1 或 2这个位置照驱动帮助示例写(该驱动示例统一是 6),别想当然替换成字符串通道的编号
变量没定义 / 改过名命令里引用的变量,实时数据库里根本不存在,或组态时改过名但脚本没同步最隐蔽的一种,肉眼看句子完全没问题
变量类型对不上字符串通道要的是字符型变量,却塞进去数值型或开关型对应「取值或赋值错误」的字面意思

第二个坑单独说一句:!SetDevice(设备名, 通道号, 命令串) 里第二个参数是通道号,而这个驱动的官方示例里统一写作 6。如果你之前自作主张把它改成了 1(字符串通道)或 2(十六进制通道),先改回帮助里的写法再排查其他项,别在这个数字上创新。

第四个坑也值得展开:昆仑通态实时数据库里的变量是有类型的,开关型、数值型、字符型各管各的。串口收发的是字符串,所以承载命令的变量必须是字符型。你拿一个数值型变量去接,驱动取不到它要的字符串,报错就是 6。

修正后的写法,核心就是让每一处都对得上:

' strSend 必须在实时数据库中定义为【字符型】
' 指令内容和结束符严格按矩阵手册来(常见是回车 \r 或回车换行 \r\n)
strSend = "矩阵指令内容"
!SetDevice(设备0, 6, "Write(strSend)")

关于结束符多啰嗦一句:很多矩阵、会议主机一类的设备,指令末尾必须带回车才认。你在屏上写字符串时不确定怎么表达,就回到上一节那个对照法——用调试助手先把「带结束符的正确帧」抓下来,看最后两个字节到底是什么,再回屏里照着拼。别猜。

改完、重新下载工程到屏、重启运行环境之后,画面上那个数字终于变成了 0,点按钮,矩阵动作。

五、别只看一个数:怎么确认真的修好了

通讯状态归 0 只是第一道关。我一般会再补两步才敢收工:

  1. 看字节流,而不是看状态值。 用调试助手盯着实际收到的帧,和你预期的逐字节比对。状态值是驱动给你的”结论”,字节流才是”证据”——偶尔会有状态显示 0 但内容根本不对的情况。
  2. 连续点 20 次。 intermittent 的问题(时好时坏)比彻底不通更烦人。连点 20 次,如果中间偶发跳成非 0,说明你面对的是稳定性问题而不是配置问题,方向要换到时序和干扰上去。

六、现场排查清单(可以照着念)

下次再遇到通讯状态非 0,按这个顺序走,能省掉大半时间:

步骤动作判据 / 说明
1确认你看的是不是目标设备的通讯状态设备窗口里挂多个子设备时,各有各的状态通道
2关闭设备调试窗口,让屏自己跑运行时开调试会干扰通讯,看到的是假数据
3用 USB 转 485 + 调试助手冒充下位机,看屏是否发帧能看到帧 → 硬件、端口号、波特率基本没问题,排除 1/2/3
4对照法比对字节流调试助手发的 vs 屏发的,逐字节一致才算对
5核对父设备五项参数端口号、波特率、数据位、停止位、校验位
6核对子设备「协议类型」ASCII 明文指令别选成十六进制
7逐字检查设备命令写法中文标点、通道号、变量名、变量类型
8确认变量在实时数据库中已定义且类型正确字符串通道必须配字符型变量
9连续操作 20 次验证稳定性偶发非 0 → 查时序、等待时间、干扰

七、顺带记几个相关的坑

都是这次顺手整理出来的,放在一起:

  • 通讯等待时间别用默认值硬扛。 回包慢的设备,等待时间偏短就容易偶发非 0。驱动帮助里的建议就是「适当延长通讯等待时间」,现场实测下来这招对间歇性掉线很有效。
  • 最小采集周期和手动下发会打架。 采集周期设得很短,又在循环策略里频繁调 SetDevice,两条指令容易互相打断。要么拉开采集周期,要么把下发收敛到按钮事件里触发。
  • 改完一定要重新下载工程并重启运行环境。 组态环境里看着对了,不等于屏里跑的是新的。
  • 485 的布线规矩要守。 屏蔽双绞线、屏蔽层单端接地、长距离加终端电阻、远离变频器和伺服。这些老生常谈的话,在真出问题的时候每一条都得回去查一遍。
  • 手册口径会有版本差异。 7 以上的状态码在不同驱动里含义不完全一致,以你当前驱动自带的帮助为准,别拿通用表硬套。

最后

这次最值钱的不是”改对了那一行命令”,而是把问题分了层。

通讯状态这个数字本身就是分层的:1、2 在物理层,3 在参数层,4、5、6 在命令层,7 往上在数据层。看到非 0 就冲去查线,等于用物理层的方法去解决命令层的问题——线当然没问题,因为从来就不是线的问题。

现在我在现场的习惯是:先花十分钟设计一个能一锤定音的验证(比如用调试助手冒充下位机看帧),把层次切开,再动手。看起来慢,实际快得多。

那台矩阵现在切得很顺。只是我大概会一直记得,自己曾经对着两根 485 线,认认真真地怀疑了它两个小时。