Parsing data in this project

Hello all,

I am working on a CAN bus project, using an arduino nano and can bus module based on the MCP2515 chip. I am using the filtering example, and the can bus message prints out nicely in the serial monitor. In this project, another device is sending can data with ID 0x101 and outputs (battery current) on byte0 and byte1. I can configure whether it's in Big endian or little endian format, right now it's in big endian by default.

I have been doing a lot of research trying to learn all of this and how it works. The library example seems to parse the data into an unsigned char. There's 8 bytes total in this message, but if I learn how to do this I can replicate with the other bytes!

So from what I understand, I'll need to "stick together" byte0 and byte1, and then convert that to an int. From there I can divide by 10 to get the true value. I feel like this is where I would need to use highByte() and lowByte() functions, but not sure how to use them. I'm also not sure how to convert it as a char to an int so I can divide it.

Any help would be greatly appeciated! I can feel like I have the right idea, but I am just missing a few pieces so can bridge this stuff together.

Thank you so much, and stay safe! I'll attach the example code I am using below

EDIT: The other device's can messages are actually Big endian by default.

// MCP2515 Mask and Filter example for standard CAN message frames.
// Written by Cory J. Fowler (20140717)

/***********************************************************************************
If you send the following standard IDs below to an Arduino loaded with this sketch
you will find that 0x102 and 0x105 will not get in.

ID in Hex  -   Two Data Bytes!   -  Filter/Mask in HEX
   0x100   + 0000 0000 0000 0000 =   0x01000000
   0x101   + 0000 0000 0000 0000 =   0x01010000
   0x102   + 0000 0000 0000 0000 =   0x01020000  This example will NOT be receiving this ID
   0x103   + 0000 0000 0000 0000 =   0x01030000
   0x104   + 0000 0000 0000 0000 =   0x01040000
   0x105   + 0000 0000 0000 0000 =   0x01050000  This example will NOT be receiving this ID
   0x106   + 0000 0000 0000 0000 =   0x01060000
   0x107   + 0000 0000 0000 0000 =   0x01070000

   This mask will check the filters against ID bit 8 and ID bits 3-0.   
    MASK   + 0000 0000 0000 0000 =   0x010F0000
   
   If there is an explicit filter match to those bits, the message will be passed to the
   receive buffer and the interrupt pin will be set.
   This example will NOT be exclusive to ONLY the above frame IDs, for that a mask such
   as the below would be used: 
    MASK   + 0000 0000 0000 0000 = 0x07FF0000
    
   This mask will check the filters against all ID bits and the first data byte:
    MASK   + 1111 1111 0000 0000 = 0x07FFFF00
   If you use this mask and do not touch the filters below, you will find that your first
   data byte must be 0x00 for the message to enter the receive buffer.
   
   At the moment, to disable a filter or mask, copy the value of a used filter or mask.
   
   Data bytes are ONLY checked when the MCP2515 is in 'MCP_STDEXT' mode via the begin
   function, otherwise ('MCP_STD') only the ID is checked.
***********************************************************************************/


#include <mcp_can.h>
#include <SPI.h>

long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];

MCP_CAN CAN0(10);                          // Set CS to pin 10

void setup()
{
  Serial.begin(115200);
  if(CAN0.begin(MCP_STDEXT, CAN_500KBPS, MCP_8MHZ) == CAN_OK) Serial.print("MCP2515 Init Okay!!\r\n");
  else Serial.print("MCP2515 Init Failed!!\r\n");
  pinMode(2, INPUT);                       // Setting pin 2 for /INT input


  CAN0.init_Mask(0,0,0x010F0000);                // Init first mask...
  CAN0.init_Filt(0,0,0x01000000);                // Init first filter...
  CAN0.init_Filt(1,0,0x01010000);                // Init second filter...
  
  CAN0.init_Mask(1,0,0x010F0000);                // Init second mask... 
  CAN0.init_Filt(2,0,0x01030000);                // Init third filter...
  CAN0.init_Filt(3,0,0x01040000);                // Init fouth filter...
  CAN0.init_Filt(4,0,0x01060000);                // Init fifth filter...
  CAN0.init_Filt(5,0,0x01070000);                // Init sixth filter...
  
  Serial.println("MCP2515 Library Mask & Filter Example...");
  CAN0.setMode(MCP_NORMAL);                // Change to normal mode to allow messages to be transmitted
}

void loop()
{
    if(!digitalRead(2))                    // If pin 2 is low, read receive buffer
    {
      CAN0.readMsgBuf(&rxId, &len, rxBuf); // Read data: len = data length, buf = data byte(s)
      Serial.print("ID: ");
      Serial.print(rxId, HEX);
      Serial.print(" Data: ");
      for(int i = 0; i<len; i++)           // Print each byte of the data
      {
        if(rxBuf[i] < 0x10)                // If data byte is less than 0x10, add a leading zero
        {
          Serial.print("0");
        }
        Serial.print(rxBuf[i], HEX);
        Serial.print(" ");
      }
      Serial.println();
    }
}

/*********************************************************************************************************
END FILE
*********************************************************************************************************/

High byte * 256 + lowbyte.

groundFungus:
High byte * 256 + lowbyte.

Thanks for the reply! Can you explain what that means? ( I want to understand everything better)

highByte(0xABCD) and lowByte(0xABCD) breaks an int into bytes
byte1 = highByte(0xABCD) -> 0xAB and
byte0 = lowByte (0xABCD) -> 0xCD

To combine them back into an int, you need to move the high bytes back into position.
One way is to multiply them by 256, and then add the low byte back in. Go ahead and try it.
Or, you can bit shift the high byte 8 bits to the left, every shift is the same as multiplying by 2.

int combined = (byte1 * 256) + byte0;
int combined = (byte1 <<8) + byte0;

There might also be union() function that does the same, I don't see it on the reference page tho.

When you run the posted code, what is the serial monitor output? Can you copy and paste the serial monitor output?

Interesting - where is the extra int coming from (i.e. unsigned long)?

More formal declaration brings things around as expected.

CrossRoads:
More formal declaration brings things around as expected.

Thank you for the reply! You mentioned using a union() function , and it reminded me of the word() function in arduino. I looked it up on the wiki and appeared to do the same thing. So same thing that you did, but you just did it manually. I appreciate you sharing that so now I know how to manually do it as well:-)

Just as you posted those last two posts, I tried the word function and received the extra int coming in as well. Defining them as an unsigned int fixed the problem.

Thank you SO much for the help. You have truly made my day today!

Here it is done with a union.

union Tester
{
   unsigned int integer;
   byte bytes[2];
};

Tester test;

void setup()
{
    Serial.begin(115200);
    test.bytes[1] = 0xAB;
    test.bytes[0] = 0xCD;
    Serial.println(test.integer, HEX);
}

void loop()
{

}