1. Arduino开发板作为Modbus主站的数据采集与中转应用方案
在工业自动化和物联网领域,数据采集与传输是核心需求之一。Arduino开发板凭借其低成本、易用性和丰富的扩展能力,成为许多中小型项目的首选控制器。而Modbus作为工业领域最常用的通信协议之一,其简单可靠的特性使其在各种设备间数据交互中占据重要地位。本文将详细介绍如何将Arduino开发板配置为Modbus主站,实现高效的数据采集与中转功能。
这个方案特别适合需要连接多个Modbus从站设备(如传感器、仪表、PLC等)并将数据汇总后转发到上位机或云平台的场景。相比直接使用工业控制器,Arduino方案成本可降低70%以上,同时保持了足够的稳定性和灵活性。我在多个工业监测项目中采用此方案,实测在100米距离内可稳定连接多达32个从站设备。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 硬件选型与基础环境搭建
2.1 Arduino开发板选型建议
对于Modbus主站应用,推荐以下几款Arduino兼容开发板:
-
Arduino Mega 2560:拥有4个硬件串口,特别适合需要连接多个Modbus从站的场景。其256KB的Flash和8KB的SRAM能够处理较复杂的数据中转逻辑。
-
ESP32开发板:内置Wi-Fi和蓝牙,适合需要无线传输的场景。双核处理器可轻松应对Modbus通信和数据预处理任务。
-
Arduino Uno:适合简单的单从站应用,但需要注意其有限的SRAM(2KB)可能成为瓶颈。
提示:如果项目需要隔离保护,务必选择带有RS485隔离模块的扩展板,如MAX485带光耦隔离版本,可有效防止工业现场的地环路干扰。
2.2 通信接口选择与配置
Modbus通信主要有三种物理接口形式:
| 接口类型 | 传输距离 | 最大节点数 | 适用场景 |
|---|---|---|---|
| RS-232 | <15m | 1对1 | 调试连接 |
| RS-485 | ≤1200m | 32/128 | 工业现场 |
| TCP/IP | 网络决定 | 理论无限制 | 远程监控 |
对于大多数工业数据采集场景,RS-485是最佳选择。配置时需要:
- 正确设置终端电阻:在总线两端各接一个120Ω电阻
- 确保所有设备共地:避免电位差导致通信异常
- 使用双绞线:推荐AWG22以上的屏蔽双绞线
2.3 开发环境准备
- 安装最新版Arduino IDE(1.8.19+)
- 添加必要的库文件:
- ModbusMaster库(主站功能)
- SimpleModbusMaster库(简易实现)
- ESP32ModbusTCP库(用于WiFi连接)
- 配置串口参数:
cpp复制#define BAUD_RATE 9600 // 标准Modbus速率 #define SERIAL_CONFIG SERIAL_8N1 // 8数据位,无校验,1停止位
3. Modbus主站实现核心代码解析
3.1 基础通信框架搭建
cpp复制#include <ModbusMaster.h>
ModbusMaster node; // 实例化Modbus主站对象
void setup() {
Serial.begin(9600); // 调试串口
Serial1.begin(9600, SERIAL_8N1); // Modbus通信串口
node.begin(1, Serial1); // 初始化从站ID为1的设备
node.preTransmission(preTransmission);
node.postTransmission(postTransmission);
}
void preTransmission() {
// 发送前切换RS485到发送模式
digitalWrite(DE_PIN, HIGH);
digitalWrite(RE_PIN, HIGH);
}
void postTransmission() {
// 发送完成后切换回接收模式
digitalWrite(DE_PIN, LOW);
digitalWrite(RE_PIN, LOW);
}
3.2 数据采集功能实现
典型的Modbus数据读取操作:
cpp复制uint16_t readHoldingRegisters(uint8_t slaveId, uint16_t regAddr, uint16_t quantity) {
node.begin(slaveId, Serial1);
uint8_t result = node.readHoldingRegisters(regAddr, quantity);
if (result == node.ku8MBSuccess) {
for (uint8_t i = 0; i < quantity; i++) {
Serial.p
