My Sirc decoder was originally developed as part of the Power Pic RGB Infrared project because at the time I couldn't find a decoder that could be run in parallel with the Pulse Width Modulator of the project.
The Power Pic RGB Infrared project runs the color management in the main loop and the PWM modulator in a timer interrupt routine, leaving me no option but to run the Sirc decoder inside an interrupt routine as well, otherwise the main loop had to be stalled at some point to wait for an IR frame.
So basically the decoder runs inside an ISR, allowing the main loop to be free to keep doing its management, and since an infrared Sirc frame is a slow event compared to the PWM (frequency), it doesn't visibly affect the colors on the RGB led.
The code is generic enough to run at least in pic families 12, 16 and 18.
A circuit to use my Sirc decoder may look like this:
A Sirc frame consists of three separate parts: a start bit, the command number and the address number. The start bit is a single pulse, 2.4ms long. The command is a 7 bits long number and the address is a 5 bits long number. Look at the next picture for more details.
Command and Address bits are encoded as a 600us "low" pulse followed by:
Please note that the output ("low" and "high" levels) of a TSOP1738 is inverted in relation to this picture.
This decoder is implemented as an "interrupt on change" service routine running on the pin where the TSOP1738 is connected. A hardware timer is used as a counter to measure the time between transitions, allowing the ISR to run for a very short time to manipulate the timer and change its internal state, leaving immediately to the main loop.
Every time the TSOP1738 pin changes the ISR changes its internal state according to the next diagram:
In short, and after running several times for very short periods, once for every time the TSOP1738 pin flips, the Sirc ISR does the following: It waits for a start bit and when it finds one, it goes on to decode the Command and Address bits, by validating both halves of the bits. The first half of each data bit is always 600us long and the second half may be 600us is the bit is a logical 0 or 1200us if the bit is a logical 1. After decoding all 12 Command and Address bits, the decoder rests at the "Wait start bit" state.
Every time an error happens, because a bit length is out of the permitted values, the decoder aborts and goes to the "Wait start bit" state, where it waits for the next frame. These errors are shown in the diagram using red arrows.
The header file of the sirc decoder is this:
#ifndef SIRC_H
#define SIRC_H
#define SIRCPIN GPIO1
void SircISR(void); // function to be placed inside the ISR
void SircInit(void); // initialization of pin and timer0
bit SircValid(void); // returns 1 if sircAddr and sircCmd have valid data
void SircClearValid(void); // clears the valid bit (should be invoked after reading sircAddr and sircCmd)
#endif
The SircISR() function should be placed inside the interrupt function for the "interrupt on change" event because it has to run every time the TSOP1738 pin changes state.
The SircInit() function initializes GPIO1 pin as an input with the "interrupt on change" feature, initializes timer0 as a counter.
The SircValid() function returns 1 if a new frame has been decoded, otherwise returns 0.
The SircClearValid() function must be called after the program read the Command and Address numbers. This function allows the decoder to process another Sirc frame, otherwise it will decode and wait forever until this function is called.
Finally, the decoded numbers for Address and Command are placed in two variables called sircAddr and sircCmd that need to be declared in the user code as extern variables:
#include "sirc.h"
extern unsigned char sircCmd, sircAddr;
Power Pic RGB Infrared example
To better explain the usage of this Sirc decoder here's a small sample of the Power Pic RGB Infrared project's main loop:
while(1)
{
if(SircValid())
{
Delay10MiliSeconds(1);
switch(sircCmd)
{
/* some code, not relevant for this example, was removed */
case BT_1:
case BT_2:
case BT_3:
case BT_4:
case BT_5:
case BT_6:
case BT_7:
case BT_8:
case BT_9:
if(powerState)
{
rotateMode=0;
n=sircCmd*(MAX_HUE/9);
ColorSelect(n);
}
break;
case BT_0:
if(powerState)
rotateMode=1;
break;
}
SircClearValid();
} // SircValid
} // while
And a small sample of the ISR:
void interrupt isr(void)
{
/* other user isr code */
if(GPIF)
{
SircISR();
GPIF=0;
}
}
The Sirc decoder has proven to be very reliable and I have several Power Pic RGB infrared lamps working without any problems.
There is one strange problem I found when writing the code that I'm not able to understand what causes it: "interrupt on change glitches". When the PWM and the Sirc decoder are running at the same time, the PWM output pins sometimes generate an interrupt on change even though the only pin with the IOCB bit enabled is GPIO1 and it is stable.
The SircISR code handles this situation and doesn't lose the frame it is decoding when the glitches occur. If you happen to know the reason for this problem, send me an email!
Published on Sunday 2009/12/27, last modified on Tuesday 2014/11/04