首页 > 其他分享 >Modbus ASCII

Modbus ASCII

时间:2024-10-24 15:33:41浏览次数:1  
标签:字符 00 字节 Modbus 寄存器 ASCII

简介

Modbus ASCII 使用ASCII字符集传递消息,方便阅读和调试。Modbus ASCII相比于Modbus RTU,协议帧中添加了起始和结束,更换了校验算法。

Modbus网络模型

这张图比较简洁清晰。Modbus网络中,只有一个Master,Master可以向Slave发起请求并获取响应,Slave只能被动发送响应而不能主动请求。

Slave最多可达247个 . 每个Slave由1到247之间的地址标识,0地址用来广播,剩余地址保留。

帧格式

字段描述
名称 字节数 描述
Start 1 B 以冒号 : 开头,ASCII十六进制值为3A
Address 2 B 十六进制节点地址,字符表示
Function 2 B 十六进制功能码,字符表示
Data 2 * n B n是数据字节数,取决于功能码
LRC 2 B LRC冗余校验码
End 2 B CRLF

Modbus ASCII为了兼容Modbus RTU,是将二进制字节改用ASCII字符来表示,例如 0xFF 这个十六进制数,Modbus RTU中,使用二进制进行传输,传输的数据是 1111 1111 。Modbus ASCII中,传输数据就变成了 0100 0110 0100 0110 ,共两个字节,每个字节对应十进制70,是 F 的ASCII码。

传输示例

校验码计算

校验算法叫LRC,纵向冗余校验。就是将所有字节相加(两个数字表示一个字节),截取最低的8位(忽略进位),再取补码。注意是十六进制数字相加,不是ASCII码。两行代码就可以算出来:

var msg = "020300030002";
// 两个十六进制数字表示一个字节,因此需要做一个转换,每两位字符转换为一个十六进制数,然后再计算LRC
// 
var bytes = Enumerable.Range(0, msg.Length / 2).Select(i => Convert.ToByte(msg.Substring(i * 2, 2), 16));
var lrc = ((bytes.Aggregate((a, b) => (byte)(a + b)) ^ 0xFF) + 1) & 0xFF;

Console.WriteLine(lrc.ToString("X2"));

前面的代码有装逼嫌疑,不用看。下面的代码是NModbus库里面的:

/// <summary>
///     Converts a hex string to a byte array.
/// </summary>
/// <param name="hex">The hex string.</param>
/// <returns>Array of bytes.</returns>
public static byte[] HexToBytes(string hex)
{
    if (hex == null)
    {
        throw new ArgumentNullException(nameof(hex));
    }

    if (hex.Length % 2 != 0)
    {
        throw new FormatException(Resources.HexCharacterCountNotEven);
    }

    byte[] bytes = new byte[hex.Length / 2];

    for (int i = 0; i < bytes.Length; i++)
    {
        bytes[i] = Convert.ToByte(hex.Substring(i * 2, 2), 16);
    }

    return bytes;
}

/// <summary>
///     Calculate Longitudinal Redundancy Check.
/// </summary>
/// <param name="data">The data used in LRC.</param>
/// <returns>LRC value.</returns>
public static byte CalculateLrc(byte[] data)
{
    if (data == null)
    {
        throw new ArgumentNullException(nameof(data));
    }

    byte lrc = 0;
    
    foreach (byte b in data)
    {
        lrc += b;
    }

    lrc = (byte)((lrc ^ 0xFF) + 1);

    return lrc;
}

打开Modbus Slave模拟器,打开虚拟串口工具,串口调试工具,手动构造请求消息试一下。

读取2号设备的3号和4号寄存器

功能码0x03(读保持寄存器)的PDU:

功能码 起始地址 读取数量
1 字节 / 2 字符 2 字节 / 4 字符 2 字节 / 4 字符

构造请求:

帧头 设备地址 功能码 起始地址 读取数量 校验码 结束符
: 02 03 00 03 00 02 F6 CRLF
:020300030002F6\r\n

得到响应:

:02030400070006EA\r\n

响应PDU:

功能码 字节数 寄存器值
1 字节 / 2 字符 1 字节 / 2 字符 N * 2 字节 / N * 4 字符(N 为读取数量)

响应解析:

设备地址 功能码 字节数 寄存器值 校验码
02 03 04 00 07 00 06 EA

一个寄存器16位,一个字节8位,一个十六进制数4位。所以我们请求了两个寄存器的值,响应给了八个字符,一共四个字节的数据,没问题。再看数据对不对:

3号寄存器值为7,4号寄存器值为6,没毛病。

将2号设备的4号和5号寄存器置为1

功能码0x10(写多个寄存器)的PDU:

功能码 起始地址 寄存器数量 字节数 寄存器值
1 字节 / 2 字符 2 字节 / 4 字符 2 字节 / 4 字符 1 字节 / 2 字符 N * 2 字节 / N * 4 字符(N 为寄存器数量)

构造请求:

设备地址 功能码 起始地址 寄存器数量 字节数 寄存器值 LRC校验码
02 10 00 04 00 02 04 00 01 00 01 F5
:0210000400020400010001E2

获得响应:

:021000040002E8

响应PDU:

功能码 起始地址 寄存器数量
1 字节 / 2 字符 2 字节 / 4 字符 2 字节 / 4 字符

解析响应:

设备地址 功能码 起始地址 寄存器数量 LRC校验码
02 10 00 04 00 02 E8

看下结果:

4号和5号寄存器的值现在都是1,没毛病。

使用NModbus

使用NModbus库,编码时除了一开始的配置,基本上无需关心用的什么协议,库都帮你封装好了。

var factory = new ModbusFactory();
// 使用NModbus RTU,传进去一个SerialPort对象
var master = factory.CreateRtuMaster(port);
// 使用Modbus ASCII,传进去一个SerialPort对象
var master = factory.CreateAsciiMaster(port);
// 使用Modbus TCP,传进去一个TcpClient对象
var master = factory.CreateMaster(tcpClient);

// 其他API都一样,直接用就行了

标签:字符,00,字节,Modbus,寄存器,ASCII
From: https://www.cnblogs.com/kui0112/p/18499678

相关文章

  • C# NModbus RTU串口通信
    ModbusRTU串口通信虚拟串口工具:https://www.virtual-serial-port.org/Modbus调试工具:https://www.modbustools.com/download.htmlNOTE:都是付费软件,但是网上有盗版。添加两个虚拟串口,这两个虚拟串口是互相连通的:串口调试工具:https://github.com/SuperStudio/SuperCom保证......
  • cubemx modbus从机搭建
    目录1.硬件准备2.CubeMX配置步骤3.集成Modbus协议栈步骤:4.编写应用代码5.测试通信代码示例6.进一步优化使用CubeMX实现Modbus丛集(Slave)的开发主要涉及到以下几个步骤:1.硬件准备你需要一块支持Modbus通信的STM32开发板,建议使用带有USART外设的......
  • Modbus协议概述及实例详解(二)附源码
        通过上一篇《Modbus协议概述及实例详解(一)》相信大家已经了解到Modbus的相关原理以及应用,也了解到了Modbus中在RTU/ASCII/TCP三种协中必不可少协议RTU协议。本章将详细讲解关于ModbusRTU协议的相关内容并附带源码一份,以帮助有需要的读者朋友可以快速开发迭代自己的......
  • Modbus协议概述及实例详解(一)
        Modbus是一种串行通信协议,最初是由Modicon公司(现为施耐德电气的一部分)在1979年开发,用于实现PLC之间的通信。由于其开放性和可靠性,Modbus已成为工业领域事实上的标准通信协议之一。当然啦,在嵌入式行业也同样流行,比如常见的电源行业,开关电源、模拟电源和数字电源等。......
  • Qt编写的modbus模拟器/支持网络和串口以及websocket/支持网络rtu
    一、使用说明1.1设备模拟-Com第一步,填写要模拟的设备地址,0表示自动处理,也就是收到什么地址就应答什么地址。第二步,填写对应的串口号和波特率。第三步,单击打开串口,成功后会变成关闭串口字样。单击清空数据会将左侧打印栏的信息清空。右侧一堆微调框用于模拟对应设备多个寄......
  • Modbus调试工具《二》快速开始
    目录前言制定采集任务暂停和继续采集工作设置单元格颜色设置单元格的字体写单个线圈值监视Modbus通讯报文总结前言DickMorley在1979年发表的Modbus协议,最初只是为了让自动化系统使用可编程逻辑控制器PLC设备而制定了这样的一个总线协议。由于其无版权而免费,简洁......
  • Modbus通信协议
    Modbus是什么一种串行通信协议,是Modicon公司(现在的施耐德电气)于1979年发表,用于PLC之间的通信,已成为工业领域通信协议事实上的业界标准,并且是现在工业电子设备之间常用的连接方式。应用场景广泛应用于PLC、传感器、继电器等设备之间的通信。协议版本ModbusTCP使用以太网,将......
  • Modbus TCP 西门子PLC指令以太口地址配置以及 Poll Slave调试软件地址配置
    1前言本篇文章讲了 ModbusTCP通讯中的一些以太网端口配置和遇到的一些问题,都是肝货自己测试的QAQ。2西门子SERVER指令该指令是让外界设备主动连接此PLC被动连接,所以这里应该填 外界设备的IP地址。这边我因为是电脑的Modbus Poll主机来进行通讯的所以填的是电脑......
  • C#轻松实现Modbus通信
    1、前言大家好!我是付工。前面给大家介绍了一系列关于RS485与Modbus的知识。终于有人把RS485说清楚了终于有人把Modbus说明白了通透!终于把ModbusRTU弄明白了这样看来,ModbusTCP协议太简单了今天跟大家聊聊关于C#如何实现Modbus通信。2、开源通信库通信库是对通信协议的封装,一般......
  • PROFINET 转 EtherCAT, EtherCAT/Ethernet/IP/Profinet/ModbusTCP协议互转工业串口网关
    EtherCAT/Ethernet/IP/Profinet/ModbusTCP协议互转工业串口网关https://item.taobao.com/item.htm?ft=t&id=822721028899协议转换通信网关PROFINET转EtherCATGW系列型号 MS-GW31概述简介MS-GW31是PROFINET和EtherCAT协议转换网关,为用户提供两种不同通讯协议......