So many PIC mcu projects I dream up seem to need a few or lots of switches to allow some program setting or control, so seeing this cheap ir remote key pad , seemed a one size fits all solution. Several code examples out there but none for the NEC ir protocol interfacing with a PIC24Fxxxxx . My method basically waits for the 9ms start burst and checks its length then checks the 4.5ms pause, the following data bits are counted and shifted into the input_data , a ZERO is one count a ONE is two . after 32 bits got_data flag is set.
:- The mcu requires a 16Bit Timer with an interrupt running at 1.125ms. The ir receiver (Detects 38khz ir bursts) drives an mcu INT pin no pull up is required. The C coding here is for a PIC24FV16KA301 running at 16Mhz (8 MIPS).The main routine has to enable the INT0 when ready for ir input and then poll the Got_data flag . This is set when all 32 bits have been received , bit dropouts or errors are ignored . The code result is accumulated as input_data (long int), but I only used the 8 Command bits , the address shown below for this remote is always h’00 so not used (some bit checking could be done if required as the remote transmits inverse data in the bit stream). Keys held down produce repeat codes , but not yet investigated that feature.
:- The mcu requires a 16Bit Timer with an interrupt running at 1.125ms. The ir receiver (Detects 38khz ir bursts) drives an mcu INT pin no pull up is required. The C coding here is for a PIC24FV16KA301 running at 16Mhz (8 MIPS).The main routine has to enable the INT0 when ready for ir input and then poll the Got_data flag . This is set when all 32 bits have been received , bit dropouts or errors are ignored . The code result is accumulated as input_data (long int), but I only used the 8 Command bits , the address shown below for this remote is always h’00 so not used (some bit checking could be done if required as the remote transmits inverse data in the bit stream). Keys held down produce repeat codes , but not yet investigated that feature.
Code:
enum {
Idle,
Pre_code,
Start_bit,
Capture_bit
};
void INT0_SETUP()
{
TRISBbits.TRISB7 = 1; // INT0 RB7 INPUT FROM ir RECEIVER.
IPC0bits.INT0IP = 6 ; //INT0 PRIORITY
INTCON2bits.INT0EP = 1;// INT0 FALLING EDGE
IFS0bits.INT0IF=0; // clr flag
}
//Set up Timer, 1.125ms interrupts
void T2_init(void)
{
PR2 = 9000 ; // PIC at 8 MIPS comparitor value for 1.125mS
TMR2= 0 ; // clear timer
T2CONbits.TCKPS = 0; //TIMER 2 pre scale 0 1:1,1 1:8, 2 1:64
IPC1bits.T2IP = 5; //set interrupt priority
IFS0bits.T2IF = 0; //reset interrupt flag
IEC0bits.T2IE = 0; // DISABLE T2 interrupt
T2CONbits.TON =0; // timer 2 off
}
// IR LED input to INT0
void __attribute__((__interrupt__, auto_psv))_INT0Interrupt(void)
{
TMR2=2000; // PRELOAD T2
T2CONbits.TON = 1; // timer ON
IEC0bits.T2IE = 1; // ENable T2 interrupt
switch (Current_state){
case Idle:
INTCON2bits.INT0EP = 0;//change INT0 rising EDGE
counter=0;
Current_state = Pre_code;
break;
// found rising edge check length 9ms COUNT 8
case Pre_code:
if (counter==8){
counter=0;
bit_count=0;
Current_state = Start_bit;
INTCON2bits.INT0EP = 1;// INT0 falling EDGE
}else{
Current_state=Idle;
counter=0;
T2CONbits.TON = 0; // timer off
IEC0bits.T2IE = 0; // DISABLE T2 interrupt
}
break;
case Start_bit:
if (counter==4){
counter=0;
bit_count=0;
input_data =0;
Current_state = Capture_bit;
}else{
Current_state=Idle;
counter=0;
T2CONbits.TON = 0; // timer off
IEC0bits.T2IE = 0; // DISABLE T2 interrupt
}
break;
case Capture_bit:
if(counter == 1){
input_data >>= 1;
bit_count++;
counter=0;
}else{
if(counter == 2){
input_data >>= 1;
input_data |= 0x80000000;
bit_count++;
counter=0;
}else{
// error reset to idle
INTCON2bits.INT0EP = 1;// INT0 FALLING EDGE
Current_state=Idle;
}
}
if(bit_count == 32){ // RX complete ( ignore last pulse)
got_data = 1;
IEC0bits.INT0IE = 0; // disable INT0 INTERRUPT.
T2CONbits.TON =0; // timer off
IEC0bits.T2IE = 0; // disable T2 interrupt
Current_state=Idle;
}
counter=0;
break;
default: Current_state=Idle;
}
IFS0bits.INT0IF = 0;
}
void __attribute__((__interrupt__, auto_psv))_T2Interrupt(void)
{
counter++ ;
if(counter > 10 ){//5
Current_state=Idle;
counter=0;
INTCON2bits.INT0EP = 1;// INT0 FALLING EDGE
T2CONbits.TON =0; // timer off
}
IFS0bits.T2IF = 0; //cleart T2 interrupt flag
}