IoTClient开发5 - ModBusRtu协议
前言
前面我们介绍了modbustcp协议。今天我们接着来介绍modbusrtu协议。和modbustcp不同的是modbusrtu基于串口通信,modbustcp是基于tcp以太网通信。
所以我们在讲解modbusrtu协议之前会先介绍下串口通信。
串口通信
串口出现在1980年前后,当初主要目的是用来做电脑外设设备的连接,如鼠标、键盘等。现在最新的电脑慢慢的取消了原始的串口接口,不过依然广泛用于工控和测量等设备。
串口通信参数
串口通信指的是串口按位(bit)发送和接收字节,串口通信参数主要有波特率、数据位、停止位、校验位。
波特率
波特率表达的是串口通信的速率,一秒钟内传送的信号单元(码元)个数。信号单元一般包含10位(7个数据位、1个校验位、1到2个停止位)。注意:波特率和距离成反比
数据位
通信中实际的数据,有效值为6、7和8。
停止位
用来表示单个包的最后一位,有效值为1、1.5和2。停止位可用来表示传输的结束和校正时钟同步。注意:停止位的位数越多,时钟同步的容忍程度越大,但是数据传输率会越慢。
校验位
奇偶校验作为通信中的检错方式,如果发现错误则重新发送。
示例数据 | 偶校验位 | 奇校验位 |
---|---|---|
0000000 | 00000000 | 00000001 |
1010001 | 10100011 | 10100010 |
1101001 | 11010010 | 11010011 |
1111111 | 11111111 | 11111110 |
从上可以看出奇偶校验就是在数据最后加一位,使数据中的1的数量保持偶数或奇数。
波特率和比特率 (扩展知识)
比特率是我们常用来表达宽带速率的一种方法。看上去和波特率很像,如果波特率的信号码元只传1比特(bit),那么它们之间是相等的。如果波特率的信号码元传10比特,那么波特率是比特率的10倍。所以,波特率和比特率表达的意义是不一样的,不要搞混了。
宽带比特率的实际下载速度 (扩展知识)
mbps和mbit/s等效、kbit/s和kbps等效、bps和bit/s等效
1mbps(mbit/s) = 11024kbit(kbit/s) = 11024*1024bps(bit/s),注意他们的单位都是bit(比特),而不是byte(字节),所以实际下载速度要除以八。1024 / 8 = 128 kb/s。
crc16校验
crc,cyclic redundancy check循环冗余检验,是基于数据计算一组效验码,用于核对数据传输过程中是否被更改或传输错误。而modbusrtu用到的是其中的crc16校验。
其计算原理,可参考 、、3
以下是crc16反向算法,经测试可用于modbusrtu的crc计算。
public class crc16 { /// <summary> /// 验证crc16校验码 /// </summary> /// <param name="value">校验数据</param> /// <param name="poly">多项式码</param> /// <param name="crcinit">校验码初始值</param> /// <returns></returns> public static bool checkcrc16(byte[] value, ushort poly = 0xa001, ushort crcinit = 0xffff) { if (value == null || !value.any()) throw new argumentexception("生成crc16的入参有误"); var crc16 = getcrc16(value, poly, crcinit); if (crc16[crc16.length - 2] == crc16[crc16.length - 1] && crc16[crc16.length - 1] == 0) return true; return false; } /// <summary> /// 计算crc16校验码 /// </summary> /// <param name="value">校验数据</param> /// <param name="poly">多项式码</param> /// <param name="crcinit">校验码初始值</param> /// <returns></returns> public static byte[] getcrc16(byte[] value, ushort poly = 0xa001, ushort crcinit = 0xffff) { if (value == null || !value.any()) throw new argumentexception("生成crc16的入参有误"); //运算 ushort crc = crcinit; for (int i = 0; i < value.length; i++) { crc = (ushort)(crc ^ (value[i])); for (int j = 0; j < 8; j++) { crc = (crc & 1) != 0 ? (ushort)((crc >> 1) ^ poly) : (ushort)(crc >> 1); } } byte hi = (byte)((crc & 0xff00) >> 8); //高位置 byte lo = (byte)(crc & 0x00ff); //低位置 byte[] buffer = new byte[value.length + 2]; value.copyto(buffer, 0); buffer[buffer.length - 1] = hi; buffer[buffer.length - 2] = lo; return buffer; } }
协议报文分析
数据【读取-请求报文】:01 03 00 04 00 01 c5 cb
- 01 站号
- 03 功能码
- 00 04 读取的寄存器的起始地址
- 00 01 读取寄存器的个数
- c5 cb 为crc16的校验码【使用上面的crc16类进行的计算结果,crc16.getcrc16([01,03,00,04,00,01])】
数据【读取-响应报文】:01 03 02 00 21 78 5c
- 01 站号
- 03 功能码
- 02 数据的字节长度
- 00 21 数据
- 78 5c 为crc16的校验码
数据【写入-请求报文】:01 10 00 04 00 01 02 00 21 67 cc
- 01 站号
- 10 功能码
- 00 04 写入的寄存器的起始地址
- 00 01 写入寄存器的个数
- 02 写字节的个数
- 00 21 要写的数据
- 67 cc 为crc16的校验码
数据【写入-响应报文】:01 10 00 04 00 01 40 08
- 01 站号
- 10 功能码
- 00 04 写入的寄存器的起始地址
- 00 01 写入寄存器的个数
- 40 08 为crc16的校验码
有了报文的分析,具体的协议实现也就不难了。完整实现可参考https://github.com/zhaopeiym/iotclient/blob/master/iotclient/clients/modbus/modbusrtuclient.cs
iotclient中modbusrtu协议的使用
安装
nuget安装 install-package iotclient
或图形化安装
使用
//1、实例化客户端 - [com端口名称,波特率,数据位,停止位,奇偶校验] modbusrtuclient client = new modbusrtuclient("com3", 9600, 8, stopbits.one, parity.none); //2、写操作 - 参数依次是:地址 、值 、站号 、功能码 client.write("4", (short)33, 2, 16); client.write("4", (short)3344, 2, 16); //3、读操作 - 参数依次是:地址 、站号 、功能码 var value = client.readint16("4", 2, 3).value; var value2 = client.readint32("4", 2, 3).value; //4、如果没有主动open,则会每次读写操作的时候自动打开自动和关闭连接,这样会使读写效率大大减低。所以建议手动open和close。 client.open(); //5、读写操作都会返回操作结果对象result var result = client.readint16("4", 2, 3); //5.1 读取是否成功(true或false) var issucceed = result.issucceed; //5.2 读取失败的异常信息 var errmsg = result.err; //5.3 读取操作实际发送的请求报文 var requst = result.requst; //5.4 读取操作服务端响应的报文 var response = result.response; //5.5 读取到的值 var value3 = result.value;
参考
- 同步至索引目录:《物联网基础组件iotclient开发系列》
- https://baike.baidu.com/item/%e4%b8%b2%e5%8f%a3%e9%80%9a%e4%bf%a1
- https://baike.baidu.com/item/%e6%af%94%e7%89%b9%e7%8e%87/1022775
- https://zh.wikipedia.org/wiki/%e5%a5%87%e5%81%b6%e6%a0%a1%e9%aa%8c%e4%bd%8d
- https://zh.wikipedia.org/wiki/%e5%be%aa%e7%92%b0%e5%86%97%e9%a4%98%e6%a0%a1%e9%a9%97
上一篇: HTML的简介