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校验。
其计算原理,可参考 1、2、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/串口通信
- https://baike.baidu.com/item/比特率/1022775
- https://zh.wikipedia.org/wiki/奇偶校验位
- https://www.cnblogs.com/esestt/archive/2007/08/09/848856.html
- https://zh.wikipedia.org/wiki/循環冗餘校驗
IoTClient开发5 - ModBusRtu协议的更多相关文章
- IoTClient开发3 - ModBusTcp协议客户端实现
前言 进过前面两章的介绍,今天开始正式的实战. 进制转换 很多朋友对于进制转换可能是在刚学计算机的时候有接触,后来做高级语言开发可能就慢慢忘记了.我们做工控开发的时候需要经常进行进制转换,这里和大家一 ...
- IoTClient开发4 - ModBusTcp协议服务端模拟
前言 上篇我们实现了ModBusTcp协议的客户端读写,可是在很多时候编写业务代码之前是没有现场环境的.总不能在客户现场去写代码,或是蒙着眼睛写然后求神拜佛不出错,又或是在办公室部署一套硬件环境.怎么 ...
- IoTClient开发6 - S7-200SmarTcp协议客户端实现
环境和工具 服务端电脑IP:192.168.1.130 客户端电脑IP:192.168.1.120 1.在服务端电脑运行IoTClientTool 2.运行Wireshark 3.在客户端电脑运行Io ...
- 物联网基础组件IoTClient开发系列
系列目录 IoTClient开发1 - 你也可以写个聊天程序 IoTClient开发2 - 你也可以写个服务器 IoTClient开发3 - ModBusTcp协议客户端实现 IoTClient开发4 ...
- 聊聊 iOS 开发中的协议
前言 何为协议,简单来说在OC中我们使用关键字@protocol可以声明一个协议,并在协议中添加多个属性.方法供于遵循者实现,从某个角度上来说,这是一种不同于category机制的category.在 ...
- 用c++开发基于tcp协议的文件上传功能
用c++开发基于tcp协议的文件上传功能 2005我正在一家游戏公司做程序员,当时一直在看<Windows网络编程> 这本书,把里面提到的每种IO模型都试了一次,强烈推荐学习网络编程的同学 ...
- Loadrunner 脚本开发-利用loadrunner开发Windows Sockets协议脚本
脚本开发-利用loadrunner开发Windows Sockets协议脚本 by:授客 QQ:1033553122 欢迎加入软件性能测试交流QQ群:7156436 实践举例 Socket服务端简单实 ...
- Loadrunner脚本开发-基于HTTP协议的流媒体视频在线播放服务器性能测试
脚本开发-基于HTTP协议的流媒体视频在线播放服务器性能测试 by:授客 QQ:1033553122 目的 实现基于http协议的流媒体在线视频播放,服务器性能测试脚本,模拟用户浏览器方式在线播放 ...
- 使用Jayrock开源组件开发基于JSON-RPC协议的接口
最近接手一个以前的项目,无意间发现此项目开发接口的组件:Jayrock(接口组件估计用的少,用的最多的估计是这个Jayrock.json.dll,用于解析json) 以下是Jayrock的介绍官网: ...
随机推荐
- 力扣(LeetCode)翻转字符串里的单词 个人题解
给定一个字符串,逐个翻转字符串中的每个单词. 示例 1: 输入: "the sky is blue" 输出: "blue is sky the" 示例 2: 输 ...
- bash:加减乘除(bc、let)
bc *. echo "$2 * $2" | bc > file let 如果只是 let a=1 和 a=1,它们没有区别,但是 let 还可以用于带赋值的运算,例如 le ...
- VSCode, Django, and Anaconda开发环境集成配置[Windows]
之前一直是在Ubuntu下进行Python和Django开发,最近换了电脑,把在Virtual Box 下跑的Ubuntu开发机挪过来总是频繁崩溃,索性就尝试把开发环境挪到Windows主力机了. 不 ...
- [FPGA]Verilog实现JK触发器组成的8421BCD码十进制计数器
目录 概述 电路分析 代码实现 参考文献 概述 本文以异步时序计数器为例,用Verilog实现以\(JK\)触发器组成的8421BCD码十进制异步计数器,并用ModelSim软件进行仿真验证. 电路分 ...
- 详解在Linux系统中安装JDK
本文以在CentOS 7.6中安装JDK8为例进行安装,其他系统和版本都是大同小异的. 下载 进入Oracle官方网站的下载页面. 首先,接受许可协议,如下图: 然后,根据Linux系统的位数选择要下 ...
- Fabric1.4源码解析:Peer节点启动过程
看一下Peer节点的启动过程,通常在Fabric网络中,Peer节点的启动方式有两种,通过Docker容器启动,或者是通过执行命令直接启动. 一般情况下,我们都是执行docker-compose -f ...
- 12、pytest -- 缓存:记录执行的状态
目录 1. cacheprovider插件 1.1. --lf, --last-failed:只执行上一轮失败的用例 1.2. --ff, --failed-first:先执行上一轮失败的用例,再执行 ...
- Python开发-实现Excel套打打印
一.目的 目前本人就职与甲方的工作,由于公司的ERP比较烂无法完美的设计套打,就想着自己用Python开发一个套打工具. 二.开发过程 刚开始我打算用Html的方式生成打印的文档,但是有两个无法解决的 ...
- Sql 修改表结构
添加字段 alter table 表名 add 字段名 nvarchar(100) not null 修改字段 alter table 表名 alter column 字段名 int not null ...
- 【数据结构】之顺序表(Java语言描述)
之前总结过使用C语言描述的顺序表数据结构.在C语言类库中没有为我们提供顺序表的数据结构,因此我们需要自己手写,详细的有关顺序表的数据结构描述和C语言代码请见[我的这篇文章]. 在Java语言的JDK中 ...