2019年10月30日星期三

RS-485误码导致的问题

前段时间开发的一个项目,我负责其中一个模块。该模块有两路RS-485接口,另一个模块(下文称为上游模块)通过这两个接口给我发送命令,我解析命令后控制160个指示灯的亮灭。
当时的命令格式是我定的,用一个bit表示一个灯。bit为1时点亮,bit为0时熄灭。160个灯总共是20个字节,外加2个字节的CRC, CRC采用Modbus协议的格式。
刚开始时,要求两路RS-485上的数据一致,才认为是有效数据,我进行了与运算,也就是同一个灯,两路上的命令对应的bit都是1, 我才会点亮,否则就熄灭。后来调试中发现会出现所有指示灯瞬间全部熄灭的情况,领导非常恼火,要我们解决。当时觉得可能是两路数据不一致导致的,上游模块觉得两路数据同步太困难了,让我改成优先取一路的数据,另一路作为备份,只有当第一路没有有效数据的时候采用第二路的数据。这样改后,瞬间熄灭的问题就消失了。
后来上游模块修改了需求,这160个指示灯大部分时间是处于全部熄灭状态,只有紧急情况下才需要点亮。因此大部分时间里,上游模块持续给我发送全部指示灯熄灭的命令。
结果客户验收那天,在指示灯本应全部熄灭的状态下,出现了两次前16个灯瞬间点亮又熄灭的问题。客户和领导都很恼火。要知道这160个指示灯指示的是道岔状态,涉及列车行驶安全,任何问题都可能导致车毁人亡。
后来排查发现,出现故障时,报文前面多出来2个字节的0xFF, 0xFF.也就是说,正常情况下指示灯全部熄灭的报文是
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 24 1B
出现故障时,报文时
FF FF 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 24 1B
巧就巧在,增加了0xFF, 0xFF后,前20个字节的CRC恰好是0x00 0x00, 也就是和报文的第21、22字节一致,这样CRC校验也通过了。因此0xFF, 0xFF对应的16个指示灯就恰好点亮了。
经查,这两个字节的0xFF, 0xFF并不是上游模块发出的,应该是RS-485线路上的干扰。
这个问题给我的启示是:
1. RS-485等串行总线,我们平时在实验桌上调试的时候,基本上不会遇到误码,但在现场环境下,长时间运行肯定会遇到少量误码,设计时不应该大意。
2. 对于指示灯亮灭这两种状态,用计算机科学的理论来看,一个bit就足以表示了,但是在特殊场合下,当出现翻转会导致严重后果时,就需要更多的bit来表示。铁路行业的计算机控制,至少会用2个bit来表示,比如01表示熄灭,10表示点亮。
3. 前期那个指示灯瞬间熄灭的问题,也可能是这个原因导致的,只是当时对问题分析不深入,错过了发现问题的机会。
4. 前期对两路同步的设计不完善。其实当发现两路上的数据不一致时,没必要马上将指示灯全部熄灭。因为上游模块是源源不断发送指示灯状态命令的,一次比对不一致,可以将这包数据丢弃,指示灯暂时维持当前状态,继续比较下一包。只有当持续一段时间的比较均不一致时(比如超过3秒),再将指示灯熄灭即可。

没有评论:

发表评论