首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >ESP8266 / Arduino modbus RTU缓冲区数据转换

ESP8266 / Arduino modbus RTU缓冲区数据转换
EN

Stack Overflow用户
提问于 2019-04-28 07:51:35
回答 2查看 1.4K关注 0票数 0

我正在使用ESP8266和ModbusMaster.h库与支持RS485的功率表进行通信。沟通工作正常,但回应让我感到困惑,我无法获得正确的值。我的功率表显示为1.49 kWh,但Modbus的响应为16318。下面是我的代码:

代码语言:javascript
运行
复制
    #include <ArduinoOTA.h>
    #include <BlynkSimpleEsp8266.h>
    #include <SimpleTimer.h>
    #include <ModbusMaster.h>
    #include <ESP8266WiFi.h> 
    /*
    Debug. Change to 0 when you are finished debugging.
    */
    const int debug = 1; 
    #define ARRAY_SIZE(A) (sizeof(A) / sizeof((A)[0]))

    int timerTask1, timerTask2, timerTask3;
    float battBhargeCurrent, bvoltage, ctemp, btemp, bremaining, lpower, lcurrent, pvvoltage, pvcurrent, pvpower;
    float stats_today_pv_volt_min, stats_today_pv_volt_max;
    uint8_t result; 
    // this is to check if we can write since rs485 is half duplex
    bool rs485DataReceived = true;

    float  data[100];

    ModbusMaster node;
    SimpleTimer timer;

    // tracer requires no handshaking
    void preTransmission() {}
    void postTransmission() {}

    // a list of the regisities to query in order
    typedef void (*RegistryList[])();
    RegistryList Registries = { 
    AddressRegistry_0001       // samo potrosnju
    };
    // keep log of where we are
    uint8_t currentRegistryNumber = 0;
    // function to switch to next registry
    void nextRegistryNumber() {
    currentRegistryNumber = (currentRegistryNumber + 1) % ARRAY_SIZE( Registries);
    }

    void setup()
    {
    // Serial.begin(115200);
    Serial.begin(9600, SERIAL_8E1); //, SERIAL_8E1

    // Modbus slave ID 1
    node.begin(1, Serial);
    node.preTransmission(preTransmission);
    node.postTransmission(postTransmission);
    // WiFi.mode(WIFI_STA); 

    while (Blynk.connect() == false) {}
    ArduinoOTA.setHostname(OTA_HOSTNAME);
    ArduinoOTA.begin();

    timerTask1 = timer.setInterval(9000, updateBlynk); 
    timerTask2 = timer.setInterval(9000, doRegistryNumber);
    timerTask3 = timer.setInterval(9000, nextRegistryNumber);
    }

    // -------------------------------------------------------------------------------- 

    void doRegistryNumber() {
    Registries[currentRegistryNumber]();
    }


    void AddressRegistry_0001() {  

  uint8_t j;
  uint16_t dataval[2];

 result = node.readHoldingRegisters(0x00, 2); 
if (result == node.ku8MBSuccess)
{  
   for (j = 0; j < 2; j++)                        // set to 0,1 for two 
datablocks
    {
        dataval[j] = node.getResponseBuffer(j);
    }


     terminal.println("---------- Show power---------");
     terminal.println("kWh: ");
     terminal.println(dataval[0]);
     terminal.println("crc: ");
     terminal.println(dataval[1]);


     terminal.println("-----------------------"); 
     terminal.flush();   
     node.clearResponseBuffer();
     node.clearTransmitBuffer(); 
} else {
  rs485DataReceived = false;
} 

}

    void loop()
    {
    Blynk.run();
    // ArduinoOTA.handle();
    timer.run();
    }

我已经尝试了类似的东西,但与树莓派和USB-RS485和它的工作。下面是NodeJS代码示例。它看起来类似于Arduino代码。

代码语言:javascript
运行
复制
    // create an empty modbus client
    var ModbusRTU = require("modbus-serial");
    var client = new ModbusRTU();

    // open connection to a serial port
    client.connectRTUBuffered("/dev/ttyUSB0", { baudRate: 9600, parity: 'even' }, read);

    function write() {
        client.setID(1);

        // write the values 0, 0xffff to registers starting at address 5
        // on device number 1.
        client.writeRegisters(5, [0 , 0xffff])
            .then(read);
    }

    function read() {
        // read the 2 registers starting at address 5
        // on device number 1.
            console.log("Ocitavanje registra 0000: ");
        client.readHoldingRegisters(0000, 12)
            .then(function(d) {
                var floatA = d.buffer.readFloatBE(0);
            // var floatB = d.buffer.readFloatBE(4);
            // var floatC = d.buffer.readFloatBE(8);
            // console.log("Receive:", floatA, floatB, floatC); })
            console.log("Potrosnja u kWh: ", floatA); })
            .catch(function(e) {
                console.log(e.message); })
            .then(close);
    }

    function close() {
        client.close();
    }

此代码在控制台中显示1.493748298302。

如何在Arduino中实现此var floatA = d.buffer.readFloatBE(0);?看起来readFloatBE(0)做到了这一点,但只在NodeJS / javascript中可用。

这是我的设备的数据表的一部分

以下是我从设备附带的原始软件中获得的结果:

如果有人能给我指个更好的方向,我会很满意的。

更新:

我找到了ShortBus Modbus扫描仪软件并测试了读数。库读取结果为无符号整数,但需要交换浮点和字序。它如下图所示。

有人能告诉我如何设置正确的转换吗?

EN

回答 2

Stack Overflow用户

发布于 2019-05-01 23:41:19

是的,所以问题确实出在var floatA = d.buffer.readFloatBE(0);Modbus返回一个字节数组的部分,客户端必须解释这些字节,理想情况下是由您正在使用的库完成的,但如果在Arduino上不可用,您可以尝试手动使用字节解码函数,注意以下事项:

Modbus寄存器的长度为16位,因此长度1= 16位,长度2= 32位,因此在文档中标注为float32的数据类型表示"2个寄存器用于此值,解释为浮点数“。

因此,在client.readHoldingRegisters(0000, 12)上,您请求读取地址为00、大小为12的寄存器。所以这是没有意义的,你只需要2个寄存器。

在您的示例节点代码中,首先将2个寄存器写入client.writeRegisters(5, [0 , 0xffff])寄存器5= 0中的地址5,以及寄存器6= 0xFFFF,为什么?然后从read()中的地址0开始读取,这是每个文档的总KwH的地址。

因此,您应该获得一个字节数组,并且需要将它们解码为一个浮点数。Modbus是单词和字节的高字节顺序,因此您需要在解码函数中使用它们。我不知道Arduino到底提供了什么,但希望你能通过这些额外的信息弄清楚。

我认为,如果只发送缓冲区进行打印,您将得到该值的整数解释,因此出现了问题

票数 0
EN

Stack Overflow用户

发布于 2019-05-22 22:41:11

你是不是正确地使用了这个函数?我正面临着同样的问题,并试图弄清楚如何从modbus地址8192 (即2个数据块)获得一个小数点后两位的浮点值。

代码语言:javascript
运行
复制
void loop()
{
  uint8_t j, result;
  uint16_t dataval[2];

  result = node.readHoldingRegisters(8192, 2);      // slave: read (6) 16-bit registers starting at register .. to RX buffer , this address is in Decimal, so convert hex to decimal to use correct address
  if (result == node.ku8MBSuccess)                  // do something with data if read is successful
  {
    for (j = 0; j < 2; j++)                        // set to 0,1 for two datablocks
    {
      dataval[j] = node.getResponseBuffer(j);


    }

    //********************************
    String myValuea =  String(dataval[0], HEX); //Convert it into Hexadecimal
    String myValueb =  String(dataval[1], HEX); //Convert it into Hexadecimal
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/55885851

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档