Pulling Arduino data apart

Jack Purdum
 

I've been going through some of the BITX/µBITX code and see a number of places where bit shifting and/or masking is being done to get rid of "unwanted" bits of data. Doing this means you have solved the "Endian" problem for the microcontroller being used. For example, on some processors, the number 5 stored as an int data type appears in memory as: 00000000 00000101. On other processors, it is stored as: 00000101 00000000. If you are bit shifting or masking, you need to know the "Endian" order for the bytes. On an Arduino, you are given two functions: lowByte() and highByte() to allow you to extract the order to determine how the data are organized in an int. Knowing the byte order can be important, such as transferring binary data from one place to another over a serial link. But what if you are working with a long data type? The lowByte() and highByte() functions don't work since a long is 4 bytes. The solution is to use a C structure called a union. Think of the union as a buffer; a small chunk of memory. I think of it as a bucket, the size of which is determined by the biggest piece of data that will be stored in the union. For example:

union {
  byte array[4];
  byte b;
  char c;
  int i;
  long L;
  float f;
} myUnion;

The long and the float data types are the biggest in the union, so the C compiler will allocate 4 bytes to the union named myUnion. It's a 4-byte bucket. If you want to, you can pour those four bytes into another long variable, or a float variable, or you could use a 1-byte dipper and spoon the 4 bytes into a 4-byte array. Your choice. Suppose, for some reason, the long in the union (i.e., the union member named L) needs to hold an RGB value for a color display. Further suppose you need to know the byte that isn't used as a color value. The following short program will show you how a union works. Note how I can fill the union with any data type, but extract it as a byte array. This makes it easy to observe the byte-order of the data. unions are a great C structure to understand as it gives you a portable way to determine the byte order of the data for a given processor.


union {
  byte array[4];
  byte b;
  char c;
  int i;
  long L;
  float f;
} myUnion;      // Define a union

void setup() {
  byte b = 255;      // create a list of variables...
  char c = 'A';
  int i = 5;
  long L = 10000000L;
  float f = 3.14;

  Serial.begin(9600);

  Serial.print("low byte = ");          // the non-portable way to see the byte order of  variable i
  Serial.print(lowByte(i));
  Serial.print("   high byte = ");
  Serial.println(highByte(i));

  myUnion.i = i;                              // Stuff the int into the union, then look at it
  Serial.print("Union:  low byte = ");
  Serial.print(myUnion.array[0]);
  Serial.print("   high byte = ");
  Serial.println(myUnion.array[1]);

  myUnion.b = b;                        // same for a byte, in DEC and HEX
  Serial.print("Union: byte = ");
  Serial.println(myUnion.array[0]);
  Serial.print("  byte (hex) = ");
  Serial.println(myUnion.array[0], HEX);

  myUnion.L = L;                           // same for a long
  Serial.print("Union: long[0] = ");
  Serial.print(myUnion.array[0]);
  Serial.print("    long[1] = ");
  Serial.print(myUnion.array[1]);
  Serial.print("    long[2] = ");
  Serial.print(myUnion.array[2]);
  Serial.print("  long[3] = ");
  Serial.println(myUnion.array[3]);
                                                         // Do some others on your own...
}

void loop() {
}

Join BITX20@groups.io to automatically receive all group messages.