Philips IR RC5 protocol

General discussion on mikroC.
Author
Message
rudolflapie
Posts: 29
Joined: 07 Jan 2009 08:40

#6 Post by rudolflapie » 18 Feb 2009 20:12

Dany,

Your algorithm works like a charm ! Fantastic code !
I converted it to MikroC with no diffuculty. I had to make some changes to the names of some registers because I use a different PIC, but other than that little or no changes

For those interested, I included the MikroC code below.

KR,
Rudy

Code: Select all

/************************************************************************************
 *               MAIN PROGRAM for PHILIPS RC5 IR RECEIVER                           *
 ************************************************************************************
 *                 Original MikroPascal version : D. Rosseel                        *
 *              http://users.edpnet.be/rosseel01/DRO/PIC/index.htm                  *
 *                                                                                  *
 *                 Converted to MikroC by Rudolf Lapie                              *
 *                                                                                  *
 * Original version : 15-FEB-2009              Last change : 16-FEB-09              *
 * MikroC version : 18-FEB-2009                Last change : 18-FEB-09              *
 *                                                                                  *
 * For Rc5 receivers with inverse output (= output active low), like the TSOP1736.  *
 * The output of the Rc5 receiver is to be connected to the PIC's external          *
 * interrupt pin (PortB.0).                                                         *
                                                                                    *
 * The timer0 requires a clock (after prescaler) of 62.5 KHz. This means, when the  *
 * CPU clock is 4 MHz a prescaler value of 16 is required: 4 MHz / 4 / 16 =62.5 KHz *
 * The time/timerstep is then 16 microsecs. (1/62500)                               *
 * For other CPU clock speeds the prescaler has to be adjusted accordingly, or      *
 * if not possible both prescaler and "RC5_TIME_..." constants have to be adapted.  *
 * e.g. for 8Mhz : use 1:32 as prescaler                                            *
 ************************************************************************************
 * Algorithm :                                                                      *
 * ~~~~~~~~~~~                                                                      *
 * Everytime the input on pin RC5 changes an interrupt is generated. In the handler *
 * the time is measured between 2 subsequent changes. Based on this difference a    *
 * decision is made on what the previous bit was : a short pulse or a double pulse  *
 * If the timing is out of range the code is considered invalid and the handler     *
 * resets itself to the initial state.  A state machine is used with 3 states :     *
 * IDLE, DECODING & COMPLETED                                                       *
 ************************************************************************************
 * Hardware config : 18F452 @ 8Mhz  + TSOP1736 + LED + LCD                          *
 * -------------------------------------------------------------------------------- *
 * LED on PortD.F2 (active when port low)                                           *
 * TSOP-1736 : Output pin connected to PORTB.F0 (active when low)                   *
 * LCD : HD44780 on PORTB : bits 1..4 = D4...D7 / 5 = EN / 6 = RS / 7 = RW          *
 * Note : when using a different Crystal speed, you will need to change prescaler   *
 * in the main program and potentially the counters in the definition section       *
 ************************************************************************************
*/
 
 
// Remove next line for production code !
#define DEBUG

//-----------------------------------------------------------------------------
// Hardware specific settings
//-----------------------------------------------------------------------------
#define LED_On()      (LATD.F2=0)
#define LED_Off()     (LATD.F2=1)
#define LED_Toggle()  (LATD.F2=~LATD.F2)

#define IR_PIN        (PORTB.F0)

//-----------------------------------------------------------------------------
// Predefined constants
//------------------------------------------------------------------------------
#define RC5_NR_Bits   14

//In total 14 Rc5_Bits are to be captured (the first "startbit" is already there
//when the first interrupt occurs)
// The format of the received bits is:
//  - 2 startbits (both "1")
//  - 1 toggle bit (changes every time when a non repeated command is sent)
//  - 5 "System" bits, most significant bit first
//  - 6 "Command" bits, most significant bit first
// The bits are recognized by the time between 2 "edges" of the RC5 signal:
//  - a "long time" means: bit received that differs from the previous one
//  - two RC5_times "short" means: bit received that equals the previous one
//    the previous bit to start with is always "1"

#define RC5_TIME_BOUNDARY       83  // below 83 = short, above = long (0.75 bittime)
#define RC5_TIME_TOO_SHORT      28  // (0.25 bittime)
#define RC5_TIME_TOO_LONG      140  // (1.25 bittime)

// 1 bit time = 1778 uS
//    "short" time = 1/2 bittime = 889 uS, = timer value 55.5 (= 889/16)
//    "long"  time = 1 bittime = 1778 uS,  = timer value 111.12 (=1778/16)
// Note : constant values depend on the speed of your crystal !

//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
enum {
      RC5_IDLE,
      RC5_DECODING,
      RC5_COMPLETED
} RC5_state = RC5_IDLE ;

#ifdef DEBUG
unsigned char RC5_times[26] ;  // array for the Rc5_Times measured
unsigned char RC5_timesIndex; // index/count for above
#endif
unsigned int   RC5_bits ;               // will hold the received bits
unsigned char  RC5_bitCount ;           // nb of bits processed
unsigned char  RC5_prevBit ;            // the value of the previous bit
unsigned char  RC5_shortPulses ;        // nr of subsequent short pulses measured

struct
{
    toggle   : 1 ;
    device   : 5 ;
    command  : 6 ;
    received : 1 ;
} IR ;

//-----------------------------------------------------------------------------
// Forward Declarations
//-----------------------------------------------------------------------------
void  Lcd_Custom_INT (int row, int col, int x, unsigned char len);

//------------------------------------------------------------------------------
// Interrupt handler
//------------------------------------------------------------------------------
void interrupt()
{
     unsigned char time, i ;

     // RB0 interrupt
     if (INTCON.INT0IF)
     {
       LED_Toggle () ;
       
       INTCON2.INTEDG0 = 1-INTCON2.INTEDG0 ; // toggle the INTEDG (interrupt edge)
       INTCON.INT0IF = 0;

       time = TMR0L;       // get time
       TMR0L = 0;          // restart timer
       
       switch (RC5_state)
       {
           ////////// IDLE STATE. NOTHING RECEIVED YET ////////////////////////
           case RC5_IDLE :
                #ifdef DEBUG
                RC5_timesIndex  = 0;
               #endif
                RC5_bits        = 1; // already 1 bit (with value "1") received
                RC5_bitCount    = 1;
                RC5_shortPulses = 0;
                RC5_prevBit     = 1;
                RC5_state       = RC5_DECODING;

                INTCON.T0IF = 0; // reset Timer0 overflow flag
                INTCON.T0IE = 1; // enable timer0 interrupt
                break ;
                
           ////////// CHANGES DETECTED. WE START PROCESSING BITS////////////////
           case RC5_DECODING :  // Execution time is about 52 uS at 4 Mhz CPU clock
                #ifdef DEBUG
                RC5_times[RC5_timesIndex] = time; // get timer value
                RC5_timesIndex ++ ;
                #endif

                if ((time > RC5_TIME_TOO_SHORT) && (time < RC5_TIME_TOO_LONG))
                {
                     if (time < RC5_TIME_BOUNDARY)  // short pulse detected
                     {
                        RC5_shortPulses ++ ;
                        if (RC5_shortPulses == 2)
                        {
                           RC5_bits <<= 1;          // store the bit received
                           RC5_bits |= RC5_PrevBit;
                           RC5_bitCount ++ ;
                           RC5_shortPulses = 0;
                        }
                     } else {    // long pulse detected
                        RC5_prevBit = 1- RC5_prevBit;  // toggle the bit
                        RC5_bits <<= 1;            // store the bit received
                        RC5_Bits |= RC5_PrevBit;
                        RC5_bitCount ++ ;
                        RC5_shortPulses = 0;
                     }

                     if (RC5_bitCount == RC5_NR_Bits)// all bits are received
                     {
                        RC5_state = RC5_COMPLETED;
                        INTCON2.INTEDG0 = 0; // next RC5 interrupt is negative going
                        INTCON.T0IE = 0;     // disable timer0 interrupt
                     }
                } else { // something is wrong about timing
                     RC5_state = RC5_IDLE;  // start all over
                     INTCON2.INTEDG0 = 0; // next RC5 interrupt is negative going
                     INTCON.T0IE  = 0; // disable timer0 interrupt
                }
                break ;

           /////////// ALL BITS RECEIVED CORRECTLY. Store the data /////////////
           case RC5_COMPLETED :
                INTCON2.INTEDG0 = 0; // next RC5 interrupt is negative going
                
                IR.toggle = ((RC5_bits>>11) & 0x01) ? 0 : 1 ;
                IR.device =  (RC5_bits>>6) & 0b00011111 ;
                IR.command=  (RC5_bits & 0b00111111) ;
                IR.received = 1 ;
                RC5_state = RC5_IDLE ;
                #ifdef DEBUG
                for (i= 0; i < sizeof(RC5_times); i++) RC5_times[i] = 0;
                #endif
                break ;
                
       } // end switch
     } // end INTCON.INT0IF

     // Timer 0 interrupt
     if (INTCON.T0IF)  // timer 0 overflow, timeout
     {
        if (RC5_state == RC5_DECODING) // something is wrong
        {
           RC5_state = RC5_IDLE;  // start all over
           INTCON2.INTEDG0 = 0;   // next RC5 interrupt is negative going
           INTCON.T0IE  = 0;      // disable timer0 interrupt
        }
     }

     INTCON.T0IF = 0; // always reset timer0 overflow flag
     
} // end interrupt routine

//-----------------------------------------------------------------------------
// MAIN PROGRAM
//------------------------------------------------------------------------------
void main ()
{
     unsigned int dev, cmd ;
     unsigned int repeat ;
     unsigned char last_toggle ;
     int i  ;
     
     // Initialize state machine
     
     RC5_state = RC5_IDLE ;
     #ifdef DEBUG
     for (i=0; i< sizeof (RC5_times); i ++) RC5_times[i] = 0 ;
     #endif

     // INITIALISE all registers
    ADCON1 = 0x00 ;         // No ADC convertors
    // CMCON  = 0x07 ;         // turn off comparators - Not available in 18F452

    LATB = 0;
    TRISB = 0b00000001;              // set PORTB D7-D1 = LCD  / D0 = IR receiver

    LATC = 0 ;
    TRISC = 0b11111111 ;    // set PORTC as input except for bits 0 : LED

    LATD = 0 ;
    TRISD = 0b1111000 ;     // set PORTD as D0-D3 output , D4-D7 = input
    
    // Setup Timer 0, but don't enable it yet  --> Settings depend on Crystal
    // Initialise TIMER0  : Prescaler= 1:32 -  1 tick = 16 usec / 62.5 Khz
    T0CON  = 0b11000100;     // enable timer, 8 bit mode, 1:32 prescaler
    TMR0L  = 0;  // preset for timer register

    INTCON.PEIE = 1;
    INTCON.T0IF = 0;
    INTCON.T0IE = 0;      // disable timer 0 interrupt for now

    // Enable external interrupt
    INTCON2.INTEDG0    = 0;            // start with downgoing edge
    INTCON.INT0IF      = 0;            // Clear interrupt
    INTCON.INT0IE      = 1;            // Enable RB0 interrupt
    INTCON.GIE         = 1;      // bit7 global interrupt enable

    // Initialise LCD
    Lcd_Custom_Config(&PORTB, 4,3,2,1,&PORTB,6,7,5);  // Initialize LCD on PORTB
    Lcd_Custom_Cmd(Lcd_CURSOR_OFF);                  // Turn off cursor
    Lcd_Custom_Out (1, 1, "Philips RC5") ;

    // Main program loop
    IR.received = 0 ;
    last_toggle = 2 ; // Impossible

    while (1)
    {
          if (IR.received)
          {
             dev = IR.device ;
             cmd = IR.command;
             IR.received = 0 ;  // Processed the command

             if (last_toggle == IR.toggle)
             {
                repeat ++ ;
             } else {
                repeat = 0 ;
                last_toggle = IR.toggle;
             }

             LCD_Custom_Out (2, 1, "DEV=") ;
             LCD_Custom_INT (2, 5,  dev, 3) ;
             LCD_Custom_Out (2, 9, "CMD=") ;
             LCD_Custom_INT (2, 13,  cmd, 3) ;
             LCD_Custom_Chr (2, 17, IR.toggle?'T':' ') ;
             LCD_Custom_INT (2, 19, repeat, 3) ;

          }
          #if 0
          else {
             if (RC5_timesIndex)
             {
              INTCON.GIE  = 0;      // bit7 global interrupt disable
               LCD_Custom_INT (2, 20, RC5_bitcount, 2) ;
                for (i=0 ; i<RC5_timesIndex; i++)
                {
                    LCD_Custom_Out (2, 1, "IDX=") ;
                    LCD_Custom_INT (2, 5,  i, 3) ;
                    LCD_Custom_Out (2, 9, "TMR=") ;
                    LCD_Custom_INT (2, 13, RC5_times[i], 3) ;
                    Delay_ms(2000) ;
                }
                LCD_Custom_Out (2, 1, "                         ") ;
                RC5_timesIndex = 0 ;
                INTCON.GIE = 1;      // bit7 global interrupt enable

             }
          }
          #endif

          Delay_ms (250) ;
    }
} // end main

//------------------------------------------------------------------------------
// AUXILIARY ROUTINES
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void  Lcd_Custom_INT (int row, int col, int x, unsigned char size)
{
      static char txt[7] ;
      int i ;

      IntToStr (x, txt) ;
      for (i=0; i<7; i++) if (txt[i] == ' ') txt[i] = '0' ;
      Lcd_Custom_Out(row, col, txt+(6-size)) ;
}


////////////////////////////////////////////////////////////////////////////////
// THAT'S ALL, FOLKS
////////////////////////////////////////////////////////////////////////////////

prettyboy
Posts: 30
Joined: 27 Jun 2007 02:59

IR remote for PIC16F877a

#7 Post by prettyboy » 20 Jul 2009 08:23

Hi. i understand how this works but i need to implement this with PIC 16f877a and 4MHz clock. My project is to use TV remote to control a robot movement. any ideas on how to integrate this with another program or how to capture the data command then control the robot? thanks in advance

lukihawk
Posts: 5
Joined: 06 Dec 2007 20:10

#8 Post by lukihawk » 22 Oct 2009 14:57

HI. I tried to use these both codes on PIC18F4520 and I can't get interrupt work, I was also trying with INT1 and INT2 changing all needed registers and program just never go to interrupt. What i should change in PROJECT EDITOR except standard crystal setting, PBADEN_OFF, LVP_OFF

gigz09
Posts: 5
Joined: 05 Dec 2008 23:58

#9 Post by gigz09 » 22 Jan 2010 04:16

rudolflapie wrote:Dany,

Your algorithm works like a charm ! Fantastic code !
I converted it to MikroC with no diffuculty. I had to make some changes to the names of some registers because I use a different PIC, but other than that little or no changes

For those interested, I included the MikroC code below.

KR,
Rudy

Code: Select all

/************************************************************************************
 *               MAIN PROGRAM for PHILIPS RC5 IR RECEIVER                           *
 ************************************************************************************
 *                 Original MikroPascal version : D. Rosseel                        *
 *              http://users.edpnet.be/rosseel01/DRO/PIC/index.htm                  *
 *                                                                                  *
 *                 Converted to MikroC by Rudolf Lapie                              *
 *                                                                                  *
 * Original version : 15-FEB-2009              Last change : 16-FEB-09              *
 * MikroC version : 18-FEB-2009                Last change : 18-FEB-09              *
 *                                                                                  *
 * For Rc5 receivers with inverse output (= output active low), like the TSOP1736.  *
 * The output of the Rc5 receiver is to be connected to the PIC's external          *
 * interrupt pin (PortB.0).                                                         *
                                                                                    *
 * The timer0 requires a clock (after prescaler) of 62.5 KHz. This means, when the  *
 * CPU clock is 4 MHz a prescaler value of 16 is required: 4 MHz / 4 / 16 =62.5 KHz *
 * The time/timerstep is then 16 microsecs. (1/62500)                               *
 * For other CPU clock speeds the prescaler has to be adjusted accordingly, or      *
 * if not possible both prescaler and "RC5_TIME_..." constants have to be adapted.  *
 * e.g. for 8Mhz : use 1:32 as prescaler                                            *
 ************************************************************************************
 * Algorithm :                                                                      *
 * ~~~~~~~~~~~                                                                      *
 * Everytime the input on pin RC5 changes an interrupt is generated. In the handler *
 * the time is measured between 2 subsequent changes. Based on this difference a    *
 * decision is made on what the previous bit was : a short pulse or a double pulse  *
 * If the timing is out of range the code is considered invalid and the handler     *
 * resets itself to the initial state.  A state machine is used with 3 states :     *
 * IDLE, DECODING & COMPLETED                                                       *
 ************************************************************************************
 * Hardware config : 18F452 @ 8Mhz  + TSOP1736 + LED + LCD                          *
 * -------------------------------------------------------------------------------- *
 * LED on PortD.F2 (active when port low)                                           *
 * TSOP-1736 : Output pin connected to PORTB.F0 (active when low)                   *
 * LCD : HD44780 on PORTB : bits 1..4 = D4...D7 / 5 = EN / 6 = RS / 7 = RW          *
 * Note : when using a different Crystal speed, you will need to change prescaler   *
 * in the main program and potentially the counters in the definition section       *
 ************************************************************************************
*/
 
 
// Remove next line for production code !
#define DEBUG

//-----------------------------------------------------------------------------
// Hardware specific settings
//-----------------------------------------------------------------------------
#define LED_On()      (LATD.F2=0)
#define LED_Off()     (LATD.F2=1)
#define LED_Toggle()  (LATD.F2=~LATD.F2)

#define IR_PIN        (PORTB.F0)

//-----------------------------------------------------------------------------
// Predefined constants
//------------------------------------------------------------------------------
#define RC5_NR_Bits   14

//In total 14 Rc5_Bits are to be captured (the first "startbit" is already there
//when the first interrupt occurs)
// The format of the received bits is:
//  - 2 startbits (both "1")
//  - 1 toggle bit (changes every time when a non repeated command is sent)
//  - 5 "System" bits, most significant bit first
//  - 6 "Command" bits, most significant bit first
// The bits are recognized by the time between 2 "edges" of the RC5 signal:
//  - a "long time" means: bit received that differs from the previous one
//  - two RC5_times "short" means: bit received that equals the previous one
//    the previous bit to start with is always "1"

#define RC5_TIME_BOUNDARY       83  // below 83 = short, above = long (0.75 bittime)
#define RC5_TIME_TOO_SHORT      28  // (0.25 bittime)
#define RC5_TIME_TOO_LONG      140  // (1.25 bittime)

// 1 bit time = 1778 uS
//    "short" time = 1/2 bittime = 889 uS, = timer value 55.5 (= 889/16)
//    "long"  time = 1 bittime = 1778 uS,  = timer value 111.12 (=1778/16)
// Note : constant values depend on the speed of your crystal !

//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
enum {
      RC5_IDLE,
      RC5_DECODING,
      RC5_COMPLETED
} RC5_state = RC5_IDLE ;

#ifdef DEBUG
unsigned char RC5_times[26] ;  // array for the Rc5_Times measured
unsigned char RC5_timesIndex; // index/count for above
#endif
unsigned int   RC5_bits ;               // will hold the received bits
unsigned char  RC5_bitCount ;           // nb of bits processed
unsigned char  RC5_prevBit ;            // the value of the previous bit
unsigned char  RC5_shortPulses ;        // nr of subsequent short pulses measured

struct
{
    toggle   : 1 ;
    device   : 5 ;
    command  : 6 ;
    received : 1 ;
} IR ;

//-----------------------------------------------------------------------------
// Forward Declarations
//-----------------------------------------------------------------------------
void  Lcd_Custom_INT (int row, int col, int x, unsigned char len);

//------------------------------------------------------------------------------
// Interrupt handler
//------------------------------------------------------------------------------
void interrupt()
{
     unsigned char time, i ;

     // RB0 interrupt
     if (INTCON.INT0IF)
     {
       LED_Toggle () ;
       
       INTCON2.INTEDG0 = 1-INTCON2.INTEDG0 ; // toggle the INTEDG (interrupt edge)
       INTCON.INT0IF = 0;

       time = TMR0L;       // get time
       TMR0L = 0;          // restart timer
       
       switch (RC5_state)
       {
           ////////// IDLE STATE. NOTHING RECEIVED YET ////////////////////////
           case RC5_IDLE :
                #ifdef DEBUG
                RC5_timesIndex  = 0;
               #endif
                RC5_bits        = 1; // already 1 bit (with value "1") received
                RC5_bitCount    = 1;
                RC5_shortPulses = 0;
                RC5_prevBit     = 1;
                RC5_state       = RC5_DECODING;

                INTCON.T0IF = 0; // reset Timer0 overflow flag
                INTCON.T0IE = 1; // enable timer0 interrupt
                break ;
                
           ////////// CHANGES DETECTED. WE START PROCESSING BITS////////////////
           case RC5_DECODING :  // Execution time is about 52 uS at 4 Mhz CPU clock
                #ifdef DEBUG
                RC5_times[RC5_timesIndex] = time; // get timer value
                RC5_timesIndex ++ ;
                #endif

                if ((time > RC5_TIME_TOO_SHORT) && (time < RC5_TIME_TOO_LONG))
                {
                     if (time < RC5_TIME_BOUNDARY)  // short pulse detected
                     {
                        RC5_shortPulses ++ ;
                        if (RC5_shortPulses == 2)
                        {
                           RC5_bits <<= 1;          // store the bit received
                           RC5_bits |= RC5_PrevBit;
                           RC5_bitCount ++ ;
                           RC5_shortPulses = 0;
                        }
                     } else {    // long pulse detected
                        RC5_prevBit = 1- RC5_prevBit;  // toggle the bit
                        RC5_bits <<= 1;            // store the bit received
                        RC5_Bits |= RC5_PrevBit;
                        RC5_bitCount ++ ;
                        RC5_shortPulses = 0;
                     }

                     if (RC5_bitCount == RC5_NR_Bits)// all bits are received
                     {
                        RC5_state = RC5_COMPLETED;
                        INTCON2.INTEDG0 = 0; // next RC5 interrupt is negative going
                        INTCON.T0IE = 0;     // disable timer0 interrupt
                     }
                } else { // something is wrong about timing
                     RC5_state = RC5_IDLE;  // start all over
                     INTCON2.INTEDG0 = 0; // next RC5 interrupt is negative going
                     INTCON.T0IE  = 0; // disable timer0 interrupt
                }
                break ;

           /////////// ALL BITS RECEIVED CORRECTLY. Store the data /////////////
           case RC5_COMPLETED :
                INTCON2.INTEDG0 = 0; // next RC5 interrupt is negative going
                
                IR.toggle = ((RC5_bits>>11) & 0x01) ? 0 : 1 ;
                IR.device =  (RC5_bits>>6) & 0b00011111 ;
                IR.command=  (RC5_bits & 0b00111111) ;
                IR.received = 1 ;
                RC5_state = RC5_IDLE ;
                #ifdef DEBUG
                for (i= 0; i < sizeof(RC5_times); i++) RC5_times[i] = 0;
                #endif
                break ;
                
       } // end switch
     } // end INTCON.INT0IF

     // Timer 0 interrupt
     if (INTCON.T0IF)  // timer 0 overflow, timeout
     {
        if (RC5_state == RC5_DECODING) // something is wrong
        {
           RC5_state = RC5_IDLE;  // start all over
           INTCON2.INTEDG0 = 0;   // next RC5 interrupt is negative going
           INTCON.T0IE  = 0;      // disable timer0 interrupt
        }
     }

     INTCON.T0IF = 0; // always reset timer0 overflow flag
     
} // end interrupt routine

//-----------------------------------------------------------------------------
// MAIN PROGRAM
//------------------------------------------------------------------------------
void main ()
{
     unsigned int dev, cmd ;
     unsigned int repeat ;
     unsigned char last_toggle ;
     int i  ;
     
     // Initialize state machine
     
     RC5_state = RC5_IDLE ;
     #ifdef DEBUG
     for (i=0; i< sizeof (RC5_times); i ++) RC5_times[i] = 0 ;
     #endif

     // INITIALISE all registers
    ADCON1 = 0x00 ;         // No ADC convertors
    // CMCON  = 0x07 ;         // turn off comparators - Not available in 18F452

    LATB = 0;
    TRISB = 0b00000001;              // set PORTB D7-D1 = LCD  / D0 = IR receiver

    LATC = 0 ;
    TRISC = 0b11111111 ;    // set PORTC as input except for bits 0 : LED

    LATD = 0 ;
    TRISD = 0b1111000 ;     // set PORTD as D0-D3 output , D4-D7 = input
    
    // Setup Timer 0, but don't enable it yet  --> Settings depend on Crystal
    // Initialise TIMER0  : Prescaler= 1:32 -  1 tick = 16 usec / 62.5 Khz
    T0CON  = 0b11000100;     // enable timer, 8 bit mode, 1:32 prescaler
    TMR0L  = 0;  // preset for timer register

    INTCON.PEIE = 1;
    INTCON.T0IF = 0;
    INTCON.T0IE = 0;      // disable timer 0 interrupt for now

    // Enable external interrupt
    INTCON2.INTEDG0    = 0;            // start with downgoing edge
    INTCON.INT0IF      = 0;            // Clear interrupt
    INTCON.INT0IE      = 1;            // Enable RB0 interrupt
    INTCON.GIE         = 1;      // bit7 global interrupt enable

    // Initialise LCD
    Lcd_Custom_Config(&PORTB, 4,3,2,1,&PORTB,6,7,5);  // Initialize LCD on PORTB
    Lcd_Custom_Cmd(Lcd_CURSOR_OFF);                  // Turn off cursor
    Lcd_Custom_Out (1, 1, "Philips RC5") ;

    // Main program loop
    IR.received = 0 ;
    last_toggle = 2 ; // Impossible

    while (1)
    {
          if (IR.received)
          {
             dev = IR.device ;
             cmd = IR.command;
             IR.received = 0 ;  // Processed the command

             if (last_toggle == IR.toggle)
             {
                repeat ++ ;
             } else {
                repeat = 0 ;
                last_toggle = IR.toggle;
             }

             LCD_Custom_Out (2, 1, "DEV=") ;
             LCD_Custom_INT (2, 5,  dev, 3) ;
             LCD_Custom_Out (2, 9, "CMD=") ;
             LCD_Custom_INT (2, 13,  cmd, 3) ;
             LCD_Custom_Chr (2, 17, IR.toggle?'T':' ') ;
             LCD_Custom_INT (2, 19, repeat, 3) ;

          }
          #if 0
          else {
             if (RC5_timesIndex)
             {
              INTCON.GIE  = 0;      // bit7 global interrupt disable
               LCD_Custom_INT (2, 20, RC5_bitcount, 2) ;
                for (i=0 ; i<RC5_timesIndex; i++)
                {
                    LCD_Custom_Out (2, 1, "IDX=") ;
                    LCD_Custom_INT (2, 5,  i, 3) ;
                    LCD_Custom_Out (2, 9, "TMR=") ;
                    LCD_Custom_INT (2, 13, RC5_times[i], 3) ;
                    Delay_ms(2000) ;
                }
                LCD_Custom_Out (2, 1, "                         ") ;
                RC5_timesIndex = 0 ;
                INTCON.GIE = 1;      // bit7 global interrupt enable

             }
          }
          #endif

          Delay_ms (250) ;
    }
} // end main

//------------------------------------------------------------------------------
// AUXILIARY ROUTINES
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void  Lcd_Custom_INT (int row, int col, int x, unsigned char size)
{
      static char txt[7] ;
      int i ;

      IntToStr (x, txt) ;
      for (i=0; i<7; i++) if (txt[i] == ' ') txt[i] = '0' ;
      Lcd_Custom_Out(row, col, txt+(6-size)) ;
}


////////////////////////////////////////////////////////////////////////////////
// THAT'S ALL, FOLKS
////////////////////////////////////////////////////////////////////////////////
hi rudolflapie,

may i know your configuration setup for this?

im using PIC18F452 in 8MHz Crystal too.. but i cant work on this.. it seems the INT0 Interrupt wont trigger in my IR Output, and to ensure that i receive/my IR works fine, i put an LED into it to monitor the output...


this is the IR that i am using.
http://www.alldatasheet.com/datasheet-p ... 18SCL.html

whenever i tried to tap the INT0 to the ground, it goes into the ISR, but then when connected to the IR... it doesnt react at all..


thanks..

gigz09
Posts: 5
Joined: 05 Dec 2008 23:58

#10 Post by gigz09 » 28 Jan 2010 08:16

^

i already tried TSOP1736..
yeah the ouput signal now triggers the INT0 interrupt but it doesnt decode the command from my remote..

argh... what should i do..

gigz09
Posts: 5
Joined: 05 Dec 2008 23:58

Re: Philips IR RC5 protocol

#11 Post by gigz09 » 12 Feb 2010 04:24

forgot to update.. i already using this code.. ^_^

i was able to function it well the day that i've posted my message above=)

thanks rudolf=)

DAXweb
Posts: 4
Joined: 19 Oct 2008 04:09

Re: Philips IR RC5 protocol

#12 Post by DAXweb » 19 Oct 2010 14:01

Your code is really really fantastic!
Thanks a lot for share your knowledge!

DAXweb

grimstoner
Posts: 2
Joined: 03 Jan 2011 17:37

Re: Philips IR RC5 protocol

#13 Post by grimstoner » 04 Jan 2011 09:38

Hi

What should the value for the prescaler and the 3 constants be if I use a 20Mhz xtal prescaled to 48Mhz (for USB communication)?

sahu
Posts: 85
Joined: 11 Apr 2010 19:37

Re: Philips IR RC5 protocol

#14 Post by sahu » 11 Jul 2011 20:37

i want to led on\off with NEC ir protocol .but cont under stand how can convert RC5 code in to NEC.
SAHU

sahu
Posts: 85
Joined: 11 Apr 2010 19:37

Re: Philips IR RC5 protocol

#15 Post by sahu » 13 Jul 2011 20:35

pl reply me
SAHU

sahu
Posts: 85
Joined: 11 Apr 2010 19:37

Re: Philips IR RC5 protocol

#16 Post by sahu » 24 Jul 2011 10:40

ANY BODY LEASING ME ?
SAHU

ducu
Posts: 30
Joined: 04 Jul 2010 02:32
Location: Galati,RO

Re: Philips IR RC5 protocol

#17 Post by ducu » 09 Feb 2012 19:18

Hello gentlemen,
Mr. Danny, I want to congratulate you for your code.
Mr. Rudolf, my congratulations for translation in mikroC,
If you would like to enlightened me in three issues:
1. Can I use instead of TSOP1736, TSOP1738? means 38KHz instead of 36khz, would work?
2. What changes do you think should be made ​​to work on 38KHz?
3. I want to translate code written by Mr. Rudolph, in mikroC Pro for Pic, can you tell me if I wrong somewhere?
I attach modified code, below:

Code: Select all

/************************************************************************************
*               MAIN PROGRAM for PHILIPS RC5 IR RECEIVER                           *
************************************************************************************
*                 Original MikroPascal version : D. Rosseel                        *
*              http://users.edpnet.be/rosseel01/DRO/PIC/index.htm                  *
*                                                                                  *
*                 Converted to MikroC by Rudolf Lapie                              *
*                                                                                  *
* Original version : 15-FEB-2009              Last change : 16-FEB-09              *
* MikroC version : 18-FEB-2009                Last change : 18-FEB-09              *
*                                                                                  *
* For Rc5 receivers with inverse output (= output active low), like the TSOP1736.  *
* The output of the Rc5 receiver is to be connected to the PIC's external          *
* interrupt pin (PortB.0).                                                         *
                                                                                    *
* The timer0 requires a clock (after prescaler) of 62.5 KHz. This means, when the  *
* CPU clock is 4 MHz a prescaler value of 16 is required: 4 MHz / 4 / 16 =62.5 KHz *
* The time/timerstep is then 16 microsecs. (1/62500)                               *
* For other CPU clock speeds the prescaler has to be adjusted accordingly, or      *
* if not possible both prescaler and "RC5_TIME_..." constants have to be adapted.  *
* e.g. for 8Mhz : use 1:32 as prescaler                                            *
************************************************************************************
* Algorithm :                                                                      *
* ~~~~~~~~~~~                                                                      *
* Everytime the input on pin RC5 changes an interrupt is generated. In the handler *
* the time is measured between 2 subsequent changes. Based on this difference a    *
* decision is made on what the previous bit was : a short pulse or a double pulse  *
* If the timing is out of range the code is considered invalid and the handler     *
* resets itself to the initial state.  A state machine is used with 3 states :     *
* IDLE, DECODING & COMPLETED                                                       *
************************************************************************************
* Hardware config : 18F452 @ 8Mhz  + TSOP1736 + LED + LCD                          *
* -------------------------------------------------------------------------------- *
* LED on PortD.F2 (active when port low)                                           *
* TSOP-1736 : Output pin connected to PORTB.F0 (active when low)                   *
* LCD : HD44780 on PORTB : bits 1..4 = D4...D7 / 5 = EN / 6 = RS / 7 = RW          *
* Note : when using a different Crystal speed, you will need to change prescaler   *
* in the main program and potentially the counters in the definition section       *
************************************************************************************
*/

/*
--------------------------------------||----------------------------------------
I intend to transfor this awesome Algorithm into MikroC Pro for Pic Language.
My Hardware config: 16f876A @8MHz + TSOP4838 + Led + Lcd
LED on PortC.F0 (active when port low)
TSOP-4838 : Output pin connected to PORTB.F0 (active when low)
LCD : HD44780 (2x16 character)on PORTB : 1 = RS / 2 = EN / bits 4..7 = D4...D7.
      RW and D0-D3 to ground.
--------------------------------------||----------------------------------------
*/




// Remove next line for production code !
//#define DEBUG

//-----------------------------------------------------------------------------
// Hardware specific settings
//-----------------------------------------------------------------------------
#define LED_On()      (PORTC.F0=0)
#define LED_Off()     (PORTC.F0=1)
#define LED_Toggle()  (PORTC.F0=~PORTC.F0)

#define IR_PIN        (PORTB.F0)

//-----------------------------------------------------------------------------
// Predefined constants
//------------------------------------------------------------------------------
#define RC5_NR_Bits   14

//In total 14 Rc5_Bits are to be captured (the first "startbit" is already there
//when the first interrupt occurs)
// The format of the received bits is:
//  - 2 startbits (both "1")
//  - 1 toggle bit (changes every time when a non repeated command is sent)
//  - 5 "System" bits, most significant bit first
//  - 6 "Command" bits, most significant bit first
// The bits are recognized by the time between 2 "edges" of the RC5 signal:
//  - a "long time" means: bit received that differs from the previous one
//  - two RC5_times "short" means: bit received that equals the previous one
//    the previous bit to start with is always "1"

#define RC5_TIME_BOUNDARY       83  // below 83 = short, above = long (0.75 bittime)
#define RC5_TIME_TOO_SHORT      28  // (0.25 bittime)
#define RC5_TIME_TOO_LONG      140  // (1.25 bittime)

// 1 bit time = 1778 uS
//    "short" time = 1/2 bittime = 889 uS, = timer value 55.5 (= 889/16)
//    "long"  time = 1 bittime = 1778 uS,  = timer value 111.12 (=1778/16)
// Note : constant values depend on the speed of your crystal !

//-----------------------------------------------------------------------------
// Global variables
//-----------------------------------------------------------------------------
enum {
      RC5_IDLE,
      RC5_DECODING,
      RC5_COMPLETED
} RC5_state = RC5_IDLE ;

#ifdef DEBUG
unsigned char RC5_times[26] ;  // array for the Rc5_Times measured
unsigned char RC5_timesIndex; // index/count for above
#endif
unsigned int   RC5_bits ;               // will hold the received bits
unsigned char  RC5_bitCount ;           // nb of bits processed
unsigned char  RC5_prevBit ;            // the value of the previous bit
unsigned char  RC5_shortPulses ;        // nr of subsequent short pulses measured

struct
{
    toggle   : 1 ;
    device   : 5 ;
    command  : 6 ;
    received : 1 ;
} IR ;

//-----------------------------------------------------------------------------
// LCD module connections
sbit LCD_RS at RB1_bit;
sbit LCD_EN at RB2_bit;
sbit LCD_D4 at RB4_bit;
sbit LCD_D5 at RB5_bit;
sbit LCD_D6 at RB6_bit;
sbit LCD_D7 at RB7_bit;

sbit LCD_RS_Direction at TRISB1_bit;
sbit LCD_EN_Direction at TRISB2_bit;
sbit LCD_D4_Direction at TRISB4_bit;
sbit LCD_D5_Direction at TRISB5_bit;
sbit LCD_D6_Direction at TRISB6_bit;
sbit LCD_D7_Direction at TRISB7_bit;
// End LCD module connections
//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
// Forward Declarations
//-----------------------------------------------------------------------------

void  Lcd_Custom_INT (int row, int col, int x, unsigned char len);

//------------------------------------------------------------------------------
// Interrupt handler
//------------------------------------------------------------------------------
void interrupt()
{
     unsigned char time, i ;

     // RB0 interrupt
     if (INTCON.INTF)
     {
       LED_Toggle ();

       INTCON.INTEDG = 1-INTCON.INTEDG ; // toggle the INTEDG (interrupt edge)
       INTCON.INTF = 0;

       time = TMR0;       // get time
       TMR0 = 0;          // restart timer

       switch (RC5_state)
       {
           ////////// IDLE STATE. NOTHING RECEIVED YET ////////////////////////
           case RC5_IDLE :
                #ifdef DEBUG
                RC5_timesIndex  = 0;
               #endif
                RC5_bits        = 1; // already 1 bit (with value "1") received
                RC5_bitCount    = 1;
                RC5_shortPulses = 0;
                RC5_prevBit     = 1;
                RC5_state       = RC5_DECODING;

                INTCON.T0IF = 0; // reset Timer0 overflow flag
                INTCON.T0IE = 1; // enable timer0 interrupt
                break ;

           ////////// CHANGES DETECTED. WE START PROCESSING BITS////////////////
           case RC5_DECODING :  // Execution time is about 52 uS at 4 Mhz CPU clock
                #ifdef DEBUG
                RC5_times[RC5_timesIndex] = time; // get timer value
                RC5_timesIndex ++ ;
                #endif

                if ((time > RC5_TIME_TOO_SHORT) && (time < RC5_TIME_TOO_LONG))
                {
                     if (time < RC5_TIME_BOUNDARY)  // short pulse detected
                     {
                        RC5_shortPulses ++ ;
                        if (RC5_shortPulses == 2)
                        {
                           RC5_bits <<= 1;          // store the bit received
                           RC5_bits |= RC5_PrevBit;
                           RC5_bitCount ++ ;
                           RC5_shortPulses = 0;
                        }
                     } else {    // long pulse detected
                        RC5_prevBit = 1- RC5_prevBit;  // toggle the bit
                        RC5_bits <<= 1;            // store the bit received
                        RC5_Bits |= RC5_PrevBit;
                        RC5_bitCount ++ ;
                        RC5_shortPulses = 0;
                     }

                     if (RC5_bitCount == RC5_NR_Bits)// all bits are received
                     {
                        RC5_state = RC5_COMPLETED;
                        INTCON.INTEDG = 0; // next RC5 interrupt is negative going
                        INTCON.T0IE = 0;     // disable timer0 interrupt
                     }
                } else { // something is wrong about timing
                     RC5_state = RC5_IDLE;  // start all over
                     INTCON.INTEDG = 0; // next RC5 interrupt is negative going
                     INTCON.T0IE  = 0; // disable timer0 interrupt
                }
                break ;

           /////////// ALL BITS RECEIVED CORRECTLY. Store the data /////////////
           case RC5_COMPLETED :
                INTCON.INTEDG = 0; // next RC5 interrupt is negative going

                IR.toggle = ((RC5_bits>>11) & 0x01) ? 0 : 1 ;
                IR.device =  (RC5_bits>>6) & 0b00011111 ;
                IR.command=  (RC5_bits & 0b00111111) ;
                IR.received = 1 ;
                RC5_state = RC5_IDLE ;
                #ifdef DEBUG
                for (i= 0; i < sizeof(RC5_times); i++) RC5_times[i] = 0;
                #endif
                break ;

       } // end switch
     } // end INTCON.INTF

     // Timer 0 interrupt
     if (INTCON.T0IF)  // timer 0 overflow, timeout
     {
        if (RC5_state == RC5_DECODING) // something is wrong
        {
           RC5_state = RC5_IDLE;  // start all over
           INTCON.INTEDG = 0;   // next RC5 interrupt is negative going
           INTCON.T0IE  = 0;      // disable timer0 interrupt
        }
     }

     INTCON.T0IF = 0; // always reset timer0 overflow flag

} // end interrupt routine

//-----------------------------------------------------------------------------
// MAIN PROGRAM
//------------------------------------------------------------------------------
void main ()
{
     unsigned int dev, cmd ;
     unsigned int repeat ;
     unsigned char last_toggle ;
     int i  ;

     // Initialize state machine

     RC5_state = RC5_IDLE ;
     #ifdef DEBUG
     for (i=0; i< sizeof (RC5_times); i ++) RC5_times[i] = 0 ;
     #endif

     // INITIALISE all registers
    ADCON0 = 0x00 ;         // No ADC convertors
    ADCON1 = 0x87;          // No ADC convertors
    CMCON  |= 7 ;           // turn off comparators - Not available in 18F452

    PORTB = 0;
    TRISB = 0b00000001;     // set PORTB D7-D1 = LCD  / D0 = IR receiver

    PORTC = 0 ;
    TRISC = 0;              // set PORTC as input except for bits 0 : LED

    // Setup Timer 0, but don't enable it yet  --> Settings depend on Crystal
    // Initialise TIMER0  : Prescaler= 1:32 -  1 tick = 16 usec / 62.5 Khz
    OPTION_REG  = 0b11000100;     // enable timer, 8 bit mode, 1:32 prescaler
    TMR0  = 0;  // preset for timer register

    INTCON.PEIE = 1;
    INTCON.T0IF = 0;
    INTCON.T0IE = 0;      // disable timer 0 interrupt for now

    // Enable external interrupt
    INTCON.INTEDG    = 0;            // start with downgoing edge
    INTCON.INTF      = 0;            // Clear interrupt
    INTCON.INTE      = 1;            // Enable RB0 interrupt
    INTCON.GIE       = 1;            // bit7 global interrupt enable

    // Initialise LCD
    Lcd_init();
    Lcd_cmd(_Lcd_cursor_off);        // Set the cursor to off;
    //Lcd_out(1,1,"Philips RC5");      // Message on first row, first column
    

    // Main program loop
    IR.received = 0 ;
    last_toggle = 2 ; // Impossible

    while (1)
    {
          if (IR.received)
          {
             dev = IR.device ;
             cmd = IR.command;
             IR.received = 0 ;  // Processed the command

             if (last_toggle == IR.toggle)
             {
                repeat ++ ;
             } else {
                repeat = 0 ;
                last_toggle = IR.toggle;
             }

             LCD_Out(2, 1, "DEV=") ;
             LCD_Custom_INT (2, 5,  dev, 3) ;
             LCD_Out (2, 9, "CMD=") ;
             LCD_Custom_INT (2, 13,  cmd, 3) ;
             LCD_Chr (1, 1, IR.toggle?'T':' ') ;
             LCD_Custom_INT (2, 3, repeat, 3) ;

          }
          #if 0
          else {
             if (RC5_timesIndex)
             {
              INTCON.GIE  = 0;      // bit7 global interrupt disable
               LCD_Custom_INT (1, 10, RC5_bitcount, 2) ;
                for (i=0 ; i<RC5_timesIndex; i++)
                {
                    LCD_Custom_Out (2, 1, "IDX=") ;
                    LCD_Custom_INT (2, 5,  i, 3) ;
                    LCD_Custom_Out (2, 9, "TMR=") ;
                    LCD_Custom_INT (2, 13, RC5_times[i], 3) ;
                    Delay_ms(2000) ;
                }
                LCD_Out (2, 1, "                         ") ;
                RC5_timesIndex = 0 ;
                INTCON.GIE = 1;      // bit7 global interrupt enable

             }
          }
          #endif

          Delay_ms (250) ;
    }
} // end main

//------------------------------------------------------------------------------
// AUXILIARY ROUTINES
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
void  Lcd_Custom_INT (int row, int col, int x, unsigned char size)
{
      static char txt[7] ;
      int i ;

      IntToStr (x, txt) ;
      for (i=0; i<7; i++) if (txt[i] == ' ') txt[i] = '0' ;
      Lcd_Out(row, col, txt+(6-size)) ;
}
I must say that on the lcd screen, nothing is shown.

microIC
Posts: 82
Joined: 06 Nov 2014 10:45

Re: Philips IR RC5 protocol

#18 Post by microIC » 24 Nov 2015 21:38

Hi to all,

is there anybody who try this software, I try it with Proteus, and is not working. Then I put it on easyPic6 and is not working.

Thanks,
Damir

Post Reply

Return to “mikroC General”