Philips IR RC5 protocol
Re: Philips IR RC5 protocol
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:
I must say that on the lcd screen, nothing is shown.
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)) ;
}
Re: Philips IR RC5 protocol
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
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