0

I have an atMega1281 micro controller using C. I have a routine to pull 4 bytes off of a CAN bus to read an SPN. I am able to get the 4 bytes but I cannot print the 4 byte number because it is truncating the the first 2 bytes making it a 16 bit number. I have tried using unsigned long as the declaration with no success. What is the trick when using 32 bit numbers with an AVR?

unsigned long engine_hours_raw;
float engine_hours_uint;

engine_hours_raw =  (OneMessage.Msg.Data[3] << 24) | (OneMessage.Msg.Data[2] << 16) | (OneMessage.Msg.Data[1] << 8) | OneMessage.Msg.Data[0]);
engine_hours_uint = engine_hours_raw * 0.05;

ftoa(engine_hours_uint, engHours, 1);
UART1_Printf("Engine Hours: %s   ", engHours);
Eddie
  • 39
  • 10

2 Answers2

2

(OneMessage.Msg.Data[3] << 24) will be 0 as the default size for an expression is an int. unless it is cast.

Instead, load the data into the long int and then perform the shift.

engine_hours_raw = OneMessage.Msg.Data[3];
engine_hours_raw <<= 8;
engine_hours_raw |= OneMessage.Msg.Data[2];
engine_hours_raw <<= 8;
engine_hours_raw |= OneMessage.Msg.Data[1];
engine_hours_raw <<= 8;
engine_hours_raw |= OneMessage.Msg.Data[0];

You could also cast the intermediate expressions as unsigned log or uint32_t, but it just as messy and may take longer.

engine_hours_raw =  ((unit32_t)(OneMessage.Msg.Data[3]) << 24) | ((unit32_t)(OneMessage.Msg.Data[2]) << 16) | ((unit32_t)(OneMessage.Msg.Data[1]) << 8) | (unit32_t)(OneMessage.Msg.Data[0]);
UncleO
  • 8,299
  • 21
  • 29
0

There is much easier and straightforward way :)

uint32_t *engine_hours_raw = (uint32_t *)OneMessage.Msg.Data;
float engine_hours_uint  = *engine_hours_raw * 0.05;
0___________
  • 60,014
  • 4
  • 34
  • 74