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.
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!
 

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.
 

rc5 pic

CMOS said:
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 said:
And yager, I tried your code several times but it doesn't seem to work :(.
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 said:
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.
 
c code for rc5 for pic

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

Thanks for your efforts and help.
 

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.
 

    CMOS

    Points: 2
    Helpful Answer Positive Rating
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 :D

Thanks once again Yager and btbass.
 

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! :D
 

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.
 

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?? :D
 
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
 

pic rc5

@CMOS :
@metal :

Could you guys post a summary of how the testing turned out ?

This is getting interesting ! This way, we have no need for external decoder anymore !
 

pic 16 bit divide by 2 rlf

vsmGuy said:
@CMOS :
@metal :

Could you guys post a summary of how the testing turned out ?

This is getting interesting ! This way, we have no need for external decoder anymore !
I have already posted my summary. Please read my previous post in this thread.

The project was 100% successful...all thanks to Yager for his wonderful code.
 

rc5 decoding algorithm

@CMOS

Sorry I was not able to follow the thread correctly.

Can you post the final files of your project so we can all have a look ?
 

rc5 c pic

Hi,
I have compiled the project source files posted by Yager without making any changes. Download the file named "IR.RC5.rar" from previous page.
I'll post the schematic soon after redrawing it....I am not able to find it right now on my drive.
 

cs3310_v10c

@CMOS

The schematic would be just wonderful. Thanks !
 

eagle pic24f

Likewise is anyone aware of any code to get going on an RC5 encoder? Again, using CCS and an emphasis (which has clearly been demonstrated in this thread) on reliability & performance?

Cheers
 

rc5 code proton basic

Hi

I am using the code provided by btbass for the last two years.Works very fine.

But I would like to know weather anybody have a fully interupt driven decoder for RC5 decoding?

The difficulty with this type of decoding is that as RC5 code is reasonabily long the system gets locked up in decoding routine for around 20ms.If we have to do some display multiplexing or some other time critical work to do along with this decoding ,it creates problems.

Any solutions?

thanks a lot to btbass for the code as I have used it in many of my projects.



see this for RC5 encoder

picstudent
 

from rc5 code to 2051

Here is my schematic vsmGuy.
 

timer0 rc5 transmit atmega

@CMOS : Wow ! It's so simple :)

@Picstudent : Have you come across RC5 code which exploits the manchester encoding of signal instead of times delays ?
 

rc6 philips code

hi

@Picstudent : Have you come across RC5 code which exploits the manchester encoding of signal instead of times delays ?

The only RC5 decoding I used is from btbass posted in this forum.

picstudent
 

Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top