// ================================================================================// // // Program : Asuro 020, Build 001, Asuro playing music.c // Release date : 2005-02-19 // Author : Henk van Winkoop // // Build : 001, 2005-02-19, original release // Build : 002, 2005-02-20 // - some bugs released // - high octave playing modes added // - keyboard 'q' and '1' keys changed/added // // ================================================================================ /* Asuro starts playing song 'Jesus bleibt mein Freude' from Bach. It's playing the song with it's engines! Frontswitches (No. 1 is front left near the dark infrared led.) No. 1. Playing song (low pitch), stop, playing higher pitch, stop ,playing lower pitch, stop, repeat... No. 2. Bottom left/right tracksensor sensors control pitch of left/right engine/speakers, stop, repeat... No. 3. Left/right wheel distance sensors control pitch of left/right engine/speakers, stop, repeat... No. 4. Playing synthesizer sounds (low pitch), stop, playing higher pitch, stop, repeat... No. 5. Playing like a siren (low pitch), stop, playing high itch, stop, repeat... No. 6. Using Hyperterminal computer keyboard keys like playing a keyboard using keys a,s,e,d,r,f,g,h,u,j,i,k,l,p,;,[,',\, '1' toggles between low/high pitch 'q' toggles right engine of in low pitch mode (due to high current drawn from both engines Asuro may hang) If No. 6. hangs itself then press switch 6 twice (stop/start) and then first press 'q' key before starting playing. How does this program work? The sound that Asuro produces is generated by it's engines. The engines are driving alternating forward and reverse at the speed of sound frequencies. The engines stator will move according this frequency and produce soft sounds. The Atmega8L microcontroller contains 3 independent timer/counters. Timer0 is used for the left engine producing sounds. Timer1 does this for the right engine. Timer2 controls the length of produced sounds. On each entry of timer0 and timer1 interrupt handlers the forward/backward direction off both engines is toggled. Timer0 is an 8-bit timer that only is capable of counting up. Timer1 is an 16-bit timer that is capable of counting up and counting down. Timer1 is an 8-bit timer that is capable of counting up and counting down. For sound generation an 8-bit timer is sufficient. Timer0 does not have any capability for triggering an event at a certain count. So timer0 is used with it's overflow interrupt (when counting from oxFF to 0x00) while the interrupt handler reloads the requested timer0 counter value from a global variable. So a higher reload value will produce a higher sound pitch. To make timer1 react equal to timer0 its WGM mode is set to 5. The TOP of timer1 now is automatically set to 0xFF and timer1 will generate an interrupt on each overflow. Both timer0 and timer1 are used with prescaler /64. This makes each counterstep last 2.048/256=8us making counter frequency range from 448Hz up to 125KHz. As the engines are toggled at each interrupt the real sound pitch frequency must be divided by two. This makes the usable frequencies range from 224Hz to 63KHz. Timer2 is set to WGM mode 0 that makes it's TOP at 0xFF and the overflow interrupt set at MAX which is also 0xFF. Timer2 reload value is not used. Timer2 just runs free and generates an interrupt at each 256 timer cycles. As timer2 prescaler is set to 1024 it's frequency ranges from 30,52Hz up to 7.813Hz. As no reload is used timer2 interrupts occur at a frequency of 30,52Hz or each 32.768us. A statemachine is used for handling the 6 software operation modes. Operation modes are executed by pressing the corresponding Asuro front switch. Mode 1. playing song 'Jesus bleibt mein Freude' with random toggling leds 2. tracksensors are controlling the corresponding engine sound pitch 3. odometrie sensors are controlling the corresponding engine sound pitch 4. two random generators generate random sound pitches with random toggling leds (startrek sounds) 5. a software upcounter and a software downconter are controlling engines producing up/down going sounds 6. received infrared codes from hyperterminal keyboard, control both engines like a music keyboard 'q' is used to toggle pitch-range and both engines produce a sound differencing 1 reload value so a nice interfering sound is produced. Controlling both engines in mode 6 may cause the power supply to drop to 3V which sometimes stops/hangs the program. Use 'q' to switch to higher pitch range which uses much less current. Also the low range sound need that much current that hyperterminal keys will not be received as long as the current tone is playing. Each tone plays about half a second. The high range does not block receving hyperterminal keys while a tone is being played. Again: a statemachine is used for handling the 6 software operation modes The statemachine runs continuously in the main() function. A statemachine state change is initiated by a frontswitch press. Each Asuro frontswitch keypress generates an interrupt. The interrupt handler then starts the ad-conversion for measuring the pressed key voltage. The ad-conversion when ready generates also an interrupt. In the ad-converter intrrupt handler the pressed keys are analysed. Each pressed key selects a unique statemachine state. Overall timing functions such as tone-duration are handled inside the timer2 overflow interrupt handler. Many states have their own specific interrupts-counting compare value at which compare they handle their specific tasks. ENGINES To make the engine produce a sound, the speed-control input must be set high and the both forward/reverse connections must be toggling between high/low and low/high. To stop the engines from playing the corresponding overflow interrupt must be disabled. But this leaves the engines forward/reverse in a high/low or low/high state which then (after an interrupt disable) will drive the engine forward or reverse. So beside disabling the interrupt, both forward/revers connections of the seected engine must be set to high/high. An alternative way would be to just disable the engine by setting the speed-control connection to low and keep the interrupts running. But this is no nice programming as why leave interrupts running if they are not needed. The timer0/timer1 interrup handlers, if enabled will automatically start toggling the forward/reverse connections so when enabling a timer0/timer1 overflow interrupt there is no need to somehow enable the engines by handling their forward/reverse connections. Just enabling the interrupts will start the sound generation. SWITCHES The switch function analyses the pressed key related mode (statemachine state). A same mode will stop the execution of the current mode. A new mode will stop the current running mode. A new mode will be activated if no mode is active at the moment. USART The usart should be disabled if not used because else the usart will keep receiving new infrared characters and will immediately start interrupt handling as soon as the usart is enabled and its interrupt-enable is activated. SOUND PITCHES A frequency of 440Hz ('A') corresponds to a period of 2273us. A toggling timer interrupt-handler must generate a delay of 2273/2=1137us to generate a sound pitch of 440Hz. 1137us divided by 8us timer step value (or 2273/16) makes decimal 142 or hex 0x8E. To make a counter count 0x8E steps it must be (re)loaded by 0x0100 - 0x8E = 0x72. Due to a misjudgement all reload values are decremented by 1. So 0x72 becomes 0x71. The generated sounds occupy the 220Hz octave and the 440Hz octave from 'C' to 'C'. So totally 25 tones may be produced. tone|white|black| us|/16|hex|^hex|+1 (range 011) 4545 > unused calculated data 4290 > unused calculated data 4050 253 FD 02 03 <------ lowest pitch used ------ C 3822 239 EF 10 11 3608 226 E2 1D 1E D 3405 213 D5 2A 2B 3214 201 C9 36 37 E 3034 190 BE 41 42 F 2863 179 B3 4C 4D 2703 169 A9 56 57 G 2551 159 9F 60 61 2408 151 97 68 69 A 440 2273 142 8E 71 72 <<<======= 440 Hz ======== 466 2145 134 86 79 7A B 494 2025 127 7f 80 81 C 523 1911 120 78 87 88 554 1804 113 71 8E 8F D 587 1703 106 6A 95 96 622 1607 100 64 9B 9C E 659 1517 95 5F A0 A1 F 698 1432 90 5A A5 A6 740 1351 84 54 AB AC G 784 1276 80 50 AF B0 831 1204 75 4B B4 B5 A 880 1136 71 47 B8 B9 932 1073 67 43 BC BD B 988 1012 63 3F C0 C1 C 1047 956 60 3C C3 C4 <------ lowest pitch used ------ 1109 902 \ 1175 851 | 1245 804 | 1319 758 | 1397 716 | 1480 676 | 1568 638 | 1661 602 | 1760 568 | 536 > unused calculated data 506 | 478 | 451 | 427 | 402 | 379 | 358 | 338 | 318 | 301 / Remember: - both Asuro engines have a 'upper' direction control and a 'lower' speed control - to make Asuro produce sounds with it's engines, it's engines must be toggled forward/reverse at the pitch of the sound - to make the engines toggle, the speed-control input of the engines must be continuous enabled - the speed-control signals are directly connected to the compare outputs of the microcontroller - to avoid that the microcontroller is switching the speed-control outputs only the timer/counter1 output modes 0 (from 0-3) may be used - to generate variable sound pitches the timer/counter TOP value must be adjustable - to generate two different sound pitches for each engine, two timers are needed Some idea's - It would be more nice if engines start/stop is done by enabling/disabling prescalers. - timer0 has lowest timers priority and should be used in stead off timer2 */ //-------------------------------------------------------------------------------- // INCLUDES //-------------------------------------------------------------------------------- #include "hvwdefines.h" #include //-------------------------------------------------------------------------------- // DEFINES //-------------------------------------------------------------------------------- // not-false = true (!0x00=0x01) and not-true is false (!0x01=0x00) #define bool unsigned char #define false 0x00 #define true 0x01 #define NUMOF_MUSIC_TONES 26 #define NUMOF_TIMER2_INTERRUPTS 100 #define NUMOF_TIMER2_KEYBOARD_INTERRUPTS 80 #define NUMOF_TIMER2_SYNTHESIZER1_INTERRUPTS 20 #define NUMOF_TIMER2_SYNTHESIZER2_INTERRUPTS 10 #define NUMOF_SONG1_TONES 100 #define NUMOF_SONG2_TONES 100 #define PLAY_MODE_NONE 0 #define PLAY_MODE_SONG_PLAYING_INIT 1 #define PLAY_MODE_SONG_PLAYING 2 #define PLAY_MODE_KEYBOARD_PLAYING_INIT 3 #define PLAY_MODE_KEYBOARD_PLAYING 4 #define PLAY_MODE_TRACK_SENSORS_INIT 5 #define PLAY_MODE_TRACK_SENSORS 6 #define PLAY_MODE_ODO_SENSORS_INIT 7 #define PLAY_MODE_ODO_SENSORS 8 #define PLAY_MODE_SYNTHESIZER1_INIT 9 #define PLAY_MODE_SYNTHESIZER1 10 #define PLAY_MODE_SYNTHESIZER2_INIT 11 #define PLAY_MODE_SYNTHESIZER2 12 #define PLAY_MODE_ALL_OFF_INIT 13 #define PLAY_MODE_ALL_OFF 14 #define KEY_NONE 0x00 #define KEY1 0x20 #define KEY2 0x10 #define KEY3 0x08 #define KEY4 0x04 #define KEY5 0x02 #define KEY6 0x01 //-------------------------------------------------------------------------------- // FUNCTION PROTOTYPES //-------------------------------------------------------------------------------- void vDisableAllInterruptsExceptSwitchesInterrupt(void); void vInitAllPortsAsInputsAndOutputs(void); void vInitTimerCounter0(void); void vInitTimerCounter1(void); void vInitTimerCounter2(void); void vDelayXMilliSeconds(int iDelMilSec); void vInitMusicPlaying(void); void vInitSwitchesForUsingWithInterrupts(void); void vShowHexNumberBySystemLed(unsigned char ucErrNum); void vInitUsartRx2400B8N1UsingRxInterrupt(void); void vInitEnginesForMusicPlayingWithoutStart(void); void vAllLedsOff(void); void vToggleAllLedsAtRandom(void); void vToggleSoundPitchEightOctaves(void); void vResetAllTimersPrescalers(void); //-------------------------------------------------------------------------------- // GLOBALS //-------------------------------------------------------------------------------- unsigned char gucTm0IntCnt; unsigned char gucTm0CurRldVal; unsigned char gucTm0NewRldVal; unsigned char gucTm1IntCnt; unsigned char gucTm1CurRldVal; unsigned char gucTm1NewRldVal; unsigned char gucTm2IntCnt; unsigned char gucNewKbdPlyTon; unsigned char gucDmy; unsigned char gucTonIdx1; unsigned char gucTonIdx2; unsigned char gucSngTonIdx; bool gbDuaTonMod; unsigned char gucNewPlyMod; unsigned char gucCurPlyMod; unsigned char gucPrvPlyMod; //unsigned char gucKeyPlyMod; unsigned char gucNewKeyPrs; unsigned char gucPrvKeyPrs; /* unsigned char gucMusTonLst[NUMOF_MUSIC_TONES]={ // C Cis D Dis E F Fis G Gis A Ais B 0x02, 0x10,0x1D,0x2A,0x36,0x41,0x4C,0x56,0x60,0x68,0x71,0x79,0x80, 0x87,0x8E,0x95,0x9B,0xA0,0xA5,0xAB,0xAF,0xB4,0xB8,0xBC,0xC0, 0xC3 }; */ unsigned char gucMusTonLst[NUMOF_MUSIC_TONES]={ // C Cis D Dis E F Fis G Gis A Ais B 0x03, 0x11,0x1E,0x2B,0x37,0x42,0x4D,0x57,0x61,0x69,0x72,0x7A,0x81, 0x88,0x8F,0x96,0x9C,0xA1,0xA6,0xAC,0xB0,0xB5,0xB9,0xBD,0xC1, 0xC4 }; unsigned char gucKeyBrdTonKey[21]={'a','s','e','d','r','f','g','y','h','u','j','i','k','l','p',';','[','\'','\\',0}; /* |- - - - - - - - - - - - - - - - - - - - - - - - - - - - | | 20 | |------------------------------------------18------------| | 17 | |----------------------------------15--------------------| | 13 | |--------------------------12----------------------------| | 10 | |-------------------8------------------------------------| etc. | 6 | 0x2A |-----------5--------------------------------------------| 0x1D | 3 | 0x10 |- -1- - - - - - - - - - - - - - - - - - - - - - - - - - | 0x02 | | */ unsigned char gucSg1[NUMOF_SONG1_TONES]= { 8,10,12,15,13,13,17,15, 15,20,19,20,15,12, 8,10,12, 13,15,17,15,13,12,10,12, 8, 7, 8,10, 3, 7,10,13,12,10, 12, 8,10,12,15,13,13,17,15, 15,20,19,20,15,12, 8,10,12, 5,15,13,12,10, 8, 3, 8, 7, 8,12,15,20,15,12, 8,12,15, 8, 8, 8,99,255};//unsigned char gucSg2[NUMOF_SONG1_TONES]= {1,3,5,8,6,6,10,8,8,13,12,13,8,5,1,3,5,6,8,10,8,6,5,3,5,1,0,1,3}; unsigned char gucSg2[NUMOF_SONG2_TONES]= { 99,99,99,99,99,99,99,99, 99,99,99,99,99,99,99,99,99, 99,99,99,99,99,99,99,99,99, 99,99,99,99,99,99,99,99,99, 3, 3, 7, 8, 8, 7, 8, 8,10, 12,12,10,12,12, 8, 5, 5, 8, 10,10, 7, 8, 8, 5,10,10, 1, 0, 0, 8,12,12,15,20,20,10, 0, 0, 0,99,255};//unsigned char gucSg2[NUMOF_SONG1_TONES]= {1,3,5,8,6,6,10,8,8,13,12,13,8,5,1,3,5,6,8,10,8,6,5,3,5,1,0,1,3}; //================================================================================ // MAIN //================================================================================ int main(void){ //set dual-tone mode gbDuaTonMod=true; //init all ports as inputs and outputs vInitAllPortsAsInputsAndOutputs(); //init tone to be played by keyboard gucNewKbdPlyTon=0; //init switches for use with interrupt vInitSwitchesForUsingWithInterrupts(); //init timer/counter0, used for generating tones by left engine vInitTimerCounter0(); //init timer/counter1, used for generating tones by right engine vInitTimerCounter1(); //init timer/counter2, used for tone duration and tone sequence control vInitTimerCounter2(); //general interrupt enable (start playing) SFRX(SREG,GIE_H); //define initial play mode gucNewPlyMod=PLAY_MODE_SONG_PLAYING_INIT; //set previous (dummy) play mode gucPrvPlyMod=PLAY_MODE_SONG_PLAYING; //init previous pressed key gucPrvKeyPrs=KEY1; //hang here while(1){ //---check-for-new-state---// //if a new statemachine is requested from outside (from switch interrupt) if(gucNewPlyMod!=PLAY_MODE_NONE){ //get new play mode gucCurPlyMod=gucNewPlyMod; //clear new play mode gucNewPlyMod=PLAY_MODE_NONE; } //analyse playmode switch(gucCurPlyMod){ //----------play-mode:-song-playing-init----------// //song playing init mode selected case PLAY_MODE_SONG_PLAYING_INIT: //define next play mode (define first, before enabling interrupt, due to this variable is checked in timer2 interrupt handler) gucCurPlyMod=PLAY_MODE_SONG_PLAYING; //disable all interrupts except switches interrupt vDisableAllInterruptsExceptSwitchesInterrupt(); //set odometers sense connections to output SFRX(DDRGC,BOD_LFT_O|BOD_RGT_O); //set odometers sense connections to low (leds off) SFRX(PORTC,BOD_LFT_L|BOD_RGT_L); //set odo-leds common connection to low SFRX(PORTD,BOD_COM_L); //init music playing vInitMusicPlaying(); //exit case break; //----------play-mode:-song-playing-init----------// //song playing mode selected case PLAY_MODE_SONG_PLAYING: //exit case break; //----------track-sensors----------// //track sensors init selected case PLAY_MODE_TRACK_SENSORS_INIT: //disable all interrupts except switches interrupt vDisableAllInterruptsExceptSwitchesInterrupt(); //init engines for music playing without starting vInitEnginesForMusicPlayingWithoutStart(); //enable tone0 and tone1 by enabling timer0/timer1interrupts (timer2 not needed) SFRX(TIMSK,TOIE1_H|TOIE0_H); //no start ad-conversion, non-free running SFRX ( ADCSRA , ADEN_H | ADSC_L | ADFR_L | ADIF_L | ADIE_L | ADPS2_H | ADPS1_H | ADPS0_L ); //set odometers sense connections to output low (leds off) SFRX(DDRGC,BOD_LFT_O|BOD_RGT_O); SFRX(PORTC,BOD_LFT_L|BOD_RGT_L); //set odo-leds common connection to low SFRX(PORTD,BOD_COM_L); //define next play mode gucCurPlyMod=PLAY_MODE_TRACK_SENSORS; //exit case break; //track sensors selected case PLAY_MODE_TRACK_SENSORS: //select ADC AVCC with external cap., select switches left-tracksensor (ADC3), left justify SFRX ( ADMUX , REFS1_L | REFS0_H | ADLAR_H |RESERVED | MUX3_L | MUX2_L | MUX1_H | MUX0_H ); //start ad-conversion, non-free running SFRX ( ADCSRA , ADSC_H ) ; //wait here until ad-conversion has finished while(SFRS(ADCSRA,ADSC_H)); //store measured adc light value into timer0 gucTm0CurRldVal=ADCH; //select ADC AVCC with external cap., select switches right-tracksensor (ADC3), left justify SFRX ( ADMUX , REFS1_L | REFS0_H | ADLAR_H |RESERVED | MUX3_L | MUX2_L | MUX1_H | MUX0_L ); //start ad-conversion, non-free running SFRX ( ADCSRA , ADSC_H ) ; //wait here until ad-conversion has finished while(SFRS(ADCSRA,ADSC_H)); //store measured adc light value into timer0 gucTm1CurRldVal=ADCH; //exit case break; case PLAY_MODE_ODO_SENSORS_INIT: //disable all interrupts except switches interrupt vDisableAllInterruptsExceptSwitchesInterrupt(); //init engines for music playing without starting vInitEnginesForMusicPlayingWithoutStart(); //enable tone0 and tone1 by enabling timer0/timer1interrupts (timer2 not needed) SFRX(TIMSK,TOIE1_H|TOIE0_H); //no start ad-conversion, non-free running SFRX ( ADCSRA , ADEN_H | ADSC_L | ADFR_L | ADIF_L | ADIE_L | ADPS2_H | ADPS1_H | ADPS0_L ); //set odometers sense connections to input with no pullup SFRX(DDRGC,BOD_LFT_I|BOD_RGT_I); SFRX(PORTC,BOD_LFT_N|BOD_RGT_N); //set odo-leds common connection to high (odo-tx leds on) SFRX(PORTD,BOD_COM_H); //define next play mode gucCurPlyMod=PLAY_MODE_ODO_SENSORS; //exit case break; case PLAY_MODE_ODO_SENSORS: //select ADC AVCC with external cap., select switches left-tracksensor (ADC3), left justify SFRX ( ADMUX , REFS1_L | REFS0_H | ADLAR_H |RESERVED | MUX3_L | MUX2_L | MUX1_L | MUX0_H ); //start ad-conversion, non-free running SFRX ( ADCSRA , ADSC_H ) ; //wait here until ad-conversion has finished while(SFRS(ADCSRA,ADSC_H)); //store measured adc light value into timer0 gucTm0CurRldVal=ADCH; //select ADC AVCC with external cap., select switches right-tracksensor (ADC3), left justify SFRX ( ADMUX , REFS1_L | REFS0_H | ADLAR_H |RESERVED | MUX3_L | MUX2_L | MUX1_L | MUX0_L ); //start ad-conversion, non-free running SFRX ( ADCSRA , ADSC_H ) ; //wait here until ad-conversion has finished while(SFRS(ADCSRA,ADSC_H)); //store measured adc light value into timer0 gucTm1CurRldVal=ADCH; //exit case break; case PLAY_MODE_SYNTHESIZER1_INIT: //disable all interrupts except switches interrupt vDisableAllInterruptsExceptSwitchesInterrupt(); //init engines for music playing without starting vInitEnginesForMusicPlayingWithoutStart(); //enable timer0, timer1 and timer2 SFRX(TIMSK,TOIE2_H|TOIE1_H|TOIE0_H); //define next play mode gucCurPlyMod=PLAY_MODE_SYNTHESIZER1; //exit case break; case PLAY_MODE_SYNTHESIZER1: //exit case break; case PLAY_MODE_SYNTHESIZER2_INIT: //disable all interrupts except switches interrupt vDisableAllInterruptsExceptSwitchesInterrupt(); //init engines for music playing without starting vInitEnginesForMusicPlayingWithoutStart(); //init timer/counter0 reload value gucTm0CurRldVal=0x00; //init timer/counter1 reload value gucTm1CurRldVal=0x00; //set odometers sense connections to output low (leds off) SFRX(DDRGC,BOD_LFT_O|BOD_RGT_O); SFRX(PORTC,BOD_LFT_L|BOD_RGT_L); //set odo-leds common connection to low SFRX(PORTD,BOD_COM_L); //prepair timer2 interrupt handler to update reload values gucTm2IntCnt=NUMOF_TIMER2_SYNTHESIZER2_INTERRUPTS-1; //---these-inits-are-not-really-neccessary---// //reset all prescalers vResetAllTimersPrescalers(); //init timer0 counter TCNT0=0x00; //init timer1 counter TCNT1=0x00; //init timer2 counter TCNT2=0x00; //define next play mode gucCurPlyMod=PLAY_MODE_SYNTHESIZER2; //enable timer0, timer1 and timer2 SFRX(TIMSK,TOIE2_H|TOIE1_H|TOIE0_H); //exit case break; case PLAY_MODE_SYNTHESIZER2: //exit case break; //playing mode selected case PLAY_MODE_KEYBOARD_PLAYING_INIT: //disable all interrupts except switches interrupt vDisableAllInterruptsExceptSwitchesInterrupt(); //switch left engine off SFRX(PORTD,REV_LFT_H|FWD_LFT_H); //switch right engine off SFRX(PORTB,REV_RGT_H|FWD_RGT_H); //init engines for music playing vInitEnginesForMusicPlayingWithoutStart(); //init usart vInitUsartRx2400B8N1UsingRxInterrupt(); //enable usart receive interrupt SFRX(UCSRB,RXCIE_H); //define next playing mode gucCurPlyMod=PLAY_MODE_KEYBOARD_PLAYING; //prepair timer2 interrupt to execute it's functions immediately on first entry gucTm2IntCnt=NUMOF_TIMER2_KEYBOARD_INTERRUPTS-1; //enable music playing by enabling overflow interrupts for SFRX(TIMSK,TOIE2_H|TOIE1_H|TOIE0_H); //exit case break; //playing mode selected case PLAY_MODE_KEYBOARD_PLAYING: //exit case break; //playing mode selected case PLAY_MODE_ALL_OFF_INIT: //disable all interrupts except switches interrupt vDisableAllInterruptsExceptSwitchesInterrupt(); //switch left engine off SFRX(PORTD,REV_LFT_H|FWD_LFT_H); //switch right engine off SFRX(PORTB,REV_RGT_H|FWD_RGT_H); //switch all leds off vAllLedsOff(); //set timer0 to range 3 (low range) //SFRX(TCCR0 ,CS00_H); //set timer1 to range 3 (low range) //SFRX(TCCR1B,CS10_H); //define next playing mode gucCurPlyMod=PLAY_MODE_ALL_OFF; //exit case break; //playing mode selected case PLAY_MODE_ALL_OFF: //exit case break; }//switch }//while //exit function return 0; } //================================================================================ // DISABLE ALL INTERRUPTS EXCEPT SWITCHES INTERUPT //================================================================================ void vDisableAllInterruptsExceptSwitchesInterrupt(void){ //disable overflow interrupts for timer/counter0,1,2 SFRX(TIMSK,TOIE2_L|TOIE1_L|TOIE0_L); //disable usart receive interrupt SFRX(UCSRB,RXCIE_L); //disable ad-converter ready interrupt SFRX(ADCSRA,ADIE_L); //disable uart receive (else still rx data in buffer when ir-data is received) SFRX(UCSRB,RXEN_L); } //================================================================================ // INIT ENGINES FOR MUSIC PLAYING WITHOUT START //================================================================================ void vInitEnginesForMusicPlayingWithoutStart(void){ //clear timer/counter0 overflow interrupt counter gucTm0IntCnt=0; //clear timer/counter1 overflow interrupt counter gucTm1IntCnt=0; //clear timer/counter2 overflow interrupt counter gucTm2IntCnt=0; //init timer/counter0, used for generating tones by left engine //vInitTimerCounter0(); //init timer/counter1, used for generating tones by right engine //vInitTimerCounter1(); //init timer/counter2, used for tone duration and tone sequence control //vInitTimerCounter2(); //switch left engine off SFRX(PORTD,REV_LFT_H|FWD_LFT_H); //switch right engine off SFRX(PORTB,REV_RGT_H|FWD_RGT_H); //set left engine speed-control on (full) SFRX ( PORTB , SPD_LFT_H ) ; //set right engine speed-control on (full) SFRX ( PORTB , SPD_RGT_H ) ; } //================================================================================ // INIT MUSIC PLAYING //================================================================================ void vInitMusicPlaying(void){ //init engines for music playing without starting vInitEnginesForMusicPlayingWithoutStart(); //clear song current-tone index gucSngTonIdx=0; //prepair timer2 interrupt to execute it's functions immediately on first entry gucTm2IntCnt=NUMOF_TIMER2_INTERRUPTS-1; //clear any eventually pending timer/counter0,1,2 interrupt SFRX(TIFR,TOV2_H|TOV1_H|TOV0_H); //start music playing by enabling overflow interrupts for // - timer/counter0 (left engine, tone1) // - timer/counter1 (right engine, tone2) // - timer/counter2 tone duration and tone sequence control SFRX(TIMSK,TOIE2_H|TOIE1_H|TOIE0_H); } //################################################################################ // interrupt handler, timer/counter0 overflow // enable bit: register TIMSK bit TOIE0 // #define SIG_OVERFLOW0 _VECTOR(9) // pdf table 18, vector number decimal 10 // tone playing control is directly controlled either by interrupt enable or by gucTonIdxn variable! //################################################################################ SIGNAL(SIG_OVERFLOW0){ //reload counter0 with predefined reload value TCNT0=gucTm0CurRldVal; //if left engine drives forward if(SFRS(PORTD,REV_LFT_H)){ //make left engine drive reverse SFRX(PORTD,REV_LFT_L|FWD_LFT_H); } //if left engine drives reverse else{ //make left engine drive forward SFRX(PORTD,REV_LFT_H|FWD_LFT_L); } } //################################################################################ // interrupt handler, timer/counter1 overflow // enable bit: register TIMSK bit TOIE1 // #define SIG_OVERFLOW1 _VECTOR(8) // pdf table 18, vector number decimal 09 // tone playing control is directly controlled either by interrupt enable or by gucTonIdxn variable! //################################################################################ SIGNAL(SIG_OVERFLOW1){ //reload counter1 with predefined reload value TCNT1=gucTm1CurRldVal; //if right engine drives forward if(SFRS(PORTB,REV_RGT_H)){ //make right engine drive reverse SFRX(PORTB,REV_RGT_L|FWD_RGT_H); } //if right engine drives reverse else{ //make right engine drive forward SFRX(PORTB,REV_RGT_H|FWD_RGT_L); } } //================================================================================ // STOP TONE0 //================================================================================ void vStopTone0(void){ //immediately stop timer0 by disabling timer0 interrupt SFRX(TIMSK,TOIE0_L); //switch left engine off (because engine is always set/left to forward or reverse by interrupt handler) SFRX(PORTD,REV_LFT_H|FWD_LFT_H); } //================================================================================ // START TONE0 //================================================================================ void vStartTone0(void){ //get tone-code for left engine from tone-codes list gucTm0CurRldVal=gucMusTonLst[gucTonIdx1]; //start playing tone by left engine (by enabling timer0 interrupt) SFRX(TIMSK,TOIE0_H); } //================================================================================ // STOP TONE1 //================================================================================ void vStopTone1(void){ //immediately stop timer1 by disabling timer1 interrupt SFRX(TIMSK,TOIE1_L); //switch right engine off (because engine is always set/left to forward or reverse by interrupt handler) SFRX(PORTB,REV_RGT_H|FWD_RGT_H); } //================================================================================ // START TONE1 //================================================================================ void vStartTone1(void){ //get tone-code for right engine from tone-codes list gucTm1CurRldVal=gucMusTonLst[gucTonIdx2]; //start playing tone by right engine (by enabling timer1 interrupt) SFRX(TIMSK,TOIE1_H); } //################################################################################ // interrupt handler, timer/counter2 overflow // enable bit: register TIMSK bit TOIE2 // #define SIG_OVERFLOW2 _VECTOR(4) // pdf table 18, vector number decimal 05 //################################################################################ SIGNAL (SIG_OVERFLOW2){ //count interrupts tone-duration counter) gucTm2IntCnt++; //analyse playmode switch(gucCurPlyMod){ //playing mode selected case PLAY_MODE_SONG_PLAYING: //if tone-play duration reached max (specific interrupt limit (tone-play duration) reached if(gucTm2IntCnt==NUMOF_TIMER2_INTERRUPTS){ //clear tone-duration counter gucTm2IntCnt=0; //toggle all leds at random vToggleAllLedsAtRandom(); //get next song-tone-index for left engine gucTonIdx1=gucSg1[gucSngTonIdx]; //get next song-tone-index for right engine gucTonIdx2=gucSg2[gucSngTonIdx]; //prepair for selecting next tone gucSngTonIdx++; //if no more tones need to be played if(gucTonIdx1==255){ //define next play mode gucNewPlyMod=PLAY_MODE_ALL_OFF_INIT; //exit function return; } //if more tones need to be played else{ //if a silent tone must be played by the left engine if(gucTonIdx1==99){ //stop (left engine) tone0 vStopTone0(); }//if //if an audible tone must be played by the left engine else{ //start (left engine) tone0 vStartTone0(); }//else //if a silent tone must be played by the right engine if(gucTonIdx2==99){ //stop (right engine) tone1 vStopTone1(); }//if //if an audible tone must be played by the right engine else{ //start (right engine) tone1 vStartTone1(); } }//else }//if //end case break; //playing mode selected case PLAY_MODE_SYNTHESIZER1: //if tone-play duration reached max (specific interrupt limit (tone-play duration) reached if(gucTm2IntCnt==NUMOF_TIMER2_SYNTHESIZER1_INTERRUPTS){ //clear tone-duration counter gucTm2IntCnt=0; //toggle all leds at random vToggleAllLedsAtRandom(); //store random value into timer/counter0 reload value gucTm0CurRldVal=(unsigned char) random(); //store random value into timer/counter1 reload value gucTm1CurRldVal=(unsigned char) random(); }//if //end case break; //playing mode selected case PLAY_MODE_SYNTHESIZER2: //if tone-play duration reached max (specific interrupt limit (tone-play duration) reached if(gucTm2IntCnt==NUMOF_TIMER2_SYNTHESIZER2_INTERRUPTS){ //clear tone-duration counter gucTm2IntCnt=0; gucTm0CurRldVal++; if(gucTm0CurRldVal>=0xF0){ gucTm0CurRldVal=0x00; } gucTm1CurRldVal--; if(gucTm1CurRldVal>=0xF0){ gucTm1CurRldVal=0xF0; } }//if //end case break; //if keyboard playing mode is selected case PLAY_MODE_KEYBOARD_PLAYING: //if tone-play duration reached max (specific interrupt limit (tone-play duration) reached if(gucTm2IntCnt==NUMOF_TIMER2_KEYBOARD_INTERRUPTS){ //clear tone-duration counter //gucTm2IntCnt=0; //stop tone0 vStopTone0(); //stop tone1 vStopTone1(); } //end case break; }//switch } //################################################################################ // interrupt handler, external interrupt int1 pin5 // enable bit: register GICR bit INT1 // modes set: register MCUCR bits ISC11/ISC10 // #define SIG_INTERRUPT1 _VECTOR(2) // pdf table 18, vector number decimal 03 //################################################################################ SIGNAL (SIG_INTERRUPT1){ //disable any further external INT1 interrupts on pin5 SFRX(GICR,INT1_L); //disable all interrupts except switches interrupt vDisableAllInterruptsExceptSwitchesInterrupt(); //switch left engine off SFRX(PORTD,REV_LFT_H|FWD_LFT_H); //switch right engine off SFRX(PORTB,REV_RGT_H|FWD_RGT_H); //define switch interrupt pin as output SFRX(DDRGD,SWI_IAC_O); //define switch interrupt pin as high (to be pulled low by pressed switch) SFRX(PORTD,SWI_IAC_H); //wait 6 milliseconds (found by experiment) to stabilize junction signal (due to capacitor C7 = 4,7uF) vDelayXMilliSeconds(6); //select AVCC with external cap., select switches ad-converter ADC4, right justify | SFRX(ADMUX,REFS1_L|REFS0_H|ADLAR_L|RESERVED|MUX3_L|MUX2_H|MUX1_L|MUX0_L); //clear any eventually pending AD-converter interrupt SFRX(ADCSRA,ADIF_H); //enable ad-converter 'conversion-finished' interrupt SFRX(ADCSRA,ADIE_H); //start ad-conversion (when ad-conversion is ready, an adc interrupt is generated) SFRX(ADCSRA,ADSC_H); } //################################################################################ // interrupt handler, ad-conversion finished // enable bit: register ADCSRA bit ADIE // #define SIG_ADC _VECTOR(14) // pdf table 18, vector number decimal 15 //################################################################################ SIGNAL (SIG_ADC){ //var unsigned char ucPrsKeyVal; unsigned int uiMsrAdcVal; //disable any further ad-converter-ready interrupt (just for sure, may be superfluous) SFRX(ADCSRA,ADIE_L); //add low-value-byte and high-value-byte from AD-converter into single 16-bit integer uiMsrAdcVal=ADCL+(ADCH<<8); //convert measured value to byte value ucPrsKeyVal=(unsigned char)(((1024.0/(float)uiMsrAdcVal-1.0))*63.0+0.5); //set interrupt on raising edge, to avoid eventually new falling edge interrupt //when key is still pressed at this point then setting pin5 to input the high level //at the interrupt pin will go low and generate a new falling edge interrupt SFRX(MCUCR,ISC11_L|ISC10_L); //---prepair-switches-interrupt-input-for-new-key-presses---// //define switch interrupt pin as input SFRX(DDRGD,SWI_IAC_I); //disconnect pullup from interrupt pin (is needed because output was set high) SFRX(PORTD,SWI_IAC_N); //wait 2 millisecond to stabilize junction signal eventually going low by pressed key and generating an unwanted interrupt vDelayXMilliSeconds(2); //set interrupt back to falling edge SFRX(MCUCR,ISC11_H|ISC10_L); //enable further external INT1 interrupts on pin5 SFRX(GICR,INT1_H); //if same key is pressed again if(ucPrsKeyVal==gucPrvKeyPrs){ //if current play mode is a normal play mode if(gucCurPlyMod!=PLAY_MODE_ALL_OFF){ //just stop playing gucNewPlyMod=PLAY_MODE_ALL_OFF_INIT; //exit fuction return; }//if //if current play mode is the 'play stopped' mode else{ //if key 1,4 or 5 pressed if(ucPrsKeyVal&(KEY1|KEY4|KEY5)){ //toggle sound pitch eight octaves vToggleSoundPitchEightOctaves(); } } } //if another key is pressed else{ //remember last (will be previous later) pressed key gucPrvKeyPrs=ucPrsKeyVal; //if current play mode is a normal play mode if(gucCurPlyMod!=PLAY_MODE_ALL_OFF){ //just stop playing gucNewPlyMod=PLAY_MODE_ALL_OFF_INIT; //exit fuction return; }//else //if current play mode is the 'play stopped' mode else{ //set timer0 to range 3 (low range) SFRX(TCCR0 ,CS00_H); //set timer1 to range 3 (low range) SFRX(TCCR1B,CS10_H); } } //program passes here // - if same key is pressed in stop mode // - if another key is pressed in stop omde //remember last (will be previous later) pressed key gucPrvKeyPrs=ucPrsKeyVal; //analyse pressed key switch(ucPrsKeyVal){ //----------key-1----------// //switch on 1st position from left/front pressed case KEY1: //define selected play mode as new play mode gucNewPlyMod=PLAY_MODE_SONG_PLAYING_INIT; //exit case break; //----------key-2----------// //switch on 2nd position from left/front pressed case KEY2: //switch track led on SFRX(PORTD,TRK_LED_H); //define selected play mode as new play mode gucNewPlyMod=PLAY_MODE_TRACK_SENSORS_INIT; //exit case break; //----------key-3----------// //switch on 3rd position from left/front pressed case KEY3: //switch green system led on SFRX(PORTB,SLD_GRN_H); //switch red system led on SFRX(PORTD,SLD_RED_H); //define selected play mode as new play mode gucNewPlyMod=PLAY_MODE_ODO_SENSORS_INIT; //exit case break; //----------key-4----------// //switch on 4th position from left/front pressed case KEY4: //define selected play mode as new play mode gucNewPlyMod=PLAY_MODE_SYNTHESIZER1_INIT; //exit case break; //----------key-5----------// //switch on 5th position from left/front pressed case KEY5: //switch red system led on SFRX(PORTD,SLD_RED_H); //define selected play mode as new play mode gucNewPlyMod=PLAY_MODE_SYNTHESIZER2_INIT; //exit case break; //----------key-6----------// //switch on 6th position from left/front pressed case KEY6: //switch green system led on SFRX(PORTB,SLD_GRN_H); //define selected play mode as new play mode gucNewPlyMod=PLAY_MODE_KEYBOARD_PLAYING_INIT; //exit case break; //more than one keypress at-one-tie detected //default: //toggle red led //SFRT(PORTD,SLD_RED); }//switch } //################################################################################ // interrupt handler, uart receive complete // enable bit: register UCSRB bit RXCIE // #define SIG_UART_RECV _VECTOR(11) // pdf table 18, vector number decimal 12 //################################################################################ SIGNAL(SIG_UART_RECV){ //var unsigned char ucRcvDat; unsigned char uci; //toggle green system led SFRT(PORTB,SLD_GRN); //toggle red system led SFRT(PORTD,SLD_RED); //----------handle-receive-errors----------// //if there is a frame error in the receive character if(UCSRA&FE_H){ //just exit function return; } //----------get-received-character----------// //read received byte from i/o register (this will clear the interrupt flag) ucRcvDat=UDR; //----------handle-hyperterminal-'q'-and'1'-keys----------// //analyse received character switch(ucRcvDat){ //hyperterminal key 'q' pressed case 'q': //if timer0 range 3 is set (low range) if(SFRS(TCCR0,CS00_H)){ //toggle dual-tone mode gbDuaTonMod=!gbDuaTonMod; } //exit function return; //exit case break; //if '1' character received case '1': //toggle sound pitch eight octaves vToggleSoundPitchEightOctaves(); //exit function return; //exit case break; }//switch //----------find-keypress-corresponding-tone-code-and-start-playing-tone----------// //clear keyboard code search index uci=0; //for all keyboard codes do... for(;;){ //if all keyboard codes in list are searched if(gucKeyBrdTonKey[uci]==0){ //key not found, store no-play tone-code for use by interrupt2 gucNewKbdPlyTon=0; //exit case break; } //not all keyboard codes searched in list else{ //if received keybord code found in keyboard code list if(gucKeyBrdTonKey[uci]==ucRcvDat){ //get corresponding tone-code and store in reload value for tone0 gucTm0CurRldVal=gucMusTonLst[uci]; //make right engine tone pitch differ from left engine tone pitch gucTm1CurRldVal=gucTm0CurRldVal+1; //clear tone-duration counter gucTm2IntCnt=0; //start tone0-playing SFRX(TIMSK,TOIE0_H); //delay to avoid tone0 and tone1 starting at the same time (battery-current reducing) vDelayXMilliSeconds(1); //if low octave is selected (timer0 range 3 is set) if(SFRS(TCCR0,CS00_H)){ //if dual tone mode is set if(gbDuaTonMod){ //start tone1-playing too SFRX(TIMSK,TOIE1_H); }//if }//if //if high octave is selected (timer0 range 2 is set) else{ //start tone1-playing too SFRX(TIMSK,TOIE1_H); }//else //start tone-duration counter SFRX(TIMSK,TOIE2_H); //exit loop break; }//if }//else //select next tone list index uci++; } } //================================================================================ // DELAY MILLI SECONDS //================================================================================ void vDelayXMilliSeconds(int iDelMilSec){ //var unsigned int i,j; //handle all milli seconds for(i=0;i /256 = 31250.00Hz = 32us | //| 010 = 8MHz/ 8 = 1.000.000Hz => /256 = 3906.25Hz = 256us | //| 011 = 8MHz/ 64 = 125.000Hz => /256 = 488.28Hz = 2.048us | //| 100 = 8MHz/ 256 = 31.250Hz => /256 = 122.07Hz = 8.192us | //| 101 = 8MHz/1024 = 7.813Hz => /256 = 30.52Hz = 32.768us | //| 110 = External clock source on T0 pin. Clock on falling edge | //| 111 = External clock source on T0 pin. Clock on rising edge | //| | //+-------------------------------------------------------------------------------------------+ //| use clkio/1024 that makes freerunning frequency of 30.52Hz | //+-------------------------------------------------------------------------------------------+ //| | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //| | - | - | - | - | - | Timer0 | Timer0 | Timer0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|signal name|RESERVED |RESERVED |RESERVED |RESERVED |RESERVED | CS02_X | CS01_X | CS00_X | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ SFRX ( TCCR0 ,RESERVED |RESERVED |RESERVED |RESERVED |RESERVED | CS02_L | CS01_H | CS00_H ); //+-------------------------------------------------------------------------------------------+ //+-------------------------------------------------------------------------------------------+ //| TIFR = Timer/Counter Interrupt Flag Register | //+-------------------------------------------------------------------------------------------+ //| | //| OCF2 = output compare flag 2 (set if timer/counter2 = OCR2) | //| TOV2 = timer/counter2 overflow flag | //| ICF1 = Timer/Counter1, Input Capture Flag (if capture event on pin ICP1) | //| OCF1A = Timer/Counter1, Output Compare A Match Flag (if TCNT1 = OCR1A) | //| OCF1B = Timer/Counter1, Output Compare B Match Flag (if TCNT1 = OCR1B) | //| TOV1 = Timer/Counter1, Overflow Flag (cleared by interrupthandler or manual writing 1)| //| RESERVED = reserved | //| TOV0 = Timer/Counter0, Overflow Flag (cleared by interrupthandler or manual writing 1)| //| | //| | //+-------------------------------------------------------------------------------------------+ //| eventually use register for overflow detection | //+-------------------------------------------------------------------------------------------+ //| | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //| | Timer2 | Timer2 | Timer1 | Timer1 | Timer1 | Timer1 | - | Timer0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|signal name| OCF2_X | TOV2_X | ICF1_X | OCF1A_X | OCF1B_X | TOV1_X |RESERVED | TOV0_X | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //SFRX ( TIFR , OCF2_X | TOV2_X | ICF1_X | OCF1A_X | OCF1B_X | TOV1_X |RESERVED | TOV0_X ); //+-------------------------------------------------------------------------------------------+ //+-------------------------------------------------------------------------------------------+ //| TIMSK = Timer/Counter Interrupt Mask Register | //+-------------------------------------------------------------------------------------------+ //| | //| OCIE2 = timer/counter2, output-compare-match interrupt enable | //| TOIE2 = timer/counter2, overflow interrupt enable | //| TICIE1 = timer/counter1, input-capture interrupt enable | //| OCIE1A = timer/counter1, equal to output-compare-A-match register, interrupt enable | //| OCIE1B = timer/counter1, equal to output-compare-B-match register, interrupt enable | //| TOIE1 = timer/counter1 overflow interrupt enable | //| RESERVED = unused | //| TOIE0 = timer/counter0 overflow interrupt enable | //| | //+-------------------------------------------------------------------------------------------+ //| enable timer/counter0 interrupt | //+-------------------------------------------------------------------------------------------+ //| | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //| | Timer2 | Timer2 | Timer1 | Timer1 | Timer1 | Timer1 | - | Timer0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|signal name| OCIE2_X | TOIE2_X |TICIE1_X |OCIE1A_X |OCIE1B_X | TOIE1_X |RESERVED | TOIE0_X | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ SFRX ( TIMSK , TOIE0_L ); //+-------------------------------------------------------------------------------------------+ //+-------------------------------------------------------------------------------------------+ //| TCNT0 = Timer/Counter Register | //+-------------------------------------------------------------------------------------------+ //| | //+-------------------------------------------------------------------------------------------+ //| timer/counter 0 read/write counter value | //+-------------------------------------------------------------------------------------------+ //| | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //| | Timer0 | Timer0 | Timer0 | Timer0 | Timer0 | Timer0 | Timer0 | Timer0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|signal name| bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ SFRW ( TCNT0 , 0x00 ); //clear counter //+-------------------------------------------------------------------------------------------+ } //================================================================================ // INIT TIMER COUNTER 1 //================================================================================ void vInitTimerCounter1(void){ //+-------------------------------------------------------------------------------------------+ //| TCCR1A = Timer Counter 1 Control Register A | //+-------------------------------------------------------------------------------------------+ //| | //| COM1A1:COM1B1 = how external pins OC1A (pin15)/OC1B (pin16) | //| COMA1:COMA0 (OC1A = external pin p15) | //| 00 : OC1A (pin15) normal I/O-port operation (OC1A (pin15) disconnected from timer1 | //| 01 : OC1A (pin15) toggle on match (dependent from selected waveform mode) | //| 10 : OC1A (pin15) low on match, high at TOP (dependent from selected waveform mode) | //| 11 : OC1A (pin15) high on match (dependent from selected waveform mode) | //| COMB1:COMB0 (OC1B = external pin p16) | //| 00 : OC1B (pin16) normal I/O-port operation (OC1B (pin16) disconnected from timer1 | //| 01 : OC1B (pin16) toggle on match (dependent from selected waveform mode) | //| 10 : OC1B (pin16) low on match, high at TOP (dependent from selected waveform mode) | //| 11 : OC1B (pin16) high on match (dependent from selected waveform mode) | //| FOC1A = immediately force a compare (set to 0, according pdf) | //| FOC1B = immediately force a compare (set to 0, according pdf) | //| WGM1n = bit 0 and 1 of operation mode nibble (bit 2 and 3 are in TCCR1B) | //| | //| | //+-------------------------------------------------------------------------------------------+ //| external OC1A/OC1B pins disconnected from timer, timer mode 10 | //+-------------------------------------------------------------------------------------------+ //| | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|signal name|COM1A1_X |COM1A0_X |COM1B1_X |COM1B0_X | FOC1A_X | FOC1B_X | WGM11_X | WGM10_X | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ SFRX ( TCCR1A ,COM1A1_L |COM1A0_L |COM1B1_L |COM1B0_L | FOC1A_L | FOC1B_L | WGM11_L | WGM10_H ); //+-------------------------------------------------------------------------------------------+ //+-------------------------------------------------------------------------------------------+ //| TCCR1B = Timer Counter 1 Control Register B | //+-------------------------------------------------------------------------------------------+ //| | //| ICNC1 = noise-canceler enabled, (expects min. for 4 signals on ICP1 pin before accepting | //| ICES1 = 0/1 = falling/rising edge on ICP1 (pin14) triggers capture event | //| WGM1n = bit 3 and 4 of operation mode nibble (bit 0 and 1 are in TCCR1A) | //| CSnn = Clock Source | //| 000 = no clock source, timer/counter stopped (counter max set to 0x00FF) | //| 001 = 8MHz/ 1 = 8.000.000Hz => /256 = 31250.00Hz = 32us (counter max set to 0x00FF) | //| 010 = 8MHz/ 8 = 1.000.000Hz => /256 = 3906.25Hz = 256us (counter max set to 0x00FF) | //| 011 = 8MHz/ 64 = 125.000Hz => /256 = 488.28Hz = 2.048us (counter max set to 0x00FF) | //| 100 = 8MHz/ 256 = 31.250Hz => /256 = 122.07Hz = 8.192us (counter max set to 0x00FF) | //| 101 = 8MHz/1024 = 7.813Hz => /256 = 30.52Hz = 32.768us (counter max set to 0x00FF) | //| 110 = External clock source on T0 pin. Clock on falling edge | //| 111 = External clock source on T0 pin. Clock on rising edge | //| | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //| no noise canceler, falling edge trigger, mode decimal 10, 4KHz with TOP set to 0xFF | //+-------------------------------------------------------------------------------------------+ //| | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|signal name| ICNC1_X | ICES1_X |RESERVED | WGM13_X | WGM12_X | CS12_X | CS11_X | CS10_X | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ SFRX ( TCCR1B , ICNC1_L | ICES1_L |RESERVED | WGM13_L | WGM12_H | CS12_L | CS11_H | CS10_H ); //+-------------------------------------------------------------------------------------------+ //+-------------------------------------------------------------------------------------------+ //| TIMSK = Timer/Counter Interrupt Mask Register | //+-------------------------------------------------------------------------------------------+ //| | //| OCIE2 = timer/counter2, output-compare-match interrupt enable | //| TOIE2 = timer/counter2, overflow interrupt enable | //| TICIE1 = timer/counter1, input-capture interrupt enable | //| OCIE1A = timer/counter1, equal to output-compare-A-match register, interrupt enable | //| OCIE1B = timer/counter1, equal to output-compare-B-match register, interrupt enable | //| TOIE1 = timer/counter1 overflow interrupt enable | //| RESERVED = unused | //| TOIE0 = timer/counter0 overflow interrupt enable | //| | //+-------------------------------------------------------------------------------------------+ //| enable timer/counter1 interrupt on output compares A and B | //+-------------------------------------------------------------------------------------------+ //| | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //| | Timer2 | Timer2 | Timer1 | Timer1 | Timer1 | Timer1 | - | Timer0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|signal name| OCIE2_X | TOIE2_X |TICIE1_X |OCIE1A_X |OCIE1B_X | TOIE1_X |RESERVED | TOIE0_X | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ SFRX ( TIMSK , TICIE1_L |OCIE1A_L |OCIE1B_L | TOIE1_L ); //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ } //================================================================================ // INIT TIMER COUNTER 2 //================================================================================ void vInitTimerCounter2(void){ //+-------------------------------------------------------------------------------------------+ //| TCCR2 = Timer/Counter2 Control Register | //+-------------------------------------------------------------------------------------------+ //| | //| FOC2 = Flag Output Compare (set to 0) | //| WGM20 = Waveform Generation Mode bit 0 | //| WGM21 = Waveform Generation Mode bit 1 | //| WGM21:WGM20 |TOP |Update-OCR2|TOV2-flag-set (interrupt)| | //| |----|-----------|-------------------------| | //| 00 : NOM Normal Operation Mode |0xFF|Immediate |MAX (count up) | | //| 01 : PWMPC Pulse Width Mode, Phase Correct |0xFF|TOP |BOTTOM (count up/down)| | //| 10 : CTC Clear Timer on Compare |OCR2|Immediate |MAX (count up) | | //| 11 : FPWM Fast Pulse Width Mode |0xFF|TOP |MAX (count up) | | //| COM21 = Compare match Output Mode bit 1 | //| COM20 = Compare match Output Mode bit 0 | //| COM21:COM20 | //| NOM and CTC mode | //| 0 0 Normal port operation, OC2 (pin17) disconnected from timer2 | //| 0 1 Toggle OC2 on Compare Match | //| 1 0 Clear OC2 on Compare Match | //| 1 1 Set OC2 on Compare Match | //| PWM PC mode | //| 0 0 Normal port operation, OC2 (pin17) disconnected from timer2 | //| 0 1 Reserved | //| 1 0 Clear OC2 on Compare Match when up-counting. Set OC2 on Compare Match when downcount. | //| 1 1 Set OC2 on Compare Match when up-counting. Clear OC2 on Compare Match when downcount. | //| FPWM mode | //| 0 0 Normal port operation, OC2 (pin17) disconnected from timer2 | //| 0 1 Reserved | //| 1 0 Clear OC2 on Compare Match, set OC2 at TOP | //| 1 1 Set OC2 on Compare Match, clear OC2 at TOP | //| CS2n = Clock Select | //| CS22:CS21:CS20 | //| 000 = no clock source, timer/counter stopped (counter max set to 0xFF) | //| 001 = 8MHz/ 1 = 8.000.000Hz => /256 = 31250.00Hz = 32us (counter max set to 0xFF) | //| 010 = 8MHz/ 8 = 1.000.000Hz => /256 = 3906.25Hz = 256us (counter max set to 0xFF) | //| 011 = 8MHz/ 64 = 125.000Hz => /256 = 488.28Hz = 2048us (counter max set to 0xFF) | //| 100 = 8MHz/ 256 = 31.250Hz => /256 = 122.07Hz = 8.192us (counter max set to 0xFF) | //| 101 = 8MHz/1024 = 7.813Hz => /256 = 30.52Hz = 32.768us (counter max set to 0xFF) | //| 110 = External clock source on T0 pin. Clock on falling edge | //| 111 = External clock source on T0 pin. Clock on rising edge | //| | //+-------------------------------------------------------------------------------------------+ //| user comment | //+-------------------------------------------------------------------------------------------+ //| | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|signal name| FOC2_X | WGM20_X | COM21_X | COM20_X | WGM21_X | CS22_X | CS21_X | CS20_X | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ SFRX ( TCCR2 , FOC2_L | WGM20_L | COM21_L | COM20_L | WGM21_L | CS22_H | CS21_L | CS20_H ); //+-------------------------------------------------------------------------------------------+ //+-------------------------------------------------------------------------------------------+ //| TIMSK = Timer/Counter Interrupt Mask Register | //+-------------------------------------------------------------------------------------------+ //| | //| OCIE2 = timer/counter2, output-compare-match interrupt enable | //| TOIE2 = timer/counter2, overflow interrupt enable | //| TICIE1 = timer/counter1, input-capture interrupt enable | //| OCIE1A = timer/counter1, equal to output-compare-A-match register, interrupt enable | //| OCIE1B = timer/counter1, equal to output-compare-B-match register, interrupt enable | //| TOIE1 = timer/counter1 overflow interrupt enable | //| RESERVED = unused | //| TOIE0 = timer/counter0 overflow interrupt enable | //| | //+-------------------------------------------------------------------------------------------+ //| enable timer/counter2 interrupt on overflow | //+-------------------------------------------------------------------------------------------+ //| | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //| | Timer2 | Timer2 | Timer1 | Timer1 | Timer1 | Timer1 | - | Timer0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|signal name| OCIE2_X | TOIE2_X |TICIE1_X |OCIE1A_X |OCIE1B_X | TOIE1_X |RESERVED | TOIE0_X | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ SFRX ( TIMSK , OCIE2_L | TOIE2_L ); //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ } //================================================================================ // RESET ALL TIMERS PRESCALRES //================================================================================ void vResetAllTimersPrescalers(void){ //+-------------------------------------------------------------------------------------------+ //| SFIOR = TCCR1A = Special Function IO Register | //+-------------------------------------------------------------------------------------------+ //| | //| ACME = Analog Comparator Multiplexer Enable | //| PUD = Pull-up Disable | //| PSR2 = PreScaler Reset, prescaler for timer2 | //| PSR10 = PreScaler Reset, combined prescaler for timer0 and timer1 | //| | //+-------------------------------------------------------------------------------------------+ //| user comment | //+-------------------------------------------------------------------------------------------+ //| | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|signal name| - | - | - | - | ACME_X | PUD_X | PSR2_X | PSR10_X | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ SFRX ( SFIOR , PSR2_H | PSR10_H ); //+-------------------------------------------------------------------------------------------+ } //================================================================================ // INIT SWITCHES FOR USING WITH INTERRUPTS //================================================================================ void vInitSwitchesForUsingWithInterrupts(void){ //+-------------------------------------------------------------------------------------------+ //| MCUCR = Micro Computer Unit Control Register | //+-------------------------------------------------------------------------------------------+ //| | //| SE = Sleep Enable (make MCU go asleep | //| SM2:SM1:SM0 = sleep mode | //| | //| ISC11:ISC10 define on what external signal the interrupt will be generated (INT1=pin5) | //| 0 0 The low level of INT1 generates an interrupt request. | //| 0 1 Any logical change on INT1 generates an interrupt request. | //| 1 0 The falling edge of INT1 generates an interrupt request. | //| 1 1 The rising edge of INT1 generates an interrupt request. | //| | //| ISC01:ISC00 define on what external signal the interrupt will be generated (INT0=pin4) | //| 0 0 The low level of INT0 generates an interrupt request. | //| 0 1 Any logical change on INT0 generates an interrupt request. | //| 1 0 The falling edge of INT0 generates an interrupt request. | //| 1 1 The rising edge of INT0 generates an interrupt request. | //| | //+-------------------------------------------------------------------------------------------+ //| interrupt INT1 on low level on pin5 | //+-------------------------------------------------------------------------------------------+ //| | //+-------------------------------------------------------------------------------------------+ //| | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //| | - | - | - | - | - | Timer0 | Timer0 | Timer0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|signal name| SE_X | SM2_X | SM1_X | SM0_X | ISC11_X | ISC10_X | ISC01_X | ISC00_X | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ SFRX ( MCUCR , SE_L | SM2_L | SM1_L | SM0_L | ISC11_L | ISC10_L | ISC01_L | ISC00_L ); //+-------------------------------------------------------------------------------------------+ //define switch interrupt pin as input SFRX(DDRGD,SWI_IAC_I); //disconnect pullup from interrupt pin SFRX(PORTD,SWI_IAC_N); //define switch junction pin as input SFRX(DDRGC,SWI_JNC_I); //disconnect pullup from junction pin SFRX(PORTC,SWI_JNC_N); //wait 2 milliseconds to stabilize junction signal eventually going low and generating an unwanted interrupt vDelayXMilliSeconds(2); //clear any eventually generated external interrupt on pin5 SFRX(GIFR,INTF1_H); //enable external INT1 interrupt on pin5 SFRX(GICR,INT1_H); //} //================================================================================ // INIT AD-CONVERTER FOR READING SWITCHES //================================================================================ //void vInitAdConverterForReadingSwitches(void){ //+-------------------------------------------------------------------------------------------+ //| ADCSRA = ADC Control and Status Register A | //+-------------------------------------------------------------------------------------------+ //| | //| A complete ad-conversion takes 13 clock cycles (clock speed defined by prescaler) | //| | //| ADEN = enable ad-converter (switch ad-converter on, consumes extra current) | //| ADSC = start ad-conversion (set low by microcontroller if conversion has finished) | //| ADFR = select free-running mode (checking on ADSC or ADIF bit is useless) | //| ADIF = ad-converter interrupt flag (is set when conversion has finished, using interrupt) | //| ADIE = ad-converter interrupt enable (interrupt occurs when conversion has finished) | //| ADPSn = select ad-converter clock prescaler | //| | //+-------------------------------------------------------------------------------------------+ //| ADC Clock frequency should be between 50KHz and 200KHz (.pdf) | //| | //| Prescaler ADC clock freq. measured ADC duration (by oscilloscoop) | //| | //| 000 8 MHz/ 2 = 4000 KHz 7.8 us | //| 001 8 MHz/ 2 = 4000 KHz 7.8 us | //| 010 8 MHz/ 4 = 2000 KHz 10 us | //| 011 8 MHz/ 8 = 1000 KHz 16 us | //| 100 8 MHz/ 16 = 500 KHz 30 us | //| 101 8 MHz/ 32 = 250 KHz 55 us | //| 110 8 MHz/ 64 = 125 KHz 110 us <--- use these | //| 111 8 MHz/128 = 63 KHz 230 us | //| | //+-------------------------------------------------------------------------------------------+ //| enable ADC, nostart ADC, no free-running, clear int. flag, disable interrupt, prescaler 6 | //+-------------------------------------------------------------------------------------------+ //| | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|signal name| ADEN_X | ADSC_X | ADFR_X | ADIF_X | ADIE_X | ADPS2_X | ADPS1_X | ADPS0_X | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ SFRX ( ADCSRA , ADEN_H | ADSC_L | ADFR_L | ADIF_H | ADIE_L | ADPS2_H | ADPS1_H | ADPS0_L ); //+-------------------------------------------------------------------------------------------+ //+-------------------------------------------------------------------------------------------+ //| ADMUX = ADC Multiplexer Selection Register | //+-------------------------------------------------------------------------------------------+ //| | //| REFS1:REFS0 Voltage Reference Selection (= maximum measurement voltage value) | //| 0 0 AREF, Internal Vref turned off | //| 0 1 AVCC with external capacitor at AREF pin | //| 1 0 Reserved | //| 1 1 Internal 2.56V Voltage Reference with external capacitor at AREF pin | //| | //| ADLAR = left justify or right justify measured value into register ADCH/ADCL | //| 0 = right justify => ADCH:ADCL = ......98:76543210 | //| 1 = left justify => ADCH:ADCL = 98765432:10...... | //| | //| MUXnnnn = select measurement-point to be connected to the AD-converter measurement input | //| 0000 ADC0 | //| 0001 ADC1 | //| 0010 ADC2 | //| 0011 ADC3 | //| 0100 ADC4 | //| 0101 ADC5 | //| 0110 ADC6 | //| 0111 ADC7 | //| 1000-1101 Reserved | //| 1110 1.23V (VBG) | //| 1111 0V (GND) | //| | //+-------------------------------------------------------------------------------------------+ //| select AVCC with external cap., select switches ad-converter ADC4, right justify | //+-------------------------------------------------------------------------------------------+ //| | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|signal name| REFS1_X | REFS0_X | ADLAR_X |RESERVED | MUX3_X | MUX2_X | MUX1_X | MUX0_X | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ SFRX ( ADMUX , REFS1_L | REFS0_H | ADLAR_L |RESERVED | MUX3_L | MUX2_H | MUX1_L | MUX0_L ); //+-------------------------------------------------------------------------------------------+ } //================================================================================ // INIT USART RECEIVE 2400 8 N 1 USING RX INTERRUPT // disable global interrupt when initiating //================================================================================ void vInitUsartRx2400B8N1UsingRxInterrupt(void){ //+-------------------------------------------------------------------------------------------+ //| UCSRA = USART Control and Status Register A | //+-------------------------------------------------------------------------------------------+ //| | //| RXC = Receive Complete, set, as long as there is unread received data in rx-buffer (UDR)| //| TXC = Transmit Complete, set, if all data from transmit buffer (UDR) is send | //| cleared automatically if transmit-complete interrupt is executed | //| UDRE = Usart Data Register Empty, set, if transmit buffer (UDR) is empty (interr: TXCIE) | //| FE = Frame Error, if (next?) received character stopbit is zero | //| DOR = Data OverRun, set, when 2 characters in Receive Buffer, 1 character in Receive | //| Shift Register, and a new startbit detected. | //| PE = Parity Error, set, if (next?) received character has a parity error. (if enabled) | //| U2X = Double the USART transmission speed (do set to 0 in normal use) | //| MPCM = Multi-processor Communication Mode. (do set to 0 in normal use) | //| | //| ALWAYS SET BITS 'FE', 'DOR' and 'PE' TO ZERO WHEN WRITING TO UCSRA!!! (pdf p151 | //| | //+-------------------------------------------------------------------------------------------+ //| clear tx-complete flag, no double usart speed, no multi-processor mode | //+-------------------------------------------------------------------------------------------+ //| | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|read/write | R | R/W | R | R | R | R | R/W | R/W | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|signal name| RXC_X | TXC_X | UDRE_X | FE_X | DOR_X | PE_X | U2X_X | MPCM_X | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ SFRX ( UCSRA , TXC_H | FE_L | DOR_L | PE_L | U2X_L | MPCM_L ); //+-------------------------------------------------------------------------------------------+ //+-------------------------------------------------------------------------------------------+ //| UCSRB = USART Control and Status Register B | //+-------------------------------------------------------------------------------------------+ //| | //| RXCIE = Receive Complete, Interrupt Enable | //| TXCIE = Transmit Complete, Interrupt Enable | //| UDRIE = Usart Data Register Empty, Interrupt Enable (tx) | //| RXEN = Usart Receiver ENable | //| TXEN = Usart Transmitter ENable, (if disabled, first all unsend data will be send) | //| UCSZ2 = number of databits (combined with UCSZ1 and UCSZ0 in UCSRC) | //| UCSZ2:UCSZ1:UCSZ0 | //| 0 0 0 5-bit | //| 0 0 1 6-bit | //| 0 1 0 7-bit | //| 0 1 1 8-bit | //| 1 0 0 Reserved | //| 1 0 1 Reserved | //| 1 1 0 Reserved | //| 1 1 1 9-bit | //| RXB8 = Received data Bit 8 (if 9 databits used) | //| TXB8 = Transmit data Bit 8 (if 9 databits used) | //| | //+-------------------------------------------------------------------------------------------+ //| rx-int. dsable, tx-int. disable, register-empty int. disable, rx enable, tx disable, 8-bit| //+-------------------------------------------------------------------------------------------+ //| | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|read/write | R/W | R/w | R/w | R/w | R/w | R/w | R | R/W | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|signal name| RXCIE_X | TXCIE_X | UDRIE_X | RXEN_X | TXEN_X | UCSZ2_X | RXB8_X | TXB8_X | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ SFRX ( UCSRB , RXCIE_L | TXCIE_L | UDRIE_L | RXEN_H | TXEN_L | UCSZ2_L | TXB8_L ); //+-------------------------------------------------------------------------------------------+ //remember(!), - do not use 'SFRX' define with register UCSRC and UBRRH because this define reads register first //but reading UCSRC/UBRRH first time will return UBRRH and next time will return UCSRC! //if you want to read UCSRC, then read UCSRC/UBRRH twice without any instruction between first and second read operation! //+-------------------------------------------------------------------------------------------+ //| UCSRC = USART Control and Status Register C | //+-------------------------------------------------------------------------------------------+ //| | //| URSEL = Usart Register SELect: 0=read/write UBRRH, 1=read/write UCSRC (=current register!)| //| equals URSEL bit in UBRRH register | //| UMSEL = Usart Mode SELect: 0 = asynchronous, 1 = synchronous | //| UPM1:UPM0 = Usart Parity Mode1: | //| 0 0 Disabled | //| 0 1 Reserved | //| 1 0 Enabled, Even Parity | //| 1 1 Enabled, Odd Parity | //| USBS = Usart StopBit Select: 0 = 1 stopbit, 1 = 2 stopbits | //| UCSZ1:UCSZ0 = number of databits (combined with UCSZ2 in UCSRB) | //| UCSZ2:UCSZ1:UCSZ0 | //| 0 0 0 5-bit | //| 0 0 1 6-bit | //| 0 1 0 7-bit | //| 0 1 1 8-bit | //| 1 0 0 Reserved | //| 1 0 1 Reserved | //| 1 1 0 Reserved | //| 1 1 1 9-bit | //| UCPOL = Usart Clock POLarity: (only used in synchronous mode) | //| +---+----------------------------+-------------------------+ | //| | | Transmitted Data Changed | Received Data Sampled | | //| | | (Output ofTxD Pin) | (Input on RxD Pin) | | //| +---+----------------------------+-------------------------+ | //| | 0 | Rising XCK | Edge Falling XCK Edge | | //| | 1 | Falling XCK | Edge Rising XCK Edge | | //| +---+----------------------------+-------------------------+ | //| | //+-------------------------------------------------------------------------------------------+ //| async mode, no parity, 1 stopbit, 8 databits | //+-------------------------------------------------------------------------------------------+ //| | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|read/write | R/W | R/W | R/W | R/W | R/W | R/W | R/W | R/W | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|signal name| URSEL_H | UMSEL_X | UPM1_X | UPM0_X | USBS_X | UCSZ1_X | UCSZ0_X | UCPOL_X | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ SFRW ( UCSRC , URSEL_H | UMSEL_L | UPM1_L | UPM0_L | USBS_L | UCSZ1_H | UCSZ0_H | UCPOL_L ); //+-------------------------------------------------------------------------------------------+ //+-------------------------------------------------------------------------------------------+ //| UBRRH = Usart Baud Rate Register High | //+-------------------------------------------------------------------------------------------+ //| | //| URSEL = Usart Register SELect: 0=read/write UBRRH, 1=read/write UCSRC (=current register!)| //| equals URSEL bit in UCSRC register | //| | //| The Baudrate generator probably uses a 16x prescaler. | //| 8MHz clock / prescaler 16 = 2us per counter step, 2400 baud = 417us per bit, | //| To generate 417 bits per second the counter should count to 417us/2us = 208 | //| According the .pdf tabel 62, a setting of 207 will do. | //| Settings also calculated for other oscillator frequencies and they all match. | //| | //+-------------------------------------------------------------------------------------------+ //| 2400 baud | //+-------------------------------------------------------------------------------------------+ //| | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|read/write | R/W | R | R | R | R/W | R/W | R/W | R/W | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|signal name| URSEL_L |RESERVED |RESERVED |RESERVED |UBRR11_X |UBRR10_X |UBRR09_X |UBRR08_X | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ SFRX ( UBRRH , URSEL_L |UBRR11_L |UBRR10_L |UBRR09_L |UBRR08_L ); //+-------------------------------------------------------------------------------------------+ //+-------------------------------------------------------------------------------------------+ //| UBRRL = Usart Baud Rate Register Low | //+-------------------------------------------------------------------------------------------+ //| | //+-------------------------------------------------------------------------------------------+ //| 2400 baud | //+-------------------------------------------------------------------------------------------+ //| | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|bit number | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|read/write | R/W | R/W | R/W | R/W | R/W | R/W | R/W | R/W | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ //|signal name|UBRR07_X |UBRR06_X |UBRR05_X |UBRR04_X |UBRR03_X |UBRR02_X |UBRR01_X |UBRR00_X | //+-----------+---------+---------+---------+---------+---------+---------+---------+---------+ SFRW ( UBRRL , 0xCF ); //+-------------------------------------------------------------------------------------------+ }