Sound Program
Explanation
This code listing is a small program that will play Smoke on the Water on an Atmega168 with a 16MHz oscillator. It uses timer 0 and timer 1 to create delays and the square wave which is responsible of the sound.
The song tones are as follows:
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | Tone | |
| E | | | F | | | G | | | G | | | Bar 1 | |
| 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Tone | E = 329.6 Hz |
| E | | | F | | | G# | | | G | | | Bar 2 | F = 349.24 Hz |
| 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | Tone | G = 392.00 Hz |
| E | | | F | | | G | | | G | | | Bar 3 | G# = 415.32 Hz |
| 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | Tone | |
| F | | | E | | | E | | | E | | | Bar 4 |
Smoke on the Water tones and frequencies.





We need tck = 47 in order to create a square signal with a frequency of 329.6 Hz.
There is an error after rounding. The final tone frequency is 
#define SETUPNIB PORTB |= (1<<7) | (1<<6) | (1<<5) | (1<<4); #define RESETUPNIB PORTB |= (0<<7) | (0<<6) | (0<<5) | (0<<4); #define RESETLOWNIB PORTB |= (0<<3) | (0<<2) | (0<<1) | (0<<0); #define INVERTPORTD PORTD = ~PORTD; #include <avr/io.h> #include <avr/interrupt.h> #include <inttypes.h> #include <avr/pgmspace.h> uint8_t count; uint8_t tone; uint8_t timeout; int ticks; void delay_ms(void){ int i; for(i=880u; i != 0; i--); } void delay(uint8_t tms){ uint8_t i; for(i = tms; i != 0; i--){ delay_ms(); } } ISR(TIMER1_COMPA_vect){ static uint8_t tck = 0; cli(); //the following code works as a multiplexer if (tone == 0 | tone == 8 | tone == 16 | tone > 26){ // to choose Hz singal if(tck == 47){ tck = 0; // reset count to create a 277 Hz signal INVERTPORTD; // create a squeare signal } else{ tck++; // increment the count } } else if(tone == 2 | tone == 10 | tone == 18 | tone == 24){ // to choose Hz if(tck == 45){ tck = 0; INVERTPORTD; } else{ tck++; } } else if(tone == 4 | tone == 5| tone == 6 | tone == 14 | tone == 20 | tone == 22){ // Hz if(tck == 39){ tck = 0; INVERTPORTD; } else{ tck++; } } else if(tone == 12){ // Hz if(tck == 38){ tck = 0; INVERTPORTD; } else{ tck++; } } else if(tone % 2 != 0 && tone != 5){ //odd = silence PORTD = 0x00;//Silence } else{ //In case for error reset tone tone = 0; // make sure we have it within its limits tck = 0; // avoid overflow if error } sei(); } ISR(TIMER0_OVF_vect){ cli(); count--; if (ticks == 11){ ticks = 0; if (count == 0x00){ RESETLOWNIB; count = 0x0f; } else{ PORTB = (PORTB & 0xf0) | (count & 0x0f); } tone++; tone = tone % 32; // tone will go from 0 to 3 } else{ ticks++; } sei(); } void iniconf(void){ cli(); // Disable interrupts /* Program timer0 */ TCNT0 = 0x00; // Reset timer count TCCR0A |= 0x00; // Normal functioning, clk_io/1024 TCCR0B |= 0x05; TIMSK0 |= _BV(TOIE0); // Enable interrupts when overflow /* Program timer1 */ TCNT1H = 0x00; // Reset timer count TCNT1L = 0x00; OCR1AH = 0x01; // Set output compare value OCR1AL = 0xFF; TCCR1A |= 0x00; // Normal functioning, clk_io TCCR1B |= 0x09; TIMSK1 |= _BV(OCIE1A); // Enable interrupts when overflow sei(); // Enable interrupts /* Program the ports */ DDRB = 0xff; // PortB as output port DDRC = 0x01; // PortC0 for wave output DDRD = 0xff; } int main(void){ /* Initialize the system */ iniconf(); /* Initialize goblal variables */ count = 0; ticks = 0; tone = 0; while(1){ delay(50); PORTB = (PORTB & 0x0f) | 0xf0; //SETUPNIB; delay(50); PORTB = (PORTB & 0x0f); //RESETUPNIB; } }
page_revision: 13, last_edited: 1209614305|%e %b %Y, %H:%M %Z (%O ago)





