0

Using Seed studio CAN shield to read and convert CAN data to dec value.

Example of expected result:

Full CAN message is 70 3B F1 FF 00 00 00 00 , using little endian first 4 bytes gives: FFF13B70 , which should be equal to converted dec value of -0.967824 (using factor of 0.000001).

Here is code to extract the text value I am using.

CAN.readMsgBuf(&len, buf);
unsigned char len = 0;
unsigned char buf[8];
    {
           String reg0 = String (buf[0], HEX);
           String reg1 = String (buf[1], HEX);
           String reg2 = String (buf[2], HEX);   
           String reg3 = String (buf[3], HEX);
           Serial.print(reg3);
           Serial.print("\t");
           Serial.print(reg2);
           Serial.print("\t");
           Serial.print(reg1);
           Serial.print("\t");
           Serial.print(reg0);
           Serial.print("\t");
           String regsumm = (reg3 + reg2 + reg1 + reg0);

           Serial.println(regsumm);
        }

As result I got only text string which couldn't be converted into dec. Any other ways how do it?

0

2 Answers 2

1

You have taken completely the wrong tack. You don't want to convert your data into text and then convert it back into data again - it's already data.

You can combine your first four buffer bytes into a single 32-bit signed integer with just:

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

That gives you the value -967824, which is 0xFFF13B70 in hex notation, or 11111111 11110001 00111011 0111000 in binary. All of them are the same thing and are just a number.

You can then multiply that result by your "factor" into a float variable:

float dec = val * 0.000001;

Chances are it won't give you -0.967824 due to the nature of floating point values, so you may be better off keeping it as -967824 and working in "micro-units" instead of "units".

1
  • Comments are not for extended discussion; this conversation has been moved to chat.
    – Majenko
    Dec 17, 2018 at 22:06
1

Since the bytes you received in the buffer are in little endian order, and your Uno is itself little endian, you don't even need to move bytes around: you can just reinterpret the bytes you already have as an int32_t:

union {
    uint8_t bytes[8];
    int32_t numbers[2];
} buffer;
unsigned char len = 0;

CAN.readMsgBuf(&len, buffer.bytes);
Serial.println(buffer.numbers[0] * 1e-6, 6);

This prints -0.967824 to the serial port.

Note that this code will not work as expected on a big endian platform. If you want something portable, the usual solution is to build the result using bit shifts, as in Majenko's answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.