C# ModBus协议(RTU )详细指南

这篇具有很好参考价值的文章主要介绍了C# ModBus协议(RTU )详细指南。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

C# ModBus协议RTU 通讯详解

前言

ModBus协议:官方的解释是Modbus协议是一种通信协议,用于在自动化设备之间进行数据传输。它最初是由Modicon公司于1979年开发的,现在已成为工业界的一种通用协议。Modbus协议有多种变体,包括Modbus-RTU、Modbus-TCP和Modbus-ASCII等,其中Modbus-RTU是最常用的变体之一。Modbus协议基于主从结构进行通信。主设备通过发送读写请求来与从设备进行通信,从设备则响应这些请求。Modbus协议支持多种数据类型,包括线圈、离散输入、保持寄存器和输入寄存器等。在Modbus协议中,每个数据帧都包含了设备地址、功能码、数据和错误检查等信息。设备地址用于标识从设备,功能码用于指定读写请求的类型,数据则包含了读取或写入的寄存器地址和数据值等信息。错误检查通常使用CRC校验码来确保数据的完整性。Modbus协议广泛应用于工业自动化领域,可以用于控制器之间的通信、传感器的数据采集和PLC与HMI之间的通信等。由于其简单、可靠和易于实现等特点,Modbus协议仍然是工业界中最常用的通信协议之一。
讲人话就是:规定了一个设备和软件之间发送和接收数据的规则,根据这个规则数据格式去发送数据和接收数据
那么为什么要用这个协议呢:

  1. 可以实现跨平台(Modbus协议可以在不同的硬件和操作系统平台上运行,因此可以实现不同设备之间的互操作性)
  2. 可靠性高(Modbus协议支持多种错误检测和纠正机制,包括CRC校验和奇偶校验等,从而保证了数据传输的可靠性)
  3. 灵活性好(Modbus协议支持多种数据类型和数据格式,可以满足不同应用场景的需求。)
  4. 易于维护,成本低(由于Modbus协议是一种标准协议,因此可以使用各种现有的工具和库来进行开发和维护,从而降低了开发和维护成本)
  5. 最关键一点也是最重要的一点就是:部署简单,易于实现(Modbus协议是一种简单的协议,易于实现和部署。这使得它成为许多工业设备和控制系统的标准通信协议)
    就是因为它部署简单容易实现才使得ModBus被广泛运用

ModBus-RTU

自我理解:
Modbus-RTU是一个串口通讯的方式,主要分为五个部分一个设备ID号(占一个字节)、功能号(占一个字节)、寄存器地址(占两个字节)、读取数据长度(占两个字节)、CRC16校验码(占两个字节),通过对前四个设置值计算出CRC16 的检验码记住(11222这个规则,代表字节)发送的规则就是这样,下面我们举例说明更好的理解
官方解释:
Modbus-RTU:RTU是Modbus-RTU协议的一部分,它代表“Remote Terminal Unit”,即远程终端单元。在Modbus-RTU协议中,RTU是指一种串行通信方式,通常在RS-485物理层上运行。在这种通信方式中,数据以二进制编码的形式传输,并使用16位CRC错误检查。RTU协议是Modbus协议的一种变体,通常在RS-485物理层上运行。它是Modbus协议的一种子集,使用二进制编码,支持16位CRC错误检查。Modbus-RTU使用主从结构进行通信。主设备通过发送读写请求来与从设备进行通信,从设备则响应这些请求。Modbus-RTU支持读写线圈、离散输入、保持寄存器和输入寄存器等四种数据类型。在Modbus-RTU中,每个数据帧都包含了设备地址、功能码、数据和CRC校验。设备地址用于标识从设备,功能码用于指定读写请求的类型,数据则包含了读取或写入的寄存器地址和值,CRC校验用于检查数据传输的正确性。由于Modbus-RTU是一种比较简单的协议,因此它在工业自动化领域得到了广泛的应用。
modbus rtu c#,C# wnform实战实例及实战资源,网络协议,1024程序员节,c#,后端,windows,wpf,visual studio
我们来解析一下这个命令的值

设备ID 功能号选择 寄存器地址 读数据长度 CRC16
01 03 00 00 00 0A C5 CD
1 1 2 2 2
01:表示从设备的地址,这里为1。                
03:表示Modbus读取保持寄存器的功能码。  	
00 00:表示要读取的保持寄存器的起始地址,这里为0。 
00 0A:表示要读取的保持寄存器的数量,这里为10。 (我们需要读取多少个值)
C5 CD:表示CRC校验码,用于检查命令是否正确。 
因此,这个命令的含义是从地址为1的Modbus设备中读取0~9号保持寄存器的值。

注:以11222的格式来看这个命令,只有功能号是需要选择,CRC校验码是计算出来的,其他的都可以根据我们的需求去定义
modbus rtu c#,C# wnform实战实例及实战资源,网络协议,1024程序员节,c#,后端,windows,wpf,visual studio
常用的功能号
modbus rtu c#,C# wnform实战实例及实战资源,网络协议,1024程序员节,c#,后端,windows,wpf,visual studio

Modbus-RTU的功能码是用于指示Modbus协议进行何种数据操作的标识符。以下是常用的Modbus-RTU功能码及其含义:
01:读取线圈状态,用于读取开关量输入(DO)。
02:读取离散输入状态,用于读取开关量输入(DI)。
03:读取保持寄存器,用于读取模拟量输入(AI)。
04:读取输入寄存器,用于读取模拟量输入(AI)。
05:写单个线圈,用于控制开关量输出(DO)。
06:写单个保持寄存器,用于控制模拟量输出(AO)。
15:写多个线圈,用于控制多个开关量输出(DO)。
16:写多个保持寄存器,用于控制多个模拟量输出(AO)。
需要注意的是,不同设备支持的功能码可能不同,因此在使用Modbus-RTU通信时需要根据实际情况选择合适的功能码。

注: ModBus通讯是基于一个主站和从站的基础,我需要一个服务端,一般我们使用PLC为主站,也就是服务端,而我们的软件是需要连接主站的服务器进行通讯的,我采用一个模拟的ModBus的主站方便通讯
modbus rtu c#,C# wnform实战实例及实战资源,网络协议,1024程序员节,c#,后端,windows,wpf,visual studio
发送命令我们得到了一个答复,我们可以看到我们的服务端的数据
modbus rtu c#,C# wnform实战实例及实战资源,网络协议,1024程序员节,c#,后端,windows,wpf,visual studio

01 03 14 00 01 00 02 00 03 00 04 00 00 00 00 00 07 00 08 00 09 00 04 34 BE 

01  设备ID号
03  功能号
14  数据长度 这里是16进制 14===》20  ,有20个数据因为我们收到数据是两个字节,所有是2*10 =20
00 01    读取到0x0000寄存器地址的数据(两个字节)(高位在前,低位在后)
00 02
00 03
00 04
00 00
00 00 
00 07 
00 08 
00 09
00 04    数据(两个字节)
34 BE   CRC16校验码(两个字节) 

注意:接收数据的长度最大是127个
**注意:注意:注意:接收的数据是高位在前低位在后 **
比如我在0x1000 地址取一个,得到的数据是2个字节 比如接收的是01 03 02 0x01 0x02 CRC CRC 那么 高字节就是01 低字节就是02
就是0x0102 我们在计算的时候要么就用 int num = 0x01; num = (num<<8)+0x2;或者你把这两个字节赋值给一个2个为的byte数组,再用数组反转,使用BitConverter.ToUInt16(数组,起始位置);

 			byte[] num = new byte[2];
            Array.Copy(data, 0, num, 0, 2);//将需要的数据复制
            num.Reverse();//将需要的数据反转,因为BitConverter 是低位在前高位在后
            UInt16 number = BitConverter.ToUInt16(num,0); //从0位置默认取两个,不会的BitConverter的可以看我前面的文章

ModBus-RTU报错代码及解决办法

错误代码 01:读取离散输入量时,请求地址错误或无法访问该地址。解决方法:检查请求地址和设备是否正确连接。如果地址正确,可能是设备故障或通信线路问题。
错误代码 02:读取线圈时,请求地址错误或无法访问该地址。解决方法:检查请求地址和设备是否正确连接。如果地址正确,可能是设备故障或通信线路问题。
错误代码 03:读取保持寄存器时,请求地址错误或无法访问该地址。解决方法:检查请求地址和设备是否正确连接。如果地址正确,可能是设备故障或通信线路问题。
错误代码 04:读取输入寄存器时,请求地址错误或无法访问该地址。解决方法:检查请求地址和设备是否正确连接。如果地址正确,可能是设备故障或通信线路问题。
错误代码 05:写单个线圈时,请求地址错误或无法访问该地址。解决方法:检查请求地址和设备是否正确连接。如果地址正确,可能是设备故障或通信线路问题。
错误代码 06:写单个保持寄存器时,请求地址错误或无法访问该地址。解决方法:检查请求地址和设备是否正确连接。如果地址正确,可能是设备故障或通信线路问题。
错误代码 07:读取异常状态时,请求的数据值无效。解决方法:检查请求的数据值是否有效,并且设备是否正确响应请求。
错误代码 08:写多个线圈时,请求的数据值无效。解决方法:检查请求的数据值是否有效,并且设备是否正确响应请求。
错误代码 09:写多个保持寄存器时,请求的数据值无效。解决方法:检查请求的数据值是否有效,并且设备是否正确响应请求。
错误代码 10:读取文件记录时,请求的文件号无效。解决方法:检查请求的文件号是否有效,并且设备是否正确响应请求。
错误代码 11:写文件记录时,请求的文件号无效。解决方法:检查请求的文件号是否有效,并且设备是否正确响应请求。
错误代码 12:屏蔽写寄存器时,请求地址错误或无法访问该地址。解决方法:检查请求地址和设备是否正确连接。如果地址正确,可能是设备故障或通信线路问题。
错误代码 13:读/写多个寄存器时,请求的数据值无效。解决方法:检查请求的数据值是否有效,并且设备是否正确响应请求。
错误代码 14:ModBus 从站设备忙。解决方法:等待从站设备空闲,并重新发送请求。
错误代码 15:ModBus 从站设备返回错误异常码。解决方法:参考 ModBus 协议文档中的异常码表,并进行相应的处理。
错误代码 16:设备返回的数据长度错误。解决方法:检查设备是否正确响应请求,并且返回的数据长度是否与请求匹配。如果不匹配,可能是设备故障或通信线路问题。
错误代码 17:设备返回的数据值错误。解决方法:检查设备是否正确响应请求,并且返回的数据值是否正确。如果不正确,可能是设备故障或通信线路问题。

C# 连接ModBus-RTU详解

我是使用第三方库,使用NModBus4
modbus rtu c#,C# wnform实战实例及实战资源,网络协议,1024程序员节,c#,后端,windows,wpf,visual studio

using System;
using System.IO.Ports;
using NModbus;

namespace ModbusRtuExample
{
    class Program
    {
        static void Main(string[] args)
        {
            // 创建SerialPort对象来配置串口参数
            SerialPort serialPort = new SerialPort("COM1");
            serialPort.BaudRate = 9600;
            serialPort.DataBits = 8;
            serialPort.Parity = Parity.None;
            serialPort.StopBits = StopBits.One;

            // 创建ModbusFactory对象来进行Modbus RTU通信
            IModbusFactory modbusFactory = new ModbusFactory();
            IModbusMaster modbusMaster = modbusFactory.CreateRtuMaster(serialPort);

            try
            {
                // 打开串口连接
                serialPort.Open();

                // 使用Modbus函数来读取和写入数据
                ushort startAddress = 0;
                ushort numRegisters = 10;

                ushort[] registers = modbusMaster.ReadHoldingRegisters(1, startAddress, numRegisters);
                Console.WriteLine($"读取位保持寄存器地址 {startAddress} 开始的 {numRegisters} 个寄存器:");
                for (int i = 0; i < registers.Length; i++)
                {
                    Console.WriteLine($"寄存器 {startAddress + i}: {registers[i]}");
                }

                // 写入保持寄存器的值
                ushort[] writeValues = new ushort[] { 10, 20, 30, 40, 50 };
                modbusMaster.WriteMultipleRegisters(1, startAddress, writeValues);
                Console.WriteLine($"将 {writeValues.Length} 个值写入位保持寄存器地址 {startAddress} 开始的寄存器。");

                // 读取离散输入的值
                bool[] inputs = modbusMaster.ReadInputs(1, startAddress, numRegisters);
                Console.WriteLine($"读取离散输入地址 {startAddress} 开始的 {numRegisters} 个输入:");
                for (int i = 0; i < inputs.Length; i++)
                {
                    Console.WriteLine($"输入 {startAddress + i}: {inputs[i]}");
                }

                // 关闭串口连接
                serialPort.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine($"发生错误:{ex.Message}");
            }
        }
    }
}


以下是NModbus4库中常用的一些函数:

01:读取线圈状态
02:读取离散输入状态
03:读取保持寄存器的值
04:读取输入寄存器的值
05:写单个线圈状态
06:写单个保持寄存器的值
0F:写多个线圈状态
10:写多个保持寄存器的值

读取线圈状态:
bool[] coils = modbusMaster.ReadCoils(slaveAddress, startAddress, numCoils);

写入单个线圈状态:
modbusMaster.WriteSingleCoil(slaveAddress, coilAddress, value);

写入多个线圈状态:
bool[] coilValues = new bool[] { true, false, true };
modbusMaster.WriteMultipleCoils(slaveAddress, startAddress, coilValues);

读取离散输入状态:
bool[] inputs = modbusMaster.ReadInputs(slaveAddress, startAddress, numInputs);

读取保持寄存器的值:
ushort[] registers = modbusMaster.ReadHoldingRegisters(slaveAddress, startAddress, numRegisters);

写入单个保持寄存器的值:
modbusMaster.WriteSingleRegister(slaveAddress, registerAddress, value);

写入多个保持寄存器的值:
ushort[] registerValues = new ushort[] { 100, 200, 300 };
modbusMaster.WriteMultipleRegisters(slaveAddress, startAddress, registerValues);

读取输入寄存器的值:
ushort[] inputs = modbusMaster.ReadInputRegisters(slaveAddress, startAddress, numInputs);

使用自定义方式发送

我们在使用自定义的方式的时候,需要知道设备号,功能码,地址,数据个数,CRC16校验,比如我们只想使用03功能码,我们就可以自己封装一个03功能码发送的方法,比如下图,我的实参是地址和长度,里面的设备号,功能码我都是固定的,然后计算CRC16,最后使用Serport的write发送,read接收数据校验CRC16码,不会serport的看我之前的文章。
modbus rtu c#,C# wnform实战实例及实战资源,网络协议,1024程序员节,c#,后端,windows,wpf,visual studio
注意:CRC16 校验是从设备号开始到CRC校验码之前,也就是最后两个字节除外,因为用前面的才能算出后两个字节的CRC16校验码

  public byte[] SendGen(UInt16 address,UInt16 number)
        {
            try
            {
                byte[] data1 = new byte[6];
                data1[0] = 0x01;
                data1[1] = 0x03;
                data1[2] = Convert.ToByte((address >> 8) & 0xff);
                data1[3] = Convert.ToByte(address & 0xff);
                data1[4] = Convert.ToByte((number >> 8) & 0xff);
                data1[5] = Convert.ToByte(number & 0xff);
                byte[] data2 = new byte[2];
                data2 = CRC16(data1);
                byte[] data3 = new byte[8];
                Array.Copy(data1, 0, data3, 0, 6);//CRC16校验,从前面设备号一直到CRC码之前的数据
                Array.Copy(data2, 0, data3, 6, 2);
                return data3;
            }
           catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
                return null;
            }
        }

CRC16 校验

  public static byte[] CRC16(byte[] data)
        {
            ushort crc = 0xFFFF;
            for (int i = 0; i < data.Length; i++)
            {
                crc ^= (ushort)data[i];
                for (int j = 0; j < 8; j++)
                {
                    if ((crc & 0x0001) != 0)
                    {
                        crc >>= 1;
                        crc ^= 0xA001;
                    }
                    else
                    {
                        crc >>= 1;
                    }
                }
            }
            return new byte[] { (byte)(crc & 0xFF), (byte)(crc >> 8) };
        }

使用自定义封装的功能方法,比较好查BUG,灵活度就高一点,我们在使用第三方库的时候,有时数据不对,第三方库不好打断点,所以我们用自定义封装的就不会出现这种情况,可以清楚知道哪里的问题。

总结

ModBus RTU 是我们广泛使用的,在我们的PLC或者上位机里面用的比较多。Modbus协议广泛应用于工业自动化领域,可以用于控制器之间的通信、传感器的数据采集和PLC与HMI之间的通信等。由于其简单、可靠和易于实现等特点,Modbus协议仍然是工业界中最常用的通信协议之一。讲人话:就是规定了一个设备和软件之间发送和接收数据的规则,根据这个规则数据格式去发送数据和接收数据;牢记使用的功能码
modbus rtu c#,C# wnform实战实例及实战资源,网络协议,1024程序员节,c#,后端,windows,wpf,visual studio文章来源地址https://www.toymoban.com/news/detail-763436.html

到了这里,关于C# ModBus协议(RTU )详细指南的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • modbus-tcp-rtu协议图表

    MODBUS TCP 读寄存器 请求 序号 意义 所占字节 字节存放格式 1 事务处理标识 2个字节 高字节在前 2 协议标识 2个字节 高字节在前 3 长度 2个字节 高字节在前 4 单元标识 1个字节 0x00-0xff 5 功能码 1个字节 0x03 6 起始寄存器地址 2个字节 高字节在前 7 寄存器个数 2个字节 高字节在前

    2024年01月23日
    浏览(36)
  • STM32开发之Modbus协议(RTU从站)

    说明 1、本文不做协议格式的讲解,只做实现,如需了解协议格式,自行搜索 2、本文不依赖于硬件相关的资源,建立在硬件通讯之上,通过回调的形式和对应的硬件进行关联 3、相关协议内容参照,上一篇RTU主站 宏定义(modbus_core_define) crc校验(modbus_core_crc) 头文件 源文件

    2024年02月11日
    浏览(45)
  • STM32开发之Modbus协议(主站RTU)

    在单片机方面,针对于通讯常用的协议之一modbus,这里将modbus协议和硬件之间的关系完全独立出来,硬件和协议之间的联系采用的是回调的方式进行一个关联。 1、此协议可直接移植,并不需要关心硬件相关的。 2、modbus相关协议概念自行查找,本文只做代码的实现。 宏定义(

    2024年02月12日
    浏览(41)
  • MODBUS RTU 通信协议 CRC16校验算法

    CRC校验码是一个2个字节(16位二进制)的数。 发送端:发送的数据计算CRC校验码----发送:数据+CRC校验码 接收端:收到数据后重新计算CRC校验码,然后和接收到数据中的CRC校验码进行比较,判断是否相等。 如果不相等:数据传输过程中出错,给出错误应答。 CRC16 校验源码

    2024年02月16日
    浏览(49)
  • 树莓派4B与智能插排通过RS485(modbus RTU协议)通信

    目标:使用树莓派4B与CANHAT扩展板读取智能插排测量的各项数据(RS485+modbus RTU),获取的数据上传到Hyperledger Fabric框架。 之前学习过了modbus RTU协议,在智能涡轮流量计的实验中应用过一次,这次用这个带485模块的智能插座再复习一次~ 实验材料: 树莓派4B/8G:  CANHAT扩展板:

    2024年02月01日
    浏览(74)
  • EthernetIP 转MODBUS RTU协议网关连接FANUC机器人作为EthernetIP通信从站

    远创智控YC-EIPM-RTU网关产品是一款高效的数据采集工具,它可以通过各种数据接口与工业领域的仪表、PLC、计量设备等产品连接,实时采集这些设备中的运行数据、状态数据等信息。采集到的数据经过整合和运算等操作后,可以被传输到其他设备或者云平台。网关可采集设备

    2024年02月08日
    浏览(55)
  • Modbus RTU(Remote Terminal Unit)与RS-485协议(rs485)介绍(主站设备(Master)、从站设备(Slave))Modbus TCP、Modbus ASCII

    参考文章:ModBus协议 参考文章:一篇文章了解 RS485 和 MODBUS 的区别,它们有什么不同? Modbus RTU和RS-485是工业通信中常用的两种协议。Modbus RTU 是一种数据表示协议,而 RS-485 则是物理传输标准。尽管这两者有时被并列讨论,但它们在通信系统中的角色却大不相同。以下内容将

    2024年02月05日
    浏览(62)
  • STM32硬件库(非HAL库)实现MODBUS RTU协议的03,06功能码(读以及与单个发送)

    本人软件工程专业,关于硬件只有408的基础,后续学习发现一些博主所讲以及b站上所给的教程并不是很清晰,故编写此文档供大家查看。 如果我说的地方哪里有问题,希望大家可以给出意见!(●ˇ∀ˇ●) 参考文档: Modbus通讯协议常用功能码解释_modbus功能码_Lee139499的博客

    2024年02月03日
    浏览(32)
  • Modbus RTU通信应用

    1.1 概述         Modbus串行通信协议是Modicon公司在1970年开发的。         Modbus串行通信协议有Modbus ASCII和Modbus RTU两种模式,Modbus RTU协议通信效率较高,应用更加广泛。         Modbus RTU协议是基于RS232和RS485串行通信的一种协议,数据通信采用主从方式进行传送,主站

    2024年02月15日
    浏览(44)
  • 树莓派4B与智能涡轮流量计通过RS485(modbus RTU协议)收发数据(二)(Hyperledger Fabric环境中上传数据)

    上一篇博客配置好了树莓派端的串口通信,这次在加入涡轮流量计之前也先用PC端模拟树莓派测试一下该仪表是否能正常工作。 流量计说明书如下:  并且在设备上电时以(9600,8n1格式)自动发送四个字节: 返码格式:站地址(1字节)+波特率(2字节)+格式(1字节) 8n1格式

    2023年04月21日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包