SimpleModbus Arduino库使用教程:让Arduino通过Modbus RTU通信

SimpleModbus 简介

SimpleModbus 是一套为 Arduino 平台开发的 Modbus RTU 协议库,托管在 Google Code Archive(项目已被归档)。它由 Juan Bester 开发,包含 SimpleModbusMaster(主站库)和 SimpleModbusSlave(从站库)两个独立的 Arduino 库。虽然项目名称里有”Simple”,但它提供的功能覆盖了 Modbus RTU 通信中最常用的功能码,非常适合 Arduino 初学者和快速原型开发。

⚠️ 注意:SimpleModbus 项目已不再活跃更新。对于新项目,推荐使用更现代化的 Modbus RTU for Arduino 库(库名为 “Modbus”)或 esp-modbus(ESP32 平台)。但 SimpleModbus 的代码简洁易懂,作为学习 Modbus 协议实现的入门资料仍然很有价值。

SimpleModbus 支持的功能

  • SimpleModbusMaster:支持 FC01(读线圈)、FC02(读离散输入)、FC03(读保持寄存器)、FC04(读输入寄存器)、FC15(写多线圈)、FC16(写多寄存器)
  • SimpleModbusSlave:支持 FC03(读保持寄存器)和 FC16(写多寄存器)
  • 硬件要求:Arduino + RS-485 转换模块(如 MAX485)

硬件连接

Arduino 通过 MAX485 模块连接 RS-485 总线。典型接线方式:

MAX485 引脚Arduino Uno说明
VCC5V电源
GNDGND
RORX (D0)接收数据 → Arduino 串口 RX
DITX (D1)发送数据 ← Arduino 串口 TX
RED2接收使能(低有效)
DED2发送使能(高有效),与 RE 并联到同一 IO
AA (总线+)RS-485 A 线(差分+)
BB (总线-)RS-485 B 线(差分-)

⚠️ 在 RS-485 总线的两端必须加 120Ω 终端电阻(A-B 之间),否则长距离通信会出现信号反射导致数据错误。

SimpleModbusSlave 示例:Arduino 作为 Modbus RTU 从站

#include <SimpleModbusSlave.h>

// 定义保持寄存器数组(10个寄存器)
enum {
    TEMP_REG = 0,      // 温度(x10)
    HUMIDITY_REG,       // 湿度(x10)
    COIL_STATUS,        // 线圈状态
    SETPOINT,           // 设定值
    // ... 更多寄存器
    TOTAL_REGS = 10
};

unsigned int holdingRegs[TOTAL_REGS];

void setup() {
    // 设置 RS-485 方向控制引脚
    pinMode(2, OUTPUT);
    
    // SimpleModbusSlave 参数:
    // 1. 寄存器数组地址
    // 2. 寄存器数量
    // 3. 发送使能引脚
    // 4. 发送使能有效电平
    // 5. 从站地址
    // 6. 波特率
    // 7. 校验(0=无校验)
    modbus_configure(holdingRegs, TOTAL_REGS,
                     2,                  // TXEN 引脚
                     HIGH,               // TXEN 高电平时发送
                     1,                  // 从站地址
                     9600,               // 波特率
                     0);                 // 校验
}

void loop() {
    // 更新传感器数据(模拟)
    holdingRegs[TEMP_REG] = analogRead(A0) / 2; // 温度(模拟)
    holdingRegs[HUMIDITY_REG] = analogRead(A1) / 3;
    holdingRegs[COIL_STATUS] = digitalRead(3);
    
    // 处理 Modbus 请求
    modbus_update();
}

SimpleModbusMaster 示例:读取从站数据

#include <SimpleModbusMaster.h>

#define TOTAL_NO_OF_REGISTERS 2
unsigned int holdingRegs[TOTAL_NO_OF_REGISTERS];

void setup() {
    Serial.begin(9600);
    
    // SimpleModbusMaster 参数:
    // 1. 本地寄存器数组
    // 2. 读取/写入的寄存器数量
    // 3. 发送使能引脚
    // 4. 发送使能有效电平
    modbus_configure(holdingRegs, TOTAL_NO_OF_REGISTERS,
                     2,      // TXEN 引脚
                     HIGH);  // TXEN 高电平时发送
}

void loop() {
    // 从站地址 1,起始地址 0,读取 2 个保持寄存器
    unsigned char result = modbus_read_holding_registers(1, 0, 2);
    
    if (result == 0) {
        Serial.print("温度: ");
        Serial.print(holdingRegs[0] / 10.0);
        Serial.print("°C, 湿度: ");
        Serial.print(holdingRegs[1] / 10.0);
        Serial.println("%");
    } else {
        Serial.print("Modbus 读取失败,错误码: ");
        Serial.println(result);
    }
    
    delay(1000);
}

SimpleModbus vs 现代替代方案

SimpleModbus 项目已经在数年前停止更新,现代 Arduino 项目推荐以下替代方案:

库名平台特点
ArduinoModbusArduino(官方)Arduino 官方维护,支持 RTU 和 TCP,Arduino IDE 库管理器一键安装
Modbus-Master-Slave-for-ArduinoArduino同时支持主站和从站,功能码覆盖全,GitHub 活跃更新
esp-modbusESP32 / ESP8266Espressif 官方库,支持 Modbus RTU/TCP/ASCII,性能优异
SimpleModbusArduino简单易懂,适合学习,但已停更

ESP32 上实现 Modbus RTU 通信(现代方案)

如果你使用 ESP32 平台,推荐 Espressif 官方的 esp-modbus 库。以下是一个最小示例:

// ESP32 使用 HardwareSerial + MAX485
#include <Arduino.h>

// 定义 RS-485 控制引脚
#define RXD2 16  // ESP32 RX2
#define TXD2 17  // ESP32 TX2
#define DE_RE 4  // RS-485 方向控制

HardwareSerial modbusSerial(2);

void setup() {
    Serial.begin(115200);
    modbusSerial.begin(9600, SERIAL_8N1, RXD2, TXD2);
    pinMode(DE_RE, OUTPUT);
    digitalWrite(DE_RE, LOW); // 默认接收模式
}

void loop() {
    // 发送 Modbus RTU 请求(手动构造帧)
    uint8_t request[] = {
        0x01,        // 从站地址
        0x03,        // 功能码(读保持寄存器)
        0x00, 0x00,  // 起始地址
        0x00, 0x02   // 读取 2 个寄存器
    };
    uint16_t crc = calculateCRC(request, 6);
    request[6] = crc & 0xFF;
    request[7] = crc >> 8;
    
    // 切换到发送模式
    digitalWrite(DE_RE, HIGH);
    delayMicroseconds(100);
    modbusSerial.write(request, 8);
    modbusSerial.flush();
    
    // 切换回接收模式
    digitalWrite(DE_RE, LOW);
    
    // 等待响应
    delay(500);
    while (modbusSerial.available()) {
        Serial.printf("%02X ", modbusSerial.read());
    }
    Serial.println();
    delay(2000);
}

Arduino 官方 ArduinoModbus 库

在 Arduino IDE 中打开库管理器(Sketch → Include Library → Manage Libraries),搜索 “ArduinoModbus”,安装即可。ArduinoModbus 支持 Modbus RTU(RS-485)和 Modbus TCP(WiFi/以太网),主站和从站模式均可。

#include <ArduinoRS485.h>
#include <ArduinoModbus.h>

void setup() {
    Serial.begin(9600);
    
    // 初始化 RS-485
    RS485.begin(9600);
    
    // 启动 Modbus RTU 从站(地址 1)
    ModbusRTUServer.begin(1, 9600);
    
    // 配置保持寄存器
    ModbusRTUServer.configureHoldingRegisters(0, 10);
}

void loop() {
    // 轮询 Modbus 请求
    ModbusRTUServer.poll();
    
    // 更新寄存器值
    int sensorValue = analogRead(A0);
    ModbusRTUServer.holdingRegisterWrite(0, sensorValue);
}

常见问题排查

通信完全没有响应

  • 检查 MAX485 DE/RE 引脚的方向切换逻辑是否正确(发送时 HIGH、接收时 LOW)
  • 确认波特率和从站地址与主站配置一致
  • 用 USB 转 RS-485 模块 + 串口助手监控总线数据,确认信号是否存在
  • 检查 A/B 线是否接反(用万用表测差分电压:A 对 B 应为正电压时总线空闲)

偶尔丢数据或 CRC 错误

  • 检查 RS-485 总线两端是否加了 120Ω 终端电阻
  • 降低波特率尝试(4800 或 2400),排除信号完整性因素
  • 缩短总线长度或加中继器
  • 确认发送完成到接收切换之间留有足够的延时(至少 1 个字符时间)

总结

SimpleModbus 作为早期 Arduino Modbus RTU 库,其代码简洁、功能明确,适合初学者理解 Modbus 协议的实现原理。但在实际项目中,推荐使用维护更活跃、功能更完善的替代方案:Arduino 官方库 ArduinoModbus(通用 Arduino 平台)或 esp-modbus(ESP32/ESP8266 平台)。无论选择哪个库,核心的 Modbus RTU 通信原理——从站地址、功能码、寄存器映射、CRC 校验——都是一致的。

把这篇资料用于真实项目?

进入工具中心进行报文解析、CRC 校验和设备调试,或提交需求获取选型与接入建议。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注