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Ω)以消除信号反射。

参考来源

相关推荐
长江后浪博客8 小时前
ESP32-SOLO-1 在 ESP-IDF v5.5 下启动不断重启问题分析与解决
单片机·嵌入式硬件·嵌入式·esp32·freertos·esp-idf
单片机仿真设计9 小时前
【proteus仿真】基于 STM32 单片机智能仓库设计(仿真图+程序)
stm32·单片机·嵌入式硬件·proteus·毕设
星游路9 小时前
单片机·电子时钟
单片机·嵌入式硬件
AOI小白新手上路13 小时前
江科协51单片机 7-2 LCD1602显示时钟实验
单片机·嵌入式硬件·51单片机
runningshark13 小时前
SC32L14GR8PJR
单片机·嵌入式硬件
智购科技无人售货机厂家13 小时前
2026自动售货机备用电池管理系统设计:从充放电保护到健康监测的工程实践~YH
大数据·linux·单片机·嵌入式硬件·微信
智购无人售货机厂家14 小时前
2026自动售货机软硬件版本管理策略:从版本号规范到兼容性矩阵的工程实践~YH
运维·服务器·人工智能·单片机·嵌入式硬件·线性代数·矩阵
花 满 楼14 小时前
RISC-V APLIC 中断模块总结——第二篇
单片机·嵌入式硬件·mcu·risc-v
无损检测小白白15 小时前
【嵌入式面试题一】
c语言·单片机
Messy create15 小时前
【BMS-Pack检测-短路检测】
单片机·嵌入式硬件·能源