Printing float array to singular Serial print outputs

Hello, I am reading register values with a Powermeter using MODBUS TCP with an ESP32 DEV Module. The output is as so:

As shown, the output are float values printed simultaneously without any separators, reason being that there is a data and error handler function:

void handleData(ModbusMessage response, uint32_t token) 
{
  float f;
  response.get(3, f);
  Serial.println(f);
}


void handleError(Error error, uint32_t token) 
{
  ModbusError me(error);
  Serial.printf("Error response: %02X - %s\n", (int)me, (const char *)me);
}

I would like to print each value as a separate output, e.g. Voltage A =....., Current A = ...., etc in separate lines. How do I isolate and select data to be printed based on the response shown in the Serial monitor, how do I print isolated values based on this response?

I'm using the eModbus library. My code:

#include <Arduino.h>
#include <WiFi.h>

#include "REG_LIB.h"
#include "ModbusClientTCP.h"

#define baud 9600
#define TCPip 192, 168, 2, 46

WiFiClient theClient;                          // Set up a client
#ifndef MY_SSID
#define MY_SSID "Process_Trainer_Internal"
#endif
#ifndef MY_PASS
#define MY_PASS "92001329"
#endif

char ssid[] = MY_SSID;                     // SSID and ...
char pass[] = MY_PASS;                     // password for the WiFi network used


ModbusClientTCP MB(theClient);


void handleData(ModbusMessage response, uint32_t token) 
{
  float f;
  response.get(3, f);
  Serial.println(f);
}


void handleError(Error error, uint32_t token) 
{
  ModbusError me(error);
  Serial.printf("Error response: %02X - %s\n", (int)me, (const char *)me);
}


void setup() {

  Serial.begin(baud);
  while (!Serial) {}
  Serial.println("__ OK __");


  WiFi.begin(ssid, pass);
  delay(200);
  while (WiFi.status() != WL_CONNECTED) {
    Serial.print(". ");
    delay(1000);
  }
  IPAddress wIP = WiFi.localIP();
  Serial.printf("WIFi IP address: %u.%u.%u.%u\n", wIP[0], wIP[1], wIP[2], wIP[3]);


  MB.begin();


}


void loop() {

  MB.onDataHandler(&handleData);

  MB.onErrorHandler(&handleError);

  MB.setTimeout(2000, 200);

  MB.setTarget(IPAddress(TCPip), 502);

  MB.addRequest((uint32_t)millis(), ID_meter, READ_HOLD_REGISTER, Reg_CurrentA, 2);
  MB.addRequest((uint32_t)millis(), ID_meter, READ_HOLD_REGISTER, Reg_CurrentB, 2);
  MB.addRequest((uint32_t)millis(), ID_meter, READ_HOLD_REGISTER, Reg_CurrentC, 2);
  //MB.addRequest((uint32_t)millis(), ID_meter, READ_HOLD_REGISTER, Reg_CurrentN, 2);
  MB.addRequest((uint32_t)millis(), ID_meter, READ_HOLD_REGISTER, Reg_VoltAB, 2);
  MB.addRequest((uint32_t)millis(), ID_meter, READ_HOLD_REGISTER, Reg_VoltBC, 2);
  MB.addRequest((uint32_t)millis(), ID_meter, READ_HOLD_REGISTER, Reg_VoltCA, 2);
//  MB.addRequest((uint32_t)millis(), ID_meter, READ_HOLD_REGISTER, Reg_AcPwrA, 2);
//  MB.addRequest((uint32_t)millis(), ID_meter, READ_HOLD_REGISTER, Reg_AcPwrB, 2);
//  MB.addRequest((uint32_t)millis(), ID_meter, READ_HOLD_REGISTER, Reg_AcPwrC, 2);
  MB.addRequest((uint32_t)millis(), ID_meter, READ_HOLD_REGISTER, Reg_AcPwrTot, 2);
  MB.addRequest((uint32_t)millis(), ID_meter, READ_HOLD_REGISTER, Reg_PwrFTot, 2);


  delay(5000);
}

Hi Ben,

the image shows that each value gets printed in a new line
This means each message is sended separately. Simply add additional serial output in front of each request.
best regards Stefan

1 Like

I can't see where in your code you are printing an array of floats

You probably need to define an unique token value you each addRequest().
This should allow you to identify what you get in handleData().


#define TOKEN_CURRENT_A 721077



MB.addRequest(TOKEN_CURRENT_A, ID_meter, READ_HOLD_REGISTER, Reg_CurrentA, 2);



void handleData(ModbusMessage response, uint32_t token) 
{
  float f;
  response.get(3, f);

  if(token == TOKEN_CURRENT_A) Serial.print("Current A = ");

  Serial.println(f);
}
1 Like

That's exactly what the "token" is for!
You just apply a token that represents which value you're reading to your request. And the callback function gets exactly that token back and can determine which request this belongs to.

// first we define a struct for our data
typedef struct MBRegs {
  char *name[10];  //we limit the name to 10 chars
  uint16_t register; // that's the actual register to read
}

// fill an array with the data (Name we want to display and register)
MBRegs registers[] = {
{ b"Current A ", Reg_CurrentA };
{ b"Current B ", Reg_CurrentB };
{ b"Current C ", Reg_CurrentC };
};

// function to make the request
void makeRequest ( MBRegs register, token ) {
  MB.addRequest( token , ID_meter, READ_HOLD_REGISTER, registers.register , 2);
}

// we make a little change to your function
void handleData(ModbusMessage response, uint32_t token) 
{
  float f;
  Serial.print(registers[token].name);
  Serial.print(b" = ");
  response.get(3, f);
  Serial.println(f);
}


void loop() {
  // call the function an a for loop
  for (uint32_t tkn=0 ; tkn < lenghtof(registers) ; tkn++) {
    makeRequest(registers[tkn], tkn)
  }
}

That's basically it...
My code will probably not work (i did not test it) but you should get the idea from it. There are much better programmers than me here that can help you fix the code a clobbered together :slight_smile:

best regards, Marco