基于Android平台的Modbus通信客户端应用
2020-11-09迟颖,何杰,耿斌,周刚,张杨
迟 颖,何 杰,耿 斌,周 刚,张 杨
(1.中国环境监测总站,北京 100012;2.光大城乡再生能源(淮安)有限公司,江苏 淮安 223001;3.南京柯普士仪器科技有限公司,江苏 南京 210012)
0 引言
随着网络技术的不断发展,移动应用端越来越多地被人们认可,Android平台所开发的APP应用软件更是被应用到了各个场合。由于工业控制领域具有特殊性,考虑到其稳定性、安全性、复杂性,一直少有相关方面的应用。积极开展移动设备在工业控制方面的应用,在未来5G平台下,将有非常广阔的前景[1]。
连续排放气态污染物监测系统(Continuous Emission Monitoring System,CEMS),应用于垃圾发电企业的烟气监测,为核对该系统的数据准确性,企业需要接受各级主管部门比对检查。受委托的检测机构持便携式检测仪进行采样比对,会涉及两套系统数据的对比,对比工作的流程如下:(1)同步。同步两套系统的时间;(2)采集。在线实时采集数据;(3)比对。比对两套系统同一时间段内的各项数据。由于两套系统的输出设备(数据显示终端)距离较远,一方在0 m层的分析小屋内,另一方在烟囱约35 m处的采样口,数据的实时核对必须两地要有人员通过通信工具进行有效沟通。探讨拉近一端数据,实现单人单地即时比对,提高工作效率,减少人员数量,具有显著的效果。
1 Modbus通信
Modbus是一种通信协议,广泛应用于工业控制领域各个系统间,其协议版本较常见的有串口和以太网两大类,是一个主站master/从站slave架构的协议。基于该协议的设备之间进行互连互通,首先,要确定主站与从站。根据协议约定,Modbus协议中主从站的关系为一对多型,即主站只能有一台,而从站可以拥有地址范围在0~247(其中0为广播地址)的多台设备(通信点),主站发出数据请求消息(查询代码),从站对主站发送的命令做出响应。主站接收从站响应过来的数据,完成一次数据通信。
Modbus RTU与Modbus TCP同属于Modbus通信协议,但RTU通信更多地在传输介质上采用双绞线、光纤,同时,以二进制数据方式直接传送数据,而TCP通信采用的传输介质更多的是常见的网线,也可以通过无线传输,将每字节二进制数据转换为固定两位16进制字符串,再依次串联在一起,以TCP码形式进行数据传送。现场的工业应用中,常见于RTU转TCP的应用,以便于搭载网络通信[2]。
2 Socket通信
OSI开放系统互连参考模型,定位于应用层与TCP/IP协议族通信的中间软件抽象层就是Socket通信接口,将复杂的TCP/IP协议族隐藏在Socket接口后面。Socket的服务端(Server)建立服务倾听socket,同时,等待并接收请求,Socket的客户端(Client)创建连接socket向服务端发送请求,此时,服务端接收到客户端的请求创建连接socket。通信时,客户端OutputStrean输出流到服务端输入InputStream,服务端OutputStream输出流到客户端的输入流InputStream。结束通信只需要关闭双方的socket即可。依靠该协议,Modbus的通信可以搭建完成一个数据交互的链接,完成双方的通信过程。
3 Android应用设计与实现
Android平台的通信基于无线网络技术,通信网络可以是基于路由器的互联网,可以借助于互联网实现数据的超远距离访问;也可以是基于AP热点的点对点的网络(或者蓝牙方式),可以在有限定的条件下确保数据安全的访问。
3.1 系统的整体架构
系统分为三大模块:(1)系统配置模块,用于配置和存储通信用IP地址、端口号、数据地址、数据长度、数据内容等信息,并保存在本地数据库中,以备下次应用时直接使用。(2)柱状图显示模块,清晰、直观地显示可以实时比对各组分在同一时间内的差异。(3)折线图显示模块,根据实际现场的比对需求,可以定义折线图的采集时间间隔和采集数据量,折线图针对单一组分的总体趋势具有很好的显示效果,增加了计算平均值、最大值和最小值的功能,完全贴合现场所要参比的数据。
系统的硬件搭配:现场数据的采集,需要通过CEMS系统自带的modbus协议端口进行二次打包转发,一般为PLC通信口。为实现无线组网通信,还必须将双方置于该网络环境中,本研究采用西门子S7-200 SMART SR40 CPU模块卡,485通信端口直接连接了一款串口转无线WiFi的工业通信设备,在配置时采用默认的AP模式,设置好串口协议、AP热点状态下所需要的通信IP和端口,完成硬件配置[3]。
3.2 数据库配置
数据库以原始DB数据库为基础,单独一个配置界面(见图1),用以存储、更改、调用通信所涉及的各项参数。为适配现场的无线通信设备,增加了通信方式的选择,在选择Serial串口方式通信时,只是代表该通信查询代码是以RTU方式发送的16进制字符串,该字符串查询代码以及返回的数据代码不同于TCP/IP格式,需要注意的是该方式并不表示要去接一个真正的串口。
图1 配置界面
3.3 数据查询
Android平台下,以手机为适配机,需要做Modbus主机的响应机制。根据协议规定,以传送8个有效浮点数据为例,发送16进制的查询代码:00 01 00 00 00 06 02 03 00 00 00 10,其中,02表示为从站号是2,03表示modbus功能码03,即读取保持寄存器地址,10表示是查询的数据长度为十进制的16。将其定义为一个byte字节数组发送出去,客户端响应该查询得到的也是一个16进制的字符串:00 01 00 00 00 23 02 03 20 00 00 40 00 00 00 40 40 00 00 40 A0 00 00 40 E0 00 00 41 00 00 00 41 40 00 00 40 40 00 00 42 84,其中,20表示是后面的数据长度为10进制的32个,是实际的数据内容。
3.4 数据处理
在获取返回的数据串后,需要进行数据的转换,将其转换为浮点数。Modbus浮点数的存储格式为SEEE EEEE EMMM MMMM MMMM MMMM MMMM MMMM,S是符号位,1表示负值;EEE EEEE E表示为指数幂;MMM MMMM MMMM MMMM MMMM MMMM表示为数据位,该数据位缺省了1.需要补上。此时,小数位可以按指数调整:得到一个负的指数就向左移动小数点,得到一个正的指数向右移动小数点。算出小数点左边和小数点右边的数,最后得到该浮点数。
核心代码:
StringbinStr = hex2Bin(hexstr);
Stringsign = binStr.substring(0, 1);
Stringex = binStr.substring(1, 9);
int exint = Integer.parseInt(ex, 2);
Stringmdatastr = binStr.substring(9);
int movebit = exint - 127;
StringBuffersb = new StringBuffer();
for (int i = 0; i < 23; i++) {
if (i == movebit)
sb.append(".");
char b = mdatastr.charAt(i);
sb.append(b);
}
Stringaddstr = "1" + sb.toString();
int sint = addstr.indexOf(".") - 1;
Doubledoublevalue = 0.0d;
for (int i = 0; i < addstr.length(); i++) {
if (addstr.charAt(i) == '.')
continue;
Doubledtmp = Math.pow(2, sint);
int itmp = Integer.valueOf(addstr.charAt(i) + "");
dtmp = dtmp * itmp;
sint = sint - 1;
doublevalue = doublevalue + dtmp;
}
if (sign.equals("1")) {
doublevalue = 0 - doublevalue;
}
}
以上转换如果得不到实际对应的数值,那就应该考虑浮点数据的翻转。按照数据存储的约定:字节顺序模式分为大端数据模式和小端数据模式,是根据数据在内存中的存储方式来区分的。小端字节顺序的数据存储模式是按内存增大的方向存储的,即低位在前高位在后;大端字节顺序的数据存储方向恰恰相反,即高位在前,低位在后。据此,只需要重新排列一下一个浮点数所占用两个寄存器地址位的前后顺序,就可以完成数据翻转。
3.5 柱状图显示
柱状图表的显示比文字更具有简洁性,也更加直观,具体如图2所示。将读取到的远端数据以图表的形式呈现出来,应用MPAndroidChart的柱状图显示功能,引入该控件的com.github.mikephil.charting.charts.BarChart包,对其X轴Y轴进行自定义,同时,增加一个以时间为刷新内容的描述项。核心代码如下:
x轴的定义
xAxis.setValueFormatter (new ValueFormatter () {
private String[] xStrs = new String[]{"CO", "HCL", "NO", "NO2", "SO2", "H2O", "Temp", "FlOW"};
@Override
public String getFormattedValue(float value) {
int position = (int) value;
if (position >= 8) {
position = 0;
}
return xStrs[position];
}
});
时间描述
Description description = new Description ();
description.setEnabled (true);
t = new SimpleDateFormat ("yyyy年MM月dd日 HH:mm:ss");
description.setText (t.format (new Date ()));
chart.setDescription (description);
图2 柱状图表的显示
3.6 折线图显示
相较于柱状图,折线图可以突出一组数据的变化趋势,将各组数据以不同的颜色标注出,既可以单组数据显示,又可以多组数据比对显示,实际第三方比对数据时常常会取一个时间段内的数据,以下拉框选择的方式将所需时间段以及数据量展现出来,减少人工输入错误,具体如图3所示。应用引入控件的com.github.mikephil.charting.charts.LineChart包,对其X轴Y轴进行自定义,同时,增加一个数据点位的标记,用以记录该条数据的详细信息:当前组分名称、当前数值、总采集数、当前条数、平均值、最大值、最小值。核心代码如下:
java.util.Set
String valName = entry.getKey ().trim ();
switch (valName) {
case "co":
coMax = (Double) Collections.max ((List) entry.getValue ());
coMin = (Double) Collections.min ((List) entry.getValue ());
coAverage = getAverage ((List) entry.getValue (), xCount);
break;
case "hcl":
……
}
}
采用java.util.Set
图3 折线图显示
4 结语
该客户端应用APP主要基于无线通信,网络质量好坏直接影响数据的传输,实际使用过程中,采用了点对点的通信方式,数据刷新周期为每30 s一次,完全可以满足现场通信监控比对的需求。工业现场端Modbus通信是常规通信协议,无论是集控室DCS端,还是现场仪表端,都有此类接口,在确保数据安全的情况下,充分利用此类接口与移动端对接,提高了整体的工作质量和效率,具有极大的实用价值。