We have seven patterns and we can encode them
with three switches as follows:
PORTB = 10011011 = 0x9B
POLARITYMASK = 00000001 = 0x01
————————————
AND = 00000001 = 0x01
Binary DecimalPattern Select
000 0 cylonEyes
001 1 cylonEyes2
010 2 cylonEyes3
011 3 wallEyes
100 4 antEyes
101 5 vibroEyes
110 6 blinkinEyes
111 7 randomEyes
bit 76543210
PORTB = 10011011 = 0x9B
SELECTMASK = 00001110 = 0x0E
————————————
AND = 00001010 = 0x0A
If you want to get your Cylon Optometry Doctorate,
you have to figure out how to encode those seven
patterns, the 16 speeds, and the polarity using just eight
switches. We will use bitwise operators, masks, and
macros to do just that for our CylonOptometry.c project.
So, dig out that PortI/O hardware project and reverse the
wires so that DIP switch 8 goes to PORTB 0, 7 to 1, 6 to
2, and so on. Yes, sorry, but I want the switches to match
the bits in a binary number like: bit #76543210 with the
rightmost switch being bit 0 and the leftmost being bit 7.
Figure 2 shows the switch pattern.
Now we will define bit masks:
bit 76543210
PORTB = 10011011 = 0x9B
SPEEDMASK = 11110000 = 0x01
————————————
AND = 10010000 = 0x90
// DIP switch masks
#define POLARITYMASK 0x01
#define SELECTMASK 0x0E
#define SPEEDMASK 0xF0
// 00000001
// 00001110
// 11110000
If we AND each of these masks with the value
we read on PORTB, we convert all the bits we aren’t
interested in to 0 and leave those we are interested in as
they were in the port.
Suppose, for instance, that we set the speed to 9, the
pattern select to 6, and the polarity to 1. We would see
10011011 (0x9B).
PORTB = 10011011 (0x9B)
bit 76543210
■ FIGURE 2. DIP switch use.
We have isolated the bit fields for each mask, but we
still have one more step. You will note that the polarity
can be only 0 or 1 — which is fine — but the pattern select
does not directly indicate the number of the pattern since
it begins at the second bit, not the first. So each value is
multiplied by two. Our count is not 0,1,2, 3, 4, 5, 6, 7; it is
0,2, 4, 6, 8, 10, 12, 14. We could use this numeric sequence
to define our pattern states, but it would be much simpler
if we could just shift the whole byte one position to the
right, dropping the first bit into the void – and we can do
that with the right shift operator >>. Our mask gave us:
00001010 = 0x0A. But (00001010 >> 1) is equal to
00000101 or for hex 0x0A >> 1 equals 0x06. The same
idea holds true for the speed value that we right shift 4:
(0x90 >> 4) is equal 0x09.
In CylonOptometry.c, we read the switch state, mask
off the polarity, speed, and pattern, shift them, and then
use a switch statement to select the function for the
specified pattern. Each of these seven functions runs
through an array containing the pattern to show on the
LED and calls the dillydally() function that delays a number
of milliseconds depending on the speed setting. It then
checks to see if PORTB has changed. If not, it returns 0 to
the function that will show the next
pattern in the array. If PORTB has changed, then it returns
1 and the function will return to main(),
and run the switch statement again to see if a new
pattern has been selected.
The following is from the cylonEyes section of
the program:
/*
00000001 == 0x01
00000010 == 0x02
00000100 == 0x04
00001000 == 0x08
00010000 == 0x10
00100000 == 0x20
01000000 == 0x40
10000000 == 0x80
01000000 == 0x40
60
December 2008