Порадовать глаз различными миганием светодиодов мы уже умеем, а почему бы нам еще и не порадовать слух. В данном уроке мы рассмотрим как сгенерировать звук при помощи таймера AVR, вывести ее на динамик, и в конце концов сделаем некоторое подобие midi плеера. Чтож за дело…
Итак для сборки понадобится Atmega8, стандартная обвязка (кварц на 8МГц, 2 конденсатора на 22пФ) и пьезоизлучатель без внутреннего генератора, например HC0903A.
Можно, конечно, взять какой нибудь динамик 8Ом, но к нему придется городить усилитель. Нам же для образовательных целей достаточно будет простейшей схемы, которая без обвязки будет выглядеть так:
Достаточно просто, поэтому сразу переходим к теории. Чтобы создать звук нам нужно заставить колебаться мембрану динамика с определенной частотой. Каждой ноте соответствует своя частота, например ноте До 1 октавы, соответствует частота 261Гц. Т.е. дрыгая ногой микроконтроллера, подключенной к динамику, со скоростью 261 раз в секунду мы будем слышать звучание этой ноты. Для тех кто не силен в музыкальной теории, звук ближе от 1кГц и выше будет более писклявый, ниже 300Гц будет басить.
Перейдем к реализации. Как заставить ногу дрыгаться с такой скоростью? В этом нам поможет таймер, работу которого мы изучили в предыдущих уроках. В данном случае, нам пригодится timer1. Принцип формирования частоты таков: таймер тикает, до тех пор пока его значение не совпадет OCR1A. В в момент совпадения OCR1A, с текущим значением таймера происходит прерывание (выполняется функция) в котором текущее состояние PORTB.3 инвертируется (включается/отключается), таким образом мы получаем «пульсирующий» сигнал(мендр). Регулируя OCR1A мы изменяем частоту. Все, никаких сложностей.
Код исполняемый в прерывании:
interrupt [TIM1_COMPA] void timer1_compa_isr(void)
{
PORTB.3=!PORTB.3;
}
Теперь, нужно соотнести каждой ноте частоты и по очереди их воспроизводить, т.е. создать массив со значениями, которые по очереди будем подставлять в OCR1A. Прошивка далеко не идеальна, но вполне работоспособна. Доступна тут.
На последок видео, подобрал первое что в голову пришло: марио и танчики)))
А есть ли возможность регулировать громкость непосредственно через МК?
Можно через ШИМ
Поправьте меня, если где-то туплю.
В atmega 8 есть два 8-битных таймера и один 16-битный. Один таймер может издавать только одну ноту (в смысле не может издавать две разные ноты одновременно). Значит ли это, что можно сделать с помощью atmega8 только 3-хдорожечную мелодию? Или есть какие-нибудь устройства, позволяющие сделать не монотонные мелодии?
Теоретически, можно настроить прерывание очень часто, а внутри прерывания дрыгать хоть всеми ножками, тем самым, количество дорожек зависит только от количества ножек мк. Другое дело, что темб будет намного сложнее сделать разным. Поэтому, проще вавки воспроизводить.
Есть задание — сделать на базе atmega8 часы с будильником.
Часы тактируются 16-битным T1, хочу запустить звук 440Гц 8-битным T2.
Вопросы:
1) Как правильно инициализировать T2.
TCCR2 = (1 << CS22) | (1 << CS21) | (1<<CS20);
OCR2 = 17;
TIMSK |= (1<<OCIE2);
Походу я где-то что-то сделал неправильно, но не знаю, как проверить, используя лишь Proteus
2) Каким динамиком в Proteus 7 можно проверить работоспособность окончательной прошивки?
Оба вопроса сняты — я, дурко, забыл порт динамика настроить на выход.
я хочу сгенерировать звук 440 Гц (Ля большой октавы, или частота телефонного гудка), но из расчета, что одновременно с ним будет идти какой-то другой звук)
Что я удумал?
Подключаю таймер T2:
TCCR2 = (0<<CS22) | (0<<CS21) | (1< каждую микросекунду
TIMSK |= (1<<OCIE2); //включаю таймер
unsigned int Counter0 = 0;
ISR (TIMER2_COMP_vect)
{
Counter0++; //счетчик микросекунд
if (Counter0==2272) //по прошествию 2.272 мс (1/440Гц ~ 2.272 мс)
{
PORTC ^= 1;
Counter0 = 0;
}
}
Но в Proteus все «дрыгания» ножкой слышны прекрасно -> по факту воспроизводится звук порядка 2-3 Гц.
Что я делаю не так, кроме того, что прогаю в AVR Studio?
Если в протеусе все слышно прекрасно, значит кварц/фьюзы/подключение
ASSR |= (1<<AS2);
TCCR2 = (1<<CS20) | (1<<WGM21); //без предделителя, со сбросом (у кварца частота 8МГц)
TCNT2 = 0x00;
OCR2 = 0; //каждый такт будет вызываться обработчик
TIMSK |= (1<<OCIE2);
Значит ли из этого кода, что обработчик будет вызываться каждые 1/8 мкс?
В обработчике каждые 74 вызова обработчика дергается ножка — 74/8 мкс, значит полный период — 74/8*2 = 18.5 мкс. То есть частота звука 1/18.5 ~ 54кГц, что как-то не вяжется с реальными данными, но реально выходит звук с частотой 440 Гц. Я в печали:D
сделайте OCR2 более реальным, кстати именно такие вещи лучше смотреть отладчиком авр студии
Изменения в худшую сторону
OCR2 = 32, предделитель тоже 32, но теперь, когда теоретически должен выходить звук в 54 кГц, выходит звук в <1Гц
По вашему: 8 000 000/32 = 250кГц это частота таймера. чтобы получить 54кГц мы должны 250/54 = 4 это то что мы должны записать в OCR, откуда у вас 32 😯
По нормальному без предделителей 8 000 000/54 000 = 148-1 пихаем в OCR и получаем 54 054 Гц на выходе
вот именно, что на выходе получается звук с частотой в тысячи раз меньше
54кГц — звук, который вообще слышим быть не может (человеческое ухо воспринимает до 20кГц звуки), но если с предделителем 32 и OCR2=4, то получается не просто слышимый звук, а к тому же довольно низкий звук с частотой меньше одного кГц.
Нужно смотреть исходник
#include
#include
ISR (TIMER2_COMP_vect)
{
PORTC ^= 1;
}
int main(void)
{
DDRC = 0xFF;
PORTC = 0x00;
ASSR |= (1<<AS2); //Подключен кварц 8МГц. Сам МК тоже 8МГц
TCCR2 = (1<<CS21) | (1<<CS20) | (1<<WGM21); //Предделитель 32
TCNT2 = 0x00;
TIMSK |= (1<<OCIE2);
OCR2 = 4;
sei();
while (1) {};
}
Проблема разрешилась. В основе лежали две причины:
1) Как ни странно, но замена динамика в Proteus реально подействовала.
2) Я просто внеэпичный «гений» устного счета.
Спасибо за помощь и терпение.
Здравствуйте! Начал изучать МК. Ваши уроки с Атмеги 8 портирую на тиньку 2313 симулирую в протеусе. Но вот что то с генерацией звука проблемы. Полная тишина. Я грешу что не правильно таймер настроил?! В атмеге и в тиньке маски прерываний отличаются, я это учел но все равно не играет мелодия. Пмогите я уже столько инфы перелопатил)))
// Timer/Counter 1 initialization
TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (1<<WGM12) | (0<<CS12) | (0<<CS11) | (1<<CS10);
TCNT1H=0x00;
TCNT1L=0x00;
ICR1H=0x00;
ICR1L=0x00;
OCR1AH=0x00;
OCR1AL=0xFB;
OCR1BH=0x00;
OCR1BL=0x00;
// Timer(s)/Counter(s) Interrupt(s) initialization
TIMSK=(0<<TOIE1) | (0<<OCIE1A) | (0<<OCIE1B) | (1<<ICIE1) | (0<<OCIE0B) | (0<<TOIE0) | (0<<OCIE0A);
Пересоздайте полностью проект Codewizard
Тогда вопрос другой: в настройке таймера T1, В code wizard я выбираю частоту 800кГц, режим СТС, разрешаю прерывание по захвату с Т1, А Вот дальше поля для ввода цифр — Comp.A и другие. Что туда вводить? 251? Или 0xFB? Маска прерываний настраивается тоже здесь? Или в другом разделе?
Compa в визарде принимает шестнадцатеричные значения. Остальное автоматом настраивается само
как записать мелодию на микроконтроллер
посмотрите 7.2 http://avr-start.ru/?p=730
объясните каким образом выбирается частота кварца? и емкость конденсаторов?
читаем тут http://avr-start.ru/?p=1065
А почему в прерывании по таймеру не сбрасывается TCNT1=0;?
Будет ли работать на внутреннем тактовом генераторе?
Я пробую делать так: например, нота До 1 октавы = 261Гц. У меня частота работы МК 2МГц, таймер1 работает на 250 кГц, прерываю его каждые OCR1A = 250000/261 и в прерывании пишу PORTB.3 = !PORTB.3; TCNT1=0;
Вроде получается
дополню немного…
Звук более стабильный и гладкий на частоте таймера 2000 кГц, то есть при частоте работы МК в 2МГц, предделитель выставляю = 0x01 (в CVavr при создании проекта соответственно выбираю 2000 кГц). Думаю на более высоких частотах таймера, звук будет еще чище (если такое определение вообще применимо к мелкому динамику 🙂 ), но тогда уже точно придется пользоваться внешним тактовым генератором, тк внутренний в атмеге больше 2МГц выдавать не может.
внутренний генератор атмега8 может спокойно работать на частоте 8МГц. Чем выше частота, тем естественно точнее будут промежутки, это естественно, главное чтобы разрешения таймера хватило, чтобы отсчитать нужные промежутки.
Точно, не увидел сразу, что может и на 4 и на 8 МГц еще. Спасибо
хтось може викласти исходний код написаний в Atmel Studio 6.0
как сделать двухтональную сирену полицейскую дайте напутствие.заранее говорю спасибо
код не прошу вылажывать .Сам буду вынашивать его
когда то уже было http://avr-start.ru/?p=4142 но вообще наверно проще сделать несколько wav файлов и воспроизводить их с карты
Правильно ли я понял:
чтобы получить сигнал 10 кГц — берем предделитель 8 при частоте 8 Мгц, таймер за секунду тикнет 1000 000 раз, значит, нужно посчитать до 50, чтобы порт 20 000 раз инвертировался?
да вроде все так
Я настроил «дрыгание» ногой таймера 1 на atmega8 аппаратно на частоту 5 гц, но вместо этого какие бы я значения не выставлял для сравнения, частота остаётся равной 1 гц.
#include
#define F_CPU 8000000UL
#include
void preset(void)
{
DDRB |= (1<<PB1);
TCCR1A |= (1<<WGM12)|(1<<COM1A0);
TCCR1B |= (1<<CS10)|(1<<CS11);
OCR1A = 12500;
}
int main(void)
{
preset();
while (1)
{
}
}
у вас ошибка в битах
Спасибо, перепутал регистры, глупая ошибка.
Зуммер подключается без обвязки?
Какой ток кушает зуммер?
в то время подключал напрямую, но вообще лучше через транзистор