What we are doing is trying to store as much of our
sensor data in an Arduino as is reasonably possible. To do
that, we’ve decided that we will store an initial value for
our data and then store a smaller nibble sized value for
the changes. (That process is the side issue I referred to.)
It isn’t really about the Arduino handheld prototyper or
sensing data; it is a convenience for storing more data
than we might otherwise be able to store. So, let’s
concentrate on fully understanding this and write a little
test program for packing and unpacking nibbles. Then,
we’ll get back to the main thread of things.
nibble to store the change. We’ve seen bytes before as
both hexadecimal and binary numbers such as:
Decimal: 165
Hexadecimal: 0xA5
Binary: 10100101
The nibbles are as follows:
Packing and Unpacking the Nibbles
First hexadecimal nibble: 0xA
Second hexadecimal nibble: 0x5
First binary nibble: 1010
Second binary nibble: 0101
Of course, there is no way to split the decimal value
into nibbles which is one of the reasons we use
hexadecimal in the first place.
Using nibbles, we can record changes between zero
and 15 — the values that can be coded by four bits. We
assume this will be enough to cover the changes over the
previous value. However, we have also added for the
complexity that the change can be positive or negative, so
we’ll need our nibble to be a signed data type (+ or -) that
can range from – 8 to 7.
Since we will be packing and unpacking nibbles in
bytes in a byte array, we are creating a virtual nibble array
that is twice the size of a real byte array. It’s virtual
because we don’t actually have a nibble array; we are
making up our own so that we can store and retrieve
nibbles by an index number just like we would store and
retrieve any other data type in a legal array. We will store
the even numbered nibbles from our virtual nibble array
into the high nibble of a byte in the real byte array, and
we will store the next nibble — the odd one — in the low
nibble of the same byte.
For example, if we take a temperature reading that is
73 degrees and in the next sample the temperature is 70
degrees, we only need to save – 3 in a nibble. Then when
we extract the data, we record the 73 degrees as our first
data point and we subtract the – 3 to get our
next data point, and so on for each
subsequent data point.
For example, if we want our virtual nibble array to
store 0xA in the first location, 0x5 in the second, 0x4 in
the third, and 0x7 in the fourth, we would pack the 0xA
into the high nibble of the first byte of our byte array and
then pack the 0x5 into the low nibble of that byte. We
would pack the 0x4 in the high nibble of the second byte
in the array and the 0x7 in the low nibble. If we had
nibble sized arrays, they would look like this:
Theoretically, we should only need to
record the full byte once and from then on we
only record the change in the following
nibbles. This nearly doubles the number of
samples we can log.
0000 0
0001 1
0010 2
nibble_array[0] = 0xA;
nibble_array[1] = 0x5;
nibble_array[2] = 0x4;
nibble_array[3] = 0x7;
November 2013 55
Bits Decimal
0011 3
0100 4
These values would actually be stored in a
real array as:
So, what are signed nibbles and how do
we use them? The most significant bit
0101 5
real_array[0] = 0xA5;
real_array[1] = 0x47;
0110 6
(leftmost) in the nibble will be used for that
sign: 0 for positive and 1 for negative. Table 1
shows how each bit in each nibble translates
to the signed decimal value we will use. Later,
we’ll write the code to use these values to
derive each data point based on the original
stored byte.
0111 7
1000 - 8
1001 - 7
1010 - 6
1011 - 5
1100 - 4
1101 - 3
1110 - 2
1111 -1
Now, our job is to figure out how to
pack and upack the nibbles from the virtual
nibble array into a real byte array. To do this
efficiently, we are going to have to use some
of the more arcane C operators: (modulo),
& (AND), >> (right shift), and << (left shift).
Let’s take a moment to review those.
Now We’re Talking About Nibbles?
Okay, now I’m lost. This is hardly the first
time we’ve gotten so deep into a side issue
that I’ve nearly lost track of what I’m doing, so
let’s refresh.
The operator finds the remainder of a
division. We will pack our nibbles in the bytes
by pairing two nibbles from the virtual nibble
array. Each even index numbered nibble
will be stored in the high nibble of a byte;
the odd indexed nibble will be stored in the low nibble of
a byte.
Table 1. Signed nibbles.
We can use the modulo operator to find out if our
index is odd or even by noting that any even number