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?
2 Answers 2
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".
-
Comments are not for extended discussion; this conversation has been moved to chat.Majenko– Majenko2018年12月17日 22:06:54 +00:00Commented Dec 17, 2018 at 22:06
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.