1. Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.
    Dismiss Notice
granddad

IR remote as mcu input

Interfacing a remote control to a PIC mcu

  1. granddad
    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.

    Code (text):
    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
    }
     

    Attached Files:

    ClydeCrashKop likes this.