Convert HEX char data array to decimal number and do some math with it

I have a serial sensor who is sending data like e.g. is running time/uptime since new battery.
This value comes to the serial terminal as: C90000E8E533

To get the actual running time we should remove the "identifier" who explains what kind of status message this is and remove the checksum. In this case C9 is the identifier part and 33 is the checksum.
The "core" running time" is 0000E8E5 which in DEC gives us 59621. So our device is running for 59621 quarterseconds, so a 4.14 hours of running time.

My function gives this, so incorrect data. 100% sure my own fault.

call operating_time
data HEX:
35
data DEC:
53
data:
5
Running Time:
C90000E8E533

I think it is because of the way that I want to construct the value from the data_array.
data = String(data_array[2,3,4,5,6,7,8,9], HEX);

Anyone a good pointer or some tips to steer me to the right functions to do this?
Thanks.

#include <SoftwareSerial.h>
#define TX D6
#define RX D7

SoftwareSerial mySerial(RX, TX); // RX, TX
bool data_chk = false;

//byte data_array[20];
char data_array[20];

char optime[8];

byte stx[] = {0x02}; //stop byte
byte etx[] = {0x03}; //start byte
byte ack[] = {0x06}; //ack byte
byte cmd1[] = {0x30, 0x34, 0x36, 0x34}; //0464
byte cmd2[] = {0x30, 0x38, 0x36, 0x38}; //0868
byte cmd3[] = {0x30, 0x39, 0x36, 0x39}; //0969
byte cmd4[] = {0x30, 0x42, 0x37, 0x32}; //0B72
byte cmd5[] = {0x30, 0x43, 0x37, 0x33}; //0C73
byte cmd6[] = {0x30, 0x44, 0x37, 0x34}; //0D74
byte cmd7[] = {0x30, 0x45, 0x37, 0x35}; //0E75
byte cmd8[] = {0x30, 0x46, 0x37, 0x36}; //0F76
byte rcvd = 0;
byte count = 0;
String data;
String data2;
String data3;
String data4;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
  mySerial.begin(9600);
}

void loop() {
  // put your main code here, to run repeatedly:
  if (mySerial.available())
  {
    while (mySerial.available() > 0)
    {
      byte rcvd = mySerial.read();
      //rcvd |=  mySerial.read();
      //Serial.println(rcvd);
      if (rcvd == stx[0] && (data_chk == false))
      {
        data_chk = true;
        count = 0;
      }
      else if ((rcvd == etx[0]) && (count > 10))
      {
        data_chk = false;
        mySerial.write(ack[0]);

        if (data_array[0] == 'C' && data_array[1] == '9') // for operating time
        {
          Serial.println("call operating_time");
          operating_time();
        }
        
          Serial.println(""); // print newline
          for (int j = 0 ; j < count; j++)
        {
          Serial.print(data_array[j]); // print data from array, this is working and the "right answer"
        }
        count = 0;
        //    break;
      }
      else if (data_chk == true)
      {
        // Serial.write(char(rcvd));
        data_array[count] = rcvd;
        // Serial.write(data_array[count]);
        count++;
      }
    }
  }
  if (Serial.available())
  {
    while (Serial.available() > 0)
    {
      //mySerial.write((char)Serial.read());
      char data = Serial.read();
      if (data == 'A')
      {
        mySerial.write(stx[0]);
        mySerial.write(cmd1[0]);
        mySerial.write(cmd1[1]);
        mySerial.write(cmd1[2]);
        mySerial.write(cmd1[3]);
        mySerial.write(etx[0]);

      }
      else if (data == 'B')
      {
        mySerial.write(stx[0]);
        mySerial.write(cmd2[0]);
        mySerial.write(cmd2[1]);
        mySerial.write(cmd2[2]);
        mySerial.write(cmd2[3]);
        mySerial.write(etx[0]);
      }
      else if (data == 'C')
      {
        mySerial.write(stx[0]);
        mySerial.write(cmd3[0]);
        mySerial.write(cmd3[1]);
        mySerial.write(cmd3[2]);
        mySerial.write(cmd3[3]);
        mySerial.write(etx[0]);
      }
    }
  }
}

void operating_time()
{
//  String data = String(data_array[2], HEX);
//  Serial.println(data);
//  data = data + String(data_array[3], HEX) + String(data_array[4], HEX) + String(data_array[5], HEX);
//  Serial.println(data);
//  data = data + String(data_array[6], HEX) + String(data_array[7], HEX) + String(data_array[8], HEX) + String(data_array[9], HEX);
//  Serial.println(data);

  data = String(data_array[2,3,4,5,6,7,8,9], HEX);
  Serial.println("data HEX: ");
  Serial.println(data);
  
  data2 = String(data_array[2,3,4,5,6,7,8,9], DEC);
  Serial.println("data DEC: ");
  Serial.println(data2);
  
  data3 = String(data_array[2,3,4,5,6,7,8,9]);
  Serial.println("data: ");
  Serial.println(data3);

// invalid conversion from 'char' to 'const char*' [-fpermissive]
//  data4 = strtoul(data_array[2,3,4,5,6,7,8,9], 0, 16);
//  Serial.println(data4);

  Serial.print("Running Time: "); // in quarter seconds
  // to do: divide decimal number / 4 / 60 / 60 to get running time in hours

//    for (int i=2; i<10; i++)  {
//      optime[i-2] = data_array[i]; // assign the members one at a time
//    }
//
//          for (int k = 0 ; k < 8; k++)
//        {
//          // mySerial.print(data_array[k]);
//          Serial.print(optime[k]);
//        }
//  Serial.println("");
//  Serial.println(optime);

}

Serial_COM_sensor.ino (4.06 KB)

data = String(data_array[2,3,4,5,6,7,8,9], HEX);

Where have you seen that syntax? :o

void setup() {
  Serial.begin(9600);
  while (!Serial);
  char* input = "C90000E8E533";
  unsigned long runtime = strtoul(&input[2], NULL, 16);  //prints 15263027
  Serial.println(runtime);

}

void loop() {}

AWOL:

data = String(data_array[2,3,4,5,6,7,8,9], HEX);

Where have you seen that syntax? :o

Don't know anymore, I googled so much, copy pasted so much things to try out I lost track...

I also had this, als found that somewhere:
data = String(data_array[2]+data_array[3]+data_array[4]+data_array[5]+data_array[6]+data_array[7]+data_array[8]+data_array[9], HEX);

jremington:

void setup() {

Serial.begin(9600);
 while (!Serial);
 char* input = "C90000E8E533";
 unsigned long runtime = strtoul(&input[2], NULL, 16);  //prints 15263027
 Serial.println(runtime);

}

void loop() {}

I have some luck if I modify it a little bit:

void setup() {
Serial.begin(115200);
}

void loop() {
  char* input = "C90000E8E533";
  unsigned long runtime = strtoul(&input[2], NULL, 16);  //prints 15263027
  Serial.println(runtime);
  char* input2 = "0000E8E5";
  unsigned long runtime2 = strtoul(&input2[0], NULL, 16);  //prints 59621
  Serial.println(runtime2);
  delay(5000);
  }

How can we get 59621 without modifying the char* input array like I did with input2?

The first input starts from the third row, which is good, but also uses row 11 and 12 which is not good, this is the checksum. Can we explane to strtoul we only want to use row 3 till 10? Or should we generate/trim the array from C90000E8E533 to 0000E8E5?

Don't include the 0x33 in the input array, or terminate the array by writing zero to the presumed final byte.

Look for the list of methods associated with the String class of arduino. Google "arduino Stringobject"

String data = string (input) ;
int leng = data.length();
String sub data = data.substring (2,leng-1);

Avoid the String class on standard Arduino, it causes memory problems and program crashes.

void setup() {
  Serial.begin(9600);
  while (!Serial);
  char input[] = "C90000E8E533";
  unsigned long runtime = strtoul(&input[2], NULL, 16);
  Serial.println(runtime);

  char copy[10];
  memcpy(copy, &input[2], 8);  //make a copy
  copy[8] = 0; //terminate it
  Serial.println(strtoul(copy, NULL, 16));

  input[10] = 0; //terminate original string early
  Serial.println(strtoul(&input[2], NULL, 16));
}

void loop() {}

Output:
15263027
59621
59621

@OP

Accepting the fact that your serial sensor transmits this/similar transmission frame (C90000E8E533) towards Arduino, the following sketch receives the frame correctly, recomputes the CHKSUM for data validity and then shows the decimal value of your 'useful data: 0000E8E5' on the Serial Monitor.

Receiver Codes:

#include<SoftwareSerial.h>
SoftwareSerial SUART(8, 9);  //SRX, STX
bool flag1 = false;
int i = 0;
byte sum = 0;
byte myData[5];

void setup()
{
  Serial.begin(115200);
  SUART.begin(115200);
}

void loop()
{
  byte n = SUART.available();
 // Serial.println(n);
  if (n != 0)
  {
    byte x = SUART.read();
    if (flag1 == false)
    {
      if (x == 0xC9) //identifier found
      {
        flag1 = true;
      }
    }
    else
    {
      myData[i] = x;
      i++;
      if(i == 5)
      {
        //compute CHKSUM and check data validity
        for(int j =0; j<4; j++)
        {
          sum += myData[j]; 
        }
        sum =~sum;
        sum++;
        //Serial.println(sum, HEX);
        if(sum == myData[4])
        {
          Serial.println("Received data is good...!");
          Serial.print("Runtime : ");
          uint32_t x =  (uint32_t)myData[0]<<24|(uint32_t)myData[1]<<16|
                        (uint32_t)myData[2]<<8|(uint32_t)myData[3];
          Serial.println(x, DEC);
          i=0;
          sum = 0;
          flag1 = false;
        }
      }
    }
  }
}

Simulated Serial Sensor Codes:

#include<SoftwareSerial.h>
SoftwareSerial SUART(8, 9);  //SRX, STX
byte myData[] = {0xC9, 0x00, 0x00, 0xE8, 0xE5, 0x33};
void setup()
{
  Serial.begin(115200);
  SUART.begin(115200);
}

void loop()
{
  SUART.write(myData, sizeof(myData));
  for(int i= 0; i<6; i++)
  {
    Serial.print(myData[i], HEX);
  }
  Serial.println();
  delay(1000);
}

The Screenshot:
sm93.png

sm93.png

jremington:

void setup() {

Serial.begin(9600);
 while (!Serial);
 char input[] = "C90000E8E533";
 unsigned long runtime = strtoul(&input[2], NULL, 16);
 Serial.println(runtime);

char copy[10];
 memcpy(copy, &input[2], 8);  //make a copy
 copy[8] = 0; //terminate it
 Serial.println(strtoul(copy, NULL, 16));

input[10] = 0; //terminate original string early
 Serial.println(strtoul(&input[2], NULL, 16));
}

void loop() {}




Output:
15263027
59621
59621

Got some luck with this code, thanks!

@GolamMostafa I'll have a look at your code, but I'm not a pro, so probably I won't understand it completely.

Knipsel.PNG

Tried to fetch some more data, like battery voltage, temperature 1 and 2. I have it working, but I doubt the code is not dirty.

void volt_temp()
{
  // example data CC 01 E6 53 53 32
  char voltagearr[10]; // 01 E6
  memcpy(voltagearr, &data_array[2], 8);  //make a copy
  voltagearr[4] = 0; //terminate it
  voltage = strtoul(voltagearr, NULL, 16);
  float voltagef = voltage;
  Serial.print("Battery voltage: ");
  Serial.println(voltagef * 0.018369);

  char temp1arr[10]; // 53
  memcpy(temp1arr, &data_array[6], 8);  //make a copy
  temp1arr[2] = 0; //terminate it
  temp1 = strtoul(temp1arr, NULL, 16);
  float temp1f = temp1;
  Serial.print("Temp 1: ");
  Serial.println((temp1f / 2) - 20);

  char temp2arr[10]; // 53
  memcpy(temp2arr, &data_array[8], 8);  //make a copy
  temp2arr[2] = 0; //terminate it
  temp2 = strtoul(temp2arr, NULL, 16);
  float temp2f = temp2;
  Serial.print("Temp 2: ");
  Serial.println((temp2f / 2) - 20);
}

GolamMostafa:
@OP

Accepting the fact that your serial sensor transmits this/similar transmission frame (C90000E8E533) towards Arduino, the following sketch receives the frame correctly, recomputes the CHKSUM for data validity and then shows the decimal value of your 'useful data: 0000E8E5' on the Serial Monitor.

...

Tried your code as well. I only think it's already converting incoming data to DEC?
When I run my command to fetch running time I get: 6026757484848485153655749693
If I change byte x = SUART.read(); to char x = SUART.read(); we get more readable results.

Only It plots weird characters, I think the CLRF / STX / ETX characters. Is that possible?

You probably should not be copying 8 bytes of data if only 4 are of interest.

  memcpy(voltagearr, &data_array[2], 8);  //make a copy
  voltagearr[4] = 0; //terminate it

jremington:
You probably should not be copying 8 bytes of data if only 4 are of interest.

  memcpy(voltagearr, &data_array[2], 4);  //make a copy

voltagearr[4] = 0; //terminate it

That's should do the trick I guess?

He is getting 4 bytes out - but he does need 8 characters, since it's hex so each byte is represented by two characters....

He is getting 4 bytes out - but he does need 8 characters, since it's hex so each byte is represented by two characters.

Perhaps, but in that case the code should look like this:

  memcpy(voltagearr, &data_array[2], 8);  //make a copy
  voltagearr[8] = 0; //terminate it