485通讯协议在java中的应用

485通讯协议在java中的应用(一)

前言

之前我博客中有提到,在javaWeb应用系统中进行串口通讯的实现。
博客地址:java串口通讯,可实现javaWeb页面同时控制多个串口,有demo
很多网友对此有疑问,特别是485通讯这块,仔细想想,这块确实挺坑。

什么是485通讯协议?

我想应该所有在做java串口通讯的人都上网查过485通讯协议,但是得到的答案应该都不太清晰。
因为网上的描述和实际的其实有很大差距,下面是百度搜索的485通讯协议:
485通讯协议在java中的应用

截图中可以看到,有【RS-485协议】和【485通讯协议标准】两种。
这里我解释下两者的区别,RS-485协议是硬件层面的,它规定了工控设备制作串口时的一些标准。比如说,为什么串口是9针?每一针起什么作用?传输速率?等等。
这是硬件层面的,我们要用的并不是这个,可以忽略这个不看,我们只要知道通讯协议即可。

然而所谓的通讯协议标准,其实只不过是一些成文的相对规范,并不一定有强制性要求。就比如说,公司的开发规范,每个公司都有,新员工进来都要看,也规定要遵守。但其实也并不是所有员工都完全遵守。个人都有个人的开发习惯,只要极度影响合作开发的规范统一了,其他的小细节,其实都没怎么在意。(当然这么干并不好,我只是举个例子让大家能理解什么叫协议标准)
还有比如说http协议中,有规定POST请求参数放在body中,请求头上不能放参数,但事实上,你往url放点参数又咋地啦?很多时候用起来贼爽…(偷笑)

言归正传,什么是485通讯协议标准呢?看了我上面的打比方,你应该就比较好理解了。这是根据RS-485协议(硬件层面的设计)制定的一个行业通讯协议标准。明白了吧,坑,就在此。这个所谓的标准,其实每个产品的厂家都不会100%遵守,因为他也不是强制性的,你不这么干也没人能管你啊。

综上所述,你能查到的资料其实只是个标准规范,了解个大概,所以实际操作的时候总觉得格格不入。

实例讲解——发送指令

好了,下面我举个实例讲解一下具体的通讯操作。
现有一个直流电源表,已经通过串口1连接上了我的电脑,我现在想要知道当前的电压,电流,功率,我就需要向直流电源表连接的串口发送指令,然后直流电源表通过串口返回数据给我。
485通讯协议在java中的应用

那么问题来了,这个指令从何而来?这里先挖坑,一会儿再说。

我发送的指令是01030000000ac5cd
这里指令是要拆开来读的,意思是:
【01 】表示通讯的串口为COM1,通讯协议规定前面1-2位数表示通讯串口号。
【03 】表示读,通讯协议规定前面3-4位数表示指令类型,指令类型有读,写,执行
【0000 】表示起始位置,即需要操作的数据所存在的位置起点。这里暂时挖坑,一会儿再讲。
【000a 】表示需要读取的数据长度,即从起始位置往后的数据长度。
【c5cd 】表示效验值,用于效验指令合法性。

这样再看上面的指令是不是觉得逻辑很清晰了呢?指令已经明确发到哪儿?用来干嘛?操作什么?最后连数据效验都做了。这样的指令,再笨的机器应该也能明白你想让他干嘛了吧。

好了,上面的指令应该都能看懂了,但是应该对起始位,数据长度和效验值还存有疑问?

1.为什么是起始位置?

因为工控设备中存储用的是寄存器,寄存器的存储方式就是链状的。
第一位存一个值,第二位存一个值,第三位存一个值,以此类推。工控设备中的芯片已经设计好了第一位存的是什么,第二位存的是什么。所以你取值的时候,就告诉他,你想要哪一位的数据,要多长?对的,就是问他要多长。因为机制问题,你不能问他要第一位和第三位的值。所以你要想得到第一位和第三位的值,你有两种方法:A.问他两次,第一次要第一位的值,第二次要第三位的值。B.问他要从第一位开始的值,长度为3,然后你就得到了第一位和第二位和第三位的值,总共3个值,你自行提取出第一位和第三位的值。

2.效验值是干嘛的?

用来效验指令的合法性。485通讯协议中有规定一个算法,根据你的指令内容算出来这个效验值,类似于MD5值一样的东西。然而实际中,大部分厂家都是自行设定…

3.这些值是不是看着莫名其妙?

因为她们是16进制的,转换成10进制你就懂了。0000起始位十进制是0,长度000a 转化为10进制的值为10,这样指令就更清晰了。

意思是:向串口COM1发送一个读的指令,从第0位置开始读,读10位。

这里推荐一个在线进制转换计算器:点击访问

接下来填一下上面说的第一个坑,我这个指令01030000000ac5cd从何而来?
【01】 串口号,因为直流电源表我把它插在串口COM1上的,所以要与之通讯,串口号就是COM1。
【03】 读,我要读数据,通讯协议上写了,读是03。有的奇葩厂家真有可能会改这个,请以厂家提供为准。
【0000 000a】 起始位和长度,直流电源表厂家提供了通讯协议手册,上面写了电压,电流,功率所在的位置,我为了一次全部拿出来,所以直接从最前面数据位开始取值,一直取10位,转换成16进制就是000a长度。
【c5cd 】效验值,厂家提供的通讯协议手册上写了。

java中如何操作?
串口需要发送的指令有了,接下来就是怎么发过去了。因为指令01030000000ac5cd是16进制的,你需要转换成二进制发送到串口中。java中二进制数据用byte[]类型接收。如果你用了我的demo,那么你可以:
java中十六进制转换成二进制 :

byte[] b = ByteUtils.hexStr2Byte(“01030000000ac5cd”);

发送串口指令:(当然,需要你串口已经打开)

SerialPortManager.sendToPort(mSerialport, ByteUtils.hexStr2Byte(“01030000000ac5cd”);

实例讲解——接收数据处理

没想到随便写写就这么多了,累了,下次再写接收数据处理。