外行小白的modbus惊心之旅

Posted 无心大魔王

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了外行小白的modbus惊心之旅相关的知识,希望对你有一定的参考价值。

外行小白的modbus惊心之旅

        这是一个悲伤的故事,笔者自真正接触编程后,学习的一直是编写javaweb项目,然而万万没想到的是,有生之年竟然会接触到串口通信的需求。为了能够帮助到一些和我面临着相同困境的小伙伴们,特此将自己这一段时间来的心得体会记录下来,希望能给大家带来一点点的助益,本文新手向,大佬请绕行~

(注意:由于笔者对于这方面也是外行,所以文章中可能有些术语不当、思路不佳之处,大家见谅!)

我接到的需求大致如下:

现有温湿度监控设备N台,需要编写一个软件,部署在用户的电脑上,通过com口对温湿度设备进行数据采集,并将采集到的数据解析后传送给平台。

       网上不难找到关于如何采集数据的代码,所以在本文中就不再赘述了,那么接下来我们就聊一下,采集到数据之后,如何解析成用户想要的数据。假设你现在得到了设备返回的一条完整数据,这条数据是以字节数组的形式存储的,示例如下:

byte数组:[01 09 00 01 01 05 49 DB]

数组下标:[0   1   2   3   4   5   6    7]

下标0:设备地址号      下标1:命令号(假设09为采集数据命令)      下标2和下标3:存储器号      下标4和下标5:温度数据      下标6和下标7:校验码

那么问题来了,byte的取值范围为-128~127,难道室内温度还能达到-128或者127不成?为什么存储温度数据要用两字节呢?

       因为一个字节占8位,而设备返回的温度数值是一个16位的整数,所以需要用两个字节来存储。比如现在室内温度为25.5摄氏度,那么设备将会返回给我255。由于我使用的是c#语言,在c#中byte是无符号的,取值范围为0~255,那么我最终采集到的数据以十进制的形式打印出来就是  0  255。那么,为什么第一个字节是0,第二个字节是255呢?

       255的二进制形式为11111111,如果保存为16位,则应该为0000 0000 1111 1111。由此可见,高八位为8个0,低八位为8个1。而一个字节为八位,所以,高八位存在了第一个字节,它的十进制也就是0,而低八位存在了第二个字节,它的十进制为255。由于我使用的是c#语言,所以,最终看到的结果为  0  255。起初的时候,我没有意识到最本质的问题,计算机存储的实际上是二进制数,所以导致了我以一种奇怪的思路来对数据进行解析,而当踩坑之后,经过不断的查阅资料和询问厂家之后,终于总结出了三个关键字:高八位、低八位、十六位整数。

进而我想到了位运算,将高八位先转为16位进行存储,然后左移八位,低位补零。那么示例中的高八位应该变成了这个样子:0000 0000 0000 0000。

然后将高八位与低八位相加:

0000 0000 0000 0000

                   1111 1111

最终得到的结果为:0000 0000 1111 1111,转为十进制也就是255。

//代码供参考
((Convert.ToInt16(b[5])) << 8) + b[6]

接下来,再来聊一下我在 这个需求之中遇到的其他坑... ...

粘包和分包问题:

最开始在网上查询资料的时候,就读到了这两个词,当时还抱着一点侥幸心理,暗自思量着这东西说不定是什么高端操作吧?我这需求里应该用不到吧?

结果后来在数据采集的时候,问题就出现了,时而可以采集到数据,时而采集不到数据。我当时的确是百思不得其解,既然能接收到数据,那我的代码应该没什么问题吧?但为什么有时候又接收不到数据呢?

后来下载一个串口监测工具才发现了问题所在,比如一条完整数据应该为8字节,但是,我接到的数据中,有时是一次性接收到8字节的数据,有时则是先接收了三字节,然后接收了五字节。

另外一种情况就是,有时还会一次性接收到十几字节的数据,当时一度怀疑是某些转接设备的问题,经过仔细观察发现,原来在这条数据中,有一部分是第一条数据,另一部分是第二条数据。

解决方案:

采用生产者和消费者的方式来解决,生产者采集数据存入缓存队列,消费者每当从队列中取出八个字节,进行一次校验,校验成功后,再对数据进行解析和转发。

以上是关于外行小白的modbus惊心之旅的主要内容,如果未能解决你的问题,请参考以下文章

NEFU 169 步步惊心

“外行”带你看国标38900-2020

小白之旅6

小白之旅18

我的Android进阶之旅NDK开发之在C++代码中使用Android Log打印日志,打印出C++的函数耗时以及代码片段耗时详情

python小白学习之旅5