Convert an array of char (HEX) into a decimal float value for math operations

Hi all,
I am reading a load cell with a RS485 communication back to my arduino mega UART (Serial 1 using an RS485-TTL logic converter). It looks like everything is working properly; everytime I sent out a particular string ({0x20, 0x03, 0x00, 0x00, 0x00, 0x02, 0xC2, 0xBA}), I get another string back that contains the weight I wanna read. Within this string, 4 bytes particularly tells you the value of the load cell weight.
I managed to read the string back and isolating the 4 bytes that contain the weight info. Unfortunately I am not able to convert this HEX weight into a decimal value.
I am using strtol function for the conversion; however I am getting a float value that is 0.
Any tips on what I am doing wrong?

The code is the following:

#define TIME_BETWEEN_COMMANDS 500
byte RT = 37;
boolean newData_LoadCell = false;
int num_LoadCell;
int incomingByte;
const unsigned int MAX_MESSAGE_LENGTH = 9;
char receivedChars_LoadCell[MAX_MESSAGE_LENGTH];
char Weight[MAX_MESSAGE_LENGTH] ;
int i;
int j;

char TimeBefore_LoadCell = false;
unsigned long CurrentTime_LoadCell;
enum ReceiveTaskState_LoadCell {
  WAIT,
  SEND_COMMAND,
  RECEIVE_RESPONSE
};


void setup() {
  pinMode (RT, OUTPUT);
  Serial.begin(9600);
  Serial1.begin(9600);

}

void loop() {

  if (Serial.available() >= 0) {
    incomingByte = Serial.read();
  }

  if (incomingByte == '0') { //pressing 0 to stop the serial
    while (1) { }
  }

  if (TimeBefore_LoadCell == false) {
    CurrentTime_LoadCell = millis();
    TimeBefore_LoadCell = true;
  }
  LoadCell();
}

void LoadCell() {

  static enum ReceiveTaskState_LoadCell currentReceiveState_LoadCell = WAIT;

  switch (currentReceiveState_LoadCell) {
    case WAIT:
      if (millis() - CurrentTime_LoadCell > 500) {
        currentReceiveState_LoadCell = SEND_COMMAND;
      }
      break;

    case SEND_COMMAND:
      digitalWrite(37, HIGH);
      Serial1.write(0x20);
      Serial1.flush();
      Serial1.write(0x03);
      Serial1.flush();
      Serial1.write(0x00);
      Serial1.flush();
      Serial1.write(0x00);
      Serial1.flush();
      Serial1.write(0x00);
      Serial1.flush();
      Serial1.write(0x02);
      Serial1.flush();
      Serial1.write(0xC2);
      Serial1.flush();
      Serial1.write(0xBA);
      Serial1.flush();
      currentReceiveState_LoadCell = RECEIVE_RESPONSE;
      break;

    case RECEIVE_RESPONSE:
      digitalWrite(37, LOW);
      if (Serial1.available() > 0) {
        recvWeight();  //receive the string and print it
        if (newData_LoadCell == true) {
          parseData_LoadCell();
          newData_LoadCell = false;
        }
        currentReceiveState_LoadCell = WAIT;
        TimeBefore_LoadCell = false;
      }
      break;
  }
}

void recvWeight() {

  static byte ndx_LoadCell = 0;

  while (Serial1.available() > 0 && newData_LoadCell == false) {
    byte rc_LoadCell = Serial1.read();
    Serial.print(rc_LoadCell, HEX);
    Serial.print("\t");
    Serial.println(ndx_LoadCell);

    if ((ndx_LoadCell < MAX_MESSAGE_LENGTH - 1 )) {
      receivedChars_LoadCell[ndx_LoadCell] = rc_LoadCell;
      ndx_LoadCell++;
    }
    else {
      receivedChars_LoadCell[8] = rc_LoadCell; // terminate the string
      ndx_LoadCell = 0;
      newData_LoadCell = true;
    }
  }
  Weight[0] = {receivedChars_LoadCell[5]};
  Weight[1] = {receivedChars_LoadCell[6]};
  Weight[2] = {receivedChars_LoadCell[3]};
  Weight[3] = {receivedChars_LoadCell[4]};
  Weight[4] = {'\0'};
}

void printHex(uint8_t num) {
  char hexCar[2];
  sprintf(hexCar, "%02X", num);
  Serial.print(hexCar);
}

void parseData_LoadCell() {      

  for (j = 0; j < 4; j++) {
    printHex(Weight[j]);
  }

  int x;
  char *endptr;

  x = strtol(Weight, &endptr, 16);
  Serial.println(x, HEX);
  Serial.println(x, DEC);  
}

Digital output 37 is used to switch between writing and reading within RS485 communication.

Don't you think it would be helpful to provide us with a complete description of the communication protocol and a sample of the returned data?

Hi @Diego .
in this line " Serial.print(hexCar); " do the printed values exactly match the individual digits of the measured weight?
Can you show how they appear on the serial monitor?

RV mineirin

It would not be HEX, whatever you think that might be. The bytes contain binary values.

yes you are right. Sorry about that

As you can see I am getting 9 bytes back and particularly byte 6,7,4,5 correspond to the weight.
In this case info about weight is 7D3 (2003 in decimal) since 20 grams were placed on the load cell. Output is with 2 decimal digits without taking into account the dot; therefore it was 20.03 grams.
When I try to convert the char array 000007D3 into a decimal I don't get any output

Post a description of the protocol, as requested earlier.

The bytes in question could be a 32 bit floating point number, and there are several ways of converting that. However, the byte order could be reversed from Arduino.

the only description of the protocol i could find is the following:



It is more or less what I was saying above.

Rearranging the byte order like this is unlikely to work, and just confuses the issue.

  Weight[0] = {receivedChars_LoadCell[5]};
  Weight[1] = {receivedChars_LoadCell[6]};
  Weight[2] = {receivedChars_LoadCell[3]};
  Weight[3] = {receivedChars_LoadCell[4]};

Please print out each byte of the received message, in the order received, using Serial.print(byte, HEX);

I think the problem is that the message is NOT a character array. It is four bytes of binary: 0x07D30000. You are re-arranging the binary bytes into 0x000007D3 and adding a null terminator but now your 'string' starts with a null character and therefor has length 0:
char Weight[] = {0x00, 0x00, 0x07, 0xD3, 0x00};

I think you want to take the two words of the value and put them in a 32-bit integer.

  uint32_t weight = *(uint16_t *) &receivedChars_LoadCell[5];
  weight <<= 16;
  weight +=  *(uint16_t *) &receivedChars_LoadCell[3];
  Serial.println(weight);  // Raw binary value
  Serial.println(weight / 100.0);  // Weight in grams

Hi @johnwasser , it works, thank you!!. you were right, message was not a character array.
Anyway, now my only problem is that I am getting the wrong integer value.
As you can see, I am receiving correctly the bytes back. On the weight scale i have 1020.15 g. Therefore the HEX code to convert in decimal should be 18E7F (my order should be byte 5--> byte 6- --> byte 3 --> byte 4).
However, result I am getting is 16809614 that is ( byte 6 --> byte 5 --> byte 4 --> byte 3). How can I modify it to get the right value?
It's not really clear to me the logic you are applying, can you please explain it to me? sorry about it. Are you creating an integer of 32 bit right? how are you creating the integer using a pointer and a bit mask?

Serial

Store the bytes in a 32-bit variable in the order you want.

  union {
    unsigned long value;
    byte b[4];
  } weight;

  weight.b[3] = receivedChars_LoadCell[5];
  weight.b[2] = receivedChars_LoadCell[6];
  weight.b[1] = receivedChars_LoadCell[3];
  weight.b[0] = receivedChars_LoadCell[4];

  Serial.println(weight.value);
  Serial.println(weight.value / 100.0);

Byte indices 5, 6, 3, 4 of the message shown in the photo are 00 01 8e 73 when properly rearranged, which is 102014 decimal, or 1020.14 g

Please DO NOT post photos of text output. Cut and paste instead.

It looks like available the needed data from the image.
Isn't it a byte order issue?
I think my code above will give the correct value.

EDIT:
@jremington
You made edits while I wrote, This post wrote to the unedited your post.

Furthermore, the value is misunderstood even after editing.
7E are shown in the image. Not 73.

Hi @Diego .
I don't know if I'm correct but I found the following values:

RV mineirin

byte 5 00
byte 6 01
byte 3 8E
byte 4 7E

0001 8E7E =~ 18E7F

This changes to:

  uint32_t weight = receivedChars_LoadCell[5];
  weight <<= 8;
  weight +=  receivedChars_LoadCell[6];
  weight <<= 8;
  weight +=  receivedChars_LoadCell[3];
  weight <<= 8;
  weight +=  receivedChars_LoadCell[4];
  Serial.println(weight);  // Raw binary value
  Serial.println(weight / 100.0);  // Weight in grams

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