Нашел хороший и рабочий код который использует ШИМ, подключил к пьезо-пищалке и заиграла музыка.
Схема подключения:
Скачать файлы Си и другие (исходники):
– скачать zip архив.
Полную теорию на английском языке здесь:
– скачать pdf на англ. языке
– скачать pdf переведённый на русский с помощью Яндекс переводчика.
В музыке, ноты имеют различную длительность, максимальная 32, есть 16-ые, 8-ые, 4-ые, половинные и целые. tempo для всех нот одинаковый поэтому ноты будут определённой длительности, независимо от tempo 16-ые будут продолжительностью в 2 раза меньше чем 8-ые. а вот tempo определяет сколько будет эта эталонная задержка. меняя tempo, меняем кол-во тактов в минуту BPM.
void InitMusic()
{
DDRB = 0xFF; //OCR1B как вывод
// настраиваем таймер
TCCR1A |= ( 1 << COM1B1); // выставлять 0 на OC1B когда таймер TCNT1 = OCR1B
TCCR1B |= ( 1 << WGM13)|( 1 << CS11);
//mode 8, CTC, Phase and Frequency Correct (TOP value is ICR1)
// Обнуляем таймер и выставляем 1 в OC1B когда TCNT1 = ICR1
//CS11 значит что предделитель таймера = 8 то есть он считаем с частотой 1 MHz
//(частота МК 8 МГц)
}
//Про то как настроить регистры для работы с AVR я писал тут Таймеры и тут ШИМ на AVR
void PlayMusic( const int* pMusicNotes, uint8_t tempo )
{
// pMusicNotes это указатель на таблицу содержащий музыкальные данные
// tempo Темп от 0 до 100 чем больше тем медленнее
int duration;
int note;
int i;
uint16_t delay = tempo * 1000;
while( *pMusicNotes ) // пока не дошли до MUSIC_END == 0
{
note = *pMusicNotes;
//Работаем с адресами, берём значение 1 ячейки массива записываем в note
pMusicNotes++;
//Т.к массив int ++ означает +4 (размер int 4 байта) и теперь у нас адрес
//нашего массива +4 как раз адрес следующей цифры
duration = *pMusicNotes;
pMusicNotes++;
if( note == PAUSE )
{
//Пауза, ничего не проигрывать
OCR1B = 0;
}
else
{
//не пауза воспроизвести звук
OCR1B = DEFAULT_VOLUME;
//OCR1B отвечает за ШИРИНУ импульса, когда TCNT1 (таймер) == OCR1B
//то на выводе OC1B выставляется 0
//выставляем необходимую нам частоту
ICR1H = (note >> 8);
// сначала пишем верхние биты (>> 8 это сдвиг на 8 битов)
// т.к AVR 8 битный нельзя записывать 16 битные числа за 1 такт
ICR1L = note;
}
//длительность ноты
for(i=0;i<32-duration; i++>//_delay_loop_2(); ждёт 4 такта МК в нашем случае 0.5 мкс
_delay_loop_2( tempo );
}
//turn off any sound
OCR1B = 0;
}



