esp32 modbus从站arduino
时间: 2025-05-25 09:36:56 浏览: 25
### ESP32 Modbus从站 Arduino 实现代码示例
以下是使用Arduino IDE编写的ESP32作为Modbus从站的代码示例。该代码实现了基本的功能,允许ESP32响应来自Modbus主机的请求并返回数据。
```cpp
#include <HardwareSerial.h>
#define MODBUS_SLAVE_ID 1 // Modbus从站ID
#define SERIAL_BAUDRATE 9600 // 波特率设置
// 定义寄存器地址范围
const int holdingRegisterStartAddress = 0;
const int inputRegisterStartAddress = 100;
// 寄存器存储数组
uint16_t holdingRegisters[10]; // 持有寄存器 (可读写)
uint16_t inputRegisters[10]; // 输入寄存器 (只读)
void setup() {
Serial.begin(SERIAL_BAUDRATE); // 初始化串口通信
}
void loop() {
if (Serial.available()) { // 如果接收到数据
processModbusRequest(); // 处理Modbus请求
}
}
void processModbusRequest() {
uint8_t buffer[256];
int length = Serial.readBytes(buffer, sizeof(buffer)); // 读取Modbus帧
if (length >= 8 && buffer[0] == MODBUS_SLAVE_ID) { // 验证帧头和从站ID匹配
switch (buffer[1]) { // 根据功能码处理不同操作
case 0x03: // 功能码0x03:读持有寄存器
handleReadHoldingRegisters(buffer);
break;
case 0x04: // 功能码0x04:读输入寄存器
handleReadInputRegisters(buffer);
break;
default:
sendExceptionResponse(0x01); // 返回非法功能异常
break;
}
} else {
sendExceptionResponse(0x02); // 返回非法数据地址异常
}
}
void handleReadHoldingRegisters(uint8_t* requestFrame) {
uint16_t startAddress = ((requestFrame[2] << 8) | requestFrame[3]); // 起始地址
uint16_t quantity = ((requestFrame[4] << 8) | requestFrame[5]); // 数据数量
if (startAddress + quantity > 10 || quantity == 0) { // 检查越界情况
sendExceptionResponse(0x02); // 返回非法数据地址异常
return;
}
uint8_t responseBuffer[quantity * 2 + 3];
responseBuffer[0] = MODBUS_SLAVE_ID; // 响应帧头部
responseBuffer[1] = 0x03; // 功能码
responseBuffer[2] = quantity * 2; // 字节数量
for (int i = 0; i < quantity; ++i) {
responseBuffer[i * 2 + 3] = highByte(holdingRegisters[startAddress + i]);
responseBuffer[i * 2 + 4] = lowByte(holdingRegisters[startAddress + i]);
}
Serial.write(responseBuffer, quantity * 2 + 3); // 发送响应帧
}
void handleReadInputRegisters(uint8_t* requestFrame) {
uint16_t startAddress = ((requestFrame[2] << 8) | requestFrame[3]); // 起始地址
uint16_t quantity = ((requestFrame[4] << 8) | requestFrame[5]); // 数据数量
if (startAddress + quantity > 10 || quantity == 0) { // 检查越界情况
sendExceptionResponse(0x02); // 返回非法数据地址异常
return;
}
uint8_t responseBuffer[quantity * 2 + 3];
responseBuffer[0] = MODBUS_SLAVE_ID; // 响应帧头部
responseBuffer[1] = 0x04; // 功能码
responseBuffer[2] = quantity * 2; // 字节数量
for (int i = 0; i < quantity; ++i) {
responseBuffer[i * 2 + 3] = highByte(inputRegisters[startAddress + i]);
responseBuffer[i * 2 + 4] = lowByte(inputRegisters[startAddress + i]);
}
Serial.write(responseBuffer, quantity * 2 + 3); // 发送响应帧
}
void sendExceptionResponse(uint8_t exceptionCode) {
uint8_t exceptionResponse[] = {MODBUS_SLAVE_ID, 0x83, exceptionCode};
Serial.write(exceptionResponse, 3); // 发送异常响应帧
}
```
以上代码展示了如何通过硬件串口实现Modbus RTU协议[^1]。它支持两种主要的操作模式:读取持有寄存器(功能码`0x03`)和读取输入寄存器(功能码`0x04`)。此外还包含了错误处理机制,用于应对非法功能或非法数据地址的情况。
### 注意事项
- **波特率配置**:确保波特率与主站一致,默认为`9600bps`。
- **寄存器初始化**:在实际应用中,可能需要动态更新寄存器值以反映当前状态。
- **CRC校验**:上述代码未包含CRC计算部分,需自行补充以满足完整的Modbus RTU需求[^3]。
---
阅读全文
相关推荐




















