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,2,3,null,5,null,4] 输出: [1, 3, 4] 解释: 1 < ...
- raid10配置流程(5块磁盘)
1.添加5块磁盘 (1)先添加一块磁盘 (2)在此基础上,再添加4块磁盘 2.使用mdadm命令创建RAID10,名称为“/dev/md0” -C 代表创建操作 -v 显示创建过程 ...
- 剖析nsq消息队列目录
剖析nsq消息队列(一) 简介及去中心化实现原理 剖析nsq消息队列(二) 去中心化源码解析 剖析nsq消息队列(三) 消息传输的可靠性和持久化[一] 剖析nsq消息队列(三) 消息传输的可靠性和持久 ...
- 2019-9-25:渗透测试,基础学习,Hydra BP爆破,js基本知识,banner信息收集笔记
使用BP和Hydra爆破相关的服务hydra:九头蛇,开源的功能强大的爆破工具,支持的服务有很多,使用hydra爆破c/s结构的服务,使用bp爆破web登陆窗口爆破需要的几个条件,爆破工具+字典字典: ...
- Java通过 Scanner 类来获取用户的输入
通过 Scanner 类来获取用户的输入. import java.util.Scanner; Scanner s = new Scanner(System.in);// 从键盘接收数据 Syste ...
- ctf线下赛中检测外来IP的shell脚本
该脚本可用于ctf线下赛中,用来检测攻击IP的接入,及时做出响应. #!/bin/bash #写自己队的ip ipA="172.22.60.230" ipB="172.2 ...
- Spring Boot2 系列教程(二十八)Spring Boot 整合 Session 共享
这篇文章是松哥的原创,但是在第一次发布的时候,忘了标记原创,结果被好多号转发,导致我后来整理的时候自己没法标记原创了.写了几百篇原创技术干货了,有一两篇忘记标记原创进而造成的一点点小小损失也能接受,不 ...
- linux命令之less命令
一.我查看日志特别喜欢用less命令来查看,下面给大家讲解下使用. less(选项)(参数) 选项如下: -e:文件内容显示完毕后,自动退出: -f:强制显示文件: -g:不加亮显示搜索到的所有关键词 ...
- 部署高可用 schduler
目录 创建 kube-scheduler 证书和私钥 创建和分发 kubeconfig 文件 创建 kube-scheduler 配置文件 创建kube-scheduler启动文件 启动kube-sc ...
- centos 7 MysSQL 5.7.23 源码安装
MySQL 5.7.23 源码安装 CentOS 7 将默认数据库MySQL替换成了Mariadb. 这里会从系统的环境准备开始一步一步安装. 环境准备 系统版本 内核版本 IP地址 Centos 7 ...