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

参考来源

相关推荐
不悔哥3 天前
开源OV-Watch:怎么做一个智能手表
单片机·开源·嵌入式
XiHongShi20163 天前
STM32F407 RTC定时器例程,建议保存
stm32·单片机·学习
深圳老胡3 天前
STM32F407 控制 L6470 步进电机驱动 —— 控制过程简介
笔记·stm32·单片机·嵌入式硬件·代码规范
女神下凡3 天前
嵌入式设计的各种存储芯片的硬件/软件设计规范,非常全面。
arm开发·单片机·嵌入式硬件
梅梅9663 天前
一款mipi转lvds的lcd调试(LT8912B)
单片机·计算机外设·电脑·显示器·pd芯片
开发笔记-阿牛3 天前
蓝牙音乐灯拆解,又一次拆到蓝牙音乐灯芯片CK6865L
人工智能·单片机·嵌入式硬件·音视频·音频
CHENKONG_CK3 天前
破解制鞋打磨痛点:RFID赋能去毛刺工序自动化升级
网络·单片机·嵌入式硬件·网络协议·tcp/ip
三佛科技-187366133973 天前
128KB~512KB Flash车规级MCU选型指南(FT32A072 / FT32A103 系列)
单片机·嵌入式硬件
Brilliantwxx3 天前
【STM32】 SPI Flash 驱动开发实战:阻塞模式驱动 W25Q64(含工程代码)
开发语言·stm32·单片机·嵌入式硬件
纳祥科技3 天前
拆机拆到芯片级:ARC功放机里的NX7026、NX8420、NX6805
单片机·音视频·智能音箱