Atmega8 мелодии. Генериране на звук чрез AVR

10.09.2021

Написах софтуерен модул, който ви позволява да добавите функцията за възпроизвеждане на мелодии или поредици от звуци към почти всеки проект на AVR микроконтролера.

Характеристики на модула:

Лесна интеграция с готов проект

Използва се само 8-битовият таймер t2, като остава възможно да се използва за запитване или формиране на времеви интервали

Модулът е регулируем на почти всяка честота на тактовия генератор

Височината на нотите се определя като символни константи (C0, A2 и т.н.) или в херцове

Продължителностите са посочени в стандартна форма (четвърти, осмини и т.н.) или в милисекунди

Има възможност за задаване на темпото на възпроизвеждане на мелодията и броя на нейните повторения

По време на възпроизвеждане мелодията може да бъде поставена на пауза


Свързване на звуков модул

1. Копирайте всички модулни файлове (tone.h, sound.h, sound.c) в папката на проекта.

2. Свържете файла sound.c към проекта.

За IAR `a – щракнете с десния бутон върху прозореца на работното пространство и изберете Добавяне > Добавяне на файлове…

За WINAVR е приблизително същото, само sound.c трябва да се добави към make-файла:

SRC = $(TARGET).c звук.c

3. Включете заглавния файл sound.h в съответния модул. Например в main.c

#include "sound.h"

4. Задайте настройките на модула във файла sound.h

//ако коментирате, продължителността на бележките ще бъде

//изчислено от BPM, посочен в мелодията

//ако остане, тогава от стойността, посочена по-долу

//#define SOUND_BPM 24

//тактова честота μ

#define SOUND_F_CPU 16U

//изход на микроконтролера, на който ще се генерира звука

#define PORT_SOUND PORTB

#define PINX_SOUND 0

//брой зададени мелодии.

#define SOUND_AMOUNT_MELODY 4

5. Добавете вашите мелодии към sound.c и напишете имената на мелодиите в масива с мелодии.

Добавяне на мелодии

Мелодията представлява масив от 16-битови числа и има следната структура

BPM (четвърт ноти в минута)е константа, използвана за изчисляване на продължителността на нотите и определя скоростта, с която се възпроизвежда мелодията.

BPM може да варира от 1 до 24, което съответства съответно на 10 и 240 четвърт ноти в минута.

Ако продължителността на нотите/звуците е посочена в милисекунди, тогава BPM, записан в масива, трябва да бъде равен на 1.

Ако константата SOUND_BPM е коментирана в заглавния файл sound.h, тогава продължителността на нотите се изчислява по време на изпълнение на програмата според BPM, посочен в масива. Ако SOUND_BPM не е коментиран, продължителността на нотите се изчислява на етапа на компилация въз основа на стойността на тази константа и всички мелодии ще се изпълняват в същото темпо. Това ограничава функционалността, но спестява няколко байта код.

Брой повторения.Може да приема стойности 1 ... 254 и LOOP (255). LOOP - означава, че мелодията ще се повтаря безкрайно, докато не бъде дадена команда SOUND_STOP или SOUND_PAUSE.

Продължителност на бележката– времето, през което се генерира даден звуков тон или се поддържа пауза. Може да се посочи в ms, като се използва макросът ms(x) или като стандартни нотни стойности - осми ноти, шестнадесети ноти и т.н. По-долу е даден списък на поддържаните продължителности. Ако има нужда от някакви екзотични продължителности, винаги можете да ги добавите във файла tone.h

n1 - цяла нота

n2 - половин нота

n4 - четвърт

n8 - осмо

n3 - осма тройка

n16 - шестнадесети

n6 - секстола

n32 - тридесет и втори

Височина на нотитесе определя с помощта на символни константи, описани във файла tone.h, например C2, A1 и т.н. Също така, височината на нотите може да бъде зададена в херцове с помощта на макроса f(x).

Програмата има ограничения за минималната и максималната честота на звука!

Маркер за край на мелодия.Стойността на последния елемент от масива трябва да е нула.

Използване на звуковия модул

В началото на main трябва да извикате функцията SOUND_Init(). Тази функция настройва изходния щифт на микроконтролера, конфигурира таймера T2 и инициализира променливите на модула.

След това трябва да зададете флага за разрешаване на прекъсване - __enable_interrupt(), тъй като модулът използва T2 препълване на таймера и прекъсвания при съвпадение.

След това можете да започнете да възпроизвеждате мелодии.

Например така:

SOUND_SetSong(2);

SOUND_Com(SOUND_PLAY); //свири мелодия

//задайте показалеца на 2-ра мелодия

//и стартирайте възпроизвеждането

SOUND_PlaySong(2);

Възпроизвеждането на мелодията може да бъде спряно по всяко време чрез подаване на команда SOUND_STOP.
Можете също така да поставите мелодията на пауза с помощта на командата SOUND_PAUSE. Последващото издаване на командата SOUND_PLAY възобновява възпроизвеждането на мелодията от мястото, където е било спряно.

По принцип тази функционалност не е особено необходима (просто си я измислих) и при работа с модула е достатъчна функцията SOUND_PlaySong(unsigned char numSong);

файлове

Можете да изтеглите примери за използване на звуковия модул от връзките по-долу. Не съм начертал диаграма, защото там всичко е просто. свързан към щифт PB0, бутонът за стартиране на мелодиите е свързан към щифт PD3. В проектите са дефинирани 4 мелодии. При натискане на бутона всеки път се стартира нова мелодия. Използва се микроконтролер atmega8535. Първоначално исках да се занимавам с проект с четири бутона - PLAY, STOP, PAUSE и NEXT, но после реших, че е излишно.

PS: Модулът не е преминал задълбочени тестове и се предоставя „както е“. Ако има някакви рационални предложения, нека го финализираме.

В тази статия ще разгледаме как да свирим тонове и ще научим как да свирим монофонична мелодия.

Подготовка за работа

Програмата декларира два масива. Масив с ноти бележкисъдържа прост списък с бележки. Тези ноти се съпоставят с продължителността на звука в масива удари. Продължителността в музиката се определя от делителя на една нота спрямо цялата нота. Стойността, взета като цяло, е 255 . Половинките, четвъртините, осмините се получават чрез разделяне на това число.
Моля, обърнете внимание, че продължителността на първата нота не се получава чрез разделяне на 255 на степен две. Тук ще трябва да преминете към музикална теория. Могат да се видят нотите на оригиналната мелодия. Тези ноти са комбинирани в триоли. Когато се комбинират по този начин, три осми ноти звучат по същия начин като една четвърт. Следователно тяхната относителна продължителност е 21.
Потребителят също трябва изрично да посочи броя на бележките в последователността с директивата:

# дефинирайте SEQU_SIZE 19

В основната програма първо се преизчисляват честотните масиви и продължителността на периодите на сигналите и продължителността на нотите.
С периоди на сигнала (масив сигнал_период) всичко е просто. За да получите продължителността на периода в микросекунди, просто разделете 1 000 000 на честотата на сигнала.
За да се изчисли абсолютната продължителност на звука на нотите, е необходимо да се посочи темпото на музикалното произведение. Това става с директива

# дефинирайте TEMPO 108

Темпото в музиката е броят четвърти ноти в минута. На линия

# дефинирайте WHOLE_NOTE_DUR 240000 / TEMPO

Изчислява се продължителността на цяла нота в милисекунди. Сега е достатъчно да преизчислите относителните стойности от масива, като използвате формулата ударикъм абсолютен масив note_duration.
В главния цикъл, променливата изминало_времесе увеличава след всеки период от възпроизвеждания сигнал с продължителността на този период, докато надвиши продължителността на нотата. Струва си да обърнете внимание на този запис:

докато (изминало_време< 1000 * ((uint32_t) note_duration[ i] ) )

Променлива изминало_време 32-битови и масивни елементи notes_duration 16-битов. Ако 16-битово число се умножи по 1000, тогава препълването е гарантирано и променливата изминало_времеще бъде сравнен с боклук. Модификатор (uint32_t)преобразува елемент от масив notes_duration[i]в 32-битово число няма препълване.
Можете да видите друга функция в аудио цикъла. Няма да е възможно да използвате функцията _delay_us(), тъй като неговият аргумент не може да бъде променлива.
За да създадете такива забавяния, използвайте функцията VarDelay_us(). В него цикъл със закъснение от 1 μs се превърта определен брой пъти.

void VarDelay_us(uint32_t takt) ( while (takt- - ) ( _delay_us(1) ; ) )

При възпроизвеждане на мелодия се използват още две забавяния. Ако нотите се свирят без паузи, те ще се слеят в една. За да направите това, между тях се вмъква забавяне от 1ms, определено от директивата:

# дефинирайте NOTES_PAUSE 1

След всеки пълен цикъл на възпроизвеждане на мелодията, програмата прави пауза за 1s и възпроизвежда отново.
В резултат на това получихме код, в който е лесно да промените темпото, да коригирате продължителността или напълно да пренапишете мелодията. За да направите това, ще бъде достатъчно да трансформирате само частта от програмата с директиви и декларации на променливи.

Индивидуални задачи

  1. В предложената мелодия опитайте да промените темпото и правете пауза от 5 секунди между повторенията.
  2. Елементи на масива удариприемайте само стойности от 0 до 255. Променете битовата ширина на елементите на масива и погледнете в изхода на компилатора, за да видите как това се отразява на количеството памет, заета от програмата.
  3. Сега опитайте сами да промените мелодията. Например, ето „Imperial March“ от същия филм: int notes = ( A4, R, A4, R, A4, R, F4, R, C5, R, A4, R, F4, R, C5, R, A4, R, E5, R, E5, R, E5, R, F5, R, C5, R, G5, R, F5, R, C5, R, A4, R);

    Модулът работи с SD карти, форматирани във FAT16 с капацитет не повече от 2 GB и възпроизвежда звукови фрагменти във формати .ad4 или .wav във всяка последователност. Вътрешните вериги на модула се захранват от вграден 3,3 V стабилизатор, което е много удобно, тъй като позволява на самия модул да се захранва с напрежение 5 V. (За да направите това, трябва да затворите “5V ” подложка със средната подложка на платката на модула, като първо отворите джъмпера за запояване с подложка "3.3V", както е показано на фигура 2).

    Модулът може да се управлява ръчно или чрез микроконтролер. В „ръчен“ режим е достатъчно да свържете бутоните към устройството съгласно схемата, представена на фигура 3. В техническото описание на модула WTV020 можете да намерите други опции за свързване, които по функционалност не се различават много от предложена диаграма.

    Високоговорителят се свързва към PWM изходите или към вградения 16-bit DAC. В последния случай трябва да свържете външен операционен усилвател и усилвател (Фигура 4). При свързване към PWM канал е възможно да се свържат високоговорители със съпротивление от 8 ома и мощност до 0,5 W.

    Разпределението на изводите на модула WTV020 е показано в таблица 1. Каналите на двупроводния комуникационен интерфейс могат да се използват както за свързване на бутони, така и за външен микроконтролер.

    Таблица1.

    Номер
    изход

    Цел

    Аудио изход от DAC

    Не се използва

    ШИМ изход

    ШИМ изход

    Не се използва

    Сила на звука "+" / CLK

    Възпроизвеждане - пауза

    Том "-" / DI

    Не се използва

    Следващ файл

    Не се използва

    За визуална проверка използвахме LCD дисплей 2x16 и съответстващ контролер. Обща схемаПлейърът е показан на фигура 5. Микроконтролерът и модулът се захранват от напрежение 3,3 V, дисплеят - 4 V, тъй като 3,3 V не беше достатъчно за избрания LCD. Тази разлика в напрежението не влияе по никакъв начин на приемането на данни от MK. Авторът реши да не активира вътрешния стабилизатор на модула WTV020.

    Линиите CLK и DI се използват за предаване на данни към модула WTV020. Според техническо описание(Фигура 6а), 16 бита данни трябва да се предават с честота 200 μs, но на практика тази стойност трябва да се увеличи до 2 ms (Фигура 6b).

    Въз основа на документацията, след подаване на захранване се препоръчва да се приложи отрицателен импулс с продължителност 5 ms към изхода „Reset“ на модула и да се изпращат команди след 300 ms. Но това е очевидна грешка, тъй като времето за инициализация на модула WTV020 е около 600 ms. Ако изпратите команди по-рано от 600 ms след нулирането, модулът просто не ги приема.

    Списъкът с основните команди, приети от модула, е представен в таблица 2. Таблицата показва, че максималният брой възпроизвеждани аудио файлове е 512, но авторът се е ограничил до тридесет. Силата на звука се регулира в 7 диапазона. На практика се наблюдава изкривяване на звука от адреси FFF0 до FFF3, както от ШИМ изхода, така и от ЦАП. Командите FFFE (Възпроизвеждане/Пауза) и FFFF (Стоп/Възпроизвеждане) са задействащи.

    включено LCD екранНомерът на възпроизвеждания файл и силата на звука се показват под формата на скала от 7 запълнени правоъгълника. снимка готово устройствопоказано на фигура 8.

    Демо видео:

    MK софтуер, виртуален модел Proteus и аудио файл във формат .ad4 -

    Програма за конвертиране на аудио записи във формат .ad4 -

    Продължението на урока отне много време, което е разбираемо, трябваше да овладея работата с карти с памет и файловата система FAT. Но все пак се случи, урокът е готов - всъщност новогодишно чудо.

    За да не претоварвам статията с информация, няма да описвам структурата на wav файловия формат, има повече от достатъчно информация в търсачките. Достатъчно е да се каже, че ако отворите файл с някакъв вид шестнадесетичен редактор, тогава първите 44 байта съдържат цялата информация за типа на файла, честотата на дискретизация, броя на каналите и т.н. Ако трябва да анализирате файла, прочетете това заглавка и ще бъдете щастливи.

    Данните за полезния товар започват от 44 байта, като по същество съдържат нивата на напрежение, които изграждат звука. Вече говорихме за нивата на напрежение в последната част на урока. По този начин всичко е просто, трябва да изведете тези стъпки към високоговорителя при честотата на семплиране на файла.

    Как физически да накарате високоговорителя да се разклати? Трябва да изведете тези нива на напрежение с помощта на ШИМ или да използвате R2R. Във всеки случай, той е много лесен за използване, прочетете номера, поставете го в OCR или PORTx. След това, след определено време, заместих следващата стойност и така до края на файла.

    Например, определен wav файл, данните идват от байт 44=0x2C, там е записано числото 0x80, ние възпроизвеждаме звука, например, чрез ШИМ на първия таймер, напишете OCR1A=0x80; Да приемем, че честотата на вземане на проби е 8 kHz, така че прекъсването трябва да бъде настроено на същата честота. В прекъсването заменете следващата стойност 0x85 след 1/8000 = 125 µs.

    Как да настроя прекъсване на 8kHz? Нека си припомним, че ако таймерът работи на честота 250 kHz, тогава регистърът за сравнение на прекъсванията трябва да бъде заменен (250/8)-1=31-1 или 0x1E. С PWM всичко също е просто; колкото по-висока е честотата, на която работи, толкова по-добре.

    За да работи фърмуерът, ще се съгласим, че флаш устройството е форматирано във FAT32, като се използва PetitFat lib от урок 23.2. Файлът е във формат wav, 8kHz или 22.050kHz, моно. Име на файла 1.wav. Нека анализираме фърмуера.

    #включи #include "diskio.h" #include "pff.h" unsigned char buffer[ 512 ] ; /* буфер, в който се копира информация от флашката */ volatile unsigned int count; //брояч на копирани даннипрекъсване [TIM2_COMP] void timer2_comp_isr(void) // прекъсване, в което се заместват стойности( OCR1A = буфер [брой] ; // извежда звук към високоговорителяако (++ брой >= 512) //увеличете броячаброй = 0; //ако 512 е нулиран) void main(void) ( unsigned int br; /* брояч за четене/запис на файлове */ unsigned char buf = 0; //променлива, определяща коя част от буфера се чете FATFS fs; /* Работно пространство (обект на файлова система) за логически устройства */ PORTB= 0x00; DDRB= 0x02; //скок shim ocr1a// Инициализация на таймер/брояч 1 // Източник на часовника: Системен часовник // Стойност на часовника: 8000 000 kHz // Режим: Бърза ШИМ топ=0x00FF // OC1A изход: Неинв. TCCR1A= 0x81; TCCR1B= 0x09; TCNT1= 0x00; OCR1A= 0x00;// Инициализация на таймер/брояч 2 // Източник на часовника: Системен часовник // Стойност на часовника: 250 000 kHz // Режим: CTC top=OCR2 TCCR2= 0x0B ; TCNT2= 0x00; //OCR2=0x1E; //настройване на регистъра за сравнение за 8kHz OCR2= 0xA ; //за 22kHz #asm("sei") // Инициализация на прекъсване на таймер(а)/брояч(а).ако (disk_initialize() == 0) //инициализиране на флаш устройството( pf_mount(&fs) ); //монтиранефайлова система pf_open("1.wav");//отваряне на тема pf_lseek(44) ;//преместете показалеца на 44< 256 ) pf_read(буфер, 512,& br);//за първи път поглъщаме 512 байта наведнъж< 256 ) { pf_read(& buffer[ 256 ] , 256 ,& br) ; TIMSK= 0x80;//включете музиката докато (1) ( if (! buf && count> 255 )< 256 ) break ; } } TIMSK = 0x00 ; //глушим все pf_mount(0x00 ) ; //ако се възпроизвеждат повече от 255 байта,( pf_read(& буфер[0], 256,& br) );

    //след това четем информацията от флашката в първата половина на буфера #include "diskio.h" #include "pff.h" unsigned char буфер; /* буфер, в който се копира информация от флашката */ volatile unsigned int count; //брояч на прекъсване на копирани данни void timer2_comp_isr(void) //прекъсване, в което се заместват стойности ( OCR1A = буфер; //извеждане на звук към високоговорителя ако (++брой >= 512) //увеличете броя на брояча = 0; //ако 512 нулиране ) void main(void) ( unsigned int br; /* брояч за четене/запис на файл */ unsigned char buf = 0; //променлива, определяща коя част от буфера се чете FATFS fs; /* Работеща област (обект на файловата система) за логически устройства */ DDRB=0x02; Fast PWM top=0x00FF // OC1A изход: Non-Inv. TCNT1=0x00; OCR2 TCCR2=0x00; //OCR2=0x1E; //задаване на регистъра за сравнение за 8kHz OCR2=0xA;//за 22kHz("sei") ( s) инициализация if(disk_initialize()==0) //инициализиране на флаш устройството ( pf_mount(&fs); //монтиране на файловата система pf_open("1.wav"); //отваряне на клона pf_lseek(44); //преместване на показалеца към 44 pf_read(buffer, 512,&br); //за първи път поглъщаме 512 байта наведнъж TIMSK=0x80; //включете музиката while(1) ( if(!buf && count>255) //ако са възпроизведени повече от 255 байта, ( pf_read(&buffer, 256,&br);//след това прочетете информацията от флаш закарайте в първата половина на буфера buf=1 ;< 256) //если буфер не содержит 256 значений значит конец файла break; } if(buf && count<256) { pf_read(&buffer, 256,&br); // читаем во вторую часть буфера с флешки buf = 0; if (br < 256) break; } } TIMSK = 0x00; //глушим все pf_mount(0x00); //демонтируем фат } while (1) { } }

    За да проверим, свързваме високоговорител към щифта OCR1A чрез кондензатор 100uF, „+“ към щифта на микроконтролера, „-“ към високоговорителя. “-” високоговорител към маса, “+” към кондензатор.

    Не очаквайте силен сигнал на изхода; за да звучи силно, трябва усилвател. Това ясно се вижда във видеото. За теста натоварих петела с 8 kHz и пистата с 22 kHz.

    Тези, които желаят, могат безопасно да увеличат честотата на timer2, за да възпроизвеждат 44 kHz файлове, експериментите показват, че може да се постигне доста добро качество на звука. Във видеото звукът е слаб и качеството е лошо, но всъщност това се дължи на факта, че го снимах с камера.

    Публикувам и материали, любезно предоставени от Apparatchik - изходния код за GCC, от който е написан фърмуерът за CAVR.

    И видео с 44kHz възпроизвеждане.

    Използвам възможността да поздравя всички за Нова година, пожелавам всички фърмуери и устройства да работят за вас :)

    проект за wav плейър на Atmega8

    Онзи ден седях и си мислех какво мога да добавя към моя скутер: има музика, има осветление, но нещо липсва, и тогава си спомних за алармата, със сигурност! В крайна сметка, точно това нямам! Предлагам ви също да сглобите алармена система за вашия двуколесен - например велосипед или може би четириколесен приятел. Алармената система е сглобена на микроконтролера AVR ATmega8, проектът се повтаря и на микроконтролера Attiny2313. За вариантите на веригата Atmega8 написах три версии на фърмуера, единият фърмуер възпроизвежда звук, напомнящ на автомобилна аларма, а другият е подобен на сирена за охранителна аларма, разположена в сграда (по-бърза и по-рязка мелодия). Всички фърмуери са подписани и се намират в архива по-долу, мисля, че ще ги разберете. В допълнение, архивът съдържа симулация на вериги в Proteus, така че можете да слушате звуците и да изберете опцията, която ви харесва най-много.

    Схема на Atmega8:

    Както можете да видите, нищо особено, микроконтролер, три резистора и два светодиода с високоговорител. Вместо бутон в диаграмата можете да използвате например тръстиков превключвател или друг контакт. Веригата работи по следния начин: ако се подаде захранване, LED D3 ще светне (или ще мига, в зависимост от версията на веригата), ако сензорът не бъде докоснат, сирената ще замълчи. Веднага щом сензорът се задейства, алармата ще прозвучи и в същото време LED D2 ще мига. Лично аз свързах пин 24 PC1 през транзисторен превключвател към релето, а релето последователно с предния фар на скутера, така че при изключване на алармата да мига фара на скутера. За да спрете сирената трябва да изключите и включите веригата или да натиснете отново бутона. Бих искал да отбележа, че сигналът от контролера може да бъде усилен от няколко транзистора чрез сглобяване на малък усилвател - което основно направих, въпреки че не изобразих тази верига на диаграмата. Микроконтролерът работи от вътрешен 8 MHz осцилатор, ние настройваме предпазителите съответно.

    PCB за Atmega8 изглежда така:

    Веригата на Attiny2313 не се различава много от първата опция, просто има различни изходни портове.

    Схема на Attiny2313:

    За тази версия на схемата написах само един фърмуер, с един вариант на сигнала; за всеки случай сглобих веригата с помощта на шарнирна инсталация и проверих нейната функционалност. Микроконтролерът работи от вътрешен 4 MHz осцилатор (може да се мига до 1 MHz), предпазителите по време на програмиране са настроени на следното:

    Тъй като нямах жив контролер Atmega8 под ръка, сглобих веригата на Attiny2313, веригата заработи веднага, сглобих веригата с помощта на повърхностно монтирана инсталация, по-долу е снимката:

    Е, ето видео на веригата, която работи, видеото наистина не е с най-добро качество и не можете да видите светодиода да мига на него, защото честотата на кадрите е ниска.

    Изтегляне Можете да намерите проекти в , фърмуер и PCB файлове по-долу

    Списък на радиоелементите

    Наименование Тип Деноминация Количество ЗабележкаМагазинМоят бележник
    U1 MK AVR 8-битов

    ATmega8-16PU

    1 Към бележника
    R1 Резистор

    47 ома

    1 Към бележника
    R2, R3 Резистор

    270 ома

    2 Към бележника
    Схема на Attiny2313
    U1 MK AVR 8-битов