/* Play monophonic RTTTL ring tones with the Orangutan, short version using PICAXE data arrays. This program uses Timer1 in "Clear Timer/Counter on Compare Match" mode to generate the buzzer frequency. The counter is incremented at 8 MHz and resets when count = OCR1A. Upon reset, toggle buzzer output line. Timer0 is used as a note duration timer, generating interrupts every 8.192 milliseconds The CPU clock frequency assumed to be 8 MHz. If different, TCCR0 and 1 dividers must be changed appropriately The data array for tunes can be generated from RTTTL monophonic ring tones by the "PICAXE Tune Wizard", included as part of the free PICAXE Editor, available from http://www.rev-ed.co.uk/picaxe/ For a complete description, including non-standard note names and octave definitions, see the PICAXE manual, part 2: picaxe_manual2.pdf, "tune command" sjames_remington at yahoo dot com */ #define F_CPU 8000000UL #include #include #include #include #include /* global variables for ring tone player */ volatile unsigned int note_duration; //note duration in 8.192 millisecond units, decremented by TIMER0 void init_tunes(void); void play_note(unsigned char note, unsigned char octave, unsigned int duration); int main(void) { // tune_array defined by the PICAXE ringtone wizard, with the first byte = tempo (1-15). See picaxe manual /* // Deep Space 9 char tune_array[]={6,0x40,0x45,0x49,0xC7,0x0A,0x49,0x4A,0xD0,0x6C,0x40,0x45,0x49,0xC7,0x0A,0x49,0x45,0x40, 0x2A,0xC5,0x2C,0x40,0x45,0x49,0xC7,0x0A,0x49,0x4A,0xD0,0x05,0x15,0x54,0x50,0x05,0xC7,0xEA,0xC0,0x45,0x85,0}; */ // Godfather char tune_array[]={10,0x67,0x40,0x43,0x42,0x40,0x43,0x40,0x42,0x40,0x68,0x6A,0xE7,0x67,0x40,0x43,0x42,0x40, 0x43,0x40,0x42,0x40,0x67,0x66,0xE5,0x65,0x68,0x6B,0xC2,0x65,0x68,0x6B,0xC0,0x60,0x63,0x6A,0x68,0x67,0x6A, 0x68,0x68,0x67,0x67,0x6B,0xC0,0}; /* Beethoven's fifth (49 bytes, contains embedded 0 so strlen() won't work to detect length) char tune_array[]={7,0x67,0x67,0x67,0x63,0x68,0x68,0x68,0x67,0x43,0x43,0x43,0x00,0x67,0x67,0x67,0x62,0x68, 0x68,0x68,0x67,0x45,0x45,0x45,0x02,0x47,0x47,0x45,0x43,0x63,0x63,0x65,0x67,0x47,0x47,0x45,0x43,0x63,0x63, 0x65,0x67,0x47,0x47,0x45,0x43,0x2C,0x40,0x2C,0xC7}; */ unsigned int duration=0; unsigned char tempo,note,octave,j; int i; init_tunes(); tempo = tune_array[0]; // set tempo as per picaxe manual 2 sei(); for (i=1; i>6; //get bits 7-6 of tune_array entry switch (j) { case 0: { duration = 8; break; } // 65 milliseconds for 1/4 note beat case 1: { duration = 4; break; } // 1/8 note case 2: { duration = 32; break; } // whole note case 3: { duration = 16;} // half note } duration = tempo*duration; //modified by tempo as per picaxe // determine note octave j= (note>>4)&3; //bits 5-4 of tune_array entry switch (j) { case 0: {octave=6; break;} //middle octave case 1: {octave=7; break;} //high octave case 2: {octave=5; break;} //low octave default: {octave=5;} //not used } // determine note and play it note = (note & 0x0F); //bits 3-0 play_note(note, octave, duration); } //end for i return 0; //exit } /* Define timer constants for the low octave of notes x=sharp (#) This table is defined according to the International Equal-Tempered Scale, with A4 = 440.00 Hz frequency standard The formula for the timer constant = 8E6/(2*frequency in Hz) The PICAXE designers use nonstandard octaves and note names. This set corresponds to "octave 5" */ #define c3 15267 #define cx3 14440 #define d3 13605 #define dx3 12862 #define e3 12121 #define f3 11461 #define fx3 10811 #define g3 10204 #define gx3 9639 #define a4 9091 #define ax4 8584 #define b4 8097 // Subroutine to play a note for "duration" milliseconds (in units of 8 ms) // note = 0-11 for C,C#,D,D#,E,F#,G,G#,A,A#,B // note > 11 = silence for "duration" milliseconds // octave = 5,6,7 defined according to the "PICAXE scale" void play_note(unsigned char note, unsigned char octave, unsigned int duration) { static unsigned int timer1_constant[]={c3,cx3,d3,dx3,e3,f3,fx3,g3,gx3,a4,ax4,b4,0,0,0,0}; static unsigned int timer1_count; // set note duration (global), units are 8.192 ms note_duration = duration; timer1_count=timer1_constant[(note&0xF)]; if (timer1_count==0) {DDRB &= ~(1); timer1_count=0xFFFF;} //silence else { // handle octave switch (octave) { case 5 : { break;} //octave 5, do nothing case 6 : { timer1_count >>= 1; break;} //divide by 2 case 7 : { timer1_count >>= 2; break;} //divide by 4 default : { }; } DDRB |= 1; //set data direction reg bit 0 to output; } //end if // set note frequency OCR1A = timer1_count; // Wait until note has finished playing while(note_duration) { }; // note is playing DDRB &= ~(1); // turn off buzzer note_duration = (duration>>3); // pause 1/8 of total note duration while (note_duration) { }; // and wait } /* TIMER 1 OCR1A interrupt service routine This routine is called when TIMER1 count (TCNT1) = OCR1A, which is set on the fly for each note. Operation: toggle the buzzer line, producing frequency = 1/(2*timer period) */ ISR(TIMER1_COMPA_vect) { PORTB ^= 1; //toggle buzzer output line, if sound flag is on } /* TIMER 0 overflow interrupt service routine This routine is called every 8.192 milliseconds Operation: decrement global note timer */ ISR(TIMER0_OVF_vect) { if (note_duration) note_duration--; } /* Set up buzzer to play tones. Timer/Counter 1 is used in CTC mode, clear timer on compare/match */ void init_tunes(void) { DDRB |= 1; //set data direction reg bit 0 to output PORTB &=~(1); //set buzzer output low note_duration=0; //initialize globals //initialize timer 0 TCCR0A = 0; TCCR0B = _BV(CS02); //normal mode with CPU clock/256 = 122 Hz TCNT0=0; //clear counter TIMSK0 = (1<