/* ================================================================================ Program : Asuro controlled by IR remote control Release date : 2004-09-16 Author : Henk van Winkoop Build : 037, 2004-09-16, V2.1 Build : 038, 2005-02-01, V2.2, comments enlarged/added ================================================================================ Asuro is remotly controlled by infrared signals according the RC5 standard. Use keys: Vol-, Vol+, Prg-, Prg+ and Standby for driving left/right/forward/reverse/stop. Remember: If Asuro is driving, both engines will draw relatively much current from the batteries. The battery voltage will drop significantly. The Asuro IR-receiver chip is very sensitive to low voltage. So with not fully charged batteries, Asuro may not respond to remote control signals when driving! An RC5 signal is 14 bits width. 2 startbits, a toggle bit, 5 address bits, 6 command bits +----+----+----+----+----+----+----+----+----+----+----+----+----+----+ | S1 | S2 | TG | A4 | A3 | A2 | A1 | A0 | C5 | C4 | C3 | C2 | C1 | C0 | +----+----+----+----+----+----+----+----+----+----+----+----+----+----+ A low bit starts with a high level, going low halfway bittime. | | +---+ | | | | | +---+ | | A high bit starts with a low level, going high halfway bittime. | | | +---+ | | | +---+ | | | Each RC5-bit duration is 1778us. Asuro contains a 3-pin IR(Infra Red)-signal receive chip. This chip demodulates any received 36KHz infrared signal and outputs a clean digital code. If Asuro is beamed with an RC5 remote control, this chip will output a clean RC5 digital code. The Asuro IR-chip output is directly connected to the ATMEGA8 (microcontroller) RXD pin. Normally, the first bit of a RC5 signal received by the ATMEGA8 RXD pin should generate an interrupt. This interrupt then would start a internal ATMEGA8 timer for analysing the next received RC5 bits. The ATMEGA8 RXD pin however can not simply generate an interrupt. It only generates an interrupt if a valid serial CHARACTER (complete valid character, not signal) is received on the RXD-pin. Probably the Asuro was not intended to be used for IR-control. So we need to use a little trick. The UART generates an interrupt when a valid complete character is received. The UART detects a valid character if a low-going startbit is detected and if after a certain time (depending on the baudrate) a valid high-level (stopbit) is detected. Now we use the low-going edge in the first RC5-startbit (S1) as the UART startbit detection. If we set the UART to 4800baud and if we set the expected/received character to have 5 bits, then the UART will expect a high-level stopbit in the middle of the high part of our second RC5-startbit (S2) |-------------------RC5-code-as-is-generated-by-Asuro-IR-receive-chip-------------------| |---startbit1---|---startbit2---|---togglebit---|---address4----|--//---|---command0----| |----low-bit----|----low-bit----|-low/high-bit--|-low/high-bit--|--//---|-low/high-bit--| |-----1778us----|-----1778us----|-----1778us----|-----1778us----|--//---|-----1778us----| |--------------------------------14*1778=24892us----------------------------------------| +-------+ +-------+ +-------+-------+-------+-------+--//---+-------+-------+ S1(h)| S1(l)| S2(h)| S2(l)| TG | TG | A4 | A4 | | C0 | C0 | +-------+ +-------+-------+-------+-------+-------+--//---+-------+-------+ |-------------| expected character-length by UART when UART is set to 4800baud/5bits per character ->| |<- startbit ->| |<- expected stopbit 0 0 0 1 1 <- received 5-bits data, not important/not used --------+ +-+-+-+-+-+-+------------- |S|1|2|3|4|5|S +-+-+-+-+-+-+| | |<- halfway stopbit an interrupt is generated by the UART (detecting valid received character) | +-------+ +----|--+ +-------+-------+-------+-------+--//---+-------+-------+ S1(h)| S1(l)| S2(h)| S2(l)| TG | TG | A4 | A4 | | C0 | C0 | +-------+ +-------+-------+-------+-------+-------+--//---+-------+-------+ So it is NOT possible to generate an interrupt in the first RC5-startbit S1 as was first intended but it IS possible to generate an interrupt in the SECOND RC5-startbit S2. Because each RC5 code always contains 2 startbits, this is no problem. In stead of using 4800baud/5bit we could also have used 9600baud/8bit to let the stopbit occur in the high part of the RC5-S2 signal. Now we can start the internal ATMEGA8 timer0 to detect the level of the remaining RC5 bits. |<- here an interrupt is generated by the UART | +-------+ +----|--+ +-------+-------+-------+-------+--//---+-------+-------+ S1(h)| S1(l)| S2(h)| S2(l)| TG | TG | A4 | A4 | | C0 | C0 | +-------+ +-------+-------+-------+-------+-------+--//---+-------+-------+ After the first interrupt, timer/counter0 is used to measure the delay to the next bits. As the first timer/counter0 interval (A1-B2) differs from the remaining timer/counter0 intervals (B2-B14), a different timer/counter0 timervalue is used. |---startbit1---|---startbit2---|---togglebit---|---address4----|--//---|---command0----| |----low-bit----|----low-bit----|-low/high-bit--|-low/high-bit--|--//---|-low/high-bit--| |-----1778us----| |---------2223us--------| |<- here an interrupt is generated by the UART | +-------+ +----|--+ +-------+-------+-------+-------+--//---+-------+-------+ S1(h)| S1(l)| S2(h)| S2(l)| TG | TG | A4 | A4 | | C0 | C0 | +-------+ +-------+-------+-------+-------+-------+--//---+-------+-------+ --|---------------|---------------|-----------------------|---- needed timer0 interrupts ---1--- timer0 interrupts counter (dummy, predefined) ---2---------------3---------------4----------------------14---- timer0 interrupts counter (updated) --------+ +-+-+-+-+-+-+------------- |S|1|2|3|4|5|S +-+-+-+-+-+-+ |-----1778us----| (length of one single RC5 bit) |---1352us---| (208us (=1/4800baud) * 6,5 (1 startbit + 5 databits + 0,5 stopbit)) |--| 426us ((A) distance between 4800baud-stopbit/interrupt and RC5-S2 going low) |---| 445us ((B) = 1778/4 = length of a quarter of one RC5-bit) |------| 871us (= (A) + (B) = 426 + 445 = distance between interrupt and half of low half of RC5-S2 So each time a UART interrupt is generated, timer0 is used to delay the running program for 871us so it will be exactly in the middle of the low part of RC5-startbit S2. Then for each remaining RC5 bit, timer0 will be used to find the middle of each second-half of each bit . Timer0 prescaler output /256 is selected. So timer0 clock frequency is 8MHz / 256 = 31250Hz = 32us period. Timer0 is 8-bits wide, so timer0 continuously counts up from 0 to 255 and then resets to 0 again. Timer0 generates an interrupt (if enabled) on each 255 to 0 transition. To make timer0 delay (first time) 871us, divide it by timer0 clockcycle duration of 32us makes 871/32 = 27 clockcycles. To make timer0 delay 27 (0x1B) clockcycles, set it's initial value to 0xFF minus 0x1B = 0xE4. So it will take 27*32 = 864us (closest to 871us) after a UART interrupt when the first timer0 interrupt will occur. |------| 871us (= (A) + (B) = 426 + 445 (871/32=27=0x1B => 0xFF-0x1B=0xE4) The USART takes 3 samples in the middle of each bit. Also in the expected stopbit. If valid, an interrupt will be generated immediately after detecting a valid stopbit, so almost halfway the stopbit, which is approximately halfway the RC5-S2 bit. The RXD interrupt handler will then disable itself and init timer/counter0 and enable timer/counter0 interrupt. When timer/counter0 interrupt handler has detected 1 dummy (RC5-S2) plus 12 real bits, it will disable it's own interrupt. Remember: each bit value is checked in the second half part of each bit, because the second half part represents the real bit value. But, because a '1' bit in real world is represented by a low voltage level, (due to IR-chip characteristics) the bit-value detected must be inverted to represent the real received infrared value.(???) Some IR signal info: Infrared signal carrier frequency = 36KHz Infrared signal carrier bit duration = 1/36000 = 27,78us Each data bit takes 64 carrier bits. so... - data bit frequency = 36000/64 = 562,5Hz - data bit size = 64*27,78us = 1778us ########## NO NEED TO READ, JUST FOR MY OWN THOUGHTS ########## TTTTTTTTTT 1234567890 +-+ +-+ +-+ | | | | | | +-+ +-+ +-+ +-// +-+ +-+-+ +-// | | | | | +-+ +-+ +-+ +---+---+---+--- S1 S2 TG To detect first startbit, be sure that a stopbit is detected at positin 6. Set baudrate to 9600, one bit is 104us, Low level from 1st startbit is at t=890us. stopbit (bit 8 from 0-7) is from 832us to 936us 4800baud and 5 bits bit time 1 = 0 - 207 ns 2 = 208 - 415 ns 3 = 416 - 623 ns 4 = 624 - 831 ns 5 = 832 - 1039 ns S = 1040 - 1247 stopbit is well inside low part T6 (T6=890ns-1780ns) Using baudrate 4800 with 5-bits dataframe will find valid stopbit inside T6. If a valid frame is detected then a '1' bit is assumed to be received. If a frame error is detected then a '1' bit followed by a '0' bit is assumed to be received. This will make the expected 4800baud stopbit detection occur in the high part of the second startbit S2. A startbit is detected when S1 is going low. The expected stopbit must be in the high part of S2. If the bitrate is set, for instance, to 9600baud (104us) then using 8-bits with 1 startbit and 1 stopbit, will expect a stopbit at (1+8+0.5) * 104 = 9.5 * 104 = 988us after S1 going low, is in high part of S2. So this bitrate will also work fine. The bitrate must be choosen that way, so that the expected stopbit will occur in the high part of S2. ########## END OF NO NEED TO READ, JUST FOR MY OWN THOUGHTS ########## */ #include "asuro.h" #include "hvwdefines.h" //remote control key codes #define REMOTE_KEY_STD_BY 12 #define REMOTE_KEY_VOL_UP 16 #define REMOTE_KEY_VOL_DW 17 #define REMOTE_KEY_PRG_UP 32 #define REMOTE_KEY_PRG_DW 33 #define REMOTE_KEY_0 0 #define ASURO_FORWARD REMOTE_KEY_PRG_UP #define ASURO_REVERSE REMOTE_KEY_PRG_DW #define ASURO_TURN_LEFT REMOTE_KEY_VOL_UP #define ASURO_TURN_RIGHT REMOTE_KEY_VOL_DW #define ASURO_STOP REMOTE_KEY_0 volatile byte gvbRxBitCnt; volatile long gvlRxDat; volatile byte gvbSysFlg; #define SYSTEM_FLAG_RX_IR_CODE 0x01 //================================================================================ // DELAY 50 MICROSECONDS //================================================================================ void vDelay50us(unsigned int iDel){ //var unsigned int i; unsigned char j; //loop number of 50us loops for(i=0;i T period=16ms) ICR1=255; //port PB1/OC1A compare count value (left engine off) OCR1A=0; //port PB2/OC1B compare count value (right engine off) OCR1B=0; } //================================================================================ // INIT ALL PORTS //================================================================================ void vInitAllPorts(void){ //disable all output pull-up resistors SFRX(SFIOR,PUD_H); //######################################################################################################################## // //DDRB (= IRTX | LEFT_DIR | PWM | GREEN_LED;) //initialize Data-Direction-Register-Port-B //+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ //|port name | PB7 | PB6 | PB5 | PB4 | PB3 | PB2 | PB1 | PB0 | //+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ //|bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ //|pin number | 10 | 9 | 19 | 18 | 17 | 16 | 15 | 14 | //+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ //|signal name| XTAL2 | XTAL1 | FWD_RGT | REV_RGT | IR_TXD1 | SPD_RGT | SPD_LFT | SLD_GRN | //+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ SFRX ( DDRB , FWD_RGT_O | REV_RGT_O | IR_TXD1_O | SPD_RGT_O | SPD_LFT_O | SLD_GRN_O ) ; //+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ SFRX ( PORTB , FWD_RGT_H | REV_RGT_L | IR_TXD1_L | SPD_RGT_L | SPD_LFT_L | SLD_GRN_H ) ; //+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ // x x . . . . . . = unused (connected to 8MHz Xtal) // . . n n . . . . = OL OL = both engine poles connected to VCC (break?) // . . n n . . . . = OL OH = set left engine direction to reverse // . . OH OL . . . . = OH OL = set left engine direction to forward // . . n n . . . . = OH OH = both engine poles are equally pulsed if speed is programmed // . . . . OL . . . = Infra Red transmit signal // . . . . . OL OL . = left-engine and right-engine speed output // . . . . . . . OH = system-led green-light control output, ON // //######################################################################################################################## // //DDRC (= ???) //initialize Data-Direction-Register-Port-C //+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ //|port name | PC7 | PC6 | PC5 | PC4 | PC3 | PC2 | PC1 | PC0 | //+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ //|bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ //|pin number | - | 1 | 28 | 27 | 26 | 25 | 24 | 23 | //+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ //|signal name| - | RESET | VPL_SNS | SWI_JNC | TRS_LFT | TRS_RGT | BOD_LFT | BOD_RGT | //+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ SFRX ( DDRC , VPL_SNS_I | SWI_JNC_I | TRS_LFT_I | TRS_RGT_I | BOD_LFT_O | BOD_RGT_O ) ; //+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ SFRX ( PORTC , VPL_SNS_N | SWI_JNC_N | TRS_LFT_N | TRS_RGT_N | BOD_LFT_L | BOD_RGT_L ) ; //+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ // . . IN . . . . . = V+ sensor measurement as input // . . . IN . . . . = key-press detector as input // . . . . IN IN . . = left/right track sensors as input // . . . . , , OL OL = left/right break/odo-meter sensors as input // //######################################################################################################################## // //DDRD (= RIGHT_DIR | FRONT_LED | ODOMETRIE_LED | RED_LED;) //initialize Data-Direction-Register-Port-D //+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ //|port name | PD7 | PD6 | PD5 | PD4 | PD3 | PD2 | PD1 | PD0 | //+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ //|bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ //|pin number | 13 | 12 | 11 | 6 | 5 | 4 | 3 | 2 | //+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ //|signal name| ODO_LDS | FRT_LED | FWD_LFT | REV_LFT | SWI_INT | SLD_RED | IR_RXD | IR_TXD2 | //+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ SFRX ( DDRD , ODO_LDS_O | FRT_LED_O | FWD_LFT_O | REV_LFT_O | SWI_INT_I | SLD_RED_O | IR_TXD2_I | IR_RXD_I ) ; //+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ SFRX ( PORTD , ODO_LDS_L | FRT_LED_L | FWD_LFT_H | REV_LFT_L | SWI_INT_L | SLD_RED_L | IR_TXD2_L | IR_RXD_L ) ; //+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+ // OL . . . . . . . = both odometrie leds (#001) // . OL . . . . . . = front (tracking) led (#002) // . . n n . . . . = OL OL = both engine poles connected to VCC (break?) // . . n n . . . . = OL OH = set left engine direction to reverse // . . OH OL . . . . = OH OL = set left engine direction to forward // . . n n . . . . = OH OH = both engine poles are equally pulsed if speed is programmed // . . . . IL . . . = 'switches' is input // . . . . . OL . . = system-led red-light control output // . . . . . . IL IL = Infra-Red signals both as input // //######################################################################################################################## //---init-timer-counter-register-1-for-controlling-engine-speeds---// //CLK-i/o lijkt 8MHz/2=4MHz te zijn! //In Waveform Generation Mode 1, 8-bit, TOP = 0xFF = 255 //In prescaler mode 1, Counter clock (CLK-i/o) should be external clock (8MHz) but seems to be external clock / 2 (4MHz) //Frequency = CLK-i/o / 8 / 256 = 4MHz / 8 / 256 = 2KHz //TCCR1A Timer Counter 1 Control Register A //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ SFRX ( TCCR1A , COM1A1_H | COM1A0_L | COM1B1_H | COM1B0_L | FOC1A_L | FOC1B_L | WGM11_L | WGM10_H ) ; //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ // n n . . . . . . = 00 : normal port operation // n n . . . . . . = 01 : toggle OC1A (pin15) on match // 1 0 . . . . . . = 10 : OC1A (pin15) low on match, high at TOP // n n . . . . . . = 11 : OC1A (pin15) high on match // . . n n . . . . = 00 : normal port operation // . . n n . . . . = 01 : toggle OC1B (pin16) on match // . . 1 0 . . . . = 10 : OC1B (pin16) low on match, high at TOP // . . n n . . . . = 11 : OC1B (pin16) high on match // . . . . 0 0 . . = set to 0 in PWM mode (for compatibility, see pdf page 96) // . . . . . . 0 1 = nn01 : WGM13-WGM10: Waveform Generation Mode 1, PWM Phase correct 8-bit // XXnn : see TCCR1B register //TCCR1B Timer Counter 1 Control Register B //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ SFRX ( TCCR1B , ICNC1_L | ICES1_L | WGM13_L | WGM12_L | CS12_L | CS11_H | CS10_L ) ; //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ // 0 . . . . . . . = no noise-canceler (no 4 clock AD conversion delay) // . 0 . . . . . . = no input-capture selection // . . x . . . . . = unused // . . . 0 0 . . . = 00nn : WGM13-WGM10: Waveform Generation Mode 1 (nnXX : see TCCR1A register) // . . . . . 0 1 0 = Counterclock = Systemclock / 8 // //enable compare A timer 1 interrupt //SFRX ( TIMSK , OCIE1A_H ) ; //---init-AD-converter-for-measuring-purposes---// //ADCSRA //prepair AD-converter, prescaler 64 //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ SFRX ( ADCSRA , ADEN_H | ADSC_L | ADFR_L | ADIF_L | ADIE_L | ADPS2_H | ADPS1_H | ADPS0_L ) ; //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ // 1 . . . . . . . = AD-Converter enable // . 0 . . . . . . = no start AD conversion (not yet) // . . 0 . . . . . = no free running mode // . . . 0 . . . . = interrupt (or: conversion finished) // . . . . 0 . . . = no AD interrupt enable // . . . . . n n n = ADC prescaler // . . . . . n n n = 000 = 2, 001=2, 002=4, 003=8, 004=16, 005=32 // . . . . . 1 1 0 = 110 = 64 // . . . . . n n n = 111 = 128 //general interrupt enable SFRX(SREG,GIE_H); } //================================================================================ // INIT USART // void vInitUsart(unsigned int uiBitRatCod){ //================================================================================ void vInitUsartForRemoteControl(void){ //+-----------+ //| UCSRA | Only bit 6,1,0 are writable //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ SFRX ( UCSRA , RXC_L | TXC_L | UDRE_L | FE_L | DOR_L | PE_L | U2X_L | MPCM_L ) ; //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ // n . . . . . . . = 1 => receive character available // . 0 . . . . . . = 1 => all data send // . . n . . . . . = 1 => USART Data Register Empty // . . . n . . . . = 1 => frame error // . . . . n . . . = 1 => data overrun // . . . . . n . . = 1 => parity error // . . . . . . 0 . = 1 => Double the USART transmission speed // . . . . . . . 0 = 1 => Multi-processor Communication Mode // //+-----------+ //| UCSRB | //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ SFRX ( UCSRB , RXCIE_L | TXCIE_L | UDRIE_L | RXEN_L | TXEN_L | UCSZ2_L | RXB8_L | TXB8_L ) ; //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ // 0 . . . . . . . = RX Complete interrupt enabled // 0 . . . . . . = TX Complete interrupt disabled // . . 0 . . . . . = Data Register Empty interrupt disabled // . . . 0 . . . . = RX disabled // . . . . 0 . . . = TX disabled // . . . . . 0 . . = UCSZ2/UCSZ1/UCSZ0 = 011 = 8 databits // . . . . . . 0 . = RX bit 8 from 0-8 (if 9-bit data enabled) // . . . . . . . 0 = TX bit 8 from 0-8 (if 9-bit data enabled) // //+-----------+ //| UCSRC | //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ SFRX ( UCSRC , URSEL_H | UMSEL_L | UPM1_L | UPM0_L | USBS_L | UCSZ1_L | UCSZ0_L | UCPOL_L ) ; //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ // 1 . . . . . . . = 1 = select UCSRC (this) register // n . . . . . . . (0 = select UBRRH register) // . 0 . . . . . . = Select Async mode (=0), 1 = Synchronous mode // . . 0 0 . . . . = 0 0 Parity Disabled // . . n n . . . . 0 1 Reserved // . . n n . . . . 1 0 Parity Enabled, Even Parity // . . n n . . . . 1 1 Parity Enabled, Odd Parity // . . . . 0 . . . = 0 = 1stopbit // . . . . n . . . 1 = 2stopbit // . . . . . n n . = UCSZ2/UCSZ1/UCSZ0 Databits // . . . . . n n . = 0=5bit,1=6bit,2=7bit,3=8bit,7=9bit // . . . . . n n . = 4=reserved,5=reserved,6=reserved // . . . . . 0 0 . = UCSZ2/UCSZ1/UCSZ0 Databits // . . . . . . . 0 = clock polarity: // 0=Rising TX-XCK Edge Falling RX-XCK Edge // 1=Falling TX-XCK Edge Rising RX-XCK Edge //+-----------+ //| UBRRH | = 0x00 //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ SFRX ( UBRRH , URSEL_L | UBRR11_L | UBRR10_L | UBRR09_L | UBRR08_L ) ; //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ // 0 . . . . . . . = 0 = select UBRRH (this) register // n . . . . . . . 1 = select UCSRC register // . . . . 0 0 0 0 = 0000 is part of baudrate setting, see UBRRL // //+-----------+ //| UBRRL | = 0xCF = 207 = 2400baud //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ SFRX ( UBRRL , UBRR07_L | UBRR06_H | UBRR05_H | UBRR04_L | UBRR03_L | UBRR02_H | UBRR01_H | UBRR00_H ) ; //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ // 1 1 0 0 1 1 1 1 = 0xCF = 207 = 2400baud // 0 1 1 0 0 1 1 1 = 0x67 = 103 = 4800baud // //set high part of bitrate code (clear bit 7 to address UBRRH) //UBRRH = (uiBitRatCod>>8)&0x7F; //set low part of bitrate code //UBRRL = uiBitRatCod; //enable receiver //SFRX ( UCSRB , RXEN_H ) ; //enable transmitter //SFRX ( UCSRB , TXEN_H ) ; } //================================================================================ // INIT TIMER COUNTER 0 //================================================================================ void vInitTimerCounter0(void){ //+-----------+ //| TCCR0 | //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ SFRX ( TCCR0 , CS02_H | CS01_L | CS00_L ) ; //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ // n n n : 000 No clock source (Timer/Counter stopped). // n n n : 001 clkI/O/(No prescaling) // n n n : 010 clkI/O/8 (From prescaler) // n n n : 011 clkI/O/64 (From prescaler) // 1 0 0 : 100 clkI/O/256 (From prescaler) // n n n : 101 clkI/O/1024 (From prescaler) // n n n : 110 External clock source on T0 pin. Clock on falling edge. // n n n : 111 External clock source on T0 pin. Clock on rising edge. // //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ //SFRX ( TIFR , TOV0_X ) ; //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ // n : Timer0 overflow (0xFF->0x00) flag // //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ SFRX ( TIMSK , TOIE0_L ) ; //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ // n : Timer0 overflow (0xFF->0x00) interrupt enable //0xC8 = 200 //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ SFRW ( TCNT0 , 0xC8 ) ; //+-----------+----------+----------+----------+----------+----------+----------+----------+----------+ // n : Timer0 counter value (r/w) // } //================================================================================ // MAIN //================================================================================ int main(void){ //init all ports vInitAllPorts(); //init engines (using mode 8) vInitEnginesUsingMode8(); //switch front led off SET_FRONT_LED_OFF; //init USART for remote control vInitUsartForRemoteControl(); //init timer/counter0 (used for sampling bit12 to bit0) vInitTimerCounter0(); //clear received bits count gvbRxBitCnt=0; //clear all user defined system flags gvbSysFlg=0x00; //enable data-receive interrupt SFRX(UCSRB,RXCIE_H); //enable receiver SFRX(UCSRB,RXEN_H); //keep checking for received code while(1){ //IR code received if(CHK_BYTE_BIT_SET(gvbSysFlg,SYSTEM_FLAG_RX_IR_CODE)){ //clear IR-received flag CLR_BYTE_BIT(gvbSysFlg,SYSTEM_FLAG_RX_IR_CODE); //analyse low 6 bits of received data switch(gvlRxDat&0x3F){ case REMOTE_KEY_0: SET_LEFT_BRAKE_LED_OFF; SET_RGHT_BRAKE_LED_OFF; SET_LEFT_ENGINE_SPEED(0x00); SET_RGHT_ENGINE_SPEED(0x00); break; case REMOTE_KEY_PRG_UP: SET_LEFT_BRAKE_LED_ON; SET_RGHT_BRAKE_LED_ON; SET_LEFT_ENGINE_SPEED(0x00); SET_RGHT_ENGINE_SPEED(0x00); SET_LEFT_ENGINE_DIRECTION_TO_FORWARD; SET_RGHT_ENGINE_DIRECTION_TO_FORWARD; SET_LEFT_ENGINE_SPEED(0xC0); SET_RGHT_ENGINE_SPEED(0xC0); //exit case break; case REMOTE_KEY_PRG_DW: SET_LEFT_BRAKE_LED_OFF; SET_RGHT_BRAKE_LED_OFF; SET_LEFT_ENGINE_SPEED(0x00); SET_RGHT_ENGINE_SPEED(0x00); SET_LEFT_ENGINE_DIRECTION_TO_REVERSE; SET_RGHT_ENGINE_DIRECTION_TO_REVERSE; SET_LEFT_ENGINE_SPEED(0xC0); SET_RGHT_ENGINE_SPEED(0xC0); //exit case break; case REMOTE_KEY_VOL_UP: SET_LEFT_BRAKE_LED_ON; SET_RGHT_BRAKE_LED_OFF; //right engine is driving if(OCR1B!=0){ SET_RGHT_ENGINE_SPEED(0x00); vDelay50us(50000); vDelay50us(50000); vDelay50us(50000); SET_RGHT_ENGINE_SPEED(0xC0); } //right engine has stopped else{ SET_LEFT_ENGINE_SPEED(0x00); SET_RGHT_ENGINE_SPEED(0x00); SET_LEFT_ENGINE_DIRECTION_TO_FORWARD; SET_RGHT_ENGINE_DIRECTION_TO_REVERSE; SET_LEFT_ENGINE_SPEED(0xC0); SET_RGHT_ENGINE_SPEED(0xC0); vDelay50us(50000); vDelay50us(50000); SET_LEFT_ENGINE_SPEED(0x00); SET_RGHT_ENGINE_SPEED(0x00); } //exit case break; case REMOTE_KEY_VOL_DW: //left engine is driving if(OCR1A!=0){ SET_LEFT_ENGINE_SPEED(0x00); vDelay50us(50000); vDelay50us(50000); vDelay50us(50000); SET_LEFT_ENGINE_SPEED(0xC0); } //left engine has stopped else{ SET_RGHT_BRAKE_LED_ON; SET_LEFT_BRAKE_LED_OFF; SET_LEFT_ENGINE_SPEED(0x00); SET_RGHT_ENGINE_SPEED(0x00); SET_LEFT_ENGINE_DIRECTION_TO_REVERSE; SET_RGHT_ENGINE_DIRECTION_TO_FORWARD; SET_LEFT_ENGINE_SPEED(0xC0); SET_RGHT_ENGINE_SPEED(0xC0); vDelay50us(50000); vDelay50us(50000); SET_LEFT_ENGINE_SPEED(0x00); SET_RGHT_ENGINE_SPEED(0x00); } //exit case break; case REMOTE_KEY_STD_BY: SET_LEFT_BRAKE_LED_OFF; SET_RGHT_BRAKE_LED_OFF; SET_LEFT_ENGINE_SPEED(0x00); SET_RGHT_ENGINE_SPEED(0x00); //exit case break; }//switch //clear received bit count gvbRxBitCnt=0; //re-enable receiver (disabled by first received character) SFRX(UCSRB,RXEN_H); }//if } return 0; } //-------------------------------------------------------------------------------- // INTERUPT HANDLER (RECEIVED USART CHARACTER) //-------------------------------------------------------------------------------- SIGNAL(SIG_UART_RECV){ //disable receiver (avoiding more interrupts) SFRX(UCSRB,RXEN_L); //reset timer/counter0 (and timer/counter1) prescaler SFRX(SFIOR,PSR10_H); //define timer/counter0 counter value (delay = 0xFF-0xE4 = 0x1B = 27 (times 32us) = 864us) SFRW(TCNT0,0xE4); //clear overflow flag (must be cleared first, else, immediately timer/0 overflow interrupt will occur!!!) SFRX(TIFR,TOV0_H); //define timer/counter0 value, to get from halfway detected 4800baud stopbit to middle of second RC5 startbit) //...sounds complicated, well it is... // - timer/counter0 is running at clockspeed of 8MHz/256 = 32us per count. // - timer/counter0 will need 0xFF-0xE4 = 0x1B = 27 clockcycles of 32us = 864us // - this 864us is the distance between de 4800baud stopbit-detection and RC5 startbit 2 centre of second half part of bit S2. //enable timer/counter0 interrupt SFRX(TIMSK,TOIE0_H); //store stopbit in received character gvlRxDat=0x0001; //count received bits gvbRxBitCnt=1; } //-------------------------------------------------------------------------------- // INTERUPT HANDLER (TIMER/COUNTER0 OVERFLOW) //-------------------------------------------------------------------------------- SIGNAL(SIG_OVERFLOW0){ //re-init timer/counter0 counter value (exact distance between RC5 bits) SFRW(TCNT0,0xC9); //shift received data one posisiton to the left gvlRxDat<<=1; //when a '1-bit' (low-level!) is received if(!(PIND&IR_RXD_H)){ //set bit at bitposition 0 gvlRxDat|=0x0001; } //count received bits gvbRxBitCnt++; //all 14 bits received if(gvbRxBitCnt==14){ //disable any further timer/counter0 interrupt SFRX(TIMSK,TOIE0_L); //set corresponding character-received user system flag SET_BYTE_BIT(gvbSysFlg,SYSTEM_FLAG_RX_IR_CODE); } }