newguy
Joined: 24 Jun 2004 Posts: 1908
|
IR Remote Code Grabber S/W |
Posted: Sat Dec 18, 2004 1:42 pm |
|
|
I just finished doing a little program that grabs the 32 bit code from an infra-red remote (i.e. a TV or stereo's remote) and displays it on an LCD. I thought that someone else may find it useful. For the schematic, refer to me labs' lab-x1 board found here: http://www.melabs.com/downloads/labx1sch.pdf
The IR remote receiver itself is the Sharp GP1UD262XK (part # 425-1117-ND from digikey: http://www.digikey.ca) The GP1UD is a 3 pin device - simple hookup: supply 5V to Vcc, ground the GND pin, and the signal out pin is hooked to the PIC's EXT0 pin (pin B0).
Here is a good link regarding IR remotes and their data format: http://www.tapspring.com/HATcker_AP_TV.htm Edit: I just tried this link, and it seems to be down for the moment. Anyway, a remote starts a packet with a lead-in sequence. In the absence of IR light, the output of the decoder is normally high. The lead-in sequence consists of a logic low lasting about 8 - 9 ms, followed by a high lasting about 4 ms. Data transfer starts immediately after that, MSbit first. A logic 0 consists of pulsetrain starting with a low level lasting about 0.5 - 0.6 ms, followed by a high level lasting about 0.4 ms. A logic 1 consists of a pulsetrain starting with a low level lasting about 0.5 - 0.6 ms, followed by a high level lasting about 1.4 ms.
I should point out that most remotes send a bare minimum of 64 bits, in two 32 bit "packets". For some functions, the two packets are identical. For others, the two packets are different - thus the reason why the code grabs two packets and displays them.
Here it is. Enjoy.
Code: | #include <18F452.h>
#device adc=8
#use delay(clock=20000000,RESTART_WDT)
#fuses HS, BROWNOUT, BORV20, PUT, STVREN, NOLVP
struct lcd_pin_map {
boolean junk;
boolean unused;
boolean junk2;
boolean junk3;
int data : 4;
boolean rs;
boolean enable;
boolean rw;
} lcd;
#byte lcd = 0xf83 // 18f452
//#byte lcd = 8 // 16f877
#define lcd_type 2 // 0=5x7, 1=5x10, 2=2 lines
#define lcd_line_two 0x40 // LCD RAM address for the second line
byte CONST LCD_INIT_STRING[4] = {0x20 | (lcd_type << 2), 0xc, 1, 6};
// These bytes need to be sent to the LCD
// to start it up.
// The following are used for setting
// the I/O port direction register.
STRUCT lcd_pin_map const LCD_WRITE = {0,0,0,0,0}; // For write mode all pins are out
STRUCT lcd_pin_map const LCD_READ = {0,0,0,0,15}; // For read mode data pins are in
byte lcd_read_byte() {
byte low,high;
set_tris_d(LCD_READ);
lcd.rw = 1;
delay_cycles(1);
lcd.enable = 1;
delay_cycles(1);
high = lcd.data;
lcd.enable = 0;
delay_cycles(1);
lcd.enable = 1;
delay_us(1);
low = lcd.data;
lcd.enable = 0;
set_tris_d(LCD_WRITE);
return( (high<<4) | low);
}
void lcd_send_nibble( byte n ) {
lcd.data = n;
delay_cycles(1);
lcd.enable = 1;
delay_us(2);
lcd.enable = 0;
}
void lcd_send_byte( byte address, byte n ) {
lcd.rs = 0;
while ( bit_test(lcd_read_byte(),7) ) ;
lcd.rs = address;
delay_cycles(1);
lcd.rw = 0;
delay_cycles(1);
lcd.enable = 0;
lcd_send_nibble(n >> 4);
lcd_send_nibble(n & 0xf);
}
void lcd_init() {
byte i;
set_tris_d(LCD_WRITE);
lcd.rs = 0;
lcd.rw = 0;
lcd.enable = 0;
delay_ms(15);
for(i=1;i<=3;++i) {
lcd_send_nibble(3);
delay_ms(5);
}
lcd_send_nibble(2);
for(i=0;i<=3;++i)
lcd_send_byte(0,LCD_INIT_STRING[i]);
}
void lcd_gotoxy( byte x, byte y) {
byte address;
if(y!=1)
address=lcd_line_two;
else
address=0;
address+=x-1;
lcd_send_byte(0,0x80|address);
}
void lcd_putc( char c) {
switch (c) {
case '\f' : lcd_send_byte(0,1);
delay_ms(2);
break;
case '\n' : lcd_gotoxy(1,2); break;
case '\b' : lcd_send_byte(0,0x10); break;
default : lcd_send_byte(1,c); break;
}
}
#define LEAD_IN_LOW 40000 // 8 ms
#define LEAD_IN_TOTAL 60000 // 12 ms
#define MIN_TIME 3000 // 0.6 ms
#define THRESHOLD 8000 // 1.6 ms
#define MAX_TIME 11500 // 2.3 ms
unsigned int8 overflow_count = 0, rx_state = 0xff;
unsigned int32 timer_at_start, timer_at_end, low_time, timer_at_mid, period, first_data = 0, second_data = 0;
unsigned int32 temp1, temp2, timer_at_mid_start;
int1 full_cycle = FALSE, got_first = FALSE, data_avail = FALSE, caught_rise = TRUE;
#int_TIMER1
void TIMER1_isr(void) {
++overflow_count; // increment when an overflow occurs
}
#int_EXT
void ext_isr(void) {
if (caught_rise) { // this is a falling edge
timer_at_end = get_timer1();
period = (0x10000 * overflow_count) + timer_at_end - timer_at_start;
overflow_count = 0;
timer_at_start = timer_at_end;
full_cycle = TRUE;
caught_rise = FALSE;
rx_state++;
ext_int_edge(0,L_TO_H);
}
else { // this is a rising edge
timer_at_mid = get_timer1();
low_time = (0x10000 * overflow_count) + timer_at_mid - timer_at_start;
if (rx_state == 33) {
rx_state = 0xff;
if (!got_first) {
got_first = TRUE;
}
else {
got_first = FALSE;
data_avail = TRUE;
}
}
caught_rise = TRUE;
ext_int_edge(0,H_TO_L);
}
}
void decode_info(void) {
// each tick = 200 ns
int i;
if (rx_state == 1) { // end of first period - lead in
if ((low_time < LEAD_IN_LOW) || (period < LEAD_IN_TOTAL)) {
rx_state = 0xff; // reset
caught_rise = TRUE;
ext_int_edge(0,H_TO_L);
}
}
else if ((rx_state > 1) && (rx_state < 34)) { // valid data
i = 33 - rx_state;
if (period < MIN_TIME) {
rx_state = 0xff; // reset
caught_rise = TRUE;
ext_int_edge(0,H_TO_L);
}
if (period < THRESHOLD) { // logic zero
if (!got_first) {
bit_clear(first_data, i);
}
else {
bit_clear(second_data, i);
}
}
else if (period < MAX_TIME) { // logic one
if (!got_first) {
bit_set(first_data, i);
}
else {
bit_set(second_data, i);
}
}
else if (period >= MAX_TIME) { // reset
rx_state = 0xff;
caught_rise = TRUE;
ext_int_edge(0,H_TO_L);
}
}
}
void main() {
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
setup_wdt(WDT_ON);
setup_timer_0(RTCC_INTERNAL);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
setup_timer_2(T2_DISABLED,0,1);
setup_timer_3(T3_DISABLED|T3_DIV_BY_1);
ext_int_edge(0,H_TO_L);
enable_interrupts(INT_TIMER1);
enable_interrupts(INT_EXT);
enable_interrupts(global);
set_tris_e(0x00);
set_tris_c(0xff);
port_b_pullups(TRUE);
set_tris_b(0xff);
lcd_init();
lcd_putc("\fReady...");
rx_state = 0xff;
while (TRUE) {
restart_wdt();
if (full_cycle) {
full_cycle = FALSE;
decode_info();
}
if (data_avail) {
data_avail = FALSE;
printf(lcd_putc,"\fCMD1 = %lx\nCMD2 = %lx", first_data, second_data);
}
}
} |
|
|