RS485 Modbus 通讯
RS485 Modbus Commmunication
我一直在尝试通过 Modbus 通信使用 Arduino 从我的电表获取电气参数。但是我的代码无法从电表中获取数据。在这段代码中,我试图从寄存器地址为 12 的电表中获取相电压值。
#include<ModbusMaster.h>
#define MAX485_DE 3
#define MAX485_RE_NEG 2
ModbusMaster node;
void preTransmission()
{
digitalWrite(MAX485_RE_NEG, 1);
digitalWrite(MAX485_DE, 1);
}
void postTransmission()
{
digitalWrite(MAX485_RE_NEG, 0);
digitalWrite(MAX485_DE, 0);
}
void setup() {
pinMode(MAX485_RE_NEG, OUTPUT);
pinMode(MAX485_DE, OUTPUT);
// Init in receive mode
digitalWrite(MAX485_RE_NEG, 0);
digitalWrite(MAX485_DE, 0);
Serial.begin(9600);
//slave ID 1
node.begin(1, Serial);
Serial.println("Starting Modbus Transaction:");
node.preTransmission(preTransmission);
node.postTransmission(postTransmission);
}
void loop() {
static uint32_t i;
uint8_t j, result;
uint16_t data[10];
i++;
result = node.readInputRegisters(0x30012,2);
Serial.println("");
if (result == node.ku8MBSuccess) {
Serial.print("Success, Received data: ");
for (j = 0; j < 2; j++) {
data[j] = node.getResponseBuffer(j);
Serial.print(data[j], HEX);
Serial.print(" ");
}
Serial.println("");
} else {
Serial.print("Failed, Response Code: ");
Serial.print(result, HEX);
Serial.println("");
delay(5000);
}
delay(1000);
}
您使用了错误的 Modbus 功能。您应该使用函数 0x03 readHoldingRegisters
(注意页面底部框架开头的 0x03)。
只需更改此行:
result = node.readInputRegisters(0x30012,2);
至:
result = node.readHoldingRegisters(12,2);
顺便说一句,您的设置一定有其他问题,因为您得到的错误代码是 0xE2
,您应该得到 0x02
,意思是 Ilegal Data Address
或者 0x01
(Illegal Function
) 取决于仪表的固件。也许你应该仔细检查波特率。
您可能还需要在设置循环中将节点 ID 设置为 0xAA
:
node.begin(170, Serial);
正如上面有人评论的那样。文档不是很好...
如果您查看底部的示例数据命令:
aa 03 0001 003C 0DC0
貌似aa
是从机地址,03
是上面讨论的功能码,003C
是要读取的寄存器个数(60个读取所有数据仪表一次)。最后两个字节 0DC0
应该是 CRC。
如果那是正确的,那么如果您想获得相电压,您应该考虑读取寄存器 11 和 12 而不是 12-13:
result = node.readHoldingRegisters(11,2);
再次强调,这只是我填补文档空白的最佳猜测。
我一直在尝试通过 Modbus 通信使用 Arduino 从我的电表获取电气参数。但是我的代码无法从电表中获取数据。在这段代码中,我试图从寄存器地址为 12 的电表中获取相电压值。
#include<ModbusMaster.h>
#define MAX485_DE 3
#define MAX485_RE_NEG 2
ModbusMaster node;
void preTransmission()
{
digitalWrite(MAX485_RE_NEG, 1);
digitalWrite(MAX485_DE, 1);
}
void postTransmission()
{
digitalWrite(MAX485_RE_NEG, 0);
digitalWrite(MAX485_DE, 0);
}
void setup() {
pinMode(MAX485_RE_NEG, OUTPUT);
pinMode(MAX485_DE, OUTPUT);
// Init in receive mode
digitalWrite(MAX485_RE_NEG, 0);
digitalWrite(MAX485_DE, 0);
Serial.begin(9600);
//slave ID 1
node.begin(1, Serial);
Serial.println("Starting Modbus Transaction:");
node.preTransmission(preTransmission);
node.postTransmission(postTransmission);
}
void loop() {
static uint32_t i;
uint8_t j, result;
uint16_t data[10];
i++;
result = node.readInputRegisters(0x30012,2);
Serial.println("");
if (result == node.ku8MBSuccess) {
Serial.print("Success, Received data: ");
for (j = 0; j < 2; j++) {
data[j] = node.getResponseBuffer(j);
Serial.print(data[j], HEX);
Serial.print(" ");
}
Serial.println("");
} else {
Serial.print("Failed, Response Code: ");
Serial.print(result, HEX);
Serial.println("");
delay(5000);
}
delay(1000);
}
您使用了错误的 Modbus 功能。您应该使用函数 0x03 readHoldingRegisters
(注意页面底部框架开头的 0x03)。
只需更改此行:
result = node.readInputRegisters(0x30012,2);
至:
result = node.readHoldingRegisters(12,2);
顺便说一句,您的设置一定有其他问题,因为您得到的错误代码是 0xE2
,您应该得到 0x02
,意思是 Ilegal Data Address
或者 0x01
(Illegal Function
) 取决于仪表的固件。也许你应该仔细检查波特率。
您可能还需要在设置循环中将节点 ID 设置为 0xAA
:
node.begin(170, Serial);
正如上面有人评论的那样。文档不是很好...
如果您查看底部的示例数据命令:
aa 03 0001 003C 0DC0
貌似aa
是从机地址,03
是上面讨论的功能码,003C
是要读取的寄存器个数(60个读取所有数据仪表一次)。最后两个字节 0DC0
应该是 CRC。
如果那是正确的,那么如果您想获得相电压,您应该考虑读取寄存器 11 和 12 而不是 12-13:
result = node.readHoldingRegisters(11,2);
再次强调,这只是我填补文档空白的最佳猜测。