Modbus-RTU帧结构与功能码解析

Modbus-RTU 是一种基于串行通信(如 RS-232、RS-485)的 Modbus 协议变体,采用二进制编码,具有高数据密度和通信效率,广泛应用于工业自动化领域。

核心原理与帧结构Modbus-RTU 采用主从(Master-Slave)架构,通信由主设备发起,从设备响应。一个完整的数据帧由以下部分组成:

组成部分 长度(字节) 说明
从站地址 1 标识目标从设备的地址(1-247)。
功能码 1 定义请求的操作类型(如读、写)。
数据域 N 包含请求或响应的具体数据,长度可变。
CRC校验 2 循环冗余校验,用于检测传输错误。

帧与帧之间需保持至少 3.5个字符 的静默时间作为间隔。

常用功能码下表列出了部分核心功能码:

功能码(十进制) 名称 作用对象
01 (0x01) 读线圈状态 离散量输出(线圈)
02 (0x02) 读离散输入状态 离散量输入
03 (0x03) 读保持寄存器 保持寄存器
04 (0x04) 读输入寄存器 输入寄存器
05 (0x05) 写单个线圈 单个线圈
06 (0x06) 写单个寄存器 单个保持寄存器
15 (0x0F) 写多个线圈 多个线圈
16 (0x10) 写多个寄存器 多个保持寄存器

CRC-16校验计算

Modbus-RTU 使用 CRC-16(多项式为 0x8005,初始值为 0xFFFF)进行校验。以下是 C 语言实现示例:

c 复制代码
/**
 * @brief 计算 Modbus RTU帧的 CRC16 校验值
 * @param pData 指向待校验数据缓冲区的指针
 * @param length 数据长度(字节数)
 * @return计算得到的 CRC16 校验值(16位无符号整数)
 */
uint16_t Modbus_CRC16(uint8_t *pData, uint16_t length) {
    uint16_t crc = 0xFFFF; // CRC初始值 uint16_t i, j;

    for (i = 0; i < length; i++) {
        crc ^= pData[i]; // 与数据字节进行异或
        for (j = 0; j < 8; j++) {
            if (crc & 0x0001) { // 检查最低位是否为1
                crc >>= 1; // 右移一位
                crc ^= 0xA001; // 与多项式 0xA001 (0x8005 的位反转) 异或 } else {
                crc >>= 1; // 右移一位 }
        }
    }
    return crc;
}

通信示例:读取保持寄存器

假设主设备(地址 0x01)请求读取从设备地址为 0x01 的 2 个保持寄存器,起始地址为 0x0000。

1. 主设备请求帧:

复制代码
[从站地址] [功能码] [起始地址高] [起始地址低] [寄存器数量高] [寄存器数量低] [CRC低] [CRC高]
   0x01      0x03       0x00         0x00         0x00         0x02        0xC4      0x0B

*数据域:起始地址 0x0000,寄存器数量 0x0002。

  • CRC 计算:对 01 03 00 00 00 02 计算得到 0x0BC4,低字节在前,故为 C4 0B。

2. 从设备正常响应帧:

复制代码
[从站地址] [功能码] [字节计数] [寄存器1值高] [寄存器1值低] [寄存器2值高] [寄存器2值低] [CRC低] [CRC高]
   0x01      0x03      0x04        0x00          0x0A0x00          0x02        0xF8      0x48
  • 数据域:字节计数 0x04(4字节数据),两个寄存器的值分别为 0x000A(十进制10)和 0x0002(十进制2)。

代码实现示例(C# 使用 NModbus库)

以下 C# 代码演示了如何使用 NModbus 库通过串口实现 Modbus RTU 主站读取保持寄存器:

csharp 复制代码
using Modbus.Device;
using System.IO.Ports;

// 1. 配置串口
SerialPort serialPort = new SerialPort("COM1", 9600, Parity.None, 8, StopBits.One);
serialPort.Open();

// 2. 创建 Modbus RTU 主站实例
IModbusSerialMaster master = ModbusSerialMaster.CreateRtu(serialPort);

// 3. 读取保持寄存器
byte slaveId = 1; // 从站地址
ushort startAddress = 0; // 起始寄存器地址
ushort numRegisters = 2; // 读取的寄存器数量
ushort[] registers = master.ReadHoldingRegisters(slaveId, startAddress, numRegisters);

// 4. 输出结果
Console.WriteLine($"Register 0: {registers[0]}");
Console.WriteLine($"Register 1: {registers[1]}");

// 5. 关闭连接
serialPort.Close();

调试与工具

  • 模拟器:可使用 Modbus Slave/Modbus Poll、ModScan32 等软件模拟从设备或主设备进行协议测试。
  • 接线:RS485 网络通常采用双绞线,需正确连接 A(+)、B(-) 信号线,并在总线两端安装终端电阻(通常为 120Ω)以消除信号反射。

参考来源

相关推荐
我是海飞7 分钟前
杰理 JL703N SDK 实现 AI 自动化调试:自动进入下载模式、下载、重启与日志抓取
人工智能·单片机·自动化·音视频·杰理
Zwawa14 分钟前
PID 的三个参数之外:位置式、增量式和反馈控制
c语言·单片机·嵌入式
创界工坊工作室20 分钟前
29-基于单片机的万年历设计
stm32·单片机·嵌入式硬件·proteus
木由里予1 小时前
NAND 这门生意
运维·服务器·网络·单片机
沐欣工作室_lvyiyi2 小时前
基于STM32的社区养老控制系统设计(论文+源码)
stm32·单片机·嵌入式硬件·社区养老控制系统·保定理工学院·华德学院·淮南师范学院
snow@li2 小时前
单片机:全景梳理核心原理与体系深度分析
单片机·嵌入式硬件
创界工坊工作室2 小时前
26-基于51单片机的智能热水器控制系统设计
stm32·单片机·嵌入式硬件·毕业设计·51单片机·proteus
霖霖7142 小时前
【ESP32笔记】蓝牙BLE连接与广播
笔记·单片机·mcu·物联网
sayang_shao2 小时前
用 Rust 开发 STM32H743:从零搭建一个能烧录、能看日志的项目
stm32·单片机·rust
碧海银沙音频科技研究院3 小时前
基于炬芯ATS308X内置音乐铃声与扫频音频功能实现
单片机·嵌入式硬件