0

I need to send data from a microcontroller through a serial port and would like to minimize the data sent, because the data is a 10bit reading from an ADC. So I thought, I would use an union. This is what I got:

union fortybit
{
 struct
 {
  unsigned int a : 10;
  unsigned int b : 10;
  unsigned int c : 10;
  unsigned int d : 10;
 } tenbits;
 unsigned char bytes[5];
};

Now I'm sending the data like this:

fortybit fb;
for (int i = 0; i < 640; i++)
{
 fb.tenbits.a = 512;
 fb.tenbits.b = 512;
 fb.tenbits.c = 512;
 fb.tenbits.d = 512;
 Serial.write(fb.bytes, 5);
}

Which results in some strange readings, which are periodic and some of the values are right, but most of them are completely wrong.

What could I be doing wrong? What is the right way to do this?

timrau
  • 22,578
  • 4
  • 51
  • 64
Matouš Vrba
  • 175
  • 1
  • 8

2 Answers2

3

You should never use bitfields in any external representation. This becomes external since you send the raw bytes where the bitfields are stored, over a serial line.

There's no way to know that the computer in the receiving end of hte serial line interprets your struct the same way. It might have a different byte ordering, a different native integer size into which the bits are packed which might mean different padding, or whatever.

It's simply not portable.

You should do it in a more controlled fashion, perhaps by manually computing each byte of the desired external representation. This is called serialization, and it's a good thing.

unwind
  • 391,730
  • 64
  • 469
  • 606
2

Its not like its that hard to do the packing transform yourself. Something like this should do the trick:

int A[4] = { 0x1,0x1,0x1,0x1 };
int B[5];

long long x=0;
for(int i=0; i<4; i++) {
    x |= A[i] << (10*i);
}
for(int i=0; i<5; i++) {
    B[i] = x & 0xFF;
    x >>= 8;
}

printf("%02x %02x %02x %02x %02x\n",B[0],B[1],B[2],B[3],B[4]);
RichardPlunkett
  • 2,998
  • 14
  • 14