reason is that when using local variables we add a lot of
compiler-generated overhead to handle them as they are,
in fact, elements of a special array (the stack).
At the top of the function, we look for a start pulse
by calling GET_IR_PULSE which is simply a shell for
the SX/B PULSIN function. PULSIN returns a value in
10 microsecond units, so we'll keep this in mind for the
comparison. Also, there will be minor variations in systems
so I use 90% of the 2.4 millisecond start pulse width as
my target; this works out to 216 units of 10 microseconds.
Once a valid start pulse has been detected, we'll clear
a word variable (ir Work) that will hold the SIRCS code bits.
A loop is set up to measure and decode 12 bits. If the
measured pulse is 90% of 1.2 milliseconds, then we set
the bit to 1. We don't have to worry about zero bits because
the right shift operator used to align the variable for the
next bit pads with zeroes. Remember that the bits arrive
LSB first hence, we shift the output value right and stuff the
new bit into the MSB position (bit 11). Using this technique,
the last bit that arrives (bit 11) lands in the correct location.
For convenience, I like to split the device code and
command code into separate bytes within the word that
holds the SIRCS result. To do this, we need to shift the
MSB (which holds the device code) one bit left and then
move bit 7 of the LSB (command code) to bit 0 of the
MSB. This is accomplished with a bit of embedded
Assembly to keep things trim. The first line copies bit 7
of ir Work_LSB to the Carry bit. The reason for this is that
the RL and RR instructions will shift the Carry bit into the
target byte. The second line takes care of shifting the MSB
and getting its bit 0 properly in place. That last line clears
the old copy of the device code bit 0 from bit 7 of the
command code byte. The final value returned to the
caller holds the five-bit device code in the MSB and the
seven-bit command code in the LSB. By separating the
device and command codes, our programs can more
easily handle multiple remote types.
A GENERIC IR CONTROL PLATFORM
To put all my remotes to use, I decided to build a
flexible platform that gives me the ability to receive IR,
control eight outputs, and send and receive serial data
over an RS-232 connection. Having learned my lesson
from past projects and wanting to give myself lots of
options with the board, I've designed it to be selectively-stuffed based on what I want to do with a particular
application. As you can see in Figures 2, 3, and 4, there is
nothing complicated
about this circuit. In
Figure 5, you can
see that the outputs
are pretty flexible —
again, not all of
these parts need to
be stuffed into a
given board. I've
designed in the
■ FIGURE 4.
IR Demodulator.
ability to have servo headers for TTL I/O, and a ULN2803
for moderate-current outputs; both have output voltage
selection. I thought that since I'm spending $60 with
ExpressPCB I really should be able to use the board to do
a lot of things — with this one, I can. You'll see that even
though the RB pins are not defined on the schematic that
I added pads to the PCB, anyway… just in case.
Figure 6 shows my completed prototype. I decided to
use a Parallax servo extender cable to attach the IR decoder
to the board. Note, though, that the pinout of the IR
demodulator does not match the cable; no worries, this is
easy to fix. You can use a pin or nail to unlock the female
crimp sockets from the plastic shell and reinstall them in the
proper position. If you look closely, you'll see that I've swapped
the red and black wires to match the IR demodulator.
JR SNIFFER DEMO
Okay, let's start easy. Let’s finish up a program that
decodes the SIRCS stream and displays it on a terminal.
We've already gone through the process of decoding, so
it's just a matter of formatting the IR code for serial output:
■ FIGURE 2. SX28.
■ FIGURE 3. Serial I/O.
January 2009 19