Help Reading Hexdecimal

Hi all! I'm in the process of building an OBD reader using FlexCan and I've got most of it working, but I'm really struggling with reading fault codes. I think my reader may be working, but when I try and read what's coming in in each of the CAN message buffers I'm just getting random symbols or unknown character squares in the Serial reader.

What I'm doing is using this code to request a MODE 3 (fault code) message from the CAN simulator I have:

CAN_Request(MODE3,0);  //Read Trouble Codes

Which runs this function:

void CAN_Request(byte CAN_MODE, byte PID_CALL) {
  can_MsgTx.buf[0] = 0x01;
  can_MsgTx.buf[1] = CAN_MODE;           //03 for Mode 3 request
  can_MsgTx.buf[2] = PID_CALL;             //0 for Mode 3 request
  can_MsgTx.buf[3] = 0;
  can_MsgTx.buf[4] = 0;
  can_MsgTx.buf[5] = 0;
  can_MsgTx.buf[6] = 0;
  can_MsgTx.buf[7] = 0;
  can_MsgTx.len = 8;
  //can_MsgTx.ext = 0;
  can_MsgTx.flags.extended = 0;
  can_MsgTx.flags.remote = 0;
  can_MsgTx.id = PID_REQUEST;              //PID_REQUEST    =     0x7DF
  //  can_MsgTx.timeout = 500;
  Can0.write(can_MsgTx);
}

So the message constructed should read:

7df 8 01 03 00 00 00 00 00 00

I then should get the following response from the simulator:

7e8 8 06 43 02 01 00 02 00 00

This is received using this call:

int CAN_Receive(byte PID_RESPONSE) {          //PID_REPLY     =      0x7E8
  while (Can0.available())
  {
    Can0.read(can_MsgRx);
    if (can_MsgRx.buf[1] == MODE3_RESPONSE) {       //MODE3_RESPONSE   =   0x43
      DTC = can_MsgRx.buf[3];
      Serial.println(can_MsgRx.buf[1]);
      Serial.println(DTC);
      return can_MsgRx.buf[3];// & can_MsgRx.buf[4] & can_MsgRx.buf[5];
    }
   }
}

I am seeing two repeating characters on the Serial print, the first says 67, which when converted to Hex is 43, which is the correct response as per what I'm expecting above. The second character is a square "unknown character" symbol in the serial print, and when shown on my OLED display it comes up as a sad face icon - how apt!

I think then I might be getting the right response but I'm not reading it correctly. I need to get it into hex format as the response code should read as follows:

43 = MODE 3 response 02 = 2 fault codes flagged 01 added to 00 = P0100 fault code (Mass airflow sensor fault) 02 added to 00 = P0200 fault code (fuel injector fault)

So does anyone see what I'm doing wrong here?

can_MsgRx.buf[1] is what type of variable?

DTC is what type of variable?

Presently DTC is “byte”
can_MsgRx.buf[1] I’m not sure, I think it comes from the FlexCan library. I don’t see it in the library though… Will keep digging to see where it’s defined.

The code that you are showing is not able to print out multiple bytes and it does read in only one byte.

So for a deeper analysis post your hole sketch. If your sketch has more than 8000 characters post the sketch as attachment.

Sure, see attachment for the full sketch. There’s a lot of other stuff in there, but the CAN functions are clustered from line 1444. The MODE1 (PID) requests all work, just MODE 3 does not. I request on line 1456, which triggers function “CAN_Request” on line 1496 then the receive code is triggered with line 1492 which receives with the function starting line 1515.

Hopefully that all makes sense!

RocketDash.ino (55.4 KB)

Serial.println(DTC, HEX);

Does this fix it?

It does! What a great function... Do I use ", HEX" in the same way when assigning the incoming information to a variable e.g.:

DTC = (can_MsgRx.buf[3], HEX) ?

Also, for the single digit decimals like 1, how do I get it to show as 01 instead of just 1, so I can construct two together to make 0100 for example

450nick: It does! What a great function... Do I use ", HEX" in the same way when assigning the incoming information to a variable e.g.:

DTC = (can_MsgRx.buf[3], HEX) ?

Also, for the single digit decimals like 1, how do I get it to show as 01 instead of just 1, so I can construct two together to make 0100 for example

No, this is part of the Steam class/ Serial.print method. Read the reference and then ask your questions.

Ok that's a useful post thanks for sharing. So is there a simple way to strip each of the two hex values as ASCII characters that I can use to work out what my message is?

If you want to convert the two hex digits in a byte into ASCII:

byte data = 0xA7;
char highNibble, lowNibble;

if ((data & 0x0F) > 9)
   lowNibble = (data & 0x0F) + 'A';  // Use 'a' if you want lowercase
else
   lowNibble = (data & 0x0F) + '0';

if (((data >> 4) & 0x0F) > 9)
  highNibble = ((data >> 4) & 0x0F) + 'A';  // Use 'a' if you want lowercase
else
   highNibble = ((data >> 4) & 0x0F) + '0';

Ok I realised that actually I need to keep the whole packet together, so I’ve rewritten it like this and it seems to work well, can you see any improvements to be gained?

    if (can_MsgRx.buf[1] == MODE3_RESPONSE) {
      int numDTCs = can_MsgRx.buf[2];
      int DTC1Raw;
      int DTC2Raw;
      char DTC1 [5];
      char DTC2 [5];
      
      if (numDTCs > 0) {
        int DTCp1 = can_MsgRx.buf[3];
        int DTCp2 = can_MsgRx.buf[4];
        if (DTCp1 < 10) DTC1Raw = (DTCp1 * 100) + DTCp2;
        else DTC1Raw = (DTCp1 * 1000) + DTCp2;
        sprintf (DTC1, "P%04u", DTC1Raw);
      }
      else sprintf (DTC1, "0");
      
      if (numDTCs > 1) {
        int DTCp1 = can_MsgRx.buf[5];
        int DTCp2 = can_MsgRx.buf[6];
        if (DTCp1 < 10) DTC2Raw = (DTCp1 * 100) + DTCp2;
        else DTC2Raw = (DTCp1 * 1000) + DTCp2;
        sprintf (DTC2, "P%04u", DTC2Raw);
      }
      else sprintf (DTC2, "0");

      Serial.println(numDTCs);
      Serial.println(DTC1);
      Serial.println(DTC2);
      return numDTCs;
    }