electronics forum

Rules | Recent posts | topic RSS | Search | Register  | Log in

PIC RC5 Code


Goto page 1, 2, 3  Next
Post new topic  Reply to topic    EDAboard.com Forum Index -> Microcontrollers -> PIC RC5 Code
Author Message
CMOS



Joined: 06 Jan 2004
Posts: 810
Helped: 39
Location: USA


Post10 Oct 2006 17:07   

pic rc5


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?
Back to top
cesarman



Joined: 01 Apr 2006
Posts: 14
Helped: 1


Post10 Oct 2006 20:55   

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
Back to top
CMOS



Joined: 06 Jan 2004
Posts: 810
Helped: 39
Location: USA


Post11 Oct 2006 18:18   

rc5 code


C code would be really helpful. Anyone please?

Anyways, thanks for your reply cesarman.
Back to top
yager



Joined: 28 May 2001
Posts: 116
Helped: 19


Post12 Oct 2006 1:33   

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: http://www.sbprojects.com/knowledge/ir/ir.htm
He made great works.
Back to top
CMOS



Joined: 06 Jan 2004
Posts: 810
Helped: 39
Location: USA


Post12 Oct 2006 16:52   

rc5 protocol pic


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

Thanks a lot anyways Very Happy
Back to top
yager



Joined: 28 May 2001
Posts: 116
Helped: 19


Post12 Oct 2006 22:27   

rc5 c code


CMOS wrote:
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
Back to top
CMOS



Joined: 06 Jan 2004
Posts: 810
Helped: 39
Location: USA


Post13 Oct 2006 6:23   

rc5 ccs


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

Thanks a lot.
Back to top
btbass



Joined: 20 Jul 2001
Posts: 1187
Helped: 113
Location: Oberon


Post13 Oct 2006 23:46   

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.

http://www.edaboard.com/viewtopic.php?t=73538&highlight=rc5

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



Joined: 30 Dec 2004
Posts: 224
Helped: 7


Post14 Oct 2006 11:06   

rc5 with pic ccs


How to code for 8051 microcontroller in asm.
Back to top
metal



Joined: 21 Dec 2004
Posts: 369
Helped: 13


Post14 Oct 2006 19:04   

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]
Back to top
CMOS



Joined: 06 Jan 2004
Posts: 810
Helped: 39
Location: USA


Post16 Oct 2006 14:26   

rc5 pic code


metal wrote:
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.
Back to top
metal



Joined: 21 Dec 2004
Posts: 369
Helped: 13


Post16 Oct 2006 18:57   

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
Back to top
CMOS



Joined: 06 Jan 2004
Posts: 810
Helped: 39
Location: USA


Post16 Oct 2006 19:12   

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.
Back to top
btbass



Joined: 20 Jul 2001
Posts: 1187
Helped: 113
Location: Oberon


Post16 Oct 2006 21:32   

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 ---*/


Last edited by btbass on 17 Oct 2006 12:48; edited 1 time in total
Back to top
Google
AdSense
Google Adsense




Post16 Oct 2006 21:32   

Ads




Back to top
metal



Joined: 21 Dec 2004
Posts: 369
Helped: 13


Post17 Oct 2006 5:53   

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
Back to top
yousafzai



Joined: 01 Jun 2006
Posts: 259
Helped: 6


Post17 Oct 2006 8:27   

rc5 c code for pic


is RC5 the same as sony SIRC....
Back to top
metal



Joined: 21 Dec 2004
Posts: 369
Helped: 13


Post17 Oct 2006 8:37   

pic ir rc5


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



Joined: 20 Jul 2001
Posts: 1187
Helped: 113
Location: Oberon


Post17 Oct 2006 12:50   

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.
Back to top
CMOS



Joined: 06 Jan 2004
Posts: 810
Helped: 39
Location: USA


Post17 Oct 2006 20:33   

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!! Very Happy

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 ---*/
Back to top
CMOS



Joined: 06 Jan 2004
Posts: 810
Helped: 39
Location: USA


Post20 Oct 2006 7:35   

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 Sad
Is it possible for you to post a working example? I want to compare btbass and your code's performance.

Thanks.
Back to top
btbass



Joined: 20 Jul 2001
Posts: 1187
Helped: 113
Location: Oberon


Post20 Oct 2006 13:22   

rc5 pic example


Good to hear the code works ok for you.
As for the noise, first check that there isnt something else transmitting. I once had a problem and it turned out that my laptop was intermitantly sending out ir signals.
also, the IS1U60 has quite a good optical filter that blocks out non ir sources.
I will try to optimise the code so that when it is calibrating the pulse length, it checks that it is close to 1.8mS long and rejects it if it isnt.
Also, after using the results, set rc5valid to false.

To get better results, a resonator or xtal is better than a rc oscillator for clock source, but with a 12F629 I dont suppose you have that choice!
Back to top
CMOS



Joined: 06 Jan 2004
Posts: 810
Helped: 39
Location: USA


Post20 Oct 2006 19:16   

rc5 code pic


I think even my laptop is doing the same thing....I'll try turning off the laptop and see if it is the culprit.

I can even use Crystal with 12F629. I'll also try and see if it gives better results.
Back to top
yager



Joined: 28 May 2001
Posts: 116
Helped: 19


Post21 Oct 2006 8:36   

rc5 pic


CMOS wrote:
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??
I encountered it before, but my problem was coming from the IR Receiver Chip.
To try to enlarge the capacitor between its VCC and GND. (I used 4.7uF)
CMOS wrote:
And yager, I tried your code several times but it doesn't seem to work Sad.
Really?! Actaully, I ripped it from my production code
which it is working for Mircosoft-Philips RC6 for XP MCE (Media Center Edition).
Since it can receive RC6 and learn/transmit any raw IR data stream under 32~455KHz carrier,
so I cut/modified to support RC5 from the big one. The core idea should be working, I think.
CMOS wrote:
Is it possible for you to post a working example?
Well, I will base on the above code and build a working one to meet your target hardware (PIC12F629 @ internal 4MHz OSC, GPIO0=TX, GPIO2=IR).

EDIT:
Here is the working one. No any true interrupt be used, all of them by polling.
RC5.h
Code:
#include <12F629.h>

#FUSES NOWDT                    //No Watch Dog Timer
#FUSES INTRC_IO                 //Internal RC Osc, no CLKOUT
#FUSES NOCPD                    //No EE protection
#FUSES NOPROTECT                //Code not protected from reading
#FUSES NOMCLR                   //Master Clear pin used for I/O
#FUSES PUT                      //Power Up Timer
#FUSES NOBROWNOUT               //No brownout reset

#use delay(clock=4000000)
#use rs232(baud=9600,parity=N,xmit=PIN_A0,rcv=PIN_A1,bits=8)

RC5.c
Code:
#include "RC5.h"

typedef unsigned int8 U8;
typedef unsigned int16 U16;
typedef          int1 BIT;
#define VOID void

#pragma use fast_io (A)

#pragma byte GPIO = 0x05
#pragma byte TMR0 = 0x01
#pragma byte INTCON = 0x0B
#pragma byte PIR1 = 0x0C
#pragma bit TMR1F = PIR1.0
#pragma byte IOC = 0x96

#pragma bit IR_IOC = IOC.2
#pragma bit IR_PIN = GPIO.2
#pragma bit IR_INT = INTCON.0
#define IR_TIME TMR0

#define enable_INT_IR() IR_IOC = 1
#define clr_INT_IR() IR_PIN = 1; IR_INT = 0
#define is_INT_IR() (IR_INT != 0)

#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
#define nIRtimeBase 32 // 32uS
#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)

   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 30000 // 25mS: 14*(889+889)=24.892mS
//#define timeout_RUNTIME_IR() (get_timer1() > nIRruntime)
#define timeout_RUNTIME_IR() (TMR1F != 0)
#define set_RUNTIME_IR(tm) set_timer1(65536UL-(tm)); TMR1F = 0
   BIT bIRphysicalBitCount; // 0:1st physical bit, 1:2nd physical bit
   BIT bIRphysicalBitData;   // last physical bit data
   BIT bIRnewHit; // 1:new IR code is received

VOID InitIR( VOID ) // initial IR engine
{
  gIRstat = stIR_NONE;
  bIRnewHit = FALSE;
  // hardware dependent: set correct snapped interrupt edge setting
  enable_INT_IR();
  clr_INT_IR();
}

VOID TimeoutIR( VOID ) // check IR running timeout
{
   if( gIRstat != stIR_NONE) {
      if( timeout_RUNTIME_IR() ) { // timeout
         InitIR();
      }
   }
}

VOID PollIR( VOID ) // put it in ISR (trigger when IR_PIN edge is changed)
{
   U8 mIRtime;

   mIRtime = get_TIME_IR(); set_TIME_IR(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
              set_RUNTIME_IR(nIRruntime); // 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
//-clr_INT_IR();
   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;
}

void main()
{
   port_a_pullups(0xFF);
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_32);
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);

   // TODO: USER CODE!!
   printf( "IR\n" );
   InitIR();
   while(TRUE) {
      if( is_INT_IR() ) {
         clr_INT_IR();
         PollIR();
         if( bIRnewHit == TRUE ) { // new IR code is coming
            bIRnewHit = FALSE;
            // process IR event here
            printf( "%4lX\n", gIRdata );
         }
      }
      TimeoutIR();
   }
}

Here is the whole project file which you can build it with CCS v4.012.
Just build or burn & play.



Sorry, but you need login in to view this attachment

Back to top
CMOS



Joined: 06 Jan 2004
Posts: 810
Helped: 39
Location: USA


Post21 Oct 2006 20:05   

c code for rc5 for pic


Ok..cool. Will try that out and post the results soon.

Thanks for your efforts and help.
Back to top
btbass



Joined: 20 Jul 2001
Posts: 1187
Helped: 113
Location: Oberon


Post25 Oct 2006 16:03   

ccs rc5


Hi CMOS

I have added pulse length checking to the code. It does not check the real time length of the first pulse due to the variations in timing from different handsets, but checks that subsequent pulses are within limits of the first calibrated pulse time. Checking that we have received 12 pulses of equal length makes the algorithm less susceptible to false reception. This adds a few extra lines to the code and a couple more variables. I have removed 'rc5valid' variable from the code but the function returns 1 or 0 so you can still use code like

If(rc5Decode()){
//valid code;
}
else{
//invalid code;
}

Code:

/*------ RC5 decoder program Version 1.1 (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 to calibrate timing.
;------ 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.
;------ Then it checks that the pulse length was within limits of the calibrated pulse.
;------ 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 pulse;
unsigned char HiLimit;
unsigned char LoLimit;

/*--- 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
          retlw   0x00        ;bail out

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

          movwf   _timer      ;take the pulse length,
          movwf   _temp       ;save it

;------ init limits

          movwf   _HiLimit;
          incf    _HiLimit
          incf    _HiLimit
          movwf   _LoLimit
          decf    _LoLimit
          decf    _LoLimit

;------ calculate delay

          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

          call    CheckIt     ;check pulse length
          movwf   _pulse
          btfsc   _pulse,0
          retlw   0x00        ;bail out

          bsf     3,0         ;gonna be a 1
          goto    clock       
           
;------ wait for low 0

waitlow   call    Wlow   

          call    CheckIt     ;check pulse length
          movwf   _pulse
          btfsc   _pulse,0
          retlw   0x00        ;bail out
     
          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         
          retlw   0x01        ;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 

;------ check pulse length

CheckIt   movf    TMR,w       ;save pulse length
          movwf   _pulse

          subwf     _LoLimit,w  ;compare with low limit
           btfsc   3,2         ;equal to low limit?
          retlw   0x00        ;pulse ok
          btfsc   3,0
          retlw   0x01        ;less then low limit!

          movf    _pulse,w    ;get pulse length
          subwf     _HiLimit,w  ;compare with high limit
          btfsc   3,2         ;equal to high limit?
          retlw   0x00        ;pulse ok
          btfss   3,0
          retlw   0x01        ;greater then high limit!
          retlw   0x00        ;pulse ok

  #endasm
  }

/*--- 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 */

#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 ---*/


I did try to write it all in C, but even when I try to help it, the Hi-Tech compiler adds a load of lines of code, increasing the size of the function quite a lot. The reason behind trying to keep the code as small as possible is that at the moment, decoding an RC5 command takes about 25mS. In a lot of applications, this is not a problem, but for some real time applications, tying the micro up for 25mS is not on. So the next step is to make it an interrupt driven function, whereby it is called on every transition of the IR input pin, updates it's state and returns as quickly as possible back to the main program flow.
Back to top
CMOS



Joined: 06 Jan 2004
Posts: 810
Helped: 39
Location: USA


Post25 Oct 2006 17:13   

pic rc5 ir


Hi btbass,
Thanks. I'll also try your new code.

In the mean time, I tested Yager's code. It is simply mind-blowing. I kept the circuit running nearly for 48 hours and not a single false data was received!! WOW...People you can consider this as the best RC5 decoder for PIC. Awsome man!! You ROCK Very Happy

Thanks once again Yager and btbass.
Back to top
CMOS



Joined: 06 Jan 2004
Posts: 810
Helped: 39
Location: USA


Post27 Oct 2006 10:31   

ir rc5 pic


Hi btbass.....I also tried your code for nearly 48 hours and sorry to say that it gives out about 1 false data every hour or so. However it can be filtered out if you allow data to be sent to serial port only if received address matches the defined one [if(address == REMOTE_ADDRESS)].
The code still needs tweaking.

In Yager's code I did not put any address comparison, yet it never gave out any false data.

Anyways thanks both of you for your time and efforts. CHEERS! Very Happy
Back to top
btbass



Joined: 20 Jul 2001
Posts: 1187
Helped: 113
Location: Oberon


Post27 Oct 2006 23:53   

pic ir rc-5 #int


Hi CMOS, thanks for your efforts in testing the code.
What did you do to test the code and get the results? What was your test set up?
Perhaps my code has advantages in size when space is tight?
I am working on my interrupt driven version, will post it when done.
Back to top
CMOS



Joined: 06 Jan 2004
Posts: 810
Helped: 39
Location: USA


Post28 Oct 2006 18:32   

12f629 rc5


Hi btbass,
My setup is not very special. The circuit include PIC12F629, MAX232 and 5V regulated power supply. Hyper-Terminal was used to monitor the data coming from serial port. With this setup I noticed that about every hour I got false data. And the weired thing was each time data received was 63 (0x3F - All data bits logic 1 !!).

Also if you are talking about the code effeciency....Here are the results with HiTech and CCS compilers (i.e. Your code in HITECH and Yager's code in CCS)

HITECH
Total ROM used 811 words (79.3%)
Total RAM used 48 bytes (75.0%)

CCS
ROM used: 354 (35%)
RAM used: 12 (19%)


Don't you think these results are surprising?? These are not totally dependent on your code but also on the the "stdio" library (printf). But still there is drastic difference!! And people still consider Hi-Tech as Industry Standard for PICs?? Very Happy



Sorry, but you need login in to view this attachment

Back to top
metal



Joined: 21 Dec 2004
Posts: 369
Helped: 13


Post28 Oct 2006 18:46   

yager rc5


Hello CMOS,

I have tested Yager's SIRC code as well on PIC16F877A, its CCS~328 words. I had the same results you got with Yager's RC5 code, it was really stable and error free.

I also wrote a small delphi software that receives the data from the COM port and controls winamp, results were just amazing and accurate.

My IR module receiver was really bad, even if I put my finger infornt of it, I get wrong data with my code for SIRC, but when I used Yager's SIRC code, it did not matter how good my IR receiver is. I concluded that if I use a real high quality IR receiver, I can say its going to be error free.

As a matter of fact, Yager's method is very brilliant, and works well in most noisy situations for both RC5 and SIRC, which is a must in a good code.

Tonight I will test Yager's SIRC ode for PICC, and report the code size and results as well.

Thank you all for the great efforts
Back to top
Arabic versionBulgarian versionCatalan versionCzech versionDanish versionGerman versionGreek versionEnglish versionSpanish versionFinnish versionFrench versionHindi versionCroatian versionIndonesian versionItalian versionHebrew versionJapanese versionKorean versionLithuanian versionLatvian versionDutch versionNorwegian versionPolish versionPortuguese versionRomanian versionRussian versionSlovak versionSlovenian versionSerbian versionSwedish versionTagalog versionUkrainian versionVietnamese versionChinese version
Post new topic  Reply to topic    EDAboard.com Forum Index -> Microcontrollers -> PIC RC5 Code
Page 1 of 3 All times are GMT + 1 Hour
Goto page 1, 2, 3  Next
Similar topics:
Pic rc5 decoder (6)
Pic IR RC5 Encoder required (10)
problem rc5 code (1)
wow!!! rc5(ir code) c source? (2)
Working RC5 decoding code? (5)
8051 rc5 simple code (2)
PIC rc5 and NEC InfraRed receving (1)
RC5 transmitter and receiver using PIC (5)
Decoding RC5 remote with pic 16f628a/ 16f628 (7)
Assembly code(8051) to decode ir rc5 remote control required (8)


Abuse || Administrator || Moderators || Support us || sitemap
topic RSS