昆明做烤瓷牙哪去柏德L网站,网站关键词重要性,东莞网站优化有哪些,郑州官网首页Modbus 协议简介
QingHub设计器在设计物联网数据采集时不可避免的需要针对Modbus协议的设备做相关数据采集#xff0c;这里就我们的实际项目经验分享Modbus协议
你可以通过QingHub作业直接体验试用#xff0c;也可以根据手册开发相应的代码块。 qinghub项目已经全面开源。 …Modbus 协议简介
QingHub设计器在设计物联网数据采集时不可避免的需要针对Modbus协议的设备做相关数据采集这里就我们的实际项目经验分享Modbus协议
你可以通过QingHub作业直接体验试用也可以根据手册开发相应的代码块。 qinghub项目已经全面开源。
源码文件地址: https://gitee.com/qingplus/qingcloud-platform
QingHub设计器体验
简介
Modbus由MODICON公司于1979年开发是一种工业现场总线协议标准。1996年施耐德公司推出基于以太网TCP/IP的Modbus协议ModbusTCP。Modbus协议是一项应用层报文传输协议包括ASCII、RTU、TCP三种报文类型。 标准的Modbus协议物理层接口有RS232、RS422、RS485和以太网接口采用master/slave方式通信。
功能码
重点介绍常用如下几个功能码: 1: 读线圈寄存器 2: 读离散输入寄存器 3: 读保持寄存器 4: 读输入寄存器 5: 写单个线圈寄存器 6: 写单个保持寄存器 15: 写多个线圈寄存器 16: 写多个保持寄存器
几种继承器介绍
线圈寄存器
实际上就可以类比为开关量每个bit都对应一个信号的开关状态。所以一个byte就可以同时控制8路的信号。
离散输入寄存器
如果线圈寄存器理解了这个自然也明白了。离散输入寄存器就相当于线圈寄存器的只读模式他也是每个bit表示一个开关量而他的开关量只能读取输入的开关信号是不能够写的。
保持寄存器
这个寄存器的单位不再是bit而是两个byte也就是可以存放具体的数据量的并且是可读写的。比如设置时间年月日不但可以写也可以读出来现在的时间。写分为单个写和多个写。
输入寄存器
只剩下这最后一个了这个和保持寄存器类似但是也是只支持读而不能写。一个寄存器也是占据两个byte的空间。
通信协议 (重点看这里就可以了)
Modbus设备可分为主站(poll)和从站(slave)。主站只有一个从站有多个主站向各从站发送请求帧从站给予响应。在使用TCP通信时主站为client端主动建立连接从站为server端等待连接(当然只要你愿意并足够熟悉也可以反向操作)。 Mobus 的报文大致分为两类 MBAPPDU。 MBAP Modbus Application Protocol Header(Modbus应用协议) 头部 PDU Protocol Data Unit 数据单元 MBAP报文
MBAP为报文头长度为7字节组成如下
事务处理标识协议标识长度单元标识符2字节2字节2字节1字节 含义: 事务处理标识可以理解为报文的序列号一般每次通信之后就要加1以区别不同的通信数据报文。 协议标识符00 00表示ModbusTCP协议。 长度表示接下来的数据长度单位为字节。 单元标识符可以理解为设备地址。 PDU报文结构 PDU结构 PDU由功能码数据组成。功能码为1字节数据长度不定由具体功能决定。 主站请求功能码数据 从站正常响应请求功能码响应数据 从站异常响应异常功能码异常码其中异常功能码即将请求功能码的最高有效位置1异常码指示差错类型 指令实例
查询功能码0x03
基本流程就是: 发送:地址 我要查 寄存器起始地址个数校验 回复:地址 回我要查 数据的字节数数据 校验 主机发送: 01 03 00 00 00 01 84 0A 含义: 01-地址 03-功能码,代表查询功能,其他功能后面再说 00 00-代表查询的起始寄存器地址.说明从0x0000开始查询. 00 01-代表查询了一个寄存器.结合前面的00 00,意思就是查询从0开始的1个寄存器值; 84 0A-CRC 从机回复: 01 03 02 12 34 B5 33 含义: 01-地址 03-功能码 02-代表后面数据的字节数,因为上面说到,一个寄存器有2个字节,所以后面的字节数肯定是2*查询的寄存器个数; 12 34-寄存器的值是12 34,结合发送的数据看出,01这个寄存器的值为12 34 B5 33-CRC校验码 修改单个寄存器功能码0x06 主机送: 01 06 00 00 00 01 48 0A 01-从机地址 06-功能码:修改单个寄存器功能,修改有些不同,有修改一个寄存器和修改多个寄存器; 00 00-修改的起始寄存器地址.说明从0x0000开始. 00 01-修改的值为00 01.结合前面的00 00,意思就是修改0号寄存器值为00 01; 48 0A-CRC 从机回复: 01 06 00 00 00 01 48 0A 01-从机地址 06-功能码:修改单个寄存器功能; 00 00-修改的起始寄存器地址.说明是0x0000. 00 01-修改的值为00 01.结合前面的00 00,意思就是修改0号寄存器值为00 01; 48 0A-CRC 修改多个寄存器功能码0x10 主机发送: 01 10 00 00 00 02 04 11 22 33 44 42 5A 01-从机地址 10-功能码,代表修改多个寄存器功能; 00 00-代表修改的起始寄存器地址.说明从0x0000开始. 00 02代表修改的寄存器数量 04 -表示修改的总字节数由于只修改了1个寄存器所以数据要有两个字节 11 22 33 44-表示修改的值结合上面就是从第0000寄存器开始修改2寄存器值为11 22 33 44就是把0000寄存器改为11 220001为33 44 42 5A -循环冗余校验,是modbus的校验公式,从首个字节开始到22前面为止; 从机回复: 01 10 00 00 00 02 41 C8 01-从机地址 10-功能码 00 00-代表修改的起始寄存器地址.说明是0x0000. 00 02-代表修改的寄存器数量只需要回复这么多久足够了从机告诉主机修改了哪几个寄存器就足够了; 41 C8-循环冗余校验; java 开发
maven 依赖
!-- Modbus --
dependencygroupIdcom.infiniteautomation/groupIdartifactIdmodbus4j/artifactIdversion3.1.0/version
/dependency
dependencygroupIdcom.digitalpetri.modbus/groupIdartifactIdmodbus-master-tcp/artifactIdversion1.2.0/version
/dependencyAPI 实例
第一建立连接
/*** 获取 Modbus Master* return ModbusMaster* throws ModbusInitException ModbusInitException*/
public ModbusMaster getMaster(ModbusConfig modbusConfig) throws ModbusInitException {log.debug(Modbus Tcp Connection Info {},{}, modbusConfig.getHostName(),modbusConfig.getPort());ModbusMaster modbusMaster masterMap.get(modbusConfig.getEquipmentId());if (null modbusMaster) {IpParameters params new IpParameters();params.setHost(modbusConfig.getHostName());params.setPort(modbusConfig.getPort());**params.setEncapsulated(true);**modbusMaster modbusFactory.createTcpMaster(params, true);modbusMaster.init();masterMap.put(modbusConfig.getEquipmentId(), modbusMaster);}return modbusMaster;
}注意 这里有一个需要特别关注的地方params.setEncapsulated(true) 如果encapsulatedtrue时API 在构建消息是会自动加上CRC 校验码。
public byte[] getMessageData() {ByteQueue msgQueue new ByteQueue();modbusMessage.write(msgQueue);ModbusUtils.pushShort(msgQueue, ModbusUtils.calculateCRC(modbusMessage));return msgQueue.popAll();
}如果encapsulatedfalse时消息会加上事务处理标识协议标识6个字节:
public byte[] getMessageData() {ByteQueue msgQueue new ByteQueue();modbusMessage.write(msgQueue);ByteQueue xaQueue new ByteQueue();ModbusUtils.pushShort(xaQueue, transactionId);ModbusUtils.pushShort(xaQueue, ModbusUtils.IP_PROTOCOL_ID);ModbusUtils.pushShort(xaQueue, msgQueue.size());xaQueue.push(msgQueue);return xaQueue.popAll();
}第二 API实例
/*** 读线圈寄存器* param modbusMaster* param slaveId* param initOffset* param count* return* throws ModbusTransportException*/
private static String batchCoilStatus01(ModbusMaster modbusMaster,Integer slaveId,Integer initOffset,Integer count) throws ModbusTransportException {ReadCoilsRequest request new ReadCoilsRequest(slaveId,initOffset,count);ReadCoilsResponse response (ReadCoilsResponse) modbusMaster.send(request);byte[] data response.getData();String bytes ByteUtils.toHexAscii(data);return bytes;
}/*** 读离散输入寄存器* param modbusMaster* param slaveId* param initOffset* param count* return* throws ModbusTransportException*/
private static String batchInputStatus02(ModbusMaster modbusMaster,Integer slaveId,Integer initOffset,Integer count) throws ModbusTransportException {ReadDiscreteInputsRequest request new ReadDiscreteInputsRequest(slaveId,initOffset,count);ReadDiscreteInputsResponse response (ReadDiscreteInputsResponse) modbusMaster.send(request);byte[] data response.getData();String bytes ByteUtils.toHexAscii(data);return bytes;
}
/***批量读取保持继承器* param modbusMaster* param slaveId* param initOffset* param count* return* throws ModbusTransportException*/
private static String batchRead03(ModbusMaster modbusMaster,Integer slaveId,Integer initOffset,Integer count) throws ModbusTransportException {ReadHoldingRegistersRequest request new ReadHoldingRegistersRequest(slaveId,initOffset,count);ReadHoldingRegistersResponse response (ReadHoldingRegistersResponse) modbusMaster.send(request);byte[] data response.getData();String bytes ByteUtils.toHexAscii(data);return bytes;
}/*** 批量读取输入继承器* param modbusMaster* param slaveId* param initOffset* param count* return* throws ModbusTransportException*/
private static String batchRead04(ModbusMaster modbusMaster ,Integer slaveId,Integer initOffset, Integer count) throws ModbusTransportException {ReadInputRegistersRequest request new ReadInputRegistersRequest(slaveId,initOffset,count);ReadInputRegistersResponse response (ReadInputRegistersResponse) modbusMaster.send(request);byte[] data response.getData();String bytes ByteUtils.toHexAscii(data);return bytes;
}