Arduino CanBus data HEX to DEC

Hello,

The project is to decode with a CAN bus data received by a sensor via an Arduino Mega card.
I have the following program everything works I can read the data frames in Hexadecimal.

What I want is to isolate in this frame the bytes 1-2 (humidity) 3-4 (temperature) 5-6 (C02) currently in hex
and convert them in real time to decimal

I am interested here to replace for example the "9C 25" by 22 degrees converted into decimal, it is necessary to reverse in "25 9C" because of the MSB LSB also.

I saw on the internet that there would be functions like strtoul() by writing this way " nResult= (nResult << 8) | (strtoul(pch, NULL, 16) & 0xff); "
but I don't really understand.

My actual code :

#include <SPI.h>
#include <SD.h>
#include <mcp_can.h>
#include "mcp2515_can.h"

File myFile;

#define CAN_2515

const int SPI_CS_PIN = 53;
const int CAN_INT_PIN = 2;

mcp2515_can CAN(SPI_CS_PIN); // Set CS pin

unsigned char flagRecv = 0;
unsigned char len = 0;
unsigned char buf[8];
char str[20];


void setup() 
{
    SERIAL_PORT_MONITOR.begin(115200);                                              // screen rate Arduino monitor
    attachInterrupt(digitalPinToInterrupt(CAN_INT_PIN), MCP2515_ISR, FALLING);      // start interrupt
    
    while (CAN_OK != CAN.begin(CAN_500KBPS))                                        // init can bus : baudrate = 500k
    {                                      
    SERIAL_PORT_MONITOR.println("CAN init fail, retry...");
    delay(100);
    }
    SERIAL_PORT_MONITOR.println("CAN init ok!");
    
    if (!SD.begin(4)) 
    {
        SERIAL_PORT_MONITOR.println("SD init fail!");
        while (1);
    }
    SERIAL_PORT_MONITOR.println("SD init OK.");
}

void MCP2515_ISR() { flagRecv = 1;}

void loop() {
    if (flagRecv) {                     // check if get data

        flagRecv = 0;                   // clear flag
        unsigned long id = 0; 

        myFile = SD.open("can.csv", FILE_WRITE);

            while (CAN_MSGAVAIL == CAN.checkReceive()) {
            CAN.readMsgBufID(&id, &len, buf);       // read data,  len: data length, buf: data buf

            SERIAL_PORT_MONITOR.print(id);
            SERIAL_PORT_MONITOR.print(",");
            
            myFile.print(id);
            myFile.print(",");

            for (int i = 0; i < len; i++) {
              
                SERIAL_PORT_MONITOR.print(buf[i]);
                SERIAL_PORT_MONITOR.print(",");

                myFile.print(buf[i]);
                myFile.print(",");

       }
            SERIAL_PORT_MONITOR.println();
            myFile.println();
        }

        myFile.close();
    }
}

// END FILE

Look forward to your replies, thanks.

#include <SPI.h>
#include <SD.h>
#include <mcp_can.h>
#include "mcp2515_can.h"

File myFile;

#define CAN_2515

const int SPI_CS_PIN = 53;
const int CAN_INT_PIN = 2;

mcp2515_can CAN(SPI_CS_PIN); // Set CS pin

unsigned char flagRecv = 0;
unsigned char len = 0;
unsigned char buf[8];
char str[20];


void setup() {
  SERIAL_PORT_MONITOR.begin(115200);                                              // screen rate Arduino monitor
  attachInterrupt(digitalPinToInterrupt(CAN_INT_PIN), MCP2515_ISR, FALLING);      // start interrupt

  while (CAN_OK != CAN.begin(CAN_500KBPS)) {                                      // init can bus : baudrate = 500k
    SERIAL_PORT_MONITOR.println("CAN init fail, retry...");
    delay(100);
  }
  SERIAL_PORT_MONITOR.println("CAN init ok!");

  if (!SD.begin(4))  {
    SERIAL_PORT_MONITOR.println("SD init fail!");
    while (1);
  }
  SERIAL_PORT_MONITOR.println("SD init OK.");
}

void MCP2515_ISR() {
  flagRecv = true;
}

void loop() {
  if (flagRecv) {                     // check if get data
    flagRecv = false;                   // clear flag
    unsigned long id = 0;

    while (CAN_MSGAVAIL == CAN.checkReceive()) {
      CAN.readMsgBufID(&id, &len, buf);       // read data,  len: data length, buf: data buf

      myFile = SD.open("can.csv", FILE_WRITE);
      myFile.print(id);
      myFile.print(",");

      for (int i = 0; i < len; i++) {
        myFile.print(buf[i]);
        myFile.print(",");
      }
      myFile.println();
      myFile.close();

      SERIAL_PORT_MONITOR.print(id);
      SERIAL_PORT_MONITOR.print(",");

      SERIAL_PORT_MONITOR.print(16 * buf[1] + buf[0], DEC);
      SERIAL_PORT_MONITOR.print(",");
      SERIAL_PORT_MONITOR.print(16 * buf[3] + buf[2], DEC);
      SERIAL_PORT_MONITOR.print(",");
      SERIAL_PORT_MONITOR.print(16 * buf[5] + buf[4], DEC);
      SERIAL_PORT_MONITOR.println();
    }
  }
}// END FILE

Thx Kolaha , but how can I retrieve the decimal value of this line of code in order to convert it by doing: "decimal value "x scale + offset

SERIAL_PORT_MONITOR.print(16 * buf[3] + buf[2], DEC);
                  SERIAL_PORT_MONITOR.print(",");

Thx so mutch for your help.

mark my sketch as solution

I don't see in sketch any "x scale" or "offset"

1 Like

yes I used your code but I miss a step before finishing, how to recover the decimal value of bytes 3 2 ? maybe " comment at the bottom of the code ".

Cordially.


#include <SPI.h>
#include <SD.h>
#include "mcp2515_can.h"

File myFile;

#define CAN_2515

const int SPI_CS_PIN = 53;
const int CAN_INT_PIN = 2;

mcp2515_can CAN(SPI_CS_PIN); // Set CS pin

unsigned char flagRecv = 0;
unsigned char len = 0;
unsigned char buf[8];
char str[20];

int Offset = 273 ;
int Scale = 0.3125 ;

void setup() 
{
    SERIAL_PORT_MONITOR.begin(115200);                                              // screen rate Arduino monitor
    attachInterrupt(digitalPinToInterrupt(CAN_INT_PIN), MCP2515_ISR, FALLING);      // start interrupt
    
    while (CAN_OK != CAN.begin(CAN_500KBPS))                                        // init can bus : baudrate = 500k
    {                                      
    SERIAL_PORT_MONITOR.println("CAN init fail, retry...");
    delay(100);
    }
    SERIAL_PORT_MONITOR.println("CAN init ok!");
    
    if (!SD.begin(4)) 
    {
        SERIAL_PORT_MONITOR.println("SD init fail!");
        while (1);
    }
    SERIAL_PORT_MONITOR.println("SD init OK.");
}

void MCP2515_ISR() { flagRecv = 1;}

void loop() {
    if (flagRecv) {                     // check if get data

        flagRecv = 0;                   // clear flag
        unsigned long id = 0; 

            while (CAN_MSGAVAIL == CAN.checkReceive()) {
            CAN.readMsgBufID(&id, &len, buf);       // read data,  len: data length, buf: data buf
            
            myFile = SD.open("can.csv", FILE_WRITE);
            myFile.print(id);
            myFile.print(",");
            
                for (int i = 0; i < len; i++) {
                myFile.print(buf[i]);
                myFile.print(",");
                }

                myFile.println();
                myFile.close();
                 
                  SERIAL_PORT_MONITOR.print(id);
                  SERIAL_PORT_MONITOR.print(",");

                  SERIAL_PORT_MONITOR.print(16 * buf[1] + buf[0], DEC);
                  SERIAL_PORT_MONITOR.print(",");
                  
                  SERIAL_PORT_MONITOR.print(16 * buf[3] + buf[2], DEC);
                  SERIAL_PORT_MONITOR.print(",");

                  // i want to do this conversion " Temperature = Value DEC buf[3]+buf[2] x Scale - Offset "  but how can i retrieve the value of byte 3 2 DEC to do that.
                  
                  SERIAL_PORT_MONITOR.print(16 * buf[5] + buf[4], DEC);
                  SERIAL_PORT_MONITOR.println();
    }
  }
}// END FILE

mark as solution

SERIAL_PORT_MONITOR.print( buf[3], DEC);
SERIAL_PORT_MONITOR.print( buf[2], DEC);

Can i do to convert my decimal value ? :

A = SERIAL_PORT_MONITOR.print(16 * buf[3] + buf[2], DEC);
Temperature = A x Scale + Offset;
SERIAL_PORT_MONITOR.println();

I mark you as solution after that of course

unsigned int A = 16 * buf[3] + buf[2];
Temperature = A * Scale + Offset;
SERIAL_PORT_MONITOR.println();
1 Like

Hello,

The project is to decode with a CAN bus data received by a sensor via an Arduino Mega card.
I have the following program everything works I can read the data frames in Hexadecimal.

What I want is to isolate in this frame the bytes 1-2 (humidity) 3-4 (temperature) 5-6 (C02) currently in hex and convert them in real time to decimal :

for exemple i receive :

" Get data from ID: 0x18FF0AEB
-> 5D AF 9C 25 64 0 64 0 "

I am interested here to replace for example the "9C 25" by 22 degrees converted into decimal, it is necessary to reverse in "25 9C" because of the MSB LSB also.

but I don't really understand how to to that

My actual code :

#include <SPI.h>
#include "mcp2515_can.h"
#define CAN_2515

const int SPI_CS_PIN = 53;
const int CAN_INT_PIN = 2;
mcp2515_can CAN(SPI_CS_PIN); 
                         
void setup() {
    SERIAL_PORT_MONITOR.begin(115200);

    while (CAN_OK != CAN.begin(CAN_500KBPS)) {             // init can bus : baudrate = 500k
        SERIAL_PORT_MONITOR.println("CAN init fail, retry...");
        delay(100);
    }
    SERIAL_PORT_MONITOR.println("CAN init ok!");
}


void loop() {
    unsigned char len = 0;
    unsigned char buf[8];

    if (CAN_MSGAVAIL == CAN.checkReceive()) {         // check if data coming
        CAN.readMsgBuf(&len, buf);    // read data,  len: data length, buf: data buf

        unsigned long canId = CAN.getCanId();

        SERIAL_PORT_MONITOR.println("-----------------------------");
        SERIAL_PORT_MONITOR.print("Get data from ID: 0x");
        SERIAL_PORT_MONITOR.println(canId, HEX);

        for (int i = 0; i < len; i++) { // print the data
            SERIAL_PORT_MONITOR.print(buf[i], HEX);
            SERIAL_PORT_MONITOR.print("\t");
        }
        SERIAL_PORT_MONITOR.println();
    }
}

Thx for your help :slight_smile:

I don't understand how 22 is represented by this HEX number. Can you explain?

this appears to be a copy of this arduino-canbus-data-hex-to-dec post

yeah , 9𝐢 25 = 𝑏𝑦𝑑𝑒𝑠 34 they are reverse LSB MSB so 43 = 0π‘₯259𝐢 = πŸ—πŸ”πŸπŸ– in decimal

temperature = decimal value ×𝑺𝒄𝒂𝒍𝒆+𝑢𝒇𝒇𝒔𝒆𝒕

For our test we obtain: 9628 Γ—0.3125 βˆ’273=πŸπŸ• °𝐂

The average ambient temperature being 22 degrees, it is possible that the electronic components of the sensor heat up during the test time.

yes but this solution gives me weird values ​​like:

419367915,3011,686,198

i dont understand because in hexa i have > AE 92 25 10 07 5F

with this part of code :

SERIAL_PORT_MONITOR.print(id);
                  SERIAL_PORT_MONITOR.print(",");

                  SERIAL_PORT_MONITOR.print(16 * buf[1] + buf[0], DEC);
                  SERIAL_PORT_MONITOR.print(",");
                  
                  SERIAL_PORT_MONITOR.print(16 * buf[3] + buf[2], DEC);
                  SERIAL_PORT_MONITOR.print(",");
                  
                  int A = 16 * buf[3] + buf[2];
                  int Temperature = A * Scale - Offset;
                  SERIAL_PORT_MONITOR.println();
                  
                  SERIAL_PORT_MONITOR.print(16 * buf[5] + buf[4], DEC);
                  SERIAL_PORT_MONITOR.println();

any idea what device is the termperature sensor sending data via canbus?
any idea what was the original temperature which gave a readings of "9C 25"?

To resume i have a Sparkfun Canbus Shield plug on a Arduino Mega and i have my sensor TR connected on the canbus shield.

Basically i just want to change my HEX data to Dec data to convert quickly.

0x259C ----> 27

Given below a Counting Method (Positional Factors are being multiplied by the corresponding Positional Weights) to convert the given hex number into decimal number.

byte myDigit[4];
int i = 0;

void setup()
{
  Serial.begin(9600);
  int y = 0x259C;
  do
  {
    myDigit[i] = y % 10;  //getting the decimal digits of the target decimal number: 8 2 6 9
    y = y / 10;
    i++;
  }
  while (y != 0);

  unsigned int myDec = myDigit[3] * 1000 + myDigit[2] * 100
                       + myDigit[1] * 10 + myDigit[0] * 1;
  myDec = (int)(myDec * 0.3125 - 273)/100;
  Serial.println(myDec);  //shows: 27
}

void loop() {}
1 Like

something like this maybe...

void setup() {
  uint8_t sample_data[8] ={0x5D, 0xAF, 0x9C, 0x25, 0x64, 0x00, 0x64, 0x00};

  Serial.begin(115200);

  uint16_t temp_raw;
  memcpy(&temp_raw, &sample_data[2],2);

  Serial.print("0x");
  Serial.println(temp_raw,HEX);
  Serial.println(temp_raw,DEC);

  float temp_degC = ((temp_raw * 0.3125) - 273)/100;

  Serial.println(temp_degC,2);

}

void loop() {

  // put your main code here, to run repeatedly:

}

Output:

0x259C
9628
27.36

hope that helps...

1 Like

An elegant approach (compared to % and / operation of post #8) who knows about the memcpy() function.

In school, the beginners like the % and / operation as the they face difficulties to understand the bureaucratic syntax of the memcpy() function.

void *memcpy(void *dest, const void * src, size_t n)
1 Like
uint8_t sample_data[8] ={0x5D, 0xAF, 0x9C, 0x25, 0x64, 0x00, 0x64, 0x00}; < this value updates all the time

This frame that I gave you is updated in real time in my monitor in the buf[i] ,
do you know if it is possible to replace buf[i] with your uint8_t sample_data[8] in your code?

And place your code in this loop of my code to have the concersion in decimal in real time :

for (int i = 0; i < len; i++) { // print the data
            SERIAL_PORT_MONITOR.print(buf[i], HEX);
            SERIAL_PORT_MONITOR.print("\t");
        }

thank you very much for your help ^^