Follow along with the video below to see how to install our site as a web app on your home screen.
Note: This feature may not be available in some browsers.
#include <p18cxxx.h>
#include <delays.h>
#pragma config WDT = OFF, LVP = OFF, OSC = XT, DEBUG = OFF
#define IR_pin PORTBbits.RB0
#define TIME_MIN (5)
#define TIME_MAX (11)
#define TIME_STEP (2)
#define LED0 PORTCbits.RC0
#define LED1 PORTCbits.RC1
#define LED2 PORTCbits.RC2
#define LED3 PORTCbits.RC3
#define LED4 PORTCbits.RC4
int RC5_receive(unsigned int *, unsigned int *);
void Delay100Us(unsigned char);
void applyIR(void);
void Delay100Us(unsigned char time)
{
char x;
for(x=0;x<time;x++)
Delay10TCYx(9);
}
unsigned int IR_addr, IR_data = 0;
void applyIR(void)
{
switch(IR_data)
{
case 0: LED0 ^= 1;break;
case 1: LED1 ^= 1;break;
case 2: LED2 ^= 1;break;
case 3: LED3 ^= 1;break;
case 4: LED4 ^= 1;break;
}
}
void main(void)
{
ADCON1 = 0x0F;
TRISB = 0x01;
TRISA = 0x00;
PORTB = 0x00;
TRISC = TRISD = TRISE = 0x00;
PORTA = PORTC = PORTD = PORTE = 0x00;
PORTC = 0x55;
while(1)
{
RC5_receive(&IR_addr, &IR_data);
applyIR();
}
}
int RC5_receive(unsigned int * RC5addr, unsigned int * RC5data)
{
int OffTime, OnTime, DevTime, DiTime, i, j, k;
unsigned int data = 0, addr = 0;
unsigned int bit_mask;
if(!IR_pin)
{
for(OffTime = 0; !IR_pin && OffTime < TIME_MAX; OffTime += TIME_STEP){Delay100Us(TIME_STEP);}
if (OffTime > TIME_MAX) return -1;
if (OffTime < TIME_MIN) return -1;
for(OnTime = 0; IR_pin && OnTime < TIME_MAX; OnTime += TIME_STEP){Delay100Us(TIME_STEP);}
if (OnTime > TIME_MAX) return -1;
if (OnTime < TIME_MIN) return -1;
//* skip token
DevTime = (2 * OffTime + OnTime + OffTime / 2);
for (k = 0; k < DevTime; k += TIME_STEP){Delay100Us(TIME_STEP);}
//* get address and data
DiTime = (OffTime + OnTime);
for (i = 0; i < 5; i++)
{
if(IR_pin) {addr <<= 1;} else{addr <<= 1; addr |= 1;}
for (k = 0; k < DiTime; k += TIME_STEP){Delay100Us(TIME_STEP);}
}
for (i = 0; i < 6; i++)
{
if(IR_pin){data <<= 1;}else{data <<= 1; data |= 1;}
for (k = 0; k < DiTime; k += TIME_STEP){Delay100Us(TIME_STEP);}
}
*RC5data = data;
*RC5addr = addr;
return 0;
}
return -1;
}
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!
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!!
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 ---*/
void main()
{
ANSEL = 0; /* Configure pins as digital I/O */
PORTA = 0xFF;
TRISA = 0; /* All outputs ??? */
PORTB = 0xFF;
TRISB = 0;
PORTC = 0x00;
TRISC = 0;
GIE = 1;
INTE = 1;
INTEDG = 0;
while(1);
}
__CONFIG(XT & CP & PWRTEN & WDTEN & MCLREN);
void interrupt isr(void)
{
if(rc5Decode())
{
switch(command)
{
case RC5_NEMERIC_KEY_0:
PORTC = 0x03;
break;
case RC5_NUMERIC_KEY_1:
PORTC = 0x0C;
break;
default :
PORTC = 0x0F;
break;
}
}
INTF = 0;
}
void interrupt isr(void)
{
if(INTF)
{
if(rc5Decode())
{
switch(command)
{
case RC5_NEMERIC_KEY_0:
PORTC = 0x03;
break;
case RC5_NUMERIC_KEY_1:
PORTC = 0x0C;
break;
default :
PORTC = 0x0F;
break;
}
}
INTF = 0;
}
}