|
To decode Sony SIRC codes output by my Harmony 880 remote control, I connected a Panasonic PNA4602M infrared sensor to P0.4 (CAP0.1). It's a 38kHz type sensor, so it works great with standard remote controls. Rather than work blind, I connected a 16x2 character LCD in 4-bit mode with busy flag checking to display the codes.
It's a fairly simple project, but very useful for all kinds of things.
The sensor works inverted. It runs with a high idle. When it receives a signal the output pulses low. The program measures the pulse-widths and builds a 12-bit "word" in buffer that contains the 7-bit command and a 5-bit address (always 1, for TV, in my case). Remote controls send every command three times. The program detects and processes all three, but only the last one is used. The code sets P0.4 up as CAP0.1 and watches for a falling edge. It interrupts on a falling edge, saves the timer counter value as start and sets to watch for a rising edge. When it detects that it calculates the width of the pulse, processes it accordingly and sets to watch for a falling edge again. You can find a partial list of SIRC codes and pretty good information at this site. Without my Saleae Logic I would have found this project incredibly difficult to get working right. My remote control's output pulse-widths are different enough from the spec that I wasted a lot of time trying to get it going, with very flaky results. Then I hooked up the Logic and could immediately see that the actual pulse-widths were a bit longer than the spec. Adjusted the code to suit and she works great now! Here's an overview of the project (left). Wiring is ugly, but totally reliable. A closer view (right) shows the PNA4602M IR sensor behind the LCD. The sensor and the LCD both need 5V power, so the breadboard has its own power supply. The input pin (P0.4) on the ARM is 5V tolerant, so no worries there. 
Couple more pics of the connections. 
I'll draw a schematic soon, but this whole thing is pretty simple. You should be able to figure it out for yourself. Here's the code, done in Eclipse/yagarto. Header file at the bottom. sirc.c#include "LPC214x.h" #include <stdio.h> #include "sirc.h"
int start,count,result,done = 0; static unsigned int buffer = 0; char number[] = " ";
int main(void) { int i,cmd,add; init(); PINSEL0 = 0x00000200; //p0.4 = capture 0.1 (timer0) IODIR0 = 0x107e3000; IOCLR0 = 0x107e0000; lcd_init(); T0TCR = 0x02; //reset counter T0CCR = 0x0030; //capture & interrupt on 0.1 falling edge VICVectCntl0 = 0x00000024; //use it for timer 0 interrupt: VICVectAddr0 = (unsigned)isr_capture; //set interrupt vector in 0 VICIntEnable = 0x00000010; //enable timer0 interrupt T0TCR = 0x01; //enable timer0 enableIRQ();
while(1){ if(done){ beep(); disableIRQ(); lcd_cmd(0x01); //clear display cmd = buffer & 0x0000007f; //mask out non-command bits add = buffer & 0x00000f80; //mask out non-address bits add = add >> 7; lcd_line1(); sprintf(number,"Command: %x",cmd); lcd_string(number); lcd_line2(); sprintf(number,"Address: %x",add); lcd_string(number); done = 0; enableIRQ(); } } }
void beep(void) { int i,j; IOCLR0 = 0x00002000; //buzzer2 low IOSET0 = 0x00001000; //buzzer1 high for(i=0;i<300;i++){ IOPIN0 ^= 0x00003000; for(j=0;j<700;j++); } }
void isr_capture(void) { if(!(IOPIN0 & 0x00000010)){ //if falling edge T0CCR = 0x0028; //set for rising edge capture & interrupt start = T0CR1; } else{ T0CCR = 0x0030; //set for falling edge capture & interrupt if(T0CR1 < start) //rollover occurred result = (0xffffffff - start) + T0CR1; else //no rollover result = T0CR1 - start;
if(result > 0x22000){ //if start pulse count = 0; buffer = 0; } else if((result > 0x12000) & (result < 0x14000)){ //check for 1 pulse buffer |= 0x10000000; buffer = buffer >> 1; count++; } else if (result < 0xb500){ //check for 0 pulse buffer = buffer >> 1; count++; } if(count == 12){ buffer = buffer >> 16; count = 0; done = 1; } } T0IR = 0x20; //clear interrupt VICVectAddr = 0; //end of interrupt - dummy write }
void lcd_string(char *senpoint) { while(*senpoint != '\0') { lcd_char(*senpoint); senpoint++; } }
void lcd_line1(void){ lcd_cmd(0x80); } void lcd_line2(void){ lcd_cmd(0xc0); }
void lcd_cmd(unsigned char letter) { unsigned char temp; temp=letter; temp=temp>>4; lcd_nybble(temp,0); temp=letter; temp=temp&0x0f; lcd_nybble(temp,0); }
void lcd_char(unsigned char letter) { unsigned char temp; temp=letter; temp=temp>>4; lcd_nybble(temp,1); temp=letter; temp=temp&0x0f; lcd_nybble(temp,1); }
void lcd_nybble(unsigned char nyb,unsigned char rs) { int i,dat; if(rs) IOSET0 = RS; //set RS pin else IOCLR0 = RS; //clear RS pin dat = nyb; //get the nybble in an int IOCLR0 = 0x001e0000; //clear D4-D7 IOPIN0 |= dat<<17; //OR the bits in there strobe_e(); //latch data to LCD }
void lcd_init(void) { delay_ms(500); //settle time delay lcd_nybble(0x03,0); //reset LCD strobe_e(); strobe_e(); lcd_nybble(0x02,0); lcd_cmd(0x28); //set 4-bit mode and 2 lines lcd_cmd(0x10); //cursor move & shift left lcd_cmd(0x06); //entry mode = increment lcd_cmd(0x0e); //display on - cursor blink on lcd_cmd(0x01); //clear display }
void lcd_busy(void) { IODIR0 &= 0xffefffff; //D7 is input IOCLR0 = RS; //set RS low IOSET0 = RW; //set R/W high IOSET0 = E; //set E high while(IOPIN0 & busyflag); //wait for busy flag to go low IOCLR0 = E; //set E low IOCLR0 = RW; //set R/W low IODIR0 |= 0x00100000; //D7 is output again }
void strobe_e(void) { IOSET0 = E; delay_us(1); IOCLR0 = E; lcd_busy(); }
void delay_ms(int x) { int a,b; for(a=0;a<x;a++){ for(b=0;b<3500;b++); } }
void delay_us(int x) { int a,b; for(a=0;a<x;a++) for(b=0;b<4;b++); }
void init(void) { PLLCFG=0x24; //set multiplier and divider values PLLFEED=0xAA; PLLFEED=0x55; PLLCON=0x01; //enable PLL PLLFEED=0xAA; PLLFEED=0x55; while(!(PLLSTAT & PLOCK)); //wait for PLL to lock to set frequency PLLCON=0x3; //connect PLL as clock source PLLFEED=0xAA; PLLFEED=0x55; MAMCR=0x02; //enable MAM MAMTIM=0x04; //set number of clocks used for flash memory fetch VPBDIV=0x01; //set peripheral clock (pclk) to system clock (cclk) }
void FIQ_Routine(void){ while(1); } void SWI_Routine(void){ while(1); } void UNDEF_Routine(void){ while(1); }
sirc.h#define PLOCK 0x400 #define E 0x00200000 //bit 21 #define RS 0x00400000 //bit 22 #define RW 0x10000000 //bit 28 #define busyflag 0x00100000 //D7 - bit 20
void beep(void); void init(void); void lcd_string(char *); void lcd_line1(void); void lcd_line2(void); void lcd_line3(void); void lcd_line4(void); void lcd_cmd(unsigned char); void lcd_char(unsigned char); void lcd_nybble(unsigned char,unsigned char); void lcd_init(void); void strobe_e(void); void delay_ms(int); void delay_us(int); void isr_capture (void) __attribute__ ((interrupt("IRQ"))); void FIQ_Routine (void) __attribute__ ((interrupt("FIQ"))); void SWI_Routine (void) __attribute__ ((interrupt("SWI"))); void UNDEF_Routine (void) __attribute__ ((interrupt("UNDEF")));
|