Reklama

Základy ovládání mikrokontroléru ATmega(16/32) 20. díl – Generování audio signálu pomocí PWM

Úvod

Tento příspěvek je zaměřen na testování možnosti využití mikrokontroléru ATmega(16/32) jako generátor audio signálu. Na úvod je asi nutné říct, že mikrokontrolér ATmega(16/32) není určen pro zpracování audio signálu, takže rozhodně nelze očekávat zvuk ve vysoké kvalitě. Možností, jak produkovat audio signál pomocí mikrokontroléru, je mnoho, ale tento příspěvek je zaměřen pouze na metodu pomocí PWM (Pulse Width Modulation). Popis modulace PWM lze nalézt ZDE.

Popis

Jak již bylo řečeno, tak k vytvoření audio signálu využijeme PWM modulaci. K tomu je potřeba použít jeden Čítač/Časovač, který bude generovat PWM signál a jeden Čítač/Časovač nastavený do režimu “CTC”, který bude v pravidelných intervalech měnit střídu PWM modulace. Jak pracovat s Čítačem/Časovačem lze nalézt ZDE. Ke generování audio signálu je použit 8bitový Čítač/Časovač 0. Ke změně střídy PWM modulace je zvolen Čítač/Časovač 1. Tímto výběrem jsme už omezili kvalitu zvuku pouze na osm bitů. Druhý problém je maximální možný kmitočet modulace PWM , který je pouze 62,5 kHz (fpwm = fclk_IO / (N x 256) => fpwm = 16e6 / 256 = 62500 Hz). Pokud by ke generování PWM byl použit Čítač/Časovač1, tak lze měnit bitovou hloubku audio vzorků, ale se změnou bitové hloubky se také mění frekvence PWM modulace. Při zvýšení bitové hloubky audio vzorků se sníží úměrně frekvence PWM modulace a naopak při snížení bitové hloubky se zvýší frekvence PWM modulace. Z tohoto pohledu mi přijde asi optimální využití 8bitového Čítače/Časovače. Dalším problémem je velikost paměti mikrokontroléru ATmega(16/32) pro uložení audio vzorků. Největší paměť mikrokontroléru je typu “Flash”, která je určena pro vlastní program (ATmega16 – 16kB, ATmega32 – 32kB) a kterou lze využít i k uložení dat v případě, že velikost programu ji nezabírá celou. Ale i v tom nejlepším případě, kdy bychom měli volnou celou programovou paměť, tak při nastavení 8b / 8000 Hz uložíme cca 4 s audia, při nastavení 8b / 22050 Hz cca 1,45 s a při nastavení 8b / 44100 Hz pouze cca 0,72 s. To je někdy těžko použitelné i pro jednoduché zvonky, sirény apod. Proto, pokud chcete přehrávat delší zvukové nahrávky, je nutné přidat nějakou externí paměť, např. připojit paměťovou kartu. Problémem s pamětí se zde zabývat nebudeme, protože v tomto příspěvku jde spíš o demonstraci principu generování zvuku a o demonstraci následného zpracování a k tomu je lepší využít definovaný signál. V našem případě se bude jednat o vygenerovaný sinusový signál o frekvenci 1 kHz. Je ovšem pravdou že při vzorkovací frekvenci např. 8 kHz jde spíše o trojúhelníkový než sinusový signál, ale i toto není překážkou pro následné testování.

Pro zpracování PWM modulace je nutné použít filtr typu “dolní propust”. Asi nejjednodušší dolní propustí prvního a druhého řádu je jednoduchý RC obvod, viz Obr. 1.

Obr. 1: Jednoduchá RC dolní propust prvního a druhého řádu

Obr. 1: Jednoduchá RC dolní propust prvního a druhého řádu

Strmost amplitudové kmitočtové charakteristiky pro dolní propust prvního řádu je -20dB / dekáda a pro dolní propust druhého řádu je strmost -40dB / dekáda. Z toho plyne, že dolní propust druhého řádu více utlumí vyšší frekvence, než dolní propust prvního řádu. Amplitudovou a fázovou kmitočtovou charakteristiku pro RC dolní propust prvního a druhého řádu ukazuje Obr. 2.

Obr. 2: Amplitudová (plná čára) a fázová (přerušovaná čára) kmitočtová charakteristika pro dolní propust prvního a druhého řádu. Vytvořeno v LTspice.

Obr. 2: Amplitudová (plná čára) a fázová (přerušovaná čára) kmitočtová charakteristika pro dolní propust prvního a druhého řádu. Vytvořeno v LTspice.

Výpočet mezního kmitočtu pro RC dolní propust prvního řádu probíhá dle vzorce:

 

fmez = 1 / (2π x R x C)

 

Pro výpočet mezního kmitočtu pro RC dolní propust druhého řádu platí:

 

fmez = 1 / (2π x √(R1 xC1 x R2 x C2))

 

Obecně platí, že by následující RC člen složený z R2 a C2 měl mít hodnoty R2 = 10xR1 a C2 = C1/10, aby tolik nezatěžoval předchozí stupeň.

Testování generace audio signálu proběhlo vždy pro bitovou hloubku 8b, ale pro vzorkovací frekvence 8000 Hz, 22050 Hz a 44100 Hz. Při výběru vzorkovací frekvence je vždy nutné počítat s omezením frekvenčního pásma původního signálu, protože musí platit Shannonův teorém [1]:

 

fvz = 2 x fmax [Hz]

 

Z toho plyne, že maximální přenesený kmitočet audio signálu je vždy poloviční než vzorkovací frekvence. Z tohoto je jasné, že je vhodné volit vysoký vzorkovací kmitočet. Ovšem protichůdné požadavky jsou na dodržení co nejvyššího odstupu vzorkovací frekvence od frekvence PWM modulace, která je 62,5 kHz a na co nejnižší velikost paměti nutné k uložení audio vzorků.

Dále bylo testováno použití dolní propusti prvního řádu a druhého řádu. Tyto dolní propusti byly postupně zařazovány za pin PB3, na kterém byl vygenerovaný PWM signál.

Jako první byl testován sinusový signál 1kHz / 8b vzorkovací frekvence 8 kHz s použitím RC dolní propusti o hodnotách R1 = 3k9, R2 = 39k, C1 = 10n a C2 = 1n, z toho plyne mezní kmitočet:
fmez = 1 / (2π x √(R1C1R2C2)) = 1 / (2π x √(3900 x 10e-9 x 39000 x 1e-9)) = 4080,9 Hz.
Výsledné měření pro dolní propust prvního řádu (horní řada obrázků) a druhého řádu (spodní řada obrázků) ukazuje Obr. 3.

Obr. 3: Průběh signálů pro 8b / 8000 Hz pro dolní propust prvního a druhého řádu ( Vstupní PWM signál - Výstupní signál - Zvlnění signálu na 62,5 kHz)

Obr. 3: Průběh signálů pro 8b / 8000 Hz pro dolní propust prvního a druhého řádu ( Vstupní PWM signál – Výstupní signál – Zvlnění signálu na 62,5 kHz)

Z Obr. 3 je patrné, že při použití dolní propusti prvního řádu je zvlnění na frekvenci 62,5 kHz (frekvence modulace PWM) 0,63V z 5V audio signálu. Pro dolní propust druhého řádu již toto zvlnění nebylo měřitelné.

Následně byl testován sinusový signál 1kHz / 8b se vzorkovací frekvencí 22050 Hz a s použitím RC dolní propusti o hodnotách R1 = 1k5, R2 = 15k, C1 = 10n a C2 = 1n , z toho plyne mezní kmitočet:
fmez = 1 / (2π x √(R1C1R2C2)) = 1 / (2π x √(1500 x 10e-9 x 15000 x 1e-9)) = 10610,3 Hz.
Výsledné měření pro dolní propust prvního řádu (horní řada obrázků) a druhého řádu (spodní řada obrázků) ukazuje Obr. 4.

Obr. 4: Průběh signálů pro 8b / 22050 Hz pro dolní propust prvního a druhého řádu ( Vstupní PWM signál - Výstupní signál - Zvlnění signálu na 62,5 kHz)

Obr. 4: Průběh signálů pro 8b / 22050 Hz pro dolní propust prvního a druhého řádu ( Vstupní PWM signál – Výstupní signál – Zvlnění signálu na 62,5 kHz)

Pro vzorkovací frekvenci 22050 Hz je zvlnění při použití RC dolní propusti prvního řádu 1,336 V, které je už celkem znatelné, proto je nutné použít dolní propust druhého řádu, kde je zvlnění signálu na frekvenci 62,5 kHz pouhých 0,166V.

Jako poslední byl testován sinusový signál 1kHz / 8b vzorkovací frekvence 44100 Hz s použitím RC dolní propusti o hodnotách R1 = 680, R2 = 6k8, C1 = 10n a C2 = 1n, z toho plyne mezní kmitočet:
fmez = 1 / (2π x √(R1C1R2C2)) = 1 / (2π x √(680 x 10e-9 x 6800 x 1e-9)) = 23405,1 Hz.
Výsledné měření pro dolní propust prvního řádu (horní řada obrázků) a druhého řádu (spodní řada obrázků) ukazuje Obr. 5.

Obr. 5: Průběh signálů pro 8b / 44100 Hz pro dolní propust prvního a druhého řádu ( Vstupní PWM signál - Výstupní signál - Zvlnění signálu na 62,5 kHz)

Obr. 5: Průběh signálů pro 8b / 44100 Hz pro dolní propust prvního a druhého řádu ( Vstupní PWM signál – Výstupní signál – Zvlnění signálu na 62,5 kHz)

Z provedeného měření vyplývá, že při použití dolní propusti prvního řádu je zkreslení výstupního signálu na frekvenci PWM 62,5 kHz 2,839V a při použití dolní propusti druhého řádu 0,8V. Takto vysoké hodnoty zkreslení jsou důsledkem malého odstupu vzorkovací frekvence od frekvence PWM modulace.

Pokud byste chtěli přímo za dolní propust připojit reproduktor, tak audio signál skoro neuslyšíte. Proto je nutné použít ještě navíc některý zesilovač. Pro jednoduché testování audia byl použit integrovaný obvod LM386. Kompletní zapojení i s použitým zesilovačem ukazuje Obr. 6.

Obr. 6: Elektronické schéma zapojení

Obr. 6: Elektronické schéma zapojení

Okomentovaný testovací zdrojový kód lze vidět níže. Ve zdrojovém kódu lze pomocí odkomentování a zakomentování jednotlivých nastavení vybrat vzorkovací frekvenci audio signálu.

Okomentovaný zdrojový kód

 

001: #include <avr/io.h>
002: #define F_CPU 16000000UL // frekvence hodinového signálu (nutné pro delay.h)
003: #include <util/delay.h> // hlavičkový soubor pro zpoždění
004: #include <avr/interrupt.h> // hlavičkový soubor pro přerušení
005:
006: volatile uint8_t indexSample;// aktuální pozice audio vzorku
007:
008: // pole audio vzorků pro sinus 1khz, fvz = 8 kHz
009: unsigned char audioStream8000 [] = {
010: 0x80, 0xC0, 0xFF, 0xC0, 0x80, 0x40, 0x00, 0x40};
011:
012: // pole vzorků pro sinus 1khz, fvz = 22050 Hz
013: unsigned char audioStream22050 [] = {
014: 0x80, 0xA2, 0xC3, 0xDF, 0xF3, 0xFE, 0xFF, 0xF5,
015: 0xE2, 0xC7, 0xA6, 0x82, 0x5E, 0x3D, 0x21, 0x0C,
016: 0x01, 0x00, 0x0A, 0x1D, 0x37, 0x70};
017:
018:
019: // pole audio vzorků pro sinus 1khz, fvz = 44100 Hz
020: unsigned char audioStream44100 [] = {
021: 0x7E, 0x8D, 0x9B, 0xA9, 0xB6, 0xC1, 0xCC, 0xD5,
022: 0xDC, 0xE1, 0xE5, 0xE6, 0xE5, 0xE2, 0xDD, 0xD7,
023: 0xCE, 0xC4, 0xB9, 0xAC, 0x9E, 0x90, 0x82, 0x73,
024: 0x65, 0x57, 0x4A, 0x3E, 0x34, 0x2B, 0x23, 0x1E,
025: 0x1B, 0x19, 0x1A, 0x1D, 0x21, 0x28, 0x30, 0x3A,
026: 0x46, 0x52, 0x61, 0x7D};
027:
028: // přerušení po shodě registru TCNT1 a OCR1A
029: ISR(TIMER1_COMPA_vect)
030: {
031: // výběr dle vzorkovací frekvence
032: // if (indexSample >= 8)
033: // if (indexSample >= 44)
034: if (indexSample >= 22)
035: {
036: indexSample = 0;
037: // výběr dle vzorkovací frekvence
038: // OCR0 = audioStream8000[indexSample];
039: // OCR0 = audioStream44100[indexSample];
040: OCR0 = audioStream22050[indexSample];
041: }
042: else
043: {
044: // výběr dle vzorkovací frekvence
045: // OCR0 = audioStream8000[indexSample];
046: // OCR0 = audioStream44100[indexSample];
047: OCR0 = audioStream22050[indexSample];
048: indexSample++;
049: }
050: }
051:
052: int main(void)
053: {
054:
055: DDRB = 0xFF// PORTB nastaven jako výstupní
056:
057: TCCR0 = 0b01101001;// rychlý PWM režim, neinvertující režim, předdělička 1 => 62500Hz
058:
059: TCCR1A = 0b00001100;// Deaktivace pinů OC1A a OC1B
060: TCCR1B = 0b00001010;// Předdělička 8, CTC režim
061:
062: TIMSK = 0b00010000;// povolení přerušení při shodě registru OCR1A
063:
064: // výběr dle vzorkovací frekvence
065: //OCR1AL = 248; // fvz = 8000 Hz
066: //OCR1AH = 0;
067:
068: //OCR1AL = 44; // fvz = 44100 Hz
069: //OCR1AH = 0;
070:
071: OCR1AL = 88;// fvz = 22050 Hz
072: OCR1AH = 0;
073:
074: indexSample = 0;
075:
076: sei();
077:
078: while(1);
079:
080:
081: return 0;
082: }
Vzorové zdrojové kódy slouží pouze k jednoduché demonstraci funkce, proto často obsahují globální proměnné, neobsahují většinou ukazatele, dále také neobsahují kontroly proměnných, definování nevyužitých pinů mikrokontroléru a podobné správné programátorské návyky. Proto je nutné tyto kódy brát s patřičnou rezervou.
 

 

[1] WIKIPEDIE. Shannonův teorém. [online] citováno 17. června 2015. Dostupné na www: http://cs.wikipedia.org/wiki/Shannon%C5%AFv_teor%C3%A9m
[2] ATMEL. 8-bit Microcontroller with 32KBytes In-System Programmable Flash. [online] citováno 17. června 2015. Dostupné na www: http://www.atmel.com/images/doc2503.pdf

 
Aktualizace: 18.6.2015
 

Jiné příspěvky v kategorii:

Základy ovládání mikrokontroléru ATmega(16/32) 1.díl – První kroky

Základy ovládání mikrokontroléru ATmega(16/32) 2. díl – Kompilace a krokování programu

Základy ovládání mikrokontroléru ATmega(16/32) 3.díl – Nahrání vytvořeného zdrojového kódu do mikrokontroléru

Základy ovládání mikrokontroléru ATmega(16/32) 4.díl – Ovládání vstupně/výstupních portů

Základy ovládání mikrokontroléru ATmega(16/32) 5.díl – Ošetření zákmitů na vstupním pinu mikrokontroléru

Základy ovládání mikrokontroléru ATmega(16/32) 6.díl – Externí přerušení

Základy ovládání mikrokontroléru ATmega(16/32) 7. díl – Jednoduchá elektronická hrací kostka

Základy ovládání mikrokontroléru ATmega(16/32) 8.díl – A/D převodník (1.část)

Základy ovládání mikrokontroléru ATmega(16/32) 9.díl – A/D převodník (2.část)

Základy ovládání mikrokontroléru ATmega(16/32) 10.díl – A/D převodník (3.část)

Základy ovládání mikrokontroléru ATmega(16/32) 11.díl – Čítač / Časovač (1.část – Základní popis)

Základy ovládání mikrokontroléru ATmega(16/32) 12.díl – Čítač / Časovač (2.část – Popis registrů)

Základy ovládání mikrokontroléru ATmega(16/32) 13.díl – Čítač / Časovač (3.část – Praktická ukázka)

Základy ovládání mikrokontroléru ATmega(16/32) 14.díl – Dvouřádkový LCD displej

Základy ovládání mikrokontroléru ATmega(16/32) 15.díl – Popis implementace komunikace I2C a EEPROM paměti 24LC512

Základy ovládání mikrokontroléru ATmega(16/32) 16.díl – Watchdog

Základy ovládání mikrokontroléru ATmega(16/32) 17.díl – Obsluha maticové klávesnice

Základy ovládání mikrokontroléru ATmega(16/32) 18.díl – Jednotka USART (1. část – Popis)

Základy ovládání mikrokontroléru ATmega(16/32) 19.díl – Jednotka USART (2. část – Praktická ukázka)

Základy ovládání mikrokontroléru ATmega(16/32) 21. díl – Analogový komparátor

Základy ovládání mikrokontroléru ATmega(16/32) 22. díl – Krokování programu v jazyce symbolických adres (JSA)
 
Tajned facebook
 

Za případné chyby v textu, ve zdrojovém kódě, nebo ve schématickém zapojení se omlouváme.
AUTOŘI NEBEROU ŽÁDNOU ODPOVĚDNOST ZA PŘÍPADNÉ ÚJMY NA ZDRAVÍ ČI MAJETKU.