At first I tried to write code myself, but I failed many times.
So i searched for a working project and found it, AVR is using PWM and simple Piezo Buzzer.
Sources on Github
void InitMusic()
{
DDRB = 0xFF; //OCR1B как вывод
// configure timer
TCCR1A |= ( 1 << COM1B1); // set 0 on OC1B when TCNT1 == OCR1B
TCCR1B |= ( 1 << WGM13)|( 1 << CS11);
//mode 8, CTC, Phase and Frequency Correct (TOP value is ICR1)
// clear timer and set 1 in OC1B when TCNT1 == ICR1
//CS11 means that prescaler is 8 so timer counts at 1 MHz
//(MC frequency is 8 MHz)
}
I wrote about Timers and PWM on AVR.void PlayMusic( const int* pMusicNotes, uint8_t tempo )
{
// pMusicNotes is a pointer on a table which keeps musical data
// tempo from 0 till 100 more == slower
int duration;
int note;
int i;
uint16_t delay = tempo * 1000;
while( *pMusicNotes ) // until MUSIC_END == 0
{
note = *pMusicNotes;
//We are working with adresses, we take 1 array value and write in note
pMusicNotes++;
//Array consist of integrers, so ++ means +4 (int size is 4 bytes) and now we get adress of
//our cell +4 wich is the adress of the next cell
duration = *pMusicNotes;
pMusicNotes++;
if( note == PAUSE )
{
//pause, do not play anything
OCR1B = 0;
}
else
{
//not a pause play sound
OCR1B = DEFAULT_VOLUME;
//OCR1B determines impulse width, when TCNT1 == OCR1B
//OC1B pin changes to 0
//we set desired note frequency
ICR1H = (note >> 8);
// at first we write high 8 bits of our 16 bits register (>> 8 means that we shift our bits by 8 to the right)
ICR1L = note;
}
//note duration
for(i=0;i<32-duration data-blogger-escaped-i="">//_delay_loop_2(); wait 4 ticks of MC, in our case 0.5 μs
_delay_loop_2( tempo );
}
//turn off any sound
OCR1B = 0;
}
Notes have different durations, maximum is 32, there are also 16, 8, 4, half and whole. (4-th note duration is 4 times less than whole).
Tempo is the same for all notes, it determines how much Bits Per Minute (BPM) we will have.
No comments :
Post a Comment