How do I use Modbus (TCP) to read PLC's 2word Data?

Hello.
I'm trying to read data from the PLC using the Modbus (TCP) protocol.
The library uses Arduino Modbus.

One word (int type) is normally read when reading the holding register data, but two word (float type) is recognized as a completely different value when reading the data.
For example, if the PLC reads the float value, it recognizes the value of 100 as 17096.
What method should I use to make it recognized as 100?
I don't know what to do. Please help me

You can start by reading this: How to get the best out of this forum - Using Arduino / Installation & Troubleshooting - Arduino Forum

And posting your code so we can all see it and hopefully help.

Thank you so much for your reply!

I will refer to the link you attached.
And I will attach my source code below
If you don't mind, can you take a look?

#include    <Arduino.h>
#include    <SPI.h>
#include    <Ethernet.h>
#include    <SPI.h>
#include    <Wire.h>  // Only needed for Arduino 1.6.5 and earlier
//#include    "SSD1306Wire.h" // legacy include: `#include "SSD1306.h"`

// TCP Modbus 관련 --------------------------------------------------
#include <ArduinoModbus.h>



#define     ETH_RST         5
#define     ETH_CS         26
#define     ETH_SCLK       23
#define     ETH_MISO       18
#define     ETH_MOSI       19


uint8_t mac[] = {
    0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED
};

// Initialize the OLED display using Wire library
//SSD1306Wire  display(0x3c, OLED_SDA, OLED_SCL);


// Initialize the Ethernet client library
// with the IP address and port of the server
// that you want to connect to (port 80 is default for HTTP):
EthernetClient client;
ModbusTCPClient modbusTCPClient(client);
// if you don't want to use DNS (and reduce your sketch size)
// use the numeric IP instead of the name for the server:
// IPAddress server(192,168,0,11);  // numeric IP for Google (no DNS)
IPAddress server(192,168,0,11);  // numeric IP for Google (no DNS)

// Variables to measure the speed
unsigned long beginMicros, endMicros;
unsigned long byteCount = 0;
bool printWebData = true;  // set to false for better speed measurement


void ethernetReset(const uint8_t resetPin)
{
    pinMode(resetPin, OUTPUT);
    digitalWrite(resetPin, HIGH);
    delay(250);
    digitalWrite(resetPin, LOW);
    delay(50);
    digitalWrite(resetPin, HIGH);
    delay(350);
}


void setup()
{
    Serial.begin(115200);
    Serial.println("ESP32 W5500 Start");

    Serial.print("ESP32 W5500 Start");

    SPI.begin(ETH_SCLK, ETH_MISO, ETH_MOSI);

    ethernetReset(ETH_RST);
    Ethernet.init(ETH_CS);

    Serial.println("Starting ETH connection...");

    if (Ethernet.begin(mac) == 0) {

        Serial.println("Failed to configure Eth using DHCP");

        if (Ethernet.hardwareStatus() == EthernetNoHardware) {
            Serial.println("Eth shield was not found.");

        } else if (Ethernet.linkStatus() == LinkOFF) {
            Serial.println("Eth cable is not connected.");

        }
        // no point in carrying on, so do nothing forevermore:
        while (true) {
            delay(1);
        }
    }


    Serial.print("Ethernet IP is: ");
    Serial.println(Ethernet.localIP());

    //display.drawString(0, 24, "Ethernet IP is: ");
    //display.drawString(0, 34, Ethernet.localIP().toString());
    //display.display();


    // give the Ethernet shield a second to initialize:
    delay(1000);
    Serial.print("connecting to ");
    Serial.print(server);
    Serial.println("...");

}

void loop()
{
    // if the server's disconnected, stop the client:
  if (!modbusTCPClient.connected()) {
    // client not connected, start the Modbus TCP client
    Serial.println("Attempting to connect to Modbus TCP server");
    
    if (!modbusTCPClient.begin(server, 502)) {
      Serial.println("Modbus TCP Client failed to connect!");
    } else {
      Serial.println("Modbus TCP Client connected");
    }
  } else {

    Serial.print("1301 : ");
    int16_t data1301 = modbusTCPClient.holdingRegisterRead(1, 1301);
    int16_t data1302 = modbusTCPClient.holdingRegisterRead(1, 1302);
    Serial.printf("%d ,", data1301);
    Serial.printf("1303 : %b ,", data1301);
    Serial.printf("%d  \n", data1302);
    int16_t value = (data1301 >> 16) | data1302;
    float floatvalue = *(float*)&value;
    Serial.printf("value : %d\n", value);
    Serial.printf("floatvalue : %d\n", floatvalue);

    Serial.println();

    Serial.print("1401 : ");
    Serial.println(modbusTCPClient.holdingRegisterRead(1, 1401-1));

    Serial.print("1402 : ");
    Serial.println(modbusTCPClient.holdingRegisterRead(1, 1402-1));

//      Serial.println(modbusTCPClient.lastError());

    Serial.println();
    

    // wait for 1 second
    delay(1000);
  }
}

What kind of PLC? If it's Rockwell they have their own special Modbus flavor and it only reads from external devices unless talking to another Rockwell product.

I'm using Siemens PLC.

Maybe I'm missing something, but why not just read it as an int in the PLC?

For that, there are about 160 2word data that need to be converted.
I don't have enough time to correct all that.
Is there a way to read 2words without data corruption or breakage?

I've done very little Siemens programming but it sounds like you have a byte swap and/or Endian issue. I don't know how to easily or quickly fix it. Sorry.

That is not correct. You are passing a float variable, but specifying a signed int parameter (%d). Try
Serial.printf("floatvalue : %f\n", floatvalue);

Are you sure you really want a float? or do you really just want a 32 bit integer? This is not right

Shifting your data1301 variable by 16 bits shifts it all to 0 since it is 16 bits. Maybe you meant to combine them?
int32_t value = (data1301 << 16 ) | data1302;

If you do try this and want to print out the value, make sure you specify "%ul"

Thank you for pointing that out
The two points that you pointed out were that I tried various things and even came up with that code.
His attempts to read 1401 points below were repeatedly unsuccessful.
Is there any other way besides shifting?
I can't understand the correlation between 17096 and 100 at all, so I can't think of a way.

What are the values of data1301 and data1302? You print them out? Posting your output would be helpful. Also, what board are you using? Uno? Mega, ESP8266?

I am using ESP32.

value is too small, int32_t would be better, no??

sorry.. ~q

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.