Sending long values through CAN Bus

Hello

I need to pass large values ​​by can bus and receive them. Both in arduino.

I am using the Seed Studio library

They are values ​​that I pass are in int32_t format
For example, the altitude given by a gps in feet is 18000.45 ft, I would have to pass 1800045, or some gps coordinates, for example -83.481029, 179.950935 which would have to pass as -83481029, 179950935

My question is how to put in an 8 byte char array and how to read it.

//Send Code

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

const int SPI_CS_PIN = 10;
MCP_CAN CAN(SPI_CS_PIN);   

unsigned char canMsgAlt[8] = {0, 0, 0, 0, 0, 0, 0, 0};

int32_t altData = 1800045;

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

    while (CAN_OK != CAN.begin(CAN_500KBPS)) {            // init can bus : baudrate = 500k
        Serial.println("CAN BUS Shield init fail");
        Serial.println(" Init CAN BUS Shield again");
        delay(100);
    }
    Serial.println("CAN BUS Shield init ok!");
}

void loop() {

    canMsgAlt[0] = altData;
    canMsgAlt[1] = altData >> 8;
    canMsgAlt[2] = altData >> 16;
    CAN.sendMsgBuf(321, 0, 3, canMsgAlt);

    Serial.println(altData);//Print for debug

}
//Receive and print code

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

const int SPI_CS_PIN = 10;

MCP_CAN CAN(SPI_CS_PIN);                                    // Set CS pin

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

    while (CAN_OK != CAN.begin(CAN_500KBPS)) {            // init can bus : baudrate = 500k
        Serial.println("CAN BUS Shield init fail");
        Serial.println(" Init CAN BUS Shield again");
        delay(100);
    }
    Serial.println("CAN BUS Shield 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

        if (CAN.getCanId()== 321){
            float altitude = (buf[0])|(buf[1]<<8)|(buf[2]<<16);
            Serial.print("Altitude: ");
            Serial.println(altitude/100);
        }

       
    }
}

jcduino:
My question is how to put in an 8 byte char array and how to read it.

what's the issue with the code you posted?

I’m printing another value, 30573 instead 1800045. It seems that there is not printing the full value in this expression:

float altitude = (buf[0])|(buf[1]<<8)|(buf[2]<<16);
Serial.print("Altitude: ");
Serial.println(altitude);

If I print each buf value I print 1b776d (in three lines, one por each buf*) that its 1800045, but if I print the code above I print 776d that is 30573. This is my problem…*

jcduino:
I’m printing another value, 30573 instead 1800045. It seems that there is not printing the full value in this expression:

float altitude = (buf[0])|(buf[1]<<8)|(buf[2]<<16);

Serial.print("Altitude: ");
Serial.println(altitude);




If I print each buf _value I print 1b776d (in three lines, one por each buf*) that its 1800045, but if I print the code above I print 776d that is 30573. This is my problem...*_
_*[/quote]*_
<em><em>That probably because of the data type you chose for 'altitude' to be **float**. try changing that to uint32_t first. that probably will fix you problem IMHO</em></em>
_*hope that helps...*_

I've change it to uint32_t and int32_t and write the same value, 30573 (776d) instead 1800045 (1b776d).

jcduino:
I’ve change it to uint32_t and int32_t and write the same value, 30573 (776d) instead 1800045 (1b776d).

forgot to mention you probably would have needed ‘type casting’ as well ie:

uint32_t altitude = ((uint32_t)buf[0])|((uint32_t)buf[1]<<8)|((uint32_t)buf[2]<<16);

I've tried it but it's the same result.

jcduino:
I’ve tried it but it’s the same result.

that is strange… you could always try a different appoach to re-combining the bytes; something like this maybe:

int32_t altitude = buf[2];
altitude = (altitude<<8)|buf[1];
altitude = (altitude<<8)|buf[0];
Serial.print("Altitude: ");
Serial.println(altitude);

hope that helps…

sherzaad:
that is strange… you could always try a different appoach to re-combining the bytes; something like this maybe:

int32_t altitude = buf[2];

altitude = (altitude<<8)|buf[1];
altitude = (altitude<<8)|buf[0];
Serial.print("Altitude: ");
Serial.println(altitude);




hope that helps...

Yes! this works perfectly!! Thank you!

The original approach was do it in a single line, but this method works well.

Thank you again!

Best regards!

There is a little update.

I’ve seen the key for my seach in google.

sherzaad:
re-combining the bytes

is the key for searching, I’m not fluent in english…

I’ve got some improvements

This works for me:

long altitude = (long)buf[3]<<24|(long)buf[2]<<16|(long)buf[1]<<8|(long)buf[0];

The cast, as you told me and do not put the buf*<<n into ()*
(long)buf*<<n[/b] works*
(long)(buf*<<n) [/b]not works*
I’ve changed the type to long, thats I think is arduino native and I’ve added (long)buf[3]<<24 because may be I need some negatives values that I coudn’t obtain with (long)buf[2]<<16
And now works fine.