Improving the code and finding bugs

Hi everyone!

My code "work" but im sure it's bad implemented, so i'm asking for some help.

Explanation of the code:
I have to read by Hardware Serial port (TTL) a petition ">PTX<" where X could be any number from 0 to 9 (from a PIC in other PCB)
When I recieve one of those, I ask via Software serial port (with a conversor RS485 in between) to a Powermeter that answer in HEX float. So I "transform" those values in a String (now in ASCII) and return this (with some other parts "hardcoded" to keep it simple for now) to the PIC. Something like " >0,3,220.0,220.0,220.0,1,999# " Where "220.0" are the values I read from the Powermeter.

The problems that I found but don't know how to resolve are:
-The response to the PIC should be (or what I was trying to do) 3 Voltage in the first response, 3 Currents in 2nd. Power Factor, Hz and Energy in 3rd. In fact, the Energy is sended as the first value of the 1st response. changing the order of all others... >0,3,25.6,220.0,220.0,1,999# "

-If I Shutdown the Powermeter, the program keeps sending responses with the value of ENERGY in all the responses. for example :" >0,3,25.6,25.6,25.6,1,999# " Energy=25.6 for a bunch of times, an then all values goes to zero.

Sorry for my English, if there is somthing that isn't clear please tell me and i'll try to clarify.

#include <avr/wdt.h> //libreria de watchdog

#include <SoftwareSerial.h>
//#define enable485  4    //Pin enable RS485

// software serial: RX = digital pin 5, TX = digital pin 6
SoftwareSerial port485(5, 6);

///////////////////////// VARIABLES GLOBALES ///////////////////////////
const int tpo_reset = 300;
const int sensXmodulo = 3;
const int enable485 = 4;
int index = 0;
char trama[9];              //Datos desde SIMT

char respuesta[9];          //Datos desde Powermeter
int indice = 0;

String valores_trama;         //Respuesta para SIMT

String pt100_trama;         //Respuesta para SIMT

///////////////////TRAMAS DE PETICION POWERMETER///////////////////////

byte peticion[9][8] = {
  {0x01, 0x03, 0x00, 0x09, 0x00, 0x02, 0x14, 0x09},  //0:Ua
  {0x01, 0x03, 0x00, 0x0B, 0x00, 0x02, 0xB5, 0xC9},  //1:Ub
  {0x01, 0x03, 0x00, 0x0D, 0x00, 0x02, 0x55, 0xC8},  //2:Uc

  {0x01, 0x03, 0x00, 0x0F, 0x00, 0x02, 0xF4, 0x08},  //3.Ia
  {0x01, 0x03, 0x00, 0x11, 0x00, 0x02, 0x94, 0x0E},  //4:Ib
  {0x01, 0x03, 0x00, 0x13, 0x00, 0x02, 0x35, 0xCE},  //5:Ic

  {0x01, 0x03, 0x00, 0x1B, 0x00, 0x02, 0xB4, 0x0C},  //6:fp
  {0x01, 0x03, 0x00, 0x1D, 0x00, 0x02, 0x54, 0x0D},  //7:hz
  {0x01, 0x03, 0x00, 0x21, 0x00, 0x02, 0x94, 0x01}   //8:ea
};

char comandos[9][7] =
{
  ">PT0<",
  ">PT1<",
  ">PT2<",
  ">PT3<",
  ">PT4<",
  ">PT5<",
  ">PT6<",
  ">PT7<",
  ">PT8<"
};

void setup() {
  wdt_disable();
  pinMode(enable485, OUTPUT);    //Configuro pin como salida
  delay(50);
  //Open serial communications and wait for port to open:
  Serial.begin(9600);
  while (!Serial) {  }
  delay(50);
  port485.begin(9600);  // Start software serial port
  wdt_enable(WDTO_2S);
  
}

void(* resetFunc) (void) = 0; // funcion para reset

void loop() {
  wdt_reset();
  if(millis()/1000>tpo_reset){
  resetFunc();  // Reset forzado
  }
  memset(trama, 0, sizeof(trama));
  String strtrama = "";
  while (Serial.available() > 0) {
    char dato = Serial.read();    // Read a character
    trama[index] = dato;          // Store it
    index++;                      // Increment where to write next
    trama[index] = '\0';          // Null terminate the string
  }
  index = 0;
  strtrama = trama;
  delay(50);                      //Delay sino rompe todo

  //Serial.print("      ");       //DEBUG  
  Serial.flush();                 //Clean serial port
  delay(50);
  for (int k = 0; k < 6 ; k++) {
    if (strtrama == comandos[k]) {   //Si es ">PTX<"

      delay(20);
      digitalWrite(enable485, HIGH);  //RS485 como Transmisor

      for (int t = 0; t < sensXmodulo ; t++) {

        for (int i = 0; i < 8; i++) {   //Envio trama de peticion a Powermeter
          port485.write(peticion[k * 3 + t][i]);
        }

        digitalWrite(enable485, LOW);   //RS485 como Receptor

        while (port485.available() > 0) { //Leo puerto serie por software

          char dato = port485.read();
          respuesta[indice] = dato;
          indice++;
          respuesta[indice] = '\0';
        }
        indice = 0;
        delay(20);
        digitalWrite(enable485, HIGH);    //RS485 como Transmisor
        delay(20);

        float data;     //Variable auxiliar

        union u_tag {
          byte b[4];
          float fval;
        } u;

        u.b[3] = respuesta[3];      //Guardo los bytes de interes
        u.b[2] = respuesta[4];      //para interpretarlos como float.
        u.b[1] = respuesta[5];
        u.b[0] = respuesta[6];

        data = u.fval;
        char flotante[6];

        dtostrf(data, 4, 1, flotante);    //Convierto de Float a String
        String flotanteStr = flotante;
        flotanteStr.replace(" ", "");

        valores_trama += flotanteStr;
        valores_trama += ",";
      }
      String cabecera0 = ">";
      String id =  String(k);
      String cabecera1 = ",3,";
      String findetrama = "1,999#";

      pt100_trama += cabecera0;         //Armo trama de respuesta
      pt100_trama += id;
      pt100_trama += cabecera1;
      pt100_trama += valores_trama;        //para SIMT.
      pt100_trama += findetrama;
      delay(20);
      port485.flush();                //Clean software serial port
      delay(20);
      Serial.print(pt100_trama);      //Respuesta para SIMT
      delay(20);
      valores_trama = "";
      pt100_trama = "";
    }
  }
}

I'm working in arduino nano.

Sorry about the languaje, I'll update the coments if something isn't clear.

Thanks in advance.

I would suggest to study Serial Input Basics to properly handle the Serial port

Just in case - This does not “clean” the incoming buffer Serial.flush();                //Clean serial portif this is what you had in mind, it just waits until your outgoing message is sent.

Thanks J-M-L, As far as I understand, the problems I have is related with "end of line" character, but if it is the case, I still don't know how to resolve it because the Powermeter doesn`t send an "end of line" character.

I think it happen because the last value received from the powermeter doesn't have an "end" but then, that value stored is sended when the Serial port is used again. Right?

The powermeter send something like " 01 03 04 43 5B 75 C3 F8 A5 " (hex values) but none of the values is constant (it change with the measurement of the powermeter)

I'm sure that your Powermeter has a protocol... what does it look like? post a link to the specification

It's a "yigedianqi" with RS485 MODBUS-RTU. It also says "IEEE-754"

Apparently there isn't a specification in english.

01 03 04 43 5B 75 C3 F8 A5

(01 03 04 << address/function/register byte number) (43 5B 75 C3 << register value(measurement)) (F8 A5 << CRC)

says "IEEE-754"

Floating point number format, sent as binary.

Stinkytronic:
It's a "yigedianqi" with RS485 MODBUS-RTU. It also says "IEEE-754"

What model is it? Maybe with that info you can find someone who has already done it.

wildbill:
What model is it? Maybe with that info you can find someone who has already done it.

Model: YG889E-9SY

TheMemberFormerlyKnownAsAWOL:
Floating point number format, sent as binary.

I know, that gave me some troubles at the begining but now it's working.

Do you guys see something weird in the code that can cause changes in the order of the data sended as a reply to the PIC?

At first I thought it was lack of a "end of line/file" character, but I add the character '\0' at the end of the received chars

while (port485.available() > 0) { //Leo puerto serie por software

  char dato = port485.read();
  respuesta[indice] = dato;
  indice++;
  respuesta[indice] = '\0';
}

EDIT: I quoted the wrong part above.
I add to "pt100_trama" the string "1,999#" and a String is supposed to add '\0' automatically right?

String findetrama = "1,999#";
[...]
pt100_trama += findetrama;
[...]
Serial.print(pt100_trama);

This is how it should look like from the Monitor:

>PT0<                                 //Petition from PIC
>0,3,220.1,220.2,220.2,1,999#         //replay from arduino (3 Voltage)
>PT1<                                 //Petition from PIC
>0,3,2.1,2.2,2.3,1,999#               //replay from arduino (3 Current)
>PT2<                                 //Petition from PIC
>0,3,1.0,50.0,25.6,1,999#             //replay from arduino (power factor, Hz, Energy)

Instead I got:

>PT0<                                 //Petition from PIC
>0,3,25.6,220.2,220.2,1,999#          //replay from arduino (Energy, 2 Voltage)
>PT1<                                 //Petition from PIC
>0,3,2.1,2.2,2.3,1,999#               //replay from arduino (1 Voltage, 2 Current)
>PT2<                                 //Petition from PIC
>0,3,1.0,50.0,25.6,1,999#             //replay from arduino (1 Current, power factor, Hz)