在之前的太阳集团tcy8722技术文章中,我们简单介绍了利用JavaScript(ECMAScript 5)脚本解析Alink JSON实现Modbus协议采集RTU设备,本文将利用“功能定义”通过“READ_R”的不同“枚举值”实现多台Modbus从机设备的寄存器采集。
这次我们使用真实的RTU进行开发,一台MA01-AXCX4040用于采集DI上传,一台GPS设备上传NMEA0183协议的RMC定位字符串数据。
手动发送数据过于麻烦,若采用云平台脚本自动发送对于PLC工程师比较陌生,这里小编将结合“MQTT模式”与串口服务器的“主动上报网关”实现物模型的数据自动更新。
一台串口服务器,用于连接MQTT服务器和主动轮询RTU设备并上报服务器;
一台MA01-AXCX4040远程IO联网模块(标准Modbus RTU设备),响应主机请求(上报DI状态);
表1 MA01-AXCX4040部分寄存器描述
功能描述 | 寄存器类型 | 寄存器 | 数量 | 支持功能码 |
干接点采集 | 离散量输入 | 0x0000 | 4 | 0x02 |
开关量输出 | 线圈 | 0x0000 | 4 | 0x01、0x05、0x0F |
Modbus地址 | 保持寄存器 | 0x07e8 | 1 | 0x03、0x06、0x10 |
一台支持Modbus RTU协议的GPS采集模块,通过读取保持寄存器值显示当前定位信息(字节序:大端,字序:大端)共计70字节字符串;
表2 GPS定位模块部分寄存器描述
功能描述 | 寄存器类型 | 寄存器 | 数量 | 支持功能码 |
RMC数据 | 保持寄存器 | 0x0005 | 35 (70字节大端字符) | 0x02 |
Modbus地址 | 保持寄存器 | 0x0002 | 1 | 0x03、0x06、0x10 |
保证设备供电与正确接入互联网,将采用阿里云MQTT服务器实现远程采集控制,因此无法在局域网中实现该功能。
参考之前的文章《利用云平台脚本解析连接物模型(一)》,这里我就不再说明如何配置。
这里我就利用上次创建的设备修改“JavaScript脚本”和“功能定义”实现本文功能,不在额外的创建新设备。
修改原有的“读取寄存器”配置,增加枚举描述和枚举值,这个值会在脚本中使用并且会作为指令的地址位使用,不可随意定义。
添加ME31-AXCX4040相关功能定义“开关量采集第一路”,以类似方法可以定义其余三路开关量采集与开关量输出反馈;
添加GPS相关功能定义“GPS定位数据”,使用字符串,长度限制70字节(可以不限制);
笔者仅学习过C语言,对于脚本语言并不了解,所有使用脚本函数均是修改阿里云教程和在W3SCHOOL中查询得到,若有更简单的字符串解析函数,以你为准。我这只是提供一种方法,不一定为最优解。
/*此函数将设备上报数据转换为Alink JSON物模型数据。*/
function rawDataToProtocol(bytes) {
/*将设备上报的原始数据转换为数组。其中bytes对象中存储着设备上报原始数据。*/
var uint8Array = new Uint8Array(bytes.length);
for (var i = 0; i < bytes.length; i++) {
uint8Array[i] = bytes[i] & 0xff;
}
var params = {}; // 定义属性存放对象。
var jsonMap = { }; // 定义模拟Alink数据报对象。
/*填写Alink数据报协议头部分。*/
jsonMap['version'] = ALINK_VERSION; // Alink 协议版本号。
jsonMap['id'] = ALINK_ID; // 消息ID。
jsonMap['method'] = ALINK_PROP_POST_METHOD; // 设备上行数据方法:设备属性上报。
/*填写Alink数据报属性部分。*/
//ME31-AXCX4040:01020100
//GPS:020346(70字节数据:$GNRMC,072905.00,A,3640.46260,N,11707.54950,E,000.0,000.0,050119,OK*20)2字节CRC
if(uint8Array[0]==0x01){
switch(uint8Array[3]){
case 0x00: params['DI1']=0;break;
case 0x01: params['DI1']=1;break;
}
}else if(uint8Array[0]==0x02){
var rmc_str="";
var count;
for(count=3;count
//从最后插入数字转字符,累计处理70次,得到GPS-RMC字符串
rmc_str=rmc_str.concat(String.fromCharCode(uint8Array[count]));
}
params['GPS_RMC']=rmc_str;
}
jsonMap['params'] = params; // 将参数打包到数据帧中。
return jsonMap; // 返回结果会发送给物联网平台。
}
根据Modbus地址编码平台下发指令,如下所示:
/*此函数实现由物联网平台下发数据转换为设备能识别的16进制数。*/
function protocolToRawData(json)
{
var method = json['method'];
var id = json['id'];
var version = json['version'];
var payloadArray = [];
if (method == ALINK_PROP_SET_METHOD) // 接收来自物联网平台的“设置设备属性”的命令。
{
var send_params = json['params'];
var prop_cur = send_params['READ_R']; // 将设置的具体值抽取出来。
//按照自定义协议格式拼接rawdata。
payloadArray = payloadArray.concat(buffer_uint8(prop_cur));
if(prop_cur == 1){
//添加查询ME31-AXCX4040第一路指令
payloadArray = payloadArray.concat(buffer_uint8(0x02));
payloadArray = payloadArray.concat(buffer_uint8(0x00));
payloadArray = payloadArray.concat(buffer_uint8(0x00));
payloadArray = payloadArray.concat(buffer_uint8(0x00));
payloadArray = payloadArray.concat(buffer_uint8(0x01));
payloadArray = payloadArray.concat(buffer_uint8(0xB9));
payloadArray = payloadArray.concat(buffer_uint8(0xCA));
}else if(prop_cur == 2){
//添加查询GPS-RMC字符串
payloadArray = payloadArray.concat(buffer_uint8(0x03));
payloadArray = payloadArray.concat(buffer_uint8(0x00));
payloadArray = payloadArray.concat(buffer_uint8(0x05));
payloadArray = payloadArray.concat(buffer_uint8(0x00));
payloadArray = payloadArray.concat(buffer_uint8(0x23));
payloadArray = payloadArray.concat(buffer_uint8(0x14));
payloadArray = payloadArray.concat(buffer_uint8(0x21));
}
}
return payloadArray; // 返回时,将数据发送至设备端。
}
ME31-AXAX4040上报数据解析;
GPS上报数据解析,以123456为例(实际数据为70字节);
物模型下发读取ME31-AXAX4040第一路DI状态指令;
物模型下发读取GPS数据指令;
在调试使用工具先测试功能是否正常,若不经过此步骤直接连接设备,若通讯失败难以分析问题导致无法实现功能。
配置连接参数,参考《利用云平台脚本解析连接物模型(一)》;
在脚本中我们指定了不同Modbus地址连接不同的设备,比如指定
MA01-AXCX4040使用地址1,指定GPS定位模块使用地址2,在脚本解析中利用地址不同执行不同的解析函数,从而将数据保存到正确变量下。
Modbus协议的响应帧只有地址码和功能码并不返回请求的寄存器地址导致设备无法调用正确的解析函数,如果要实现同一设备地址的不同寄存器地址采集则需要在请求时记录发送的寄存器地址,因此实现同一设备不同寄存器请求时需要采用与Modbus机制相同的采集机制(主从模式,主机请求从机应答,一请一答),这个问题留到下篇文章中处理,现在只考虑每个地址读取一个连续寄存器的情况。
软件地址配置(出厂默认为1):
硬件地址(全部拨向背离数字一侧,出厂默认为31,需要修改为1):
查询Modbus寄存器表可以知道保持地址的寄存器位(0x0002),通过Modbus指令配置Modbus地址为2,如下图所示;
可通过串口服务器MQTT模式连接阿里云物模型,并通过平台手动请求RTU设备返回数据,串口服务器配置如下:
云平台通过“在线调试”手动发送查询DI指令;
云平台通过“在线调试”手动发送查询GPS指令;
可以利用串口服务器的“Modbus网关”主动上报功能实现,周期更新数据,Modbus RTU轮询间隔免费用户不建议小于1000ms,轮询间隔指的是每条指令的间隔,例如这里配置的间隔为10s,平台将以20s的周期刷新平台数据;