Philips IR RC5 protocol

General discussion on mikroC.
Author
Message
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”