In Part 1 I described the design and building of the circuit. Now it’s time to get onto the software.
This is the tricky part. I’ll have to digress into how infra-red controls work.
An infra-red controller pulses it’s LED at 38kHz. This ‘carrier’ is then switched on and off to produce a sequence of carrier bursts. The length of the bursts are usually the same and the data is encoded in the gaps between the bursts. A short gap represents a binary ’0′ and a long gap represents a ’1′. Here’s what a typical signal looks like:
So the software needs to:
Produce the 38kHz carrier frequency
Output bursts of carrier in the correct sequence
Replay different sequences in response to button presses
Shut down everything when the code is finished so as not to drain the battery
The PIC10F206 has 0.5k of ROM and 24 bytes of RAM which should be more than enough. It has an internal oscillator and runs a fixed instruction-cycle time of 1µs. It has a timer/counter peripheral but I’m not going to use that. 38kHz equates to about 26 clock cycles so if I make a loop which takes exactly 26 cycles to run, that will be simple and deterministic. I won’t have to worry about interrupt latency.
Now I need to know the length of the digital pulses that make up the code. How do I find out that timing, especially since I no longer have the original remote? Well, it so happens that I used to be the lead programmer at a company that does a lot of infra-red control and automation. During my time there, I amassed quite a collection of codes from various equipment.
My amplifier is a 1990s vintage Matsushita SUX911 (what an awful name!). These were sold under the brand name “Technics” in Australia. Most Matsushita gear use the same set of codes. You can take a Technics, or a Panasonic controller and use it on just about any other piece of equipment made by them.
The burst timing for the Matsushita code is:
|Start pulse length||4.0ms||154 cycles|
|Start gap length||3.5ms||135 cycles|
|Data pulse length||1.2ms||46 cycles|
|’0′ gap||0.7ms||27 cycles|
|’1′ gap||2.5ms||96 cycles|
Since our carrier frequency loop is 26 CPU cycles, I now need to count the loops to get the pulse length. As you can see in the table above, I have expressed each timing value in the number of carrier cycles.
I wrote a bunch of lookup tables to direct the sequence of pulses and gaps using the pre-calculated cycle counts. After a code is completed, the chip is placed into SLEEP mode which draws only 100nA of current and will wake up from sleep when a button is pressed which is a nice feature of the PIC10.
Here is a flow chart of the software. As you can see, it is dead simple:
The software came together without too many problems, it turned out to be about 300 lines of assembler, about 1/3 of which was the code lookup tables. It uses 0.1k of ROM and 3 bytes of RAM fitting easily into the PIC10F.
There are usually a few gotchas with the various PIC chips and the PIC10F was no exception. I wasted a couple of hours trying to get the internal pullups to work only to find that pins GP0 and GP1 would default to being a comparator unless you specifically disable that function.
After whacking a couple of software bugs, I got the signal looking good on the oscilloscope. Now to test on the real equipment.
Final testing was a bit of a disappointment though. It kind of worked but you had to hold it within an inch of the receiver. Seems the output power of the Infra Red LED was nowhere near strong enough.
First I tried changing the resistor value from 39Ω down to 20Ω and then 10Ω but it made no difference. What I eventually discovered was that the maximum output power of the PIC was closer to 10mA than the 25mA advertised.
No matter. I patched on a quick little transistor amplifier using a PNP surface-mount transistor from my junk box and now it’s blasting at about 100mA which is enough power for it to work from across the room.
Unfortunately I don’t have any key caps for the buttons so it looks a bit raw and ugly in its box but it works. It ended taking a day and a half to design and build this thing. Definitely a complete waste of time. I could have just bought a replacement controller but where’s the fun in that?
Here’s the finished product.