Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

C codes for decoding RC5 signals using PIC microcontoller

Status
Not open for further replies.

CMOS

Advanced Member level 3
Joined
Jan 6, 2004
Messages
862
Helped
94
Reputation
186
Reaction score
50
Trophy points
1,308
Location
USA
Activity points
5,673
Can anyone share C code for decoding RC5 signals using PIC microcontoller? I've googled for days and all the code that I found used delays to sample the signal..which causes problem when RC5 signal timings are slightly different than standard. None of them actually uses manchester decoding.

I am looking for a code like the BASCOM 8051/AVR compilers internal library has. Till date its the best RC5 decoding code I have found...it works for any damn RC5 remote...irrespective of timing variations.

Now I am looking for similar code for PIC. Anyone please?
 

rc5 pic

mm C, i don know any library, but same to bascom only Proton 3.0 has RC5 library, and Sony IR Protocols library. but is in Basic.


Example

Device = 16F877
RC5IN_PIN = PORTC.0 ' Choose the port and pin for the infrared sensor
DIM RC5_WORD as WORD ' Create a WORD variable to receive the data
DIM RC5_COMMAND as RC5_WORD.Lowbyte ' Alias the COMMAND byte to RC5_WORD low byte
DIM RC5_SYSTEM as RC5_WORD.Highbyte ' Alias the COMMAND byte to RC5_WORD high byte

ALL_DIGITAL = ON ' Make all pins digital mode
Cls ' Clear the LCD
While 1 = 1 ' Create an infinite loop
Repeat
RC5_WORD = RC5In ' Receive a signal from the infrared sensor
Until RC5_COMMAND<> 255 ' Keep looking until a valid header found
Print at 1,1,"SYSTEM ",Dec RC5_SYSTEM," " ' Display the SYSTEM value
Print at 2,1,"COMMAND ",Dec RC5_COMMAND," " ' Display the COMMAND value
Wend
 
  • Like
Reactions: baburupesh

    CMOS

    Points: 2
    Helpful Answer Positive Rating

    baburupesh

    Points: 2
    Helpful Answer Positive Rating
rc5 code

C code would be really helpful. Anyone please?

Anyways, thanks for your reply cesarman.
 
pic rc5 decoder

To suppose the IR receiver chip will filter out the carrier, and define the modulated carrier is SIGNAL, other is IDLE.
In fact, to decode Philips RC-5/RC-5X (bi-phase/Manchester coding) is similar to others (such like NEC/Sony).
An important trick for robust implementation is: tolerance. (ex: SIGNAL will be short if distance is long)
All of them are only tracking/measuring the tolerances of SIGNAL and IDLE time.

Well, here are the modified code (remove useless code for RC5), FYR.

Code:
// hardware dependent 
#define is_SIGNAL_IR() (IR_PIN==0)
#define is_IDLE_IR() (IR_PIN==1)
#define set_TIME_IR(tm) IR_TIME=tm
#define get_TIME_IR() IR_TIME
Code:
// definition
#define nIRtimeBase 1 // 1uS
#define nIRtolerance 30 // +/- 30%
#define defIRtime 889 // 889uS RC-5/RC-5X 1 physical (half logic) bit time
#define minIRtime ((((((100-nIRtolerance)*defIRtime)*10)/(nIRtimeBase*100))+5)/10) 
#define maxIRtime ((((((100+nIRtolerance)*defIRtime)*10)/(nIRtimeBase*100))+5)/10)
Code:
// parameter declaration
	U8 gIRstat; // IR state number
enum { stIR_NONE=0, stIR_IDLE, stIR_SIGNAL };
	U16 gIRdata; // IR data (14 logic bits)
#define add_Data_0_IR()  gIRdata <<= 1
#define add_Data_1_IR()  gIRdata <<= 1; gIRdata |= 1
	U8 gIRcount; // IR bit counter
#define    nIRcount	(14*2)	// 14 logic bits = 28 physical bits
	U8 gIRruntime; // IR running time (counting only if gIRstat != stIR_NONE)
#define    nIRruntime 25000 // 25mS: 14*(889+889)=24.892mS
	BIT bIRphysicalBitCount; // 0:1st physical bit, 1:2nd physical bit
	BIT bIRphysicalBitData;	// last physical bit data
	BIT bIRnewHit; // 1:new IR code is received
Code:
VOID InitIR( VOID ) // initial IR engine
{
  gIRstat = stIR_NONE;
  bIRnewHit = FALSE;
  // hardware dependent: set correct snapped interrupt edge setting
}
Code:
VOID TimeoutIR( VOID ) // check IR running timeout
{
   if( gIRstat != stIR_NONE) {
      if( gIRruntime > nIRruntime ) { // timeout
         InitIR();
      }
   }
}
This PollIR can be processed by fast polling loop (due to RC5 bit time) or interrupt driven.
To suppose to use interupt driven here. The Port Change or External INT are well done. But it is only called when the edge of IR signal is changed.
Code:
VOID PollIR( VOID ) // put it in ISR (trigger when IR_PIN edge is changed)
{
   U8 mIRtime;

   mIRtime = get_IR_TIME(); set_IR_TIME(0);
   switch( gIRstat ) {
      case stIR_NONE:
           if( is_SIGNAL_IR() ) { // 1st logic bit (start bit) is 1 (01)
              // IR engine is starting
              gIRstat++; //  gIRstat =  stIR_IDLE; 
              gIRruntime = 0; // IR running time is counting
              gIRdata = 0; // it is not necessary if mask unused bits before using it
              gIRcount = 1; // as hit 1st physical bit
              bIRphysicalBitCount = 1; // ready to process 2nd physical bit
              return;
           }
           return;
      case stIR_IDLE: // now is IR.IDLE signal (process last SIGNAL)
           if( mIRtime > 2*maxIRtime ) { // time > 2t
              goto _error_IDLE_PollIR; // last signal too long
           }
           if( mIRtime < 1*minIRtime ) { // time < 1t
              goto _error_IDLE_PollIR; // last signal too short
           }
           bIRphysicalBitData = 0; // now is IDLE
           if( bIRphysicalBitCount == 0 ) { // now is 1st physical bit (1x)
              if( mIRtime > 2*minIRtime ) { // time > 2t
                 goto _error_IDLE_PollIR; // bad code, bi-phase no this (11) combination
              }
              bIRphysicalBitCount = 1; // ready to process 2nd physical bit
           } else { // now is 2nd physical bit (01)
              add_Data_1_IR(); // add logic bit data 1 (01)
              if( mIRtime < 2*minIRtime ) { // time < 2t 
                 bIRphysicalBitCount = 0; // ready to process 1st physical bit
              } else { // time >= 2t, it is 011 (extra physical bit) 
                 gIRcount++; // add extra physical bit count
                 bIRphysicalBitCount = 1; // ready to process 2nd physical bit
              }
           }
           break;	
      case stIR_SIGNAL: // now is IR.SIGNAL signal (process last IDLE)
           if( mIRtime > 2*maxIRtime ) { // time > 2t
              goto _error_SIGNAL_PollIR; // last signal too long
           }
           if( mIRtime < 1*minIRtime ) { // time < 1t
              goto _error_SIGNAL_PollIR; // last signal too short
           }
           bIRphysicalBitData = 1; // now is SIGNAL
           if( bIRphysicalBitCount == 0 ) { // now is 1st physical bit (0x)
              if( mIRtime > 2*minIRtime ) { // time > 2t
                 goto _error_SIGNAL_PollIR; // bad code, bi-phase no this (00) combination
              }
              bIRphysicalBitCount = 1; // ready to process 2nd physical bit
          } else { // now is 2nd physical bit (10)
              add_Data_0_IR(); // add logic bit data 0 (10)
              if( mIRtime < 2*minIRtime ) { // time < 2t 
                 bIRphysicalBitCount = 0; // ready to process 1st physical bit
              } else { // time >= 2t, it is 100 (extra physical bit) 
                 gIRcount++; // add extra physical bit count
                 bIRphysicalBitCount = 1; // ready to process 2nd physical bit
              }
          }
          break;	
   }

   // ready to process next physical bit
   gIRcount++; 
   if( gIRcount >= nIRcount ) { // the last physical bit
      goto _complete_check_PollIR;
   }
   if( gIRcount == nIRcount-1 ) { // the 27th physical bit
      if(  bIRphysicalBitData == 0 ) { // now is 0 as complete, due to no more new edge will be changed
         bIRphysicalBitCount = 0; // as ready to process 1st physical bit
         add_Data_0_IR(); // add logic bit data 0 (10)
         goto _complete_check_PollIR;
      }
   }
   // the 1~27th physical bit
   gIRstat = bIRphysicalBitData == 0 ? stIR_SIGNAL : stIR_IDLE; // swap state
   // hardware dependent: toggle snapped interrupt edge setting
   return;

_complete_check_PollIR:
   if( bIRphysicalBitCount == 0 ) { // correct, no any pending physical bit
      InitIR();
      // ex: check Start Bit, process Toggle(Repeat) Bit, translate Address/Command Bits....
      bIRnewHit = TRUE;
      return;
   }

_error_IDLE_PollIR:
_error_SIGNAL_PollIR:
   InitIR();
   return;
}
Actually, the stIR_IDLE and stIR_SIGNAL states can be merged together for saving code space.
But I still split them and use 'goto' (non-structued coding style) for easy reading.
Besides, we have to process 1st and last physical bit carefully.
1st physical bit: it is hidden (as IDLE) because RC5's start logic bit is 1 (01)
last physical bit: it will be hidden if last logic bit is 0 (10)
Code:
VOID main( VOID )
{
   InitIR(); // initial IR engine

   while(1) { // main endless polling loop
      if( bIRnewHit == TRUE ) { // new IR code is coming
         bIRnewHit = FALSE;
         // process IR event here
      }
      TimeoutIR(); // check IR running timeout
   }
}
The above code will not handle the Toggle(Repeat) Bit. (RC5/RC5X used it to notify the key is repeating)
It also will not check the 2nd Start Bit. It should be 1 if RC5. RC5X (Extended RC-5) inverted it as the 7th (MSB) Command Bit.

Last, for more IR Remote Control informations, I suggest the San Bergmans's Knowledge Base pages: https://www.sbprojects.com/knowledge/ir/ir.htm
He made great works.
 
rc5 protocol pic

yager, I didnt quite understand "#define get_TIME_IR() IR_TIME"...Can you explain this?

Thanks a lot anyways :D
 

rc5 c code

CMOS said:
I didnt quite understand "#define get_TIME_IR() IR_TIME"...Can you explain this?
It is a hardware dependent macro to get a time value from real hardware TIMER or something.
In fact, we have to consider it with 'set_TIME_IR' and 'nIRtimeBase' together.
1. to suppose to use 8-bit hardware timer as our IR timer and it is used for IR only
the 'maxIRtime' will be 2312 (2t = 4624), so use your PIC's timer0 and set 1:32 prescaler (clock source: fosc/4, with internal 4MHz), ie:
Code:
#define IR_TIME TMR0
#define nIRtimeBase 32
2. as the above, but the IR timer is shared with others
we have to treat the timer0 as free running timer and:
Code:
#define IR_TIME TMR0
U8 gIR_TIME;
#define set_TIME_IR(tm) gIR_TIME = IR_TIME
#define get_TIME_IR() (IR_TIME - gIR_TIME)
#define nIRtimeBase 32
Since they are hardware dependent parts, so I split them to increase the code portability.
i.e. we do not need to modify the core, just adjust them for other platform or different hardware settings (8MHz OSC, 16-bit timer.....)

BTW, to implement these time critical code by internal OSC, we have to consider the Oscillator Accuracy.
The PIC is good enough: +/- 1% at 25oC, +/- 2% at 0~85oC for a wide working voltage
 

    CMOS

    Points: 2
    Helpful Answer Positive Rating
rc5 ccs

Ok...I got it now. I'll try that out and let you know the results.

Thanks a lot.
 

rc5 decoder pic

I posted a RC5 decoder in asm some time ago. This calibrates the timing every time and uses Manchester coding. It works well! To use it in a C program, compile it to a lib and just link it in.



Well it was some time ago, just had a look at what I done.
This code kicks ass!
 

rc5 with pic ccs

How to code for 8051 microcontroller in asm.
 

pic rc5 code

I found this simple code a while ago, its really simple.

I have not tested it my self yet.

Use RB0 interrupt to be able todetect RC5 incomming packets. As the code shows, the interrupt has to be triggered on the rising edge of RB0 pin, means from 0 to 1 change.

Code:
#define IR		RB0


Code:
/*--------------------------------------------------------------
 *
 * RC5_RECEIVE - Checks IR receiver and returns the following:
 *
 *               0:  no meaningful IR data present
 *              !0:  14 bit RC5 packet
 *
 *-------------------------------------------------------------*/

unsigned int
rc5_receive(void)
{
	unsigned int message;
	unsigned char i, cnt, IR_old;
	message = 0;
	if (!IR) {	// in middle of start bit
		for (i=0;i<14;i++) {
			message = message << 1 + IR;
			cnt = 6;	// wait 1500ms (just before middle of 
next bit at 1778ms)
			do {
				DelayUs(250);
			} while (--cnt);
			IR_old = IR;
			cnt = 50;
			do {
				DelayUs(10);
			} while (IR_old == IR & --cnt);
			if (!cnt) return (0);	// cnt = 0 indicates timeout - return 0
		}
	}
	return (message);
}
[/quote]
 

rc5 pic code

metal said:
I found this simple code a while ago, its really simple.

I have not tested it my self yet.

Use RB0 interrupt to be able todetect RC5 incomming packets. As the code shows, the interrupt has to be triggered on the rising edge of RB0 pin, means from 0 to 1 change.

I already have similar kind of code. It doesnt work with all types of RC5 remotes. If there is slight difference in signal timings, you have to sit and trim the counter values. Instead if you use manchester decoding, you can derive the clock from signal itself solving the problem of timing variations.
 

rc5 coding in pic

Hi,

As I have already stated, I have not tested this code.

Any way, you are completely right about that, and I have read this kind of info regarding the use of mancheter decoding in order to derive the clock from the RC5 signal it self inorder to detect the leading and trailing edges of the RC5 signal.

I don't know if the code posted by yager does this kind of manchester decoding. Any way, we still need a real simple and reliable code to do that.

I am still a beginner @ C coding, hence I will be watching this thread and see what result we get, hopefully we will end with a good code for RC5 decoding.


Regards
 

pic rc-5

Yea...I am in the process of testing yage's code. It actually does manchester decoding. Will post out the results soon.
 

rc5 pic c

Working RC5 decoder thats calibrates timing and uses Manchester decoding.
Call routine from interrupt when RB0 goes low, or call by polling IR input pin and call when it goes low.

Code:
/*------ RC5 decoder program Version 1.0 (by btbass) 'bob the bass' 4MHz clock

;------ RC5 code is 14 bits each of 1.8mS duration with carrier frequency of 36KHz.
;------ A '0' is a mid pulse transition from high to low.
;------ A '1' is a mid pulse transition from low to high.
;------ The first 2 bits are always 1, for timing calibration.
;------ The next bit is the toggle bit, indicating a new keypress.
;------ Then 5 bits of address and 6 bits of command code.
;------ The IR receiver inverts the data stream. (check, but most do!)
;------ This program uses the first 2 bits to calibrate the timing of one pulse length.
;------ It then waits 3/4 pulse length and looks at the input.
;------ If its high, it waits for a low '0'. 
;------ If it's low, it waits for a high '1', then resets the timer on the transition.
;------ It returns 0x01 if the code is ok and 0x00 if an error.
;------ The rc5 system address is returned in address, the command in command.
;------ The toggle bit is bit 5 of the address byte. 
;------ Using a 4 Meg xtal with timer divided by 128. */

#include <pic.h>
#include "rc5decode.h"

/*--- globals ---*/

unsigned char command;
unsigned char address;
unsigned char temp;
unsigned char timer;
unsigned char rc5valid;

/*--- rc5 decode function ---*/

unsigned char rc5Decode(void)
  {
  #asm
                                              
;------ calibrate timing 

          bcf     3,5         ;select bank 0
          clrf    TMR         ;start timer      
          call    Wlow        ;get the pulse length                           
          call    Whigh

          btfsc   TMR,7       ;test for timer overflow
          goto    codeError   ;bail out

          movf    TMR,w       ;save pulse length 
          clrf    TMR         ;start timer                      

          movwf   _timer      ;take the pulse length,
          movwf   _temp       ;save it
          bcf     3,0         ;clear carry
          rrf     _temp,f     ;divide by 2
          bcf     3,0         ;clear carry
          rrf     _temp,f     ;divide by 4
          movf    _temp,w     ;and subtract to get
          subwf   _timer,f    ;3/4 pulse length

          movlw   0x0c
          movwf   _temp       ;init bit counter
                     
;------ wait for start of data

nextBit   movf    _timer,w    ;wait 3/4 pulse length
          subwf   TMR,w
          btfss   3,2         ;take a look
          goto    nextBit
                                                                                                                            
;------ start of data stream

          btfss   IR_IN       ;if its high
          goto    waitlow     ;gonna be an 0
                       
;------ wait for high 1

          call    Whigh       ;if its low
          bsf     3,0         ;gonna be a 1
          goto    clock       
            
;------ wait for low 0

waitlow   call    Wlow        
          bcf     3,0         ;gonna be an 0
            
;------ clock data

clock     clrf    TMR         ;restart timer
          rlf     _command,f  ;save the bit
          rlf     _address,f
          decfsz  _temp,f     ;done all bits?
          goto    nextBit                  
                            
;------ get system address, toggle bit and command code

          movf    _command,w  ;copy low byte
          movwf   _temp       ;into temp 
          rlf     _temp,f     ;need to shift 2 bits
          rlf     _address,f  ;into address
          rlf     _temp,f
          rlf     _address,f  ;system address is 5 bits

          movlw   0x3f        ;mask system address + toggle bit
          andwf   _address,f
           
          movlw   0x3f        ;mask command code
          andwf   _command,f  ;command code is 6 bits          
          goto    rc5ok       ;done ok                       
            
;------ wait while low

Wlow      btfsc   TMR,7       ;test for timer overflow
          return              ;bail out
          btfss   IR_IN
          goto    Wlow
          return  
            
;------ wait while high

Whigh     btfsc   TMR,7       ;test for timer overflow
          return              ;bail out
          btfsc   IR_IN
          goto    Whigh
          return   

rc5ok     movlw   0x01
          movwf   _rc5valid
          goto    rc5end
codeError clrf    _rc5valid 
rc5end    nop       

  #endasm

  return rc5valid;
  }

/*--- End of File ---*/

Header file

Code:
/*--- rc5decode.h ---*/

#ifndef RC5DECODE
#define RC5DECODE 

/*--- Function prototype ---*/

unsigned char rc5Decode(void);

/*---- globals ---*/

extern unsigned char command;   /* rc5 command code */
extern unsigned char address;   /* rc5 system address */
extern unsigned char rc5valid;  /* valid rc5 data flag */

#endif

/*--- Macros ---*/

#define IR_IN _PORTB,0  /* Infra Red input pin */
#define TMR   _TMR0     /* Pulse timer */

/*--- rc5 infra red codes ---*/

#define SYSTEM_ADD    0x10    /* System address */

#define RC5_VOL_UP    0x10    /* VOL+ */
#define RC5_VOL_DOWN  0x11    /* VOL- */
#define RC5_PHONO     0x01    /* PHONO */
#define RC5_TUNER     0x02    /* TUNER */
#define RC5_CD        0x03    /* CD */
#define RC5_AV        0x04    /* AV */
#define RC5_AUX1      0x08    /* AUX1 */
#define RC5_AUX2      0x09    /* AUX2 */
#define RC5_MUTE      0x0D    /* MUTE */

/*--- End of file ---*/
 

    CMOS

    Points: 2
    Helpful Answer Positive Rating
philips rc5 codes

Hi,

Thanks for sharing the code btbass. I would like to know what IR receiver chip I can use with this code, also how to connect it to PIC RB0 pin. Do I have to invert it, or just copnnect it to the IR receiver without any inversion.

Another thing, how can I know that a remote control unit is using RC5 protocol. I mean what kind of well known TVs that use it. For example we all know that sony TVs does use SIRC, and philips TVs use RC5.

Here we have non-branded remote control units shops that have no brands, just tell the shop man what TV brand you have, and he gives you the remote control unit that replaces the broken old one.

Regards
 

rc5 c code for pic

is RC5 the same as sony SIRC....
 

pic ir rc5

No, they are different. I don't know what the exact difference, but according to my knowledge, they are different.
 

philips rc5 code

I use a IS1U60 from RS, order code 577-897. But there are a lot of other similar receivers available.
This is a 3 terminal device, 5V, GND and output. It has an optical filter, an amplifier, demodulator and output driver all inside so you just take the output pin straight into the Pic input pin. The only other component needed is a 0.1uF decoupling cap accross its supply rail.
RC5 is a Philips protocol, but is also used by some other manufacturers.

PS. Please recopy the code, I made a typo translating the asm to c function.
 

rc5 code yager

Hi btbass,
I tried your code with 12F629, and it is working like charm.

My conenctions are like this
GPIO2 = IR Receiver
GPIO1 = RX Pin (MAX232)
GPIO0 = TX Pin (MAX232)

Thanks a lot buddy!! :D

Here is the full code.
Code:
//Main.c
/*------ RC5 decoder program Version 1.0 (by btbass) 'bob the bass' 4MHz clock

;------ RC5 code is 14 bits each of 1.8mS duration with carrier frequency of 36KHz.
;------ A '0' is a mid pulse transition from high to low.
;------ A '1' is a mid pulse transition from low to high.
;------ The first 2 bits are always 1, for timing calibration.
;------ The next bit is the toggle bit, indicating a new keypress.
;------ Then 5 bits of address and 6 bits of command code.
;------ The IR receiver inverts the data stream. (check, but most do!)
;------ This program uses the first 2 bits to calibrate the timing of one pulse length.
;------ It then waits 3/4 pulse length and looks at the input.
;------ If its high, it waits for a low '0'.
;------ If it's low, it waits for a high '1', then resets the timer on the transition.
;------ It returns 0x01 if the code is ok and 0x00 if an error.
;------ The rc5 system address is returned in address, the command in command.
;------ The toggle bit is bit 5 of the address byte.
;------ Using a 4 Meg xtal with timer divided by 128. */

#include <pic.h>
#include <stdio.h>
#include "rc5decode.h"

__CONFIG(INTIO & WDTDIS & PWRTEN & MCLRDIS);

/*--- globals ---*/
unsigned char command;
unsigned char address;
unsigned char temp;
unsigned char timer;
unsigned char rc5valid;

#define	PORTBIT(adr, bit)	((unsigned)(&adr)*8+(bit))
static bit	IR_PIN @	PORTBIT(GPIO, 2);

/*--- rc5 decode function ---*/
//static void interrupt 
unsigned char rc5decode(void)
{
  #asm
                                             
;------ calibrate timing

          bcf     3,5         ;select bank 0
          clrf    TMR         ;start timer     
          call    Wlow        ;get the pulse length                           
          call    Whigh

          btfsc   TMR,7       ;test for timer overflow
          goto    codeError   ;bail out

          movf    TMR,w       ;save pulse length
          clrf    TMR         ;start timer                     

          movwf   _timer      ;take the pulse length,
          movwf   _temp       ;save it
          bcf     3,0         ;clear carry
          rrf     _temp,f     ;divide by 2
          bcf     3,0         ;clear carry
          rrf     _temp,f     ;divide by 4
          movf    _temp,w     ;and subtract to get
          subwf   _timer,f    ;3/4 pulse length

          movlw   0x0c
          movwf   _temp       ;init bit counter
                     
;------ wait for start of data

nextBit   movf    _timer,w    ;wait 3/4 pulse length
          subwf   TMR,w
          btfss   3,2         ;take a look
          goto    nextBit
                                                                                                                           
;------ start of data stream

          btfss   IR_IN       ;if its high
          goto    waitlow     ;gonna be an 0
                       
;------ wait for high 1

          call    Whigh       ;if its low
          bsf     3,0         ;gonna be a 1
          goto    clock       
           
;------ wait for low 0

waitlow   call    Wlow       
          bcf     3,0         ;gonna be an 0
           
;------ clock data

clock     clrf    TMR         ;restart timer
          rlf     _command,f  ;save the bit
          rlf     _address,f
          decfsz  _temp,f     ;done all bits?
          goto    nextBit                 
                           
;------ get system address, toggle bit and command code

          movf    _command,w  ;copy low byte
          movwf   _temp       ;into temp
          rlf     _temp,f     ;need to shift 2 bits
          rlf     _address,f  ;into address
          rlf     _temp,f
          rlf     _address,f  ;system address is 5 bits

          movlw   0x3f        ;mask system address + toggle bit
          andwf   _address,f
           
          movlw   0x3f        ;mask command code
          andwf   _command,f  ;command code is 6 bits         
          goto    rc5ok       ;done ok                       
           
;------ wait while low

Wlow      btfsc   TMR,7       ;test for timer overflow
          return              ;bail out
          btfss   IR_IN
          goto    Wlow
          return 
           
;------ wait while high

Whigh     btfsc   TMR,7       ;test for timer overflow
          return              ;bail out
          btfsc   IR_IN
          goto    Whigh
          return   

rc5ok     movlw   0x01
          movwf   _rc5valid
          goto    rc5end
codeError clrf    _rc5valid
rc5end    nop       

  #endasm
	return rc5valid;
}

static void interrupt
isr(void)
{
	if(rc5decode())
	{
		address &= 0x1F;
		if(address == REMOTE_ADDRESS)
			printf("%d\r\n",command);
			//printf("Address:%d\r\nCommand:%d\r\n\n",address,command);
	}
	INTF = 0;
}

void main(void)
{
    OSCCAL = _READ_OSCCAL_DATA(); 		// restore oscillator calibration

	CMCON = 0x07;	// turn off comparator
	TRISIO = 0x3E;
	OPTION = 0x06;
	
	INTE = 1;		// enable the external interrupt
	GIE = 1;		// Global interrupt enable

	while(1);
}

/*--- End of File ---*/

Code:
//Serial.c
/*
 *	Serial port driver (uses bit-banging)
 *	for 16Cxx series parts.
 *
 * 	IMPORTANT: Compile this file with FULL optimization
 *
 *	Copyright (C)1996 HI-TECH Software.
 *	Freely distributable.
 */
#include	<pic.h>
/*
 *	Tunable parameters
 */

/*	Transmit and Receive port bits */
#define SERIAL_PORT	GPIO
#define SERIAL_TRIS	TRISIO
#define	TX_PIN		0
#define RX_PIN		1

/*	Xtal frequency */
#define	XTAL	4000000

/*	Baud rate	*/
#define	BRATE	9600

/*	Don't change anything else */
#define SCALER		10000000
#define ITIME		4*SCALER/XTAL	/* Instruction cycle time */
#if BRATE > 1200
 #define	DLY		3		/* cycles per null loop */
 #define	TX_OHEAD 13		/* overhead cycles per loop */
#else
 #define	DLY		9		/* cycles per null loop */
 #define TX_OHEAD  14
#endif
#define	RX_OHEAD	12		/* receiver overhead per loop */

#define	DELAY(ohead)	(((SCALER/BRATE)-(ohead*ITIME))/(DLY*ITIME))

static bit	TxData @ (unsigned)&SERIAL_PORT*8+TX_PIN;	/* Map TxData to pin */
static bit	RxData @ (unsigned)&SERIAL_PORT*8+RX_PIN;	/* Map RxData to pin */
#define	INIT_PORT	SERIAL_TRIS |= 1<<RX_PIN				/* set up I/O direction */

void
putch(char c)
{
	unsigned char	bitno;
#if BRATE > 1200
	unsigned char	dly;
#else
	unsigned int	dly;
#endif

	INIT_PORT;
	TxData = 0;			/* start bit */
	bitno = 12;
	do {
		dly = DELAY(TX_OHEAD);	/* wait one bit time */
		do
			/* waiting in delay loop */ ;
		while(--dly);
		if(c & 1)
			TxData = 1;
		if(!(c & 1))
			TxData = 0;
		c = (c >> 1) | 0x80;
	} while(--bitno);
NOP();
}

char
getch(void)
{
	unsigned char	c, bitno;
#if BRATE > 1200
	unsigned char	dly;
#else
	unsigned int	dly;
#endif

	for(;;) {
		while(RxData)
			continue;	/* wait for start bit */
		dly = DELAY(3)/2;
		do
			/* waiting in delay loop */ ;
		while(--dly);
		if(RxData)
			continue;	/* twas just noise */
		bitno = 8;
		c = 0;
		do {
			dly = DELAY(RX_OHEAD);
			do
			/* waiting in delay loop */ ;
			while(--dly);
			c = (c >> 1) | (RxData << 7);
		} while(--bitno);
		return c;
	}
}

char
getche(void)
{
	char c;

	putch(c = getch());
	return c;
}

Code:
/*--- rc5decode.h ---*/

#ifndef RC5DECODE
#define RC5DECODE

/*--- Function prototype ---*/

unsigned char rc5Decode(void);

/*---- globals ---*/

extern unsigned char command;   /* rc5 command code */
extern unsigned char address;   /* rc5 system address */
extern unsigned char rc5valid;  /* valid rc5 data flag */

#endif

/*--- Macros ---*/
#define REMOTE_ADDRESS	19
#define IR_IN _GPIO,2  /* Infra Red input pin */
#define TMR   _TMR0     /* Pulse timer */

/*--- rc5 infra red codes ---*/

#define SYSTEM_ADD    0x10    /* System address */

#define RC5_VOL_UP    0x10    /* VOL+ */
#define RC5_VOL_DOWN  0x11    /* VOL- */
#define RC5_PHONO     0x01    /* PHONO */
#define RC5_TUNER     0x02    /* TUNER */
#define RC5_CD        0x03    /* CD */
#define RC5_AV        0x04    /* AV */
#define RC5_AUX1      0x08    /* AUX1 */
#define RC5_AUX2      0x09    /* AUX2 */
#define RC5_MUTE      0x0D    /* MUTE */

/*--- End of file ---*/
 
rc5 c source encoder

Hi btbass,
Your code is working well but sometimes I get data even though no switch on remote is pressed. Is there any way to filter this??


And yager, I tried your code several times but it doesn't seem to work :(
Is it possible for you to post a working example? I want to compare btbass and your code's performance.

Thanks.
 
Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top