C# NModbus RTU串口通信

news/2024/10/22 20:46:21/文章来源:https://www.cnblogs.com/kui0112/p/18493692

Modbus RTU 串口通信

虚拟串口工具:https://www.virtual-serial-port.org/

Modbus调试工具:https://www.modbustools.com/download.html

NOTE:都是付费软件,但是网上有盗版。

添加两个虚拟串口,这两个虚拟串口是互相连通的:

串口调试工具:https://github.com/SuperStudio/SuperCom

保证两个串口可以互相通信,然后打开Modbus Slave,并连接到COM2:

打开串口调试工具,先手工构造消息,熟悉一下Modbus协议。

NOTE:Modbus协议规范网上有中文版可以下载。

CRC计算工具:https://crccalc.com

  • 位于地址1的设备的数据类型是线圈,现在读取1号设备的前4个线圈数据:

    请求:

    设备地址 1B 功能 1B 起始地址 2B 读取数量 2B CRC校验码 2B
    01 01 00 00 00 04 3D C9

    计算器计算出的校验码是 C9 3D,但不能直接用,要将高位字节和低位字节反转,即 3D C9 。

    响应:

    设备地址 1B 功能 1B 数据个数 1B 线圈状态 NB CRC校验码
    01 01 01 08(00001000) 50 4E

    根据协议规范:

    • 响应数据数据从低位到高位起,依次对应设备中的线圈寄存器地址。
    • 如果结果数量大于8个,则再加一个字节,新加的字节从低位到高位,依次对应剩余的寄存器地址(8 ~ N)。
    • 如果数据数量不是8的倍数,则在高位补零。

    所以可以看到1号设备的前三个寄存器值都是0,第4个(3号地址)值是1。

    再试一下,读取1号设备前9个线圈的数据:

    设备地址 1B 功能 1B 起始地址 2B 读取数量 2B CRC校验码 2B
    01 01 00 00 00 0A BC 0D

    响应:

    设备地址 1B 功能 1B 数据个数 1B 线圈状态 NB CRC校验码
    01 01 02 C8 02(1100 1000 0000 0010) 6F FD

    从响应结果来看,前10个寄存器中,地址为3、6、7、9的这四个寄存器值为1,其他都是0 。

    看下模拟器是不是这样:

    没毛病。注意地址为B的那个寄存器值也是1,但它是第12个寄存器,我们只请求了前10个,所以只给了前十个寄存器的值,剩余的比特位协议规定要补零,因为要按字节对齐。

    再试一下发个错误的报文,看下错误响应。

    错误类型:校验码错误

    错误请求:01 01 00 00 00 0A BC 00

    结果:无响应

    错误类型:读取线圈数量65535

    错误请求:01 01 00 00 FF FF 3D BA

    结果:

    设备地址 1B 功能码 1B (功能码 + 0x80) 异常码 1B CRC校验码
    01 81 03 00 51

    Modbus协议规范中的异常码说明:

    异常码 异常名称 备注
    01 非法的功能码 服务器不认识功能码
    02 非法的数据地址 与请求有关
    03 非法的数据值 与请求有关
    04 服务器故障 执行过程中,服务器故障
    05 确认 服务器接收服务调用,但是需要相对长的时间完成服务,
    因此,服务器仅返回一个服务调用接收的确认
    06 服务器繁忙 服务器不能接受MODBUS请求的PDU,
    客户应用有责任决定是否和何时重发请求
    0A 网关故障 网关路径是无效的
    0B 网关故障 目标设备没有响应时,网关生成这个异常信息

    1号设备一共只有16个寄存器,要读取65535个寄存器,得到的响应是03:非法的数据值。

NModbus

NMondbus是C#中Modbus通信协议的一个实现。

安装

打开NuGet控制台,或者包管理器,安装下面两个包。NModbus.Serial 用于串口通信。

PM> Install-Package NModbus
PM> Install-Package NModbus.Serial
官方示例

NMondbus Github仓库地址:https://github.com/NModbus/NModbus.git

官方示例:https://github.com/NModbus/NModbus/blob/master/Samples/Program.cs

串口通信

串口通信中,数据以帧的形式发送,每一帧通常包括:起始位(Start Bit)、数据位(Data Bits)、可选的奇偶校验位(Parity Bit)以及停止位(Stop Bits)。

同步通信
using System.IO.Ports;
using NModbus;
using NModbus.Serial;var portName = "COM3";
var baudRate = 9600;var port = new SerialPort();
// 设置串口名
port.PortName = portName;
// 设置波特率
port.BaudRate = baudRate;
// 设置奇偶校验方式,要跟Modbus Slave那边同步,默认是None,我这里改成偶校验了
port.Parity = Parity.Even;
// 停止位
port.StopBits = StopBits.One;// 打开串口
port.Open();var factory = new ModbusFactory();
// 创建一个Modbus RTU协议的Master
var master = factory.CreateRtuMaster(port);// 数组输出为字符串
string ArrayToString<T>(T[] values, string sep = " ")
{return string.Join(sep, values.Select(r => Convert.ToString(r)).ToArray());
}// 随机数对象
var random = new Random();// 随机Boolean
bool RandomBoolean()
{return random.NextDouble() > 0.5;
}// 随机ushort
ushort RandomUnsignedShort()
{return (ushort)random.Next(ushort.MinValue, ushort.MaxValue);
}try
{// 写线圈var coilsToWrite = Enumerable.Range(0, 4).Select(i => RandomBoolean()).ToArray();Console.WriteLine($"写线圈:{ArrayToString(coilsToWrite)}");master.WriteMultipleCoils(1, 0, coilsToWrite);// 读线圈var coils = master.ReadCoils(1, 0, 4);Console.WriteLine($"读线圈:{ArrayToString(coils)}");// 写单个线圈 / 写之前Console.WriteLine($"读线圈:{ArrayToString(master.ReadCoils(1, 0, 4))}");// 写单个线圈var coilValue = RandomBoolean();master.WriteSingleCoil(1, 1, coilValue);Console.WriteLine($"写单个线圈(地址=1):{coilValue}");// 写单个线圈coilValue = RandomBoolean();master.WriteSingleCoil(1, 2, coilValue);Console.WriteLine($"写单个线圈(地址=2):{coilValue}");// 写单个线圈 / 写之后Console.WriteLine($"读线圈:{ArrayToString(master.ReadCoils(1, 0, 4))}");// 读输入状态var inputs = master.ReadInputs(2, 0, 4);Console.WriteLine($"读输入状态:{ArrayToString(inputs)}");// 写多个保持寄存器var registerValues = Enumerable.Range(0, 4).Select(i => RandomUnsignedShort()).ToArray();Console.WriteLine($"写保持寄存器:{ArrayToString(registerValues)}");master.WriteMultipleRegisters(3, 0, registerValues);// 写单个寄存器 / 写之前registerValues = master.ReadHoldingRegisters(3, 0, 4);Console.WriteLine($"读保持寄存器:{ArrayToString(registerValues)}");// 写单个寄存器var value = RandomUnsignedShort();Console.WriteLine($"写单个寄存器(地址=1):{value}");master.WriteSingleRegister(3, 1, value);// 写单个寄存器value = RandomUnsignedShort();Console.WriteLine($"写单个寄存器(地址=2):{value}");master.WriteSingleRegister(3, 2, value);// 写单个寄存器 / 写之后registerValues = master.ReadHoldingRegisters(3, 0, 4);Console.WriteLine($"读保持寄存器:{ArrayToString(registerValues)}");// 读多个输入寄存器var inputRegisters = master.ReadInputRegisters(4, 0, 4);Console.WriteLine($"读输入寄存器:{ArrayToString(inputRegisters)}");
}
catch (SlaveException ex)
{Console.WriteLine(ex.Message);
}// 关闭串口
port.Close();

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/819371.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

7-1计算阶乘和【PTA嵌套循环程序设计】

嵌套循环程序设计 7-1计算阶乘和#include<stdio.h>int f(int a){int sum = 1;for(int i=1;i<=a;i++){sum *= i;}return sum;}//构造N!函数int main(){int N = 0,sum = 0;//初始化scanf("%d",&N);if(N>1){for(int i=1;i<=N;i++){sum += f(i);//实…

从认识 Kubernetes 开始

你也说,我也说,那什么是 K8s 呢?Author: ACatSmiling Since: 2024-10-21认识 Kubernetes 什么是 Kubernetes 官方网站:https://kubernetes.io Kubernetes,是 Google 严格保密十几年的秘密武器 Borg 系统的一个开源版本,于 2014 年 9 月发布第一个版本,2015 年 7 月发布第…

java的三大程序结构

JAVA的三大程序结构 一:顺序结构 程序走上执行到下。 二:选择结构 if单选择结构 if(布尔表达式){ //如果布尔表达式的值为ture则执行{}里的语句块 } public class IfDemo01 {public static void main(String[] args) {//接收键盘输入Scanner scanner = new Scanner(System.…

CSP模拟赛 #42

#40 懒得写了,#41 题目质量过低。A 有 \(n\) 张长度为 \(m\) 的纸条,每张纸条有 \(k_i\) 个位置有小写字母,其他位置透明。你需要合理从上到下排列这些纸条,使得最终在上方看到的字符串为 \(s\),保证对于每个位置,至少一张纸条在该位置有一个字母。给出方案或无解。 \(1\…

markdown转pdf,方法总结

需求 markdown格式转为pdf我遇到的: 1. 我现在想把多个八股文文档(GitHub项目里的 scutan90/DeepLearning-500-questions: 深度学习500问,以问答形式对常用的概率知识、线性代数、机器学习、深度学习、计算机视觉等热点问题进行阐述,以帮助自己及有需要的读者。 全书分为18…

苦寻多日,终于搞定了地形切片,向大家安利一下这款超简单的免费GIS工具箱

概述 地形切片是将大范围的地形数据分割成小块(切片)进行存储和展示的技术,常用于高效的三维地形可视化和动态加载。在实际操作中,可以通过GISBox等工具进行地形切片处理。今天和大家安利的GISBox 是一个用于GIS模型切片、服务分发的免费GIS工具箱,其中包括了支持地形切片…

历届 CSP 刷题记录

\(\texttt{CSP 2019}\) J 组 \(\texttt{T3}\) 题目传送门 注意到一点:每天卖出纪念品换回的金币可以立即用于购买纪念品,当日购买的纪念品也可以当日卖出换回金币。当然,一直持有纪念品也是可以的。 这告诉我们:在一天内,纪念品就是钱,钱就是纪念品,钱和纪念品没有本质区…

Nacos K8s

Nacos 是 Dynamic Naming and Configuration Service 的首字母简称,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 Nacos 是构建以服务为中心的现代应用架构 (例如微服务范式、云原生范式) 的服务基础设施。更多的功能特性介绍请查看 Nacos 概览。 在本文…

RocketMQ - 总结

1. 为什么要使用MQ,使用场景是什么异步 : 减少请求响应时间,实现非核心流程异步化 (架构设计原则,能异步就不要同步) 解耦:屏蔽异构平台的细节,生产者消费者可自行扩展修改系统能力只需遵循消息约束,生产者消费者不受对方影响 流量削峰:消息堆积能力,消息保存在MQ中,…

数据采集作业一

一、用requests和BeautifulSoup库方法定向爬取给定网址(http://www.shanghairanking.cn/rankings/bcur/2020)的数据,屏幕打印爬取的大学排名信息点击查看代码 # 目标网址 url = "http://www.shanghairanking.cn/rankings/bcur/2020"# 获取网页内容 response = url…

PbootCMS提示错误信息“未检测到您服务器环境的sqlite3数据库扩展

检查并开启 sqlite3 扩展打开 PHPStudy Pro 软件。 导航至设置 -> 配置文件 -> php.ini。 选择你当前使用的 PHP 版本(例如 php7.3.4nts)并点击打开 php.ini 文件。 在 php.ini 文件中搜索 extension=sqlite3。 如果该行被注释掉(前面有分号 ;),则去掉分号以启用扩展…

PbootCMS上传空间后前台打开内页显示404错误怎么解决

检查 URL 规则配置登录 PbootCMS 后台。 导航至 配置参数 -> URL规则。 选择 伪静态模式 并保存。添加伪静态规则根据你的服务器环境,选择合适的伪静态规则文件。 一般情况下,Apache 环境使用 .htaccess 文件。Apache 环境配置将 rewrite 文件夹中的 .htaccess 文件复制到…