/****************************************************************************** Title: Philips RC-5 Remote Control Decoder Author: Peter Fleury http://jump.to/fleury Date: December 2002 Purpose: Decodes RC5-commands Software: AVR-GCC 3.3 Hardware: AT90S8515 at 4 Mhz, IR-Receiver SFH506-36 RC5 data format: SB1 SB2 TB AB5 AB4 AB3 AB2 AB1 AB0 CB5 CB5 CB4 CB3 CB2 CB1 CB0 SB = Start bit, TB = Toggle bit, AB = address bits, CB = command bits Program description: The IR-Receiver SFH506-36 receives and demodulates the IR-signal from the remote control into an active-low signal, which is feed into port PD3. The rc5decode function first measures the length of the first start bit. If the start bit is recognized as a valid RC5 bi-phase code, the routine synchronizes into the middle of the first half of the second bit. Then the state is stored into variable rc5data. The function uses the edge in the middle of every bit to synchronize the timing. 3/4 bit length after this edge, the state is sampled. This is repeated for the following bits. The function returns the decoded RC5-command or zero if valid RC5-code not recognized. Timer0 is used as a time base. The timer0 overflow interrupt sets the global variable timerflag to 1. See also Atmel AVR Application Note AVR410 *******************************************************************************/ //============================================================================================================= //============================================================================================================= // // rc5_m8: // Written by: David McDougall // 12/20/09 // // ATMega8 @ 8MHz // Radio Shack 38 kHz IR demodulator into PIN 5 // 10uf across IRvcc & IRgnd, no PU or PD needed // // // basic printf: from Nathan Siedel @ sparfun.com // //============================================================================================================= //============================================================================================================= #include // ??? #include // ??? printf command ??? #include // Defines pins, ports, etc to make programs easier to read #include // Allows for delay to be used #include // Enables IO #include "iocompat.h" // Timers on various Atmega chips.z #define FOSC 8000000 // FCPU Speed (speed of external oscillator) //3579545 #define BAUD 57600 // Serial Baud Rate #define MYUBRR 8 // Set for correct serail Baud rate #define sbi(var, mask) ((var) |= (uint8_t)(1 << mask)) // ??? #define cbi(var, mask) ((var) &= (uint8_t)~(1 << mask)) // ??? // PF _ /* this should be in !! */ #define TMC8_STOP 0 #define TMC8_CK8 _BV(CS01) // CS01 = (clk/8) Timer Counter Control Register 0 /* ** Macros and constants */ #define RC5BitHigh() (bit_is_set(PIND,PD3)) // INT1 = 1; ATmega8 pin 5 #define RC5BitLow() (bit_is_clear(PIND,PD3)) // INT1 = 0; ATmega8 pin 5 #define WAITFORTIMER() { while ( timerflag == 0); timerflag = 0; } // delay!!!!!!! /* (0xCA = 4 MHz), (0x95 = 8MHz); Calc from: dec_to_hex[255 - (13.25 * Y_in_MHz)] */ #define TIMER_0_CNT 0x95//0xCA // 111us with CLK/8 prescale (closer to 106us @ 4 MHz) #define RC5BITREF1 6 // #define RC5BITREF2 11 // #define RC5BITREF3 14 // //============================================================================================================= // FUNCTION PROTOTYPES //============================================================================================================= void ioinit(void); // initializes IO void delay_ms(uint16_t x); // general purpose delay static int uart_putchar(char c, FILE *stream); // UART write static FILE mystdout = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE); // printf(); uint8_t uart_getchar(void); // UART read unsigned int rc5decode( void ); // What button was pressed ? //======================================================================================================================== // Global Variables //======================================================================================================================== /* ** module global variables */ static volatile uint8_t timerflag; //must be volatile because modified by interrupt handler //========================================================================================================= //========================================================================================================= // // MAIN // //========================================================================================================= //========================================================================================================= int main(void) { ioinit(); // Setup IO pins and defaults printf("=== START ===\n"); // User feedback unsigned int rc5data; // Integer to store RC5 Data sei(); // Enable Interrupts while(1) { while ( RC5BitHigh() ); // wait until RC5 code received = (bit_is_set(PIND,PD3)) rc5data = rc5decode(); if ( rc5data & 0x2000 ) // If the toggle bit is 1 { printf("%x\n", (rc5data & 0x003f)); // Print the command bits in HEX //PORTB = ~(rc5data & 0x003f); // output command bits of RC5 command /* RC 5 Values read from PHILLIPS Universal Remote: Button: Hex Value: Power 0x0C 0 0x00 1 0x01 2 0x02 3 0x03 4 0x04 5 0x05 6 0x06 7 0x07 8 0x08 9 0x09 (-) 0x0a vol+ 0x10 vol- 0x11 ch+ 0x20 ch- 0x21 up 0x1c down 0x1d left 0x2c right 0x2b // same * center 0x2b // same * mute 0x0d pip 0x3a swap 0x37 // same $ repeat 0x22 subtitle 0x3b arc 0x13 input 0x38 sleep 0x26 rewind 0x32 play 0x35 ffwd 0x34 rec 0x37 // same $ stop 0x36 pause 0x29 ENTER 0x1a GUIDE 0x3e MENU 0x2e INFO 0x0f // same * QUIT 0x0f // same * */ } } return(0); } //============================================================================================================= // DECODE THE RC5 VALUE - decoded RC5 data is returned, or 0x0000 if RC5 data not recognized //============================================================================================================= unsigned int rc5decode( void ) { unsigned int rc5data; unsigned char timer, i; // init timer/Counter0 TCCR0 = TMC8_CK8; // use CLK/8 prescale TCNT0 = TIMER_0_CNT; // set timer T/16 = 111us TIMSK = _BV(TOIE0); // enable TCNT0 overflow interrupt // measure startbit timerflag = 0; timer = 0; while ( RC5BitLow() && (timer < RC5BITREF2) ) // INT1 = 0 && (timer < 11) { WAITFORTIMER(); // while the signal is low and it hasn't timed out (invalid low) timer++; } if ( (timer > RC5BITREF1) && (timer < RC5BITREF2) ) // ((timer > 6) && (timer < 11)) { // startbit ok, decode while ( timer < RC5BITREF3 ) // wait T/4: synchronize in the middle of first half of second bit { WAITFORTIMER(); timer++; } // read the remaining bits rc5data = 1; // MSB is always a 1 for (i=0; i<13; i++) // check for 14 bits? only 12 in RC5 { rc5data <<= 1; // Left Shift rc5data by 1 bit (preserves highest bit, only reset lowest bit) if ( RC5BitHigh() ) // ** Next bit is a 1 { rc5data |= 0x0001; // Set the lowest bit to 1 // wait max T/2 for H->L transition (middle of next bit) timer = 0; while ( RC5BitHigh() && (timer < 16) ) { WAITFORTIMER(); timer++; } } else // ** Next bit is a 0 { rc5data &= ~0x00001; // set the lowest bit to 0 // wait max T/2 for L->H transition (middle of next bit) timer = 0; while ( RC5BitLow() && (timer < 16) ) { WAITFORTIMER(); timer++; } } if ( timer == 16 ) // Missed a bit value ???? { rc5data = 0x0000; // error, next bit not found break; } // wait 3/4 T: await next bit for ( timer=0; timer < 12 ; timer++) WAITFORTIMER(); } } else { rc5data = 0x0000; // error, invalid RC-5 code printf('invalid code'); } TCCR0 = TMC8_STOP; // stop timer0 return (rc5data); }//rc5decode //============================================================================================================= // TIMER 1 OVERFLOW INTERRUPT- //============================================================================================================= SIGNAL (TIMER0_OVF_vect) // Interrupt Service Routine, Called when Timer 1 () overflows { //printf("=== T0 ===\n"); // User feedback timerflag = 1; // set global variable TCNT0 = TIMER_0_CNT; // reset counter to get this interrupt again } //============================================================================================================= // UNUSED INTERRUPTS - //============================================================================================================= SIGNAL (TIMER1_OVF_vect) // Interrupt Service Routine, Called when Timer 1 () overflows { printf("=== T1 ===\n"); // User feedback } SIGNAL (INT0_vect) { printf("=== INT0 ===\n"); // User feedback } SIGNAL (INT1_vect) { printf("=== INT1 ===\n"); // User feedback } SIGNAL(ADC_vect) { printf("=== ADC ===\n"); // User feedback } SIGNAL(USART_RXC_vect) { } //============================================================================================================= // INITIALIZATIONS //============================================================================================================= void ioinit (void) { //======================================== // SETUP TIMER 1 //======================================== /* TCCR1A = 0b00000011; // Start timer1 TCCR1B |= TIMER1_CLOCKSOURCE; // Defined @ end of iocompat.h #if defined(TIMER1_SETUP_HOOK) // Run any device-dependent timer 1 setup hook if present. TIMER1_SETUP_HOOK(); #endif TIMSK = _BV (TOIE1); // Enable timer 1 overflow interrupt */ //======================================== // DIGITAL IO 1 = output, 0 = input //======================================== DDRB = 0b11111111; // PB4 = MISO, was originally 0 DDRC = 0b11011100; // DDRD = 0b00010110; // PORTD (RX = PD0, TX = PD1, INTO = PD2, INT1 = PD3) PORTC = 0b00011000; // Set up for ADC (lowest two) and SPI (pin 3, 4, 5) //======================================== // SETUP USART //======================================== UBRRH = (MYUBRR >> 8); UBRRL = MYUBRR; UCSRB = (1<