Generovanie tónov: Rozdiel medzi revíziami
Zo stránky SensorWiki
Bez shrnutí editace |
|||
(41 medziľahlých úprav od rovnakého používateľa nie je zobrazených.) | |||
Riadok 5: | Riadok 5: | ||
My sa však v ďalšom budeme zaoberať len pasívnym meničom, čo je vlastne miniatúrny reproduktor, ktorý musíme vybudiť vhodnou frekvenciou, aby sme z neho dostali nejaký zvuk. Na prvý pohľad je to nevýhoda, ale takto môžeme generovať oveľa širšiu škálu zvukov. Nepočítajte však s nejakou hi-fi kvalitou, piezomeniče sú určené najmä na signalizáciu a nie na prehrávanie Carminy Burana. | My sa však v ďalšom budeme zaoberať len pasívnym meničom, čo je vlastne miniatúrny reproduktor, ktorý musíme vybudiť vhodnou frekvenciou, aby sme z neho dostali nejaký zvuk. Na prvý pohľad je to nevýhoda, ale takto môžeme generovať oveľa širšiu škálu zvukov. Nepočítajte však s nejakou hi-fi kvalitou, piezomeniče sú určené najmä na signalizáciu a nie na prehrávanie Carminy Burana. | ||
<div style='text-align: center;'> | |||
[[Súbor:MIPS_buzzerDemoSchema02.png|500px]]<BR> | |||
''Schéma pripojenia piezomeniča k procesoru. Ak vám nepomôže, použite [[Media:MIPS_buzzerDemoSchema01.png|zapojovací diagram]]'' | |||
<HTML> | |||
<IFRAME Src="https://senzor.robotika.sk/mmp/anim/counter2.html" width="700" height="450" style="border:none;"></IFRAME><BR> | |||
<I><A HREF="https://senzor.robotika.sk/mmp/anim/counter2.html">Simulácia počítadla 0 v režime CTC</A></I> | |||
</HTML> | |||
</div> | |||
== Najjednoduchší program == | == Najjednoduchší program == | ||
Frekvečný signál môžeme na výstupoch procesora generovať dvoma spôsobmi | Frekvečný signál môžeme na výstupoch procesora generovať dvoma spôsobmi | ||
# priamo ovládať daný výstup (v takom prípade však procesor nerobí nič iné), alebo | |||
# využiť vstavané periférie, v tomto prípade počítadlo <code>Timer0</code> v režime generátora frekvencie <code>CTC</code>. | |||
Ďalej sa budeme zaoberať len druhým spôsobom. To nám obmedzí možné výstupy - môžu to byť len tie, na ktoré sú pripojené interné počítadlá, t.j. 3,5,6,9,10 alebo 11. Na doske Arduino UNO majú tieto výstupy pri čísle aj vlnovku. | Ďalej sa budeme zaoberať len druhým spôsobom. To nám obmedzí možné výstupy - môžu to byť len tie, na ktoré sú pripojené interné počítadlá, t.j. 3,5,6,9,10 alebo 11. Na doske Arduino UNO majú tieto výstupy pri čísle aj vlnovku. | ||
Riadok 17: | Riadok 30: | ||
<tabs> | <tabs> | ||
<tab name="Arduino code"><source lang="arduino" style="background: | <tab name="AVR C-code"><source lang="c++" style="background: LightYellow;"> | ||
#define F_CPU 16000000UL // toto je lepsie vlozit do parametrov pre kompilator | |||
#include <avr/io.h> | |||
#include <util/delay.h> | |||
void delay(int delay) // vlastna funkcia, lebo inak je max 16ms | |||
{ | |||
for (int i=1; i<=delay; i++) | |||
_delay_ms(1); | |||
} | |||
int main(void) | |||
{ | |||
DDRD |= (1 << PD6); // port D.6 pin ako vystup | |||
TCCR0A = (1 << COM0A0) // toggle pin on match | |||
| (1 << WGM01); // timer 0 in CTC mode | |||
TCCR0B = (1 << CS02); // set prescaler 256 | |||
OCR0A = 70; // initialize timer0 | |||
while(1) | |||
{ | |||
delay(250); // 50ms delay | |||
OCR0A = 70; // for 440 Hz #A4 | |||
delay(250); // 50ms delay | |||
OCR0A = 35; // for 880 Hz #A5 | |||
} | |||
} | |||
</source></tab> | |||
<tab name="Arduino code"><source lang="arduino" style="background: #9dd1e1;"> | |||
/* ************************************************* | /* ************************************************* | ||
* | * | ||
Riadok 30: | Riadok 77: | ||
} | } | ||
void loop(){ | void loop(){ | ||
tone(buzzer, | tone(buzzer, 440); // send 440 Hz wave to the output | ||
delay( | delay(250); // and do it for 1 sec | ||
noTone(buzzer); // stop frequency output | noTone(buzzer); // stop frequency output | ||
delay( | delay(250); // again for 1 sec | ||
tone(buzzer, | tone(buzzer, 880, 500); // third parameter is length in ms | ||
delay( | delay(250); // in reality 1000 - 500 | ||
} | } | ||
</source> | |||
Obmedzenia pre Arduino<REF>Referenčná príručka Arduino, dostupná na adrese https://www.arduino.cc/reference/en/language/functions/advanced-io/tone/</REF>: | |||
* Ak použijete funkciu tone(), tak nemôžete zároveň použiť analogWrite() na pinoch 3 alebo 11, pretože obe používajú ten istý časovač. | |||
* Funkcia tone() nevie generovať tón s frekvenciou menšou ako 31 Hz. | |||
* Funkcia tone() sa nedá použiť súčasne na dvoch rôznych výstupoch. | |||
</tab> | |||
</tabs> | |||
'''Úloha:''' Naprogramujte vlastnú funkciu <code lang="c">void tone (int TONE, int DURATION);</code> s dvoma parametrami - <code>TONE</code> je výška tónu, | |||
pričom odporúčame zadefinovať jednotlivé tóny napr. takto | |||
<source lang="c"> | |||
#define A4 70 | |||
// tone __| |__ value for OCR is 70 | |||
</source> | |||
Druhý parameter, <CODE>DURATION</CODE> je dĺžka trvania v ms. | |||
'''Poznámky k programu pre AVR-GCC''' | |||
Podla https://balau82.wordpress.com/2014/10/15/using-a-buzzer-with-arduino-in-pure-c/ | |||
V horeuvedenom príklade využívame <syntaxhighlight inline>Timer0</syntaxhighlight> a jeho výstup <syntaxhighlight inline>OC0A</syntaxhighlight>, ktorý je mapovaný na pin '''6''' portu '''D''' procesora ATmega328P, (na Arduino doske označený ako D6). | |||
Počítadlo a časovač <syntaxhighlight inline>Timer0</syntaxhighlight> má niekoľko režimov činnsotí, my sme využili režim ''Clear Timer on Compare Match'' (CTC). V tomto režime sa dá výstup pinu <syntaxhighlight inline>OC0A</syntaxhighlight> ovládať frekvenciou, ktorú vieme | |||
nastaviť pomerne presne aj s potrebnou striedou 50% (pripomínam, že výstup je obdĺžnikový, nie harmonický). Vzťah pre nastavenie frekvencie je podľa datasheetu: | |||
<math> | |||
f_{OCnx}=\frac{f_{clkIO}}{2\cdot N\cdot (1+OCRnx)} | |||
</math> | |||
Kde <math>f_{OCnx}</math> je frekvencia generovaného signálu, <math>f_{clkIO}</math> je frekvencia oscilátora (pre Arduino UNO je to 16 MHz), <math>N</math> je preddelič a <syntaxhighlight inline>OCRnx</syntaxhighlight> je príslušný Output Compare Register, v našom prípade <syntaxhighlight inline>OCR0A</syntaxhighlight>, ktorý prislúcha k pinu <syntaxhighlight inline>OC0A</syntaxhighlight>. | |||
Ako príklad uvedieme výpočet hodnôt pre komorné A, teda tón s frekvenciou 440Hz. Preddelič môžeme nastaviť len na hodnoty z množiny {1; 8; 64; 256; 1024}, tak vyberieme napríklad N = 256 a k tomu dopočítame hodnotu pre register OCR0A = 70. Pre iné hodnoty nám nevyjde hodnota, ktorá by sa vošla do 8-bitového registra. | |||
<div style='text-align: center;'> | |||
[[Súbor:timer0avrCalc.png]]<BR> | |||
''Pre výpočet sa dá použiť aj niektorá z utilitiek na internete, napríklad | |||
[https://sourceforge.net/projects/avrcalc/ AVR Calc] od Brandona Robertsa'' | |||
</div> | |||
= | <div style='text-align: center;'> | ||
[[Súbor:timer0scopeSignal.png]]<BR> | |||
''Takto vyzerá priebeh na výstupe zmeraný osciloskopom. V ľavej časti je priebeh 880 Hz signálu, v pravej je 440 Hz. Hodnoty namerané kurzormi sú v dolnej časti obrázku.'' | |||
</div> | |||
'''Poznámky k <syntaxhighlight inline>_delay_ms()</syntaxhighlight>''' pozri -> [[Oneskorenia s AVR]] | |||
'''Úloha:''' | |||
Naprogramujte melódiu niektorej slovenskej pesničky s minimálnym počtom 15 tónov. | |||
== Komplexnejšie melódie == | |||
Ak sa nám bude chcieť, tak sem dáme aj zložitejšie programíky... | |||
Napríklad tento odtialto https://learn.sparkfun.com/tutorials/sik-experiment-guide-for-arduino---v32/experiment-11-using-a-piezo-buzzer | |||
<tabs> | |||
<tab name="Arduino code"><source lang="arduino" style="background: LightBlue;"> | |||
/* | |||
Connect the positive pin to Arduino digital pin 9. | Connect the positive pin to Arduino digital pin 9. | ||
Connect the negative pin to GND. | Connect the negative pin to GND. | ||
This sketch was written by SparkFun Electronics, | This sketch was written by SparkFun Electronics, | ||
with lots of help from the Arduino community. | with lots of help from the Arduino community. | ||
(This sketch was originally developed by D. Cuartielles for K3) | (This sketch was originally developed by D. Cuartielles for K3) | ||
Version 2.0 6/2012 MDG */ | |||
Version 2.0 6/2012 MDG | |||
*/ | |||
const int buzzerPin = 6; | const int buzzerPin = 6; | ||
Riadok 168: | Riadok 217: | ||
} | } | ||
while(true){} // stop here | |||
while(true){} | |||
} | } | ||
Riadok 207: | Riadok 253: | ||
// but we still need to return a value, so return 0. | // but we still need to return a value, so return 0. | ||
} | } | ||
</source></tab></tabs> | |||
'''Literatúra''' | |||
* Katalógový list [http://senzor.robotika.sk/mmp/AL-60P01-Datasheet.pdf piezomeniča AL-60P01] | |||
* Príklady aj s niekoľkými už predpripravenými melódiami: | |||
** https://dragaosemchama.com/en/2019/02/songs-for-arduino/ | |||
** https://github.com/robsoncouto/arduino-songs | |||
* A tu je to aj s hudobnou teóriou: | |||
** https://www.meccanismocomplesso.org/en/generate-musical-tones-at-440hz-and-432hz-with-arduino/ | |||
* Podrobnejšie vysvetlenie časovačov https://www.avrfreaks.net/forum/tut-c-newbies-guide-avr-timers?page=all | |||
[[Mikropočítačové systémy (MIPS)#Cvičenia|Návrat na zoznam cvičení...]] | |||
[[Category:AVR]][[Category:MIPS]] | [[Category:AVR]][[Category:MIPS]] |
Aktuálna revízia z 14:04, 12. marec 2024
Generovanie tónov prostredníctvom pripojeného miniatúrneho reproduktora je veľmi obľúbené a využíva sa aj ako akustická signalizácia pri prekročení hraničných stavov, alebo ako alarm.
Pri použití miniatúrnych piezoreproduktorov si treba dať pozor na správny typ. V praxi sa veľmi často vyskytujú aj samobudené signazlizačné prvky - sirénky, ku ktorým stačí priviesť správne napájacie napätie a zvuk začnú generovať automaticky, pomocou zabudovaného oscilátora, najčastejšie naladeného na mechanickú rezonančnú frekvenciu meniča, takže obvykle aj účinnosť je výborná a hlasitosť ľahko presiahne desiatky dB.
My sa však v ďalšom budeme zaoberať len pasívnym meničom, čo je vlastne miniatúrny reproduktor, ktorý musíme vybudiť vhodnou frekvenciou, aby sme z neho dostali nejaký zvuk. Na prvý pohľad je to nevýhoda, ale takto môžeme generovať oveľa širšiu škálu zvukov. Nepočítajte však s nejakou hi-fi kvalitou, piezomeniče sú určené najmä na signalizáciu a nie na prehrávanie Carminy Burana.
Schéma pripojenia piezomeniča k procesoru. Ak vám nepomôže, použite zapojovací diagram
Najjednoduchší program
Frekvečný signál môžeme na výstupoch procesora generovať dvoma spôsobmi
- priamo ovládať daný výstup (v takom prípade však procesor nerobí nič iné), alebo
- využiť vstavané periférie, v tomto prípade počítadlo
Timer0
v režime generátora frekvencieCTC
.
Ďalej sa budeme zaoberať len druhým spôsobom. To nám obmedzí možné výstupy - môžu to byť len tie, na ktoré sú pripojené interné počítadlá, t.j. 3,5,6,9,10 alebo 11. Na doske Arduino UNO majú tieto výstupy pri čísle aj vlnovku.
Poznámka: výstupný frekvenčný signál bude mať síce správnu frekvenciu, ale tvar bude obdĺžnikový. Jednoduchými prostriedkami nedokážeme na výstupe generovať spojitý harmonický signál (sínusovku).
#define F_CPU 16000000UL // toto je lepsie vlozit do parametrov pre kompilator
#include <avr/io.h>
#include <util/delay.h>
void delay(int delay) // vlastna funkcia, lebo inak je max 16ms
{
for (int i=1; i<=delay; i++)
_delay_ms(1);
}
int main(void)
{
DDRD |= (1 << PD6); // port D.6 pin ako vystup
TCCR0A = (1 << COM0A0) // toggle pin on match
| (1 << WGM01); // timer 0 in CTC mode
TCCR0B = (1 << CS02); // set prescaler 256
OCR0A = 70; // initialize timer0
while(1)
{
delay(250); // 50ms delay
OCR0A = 70; // for 440 Hz #A4
delay(250); // 50ms delay
OCR0A = 35; // for 880 Hz #A5
}
}
/* *************************************************
*
* Arduino code for Passive buzzer / Piezo Speaker
*
* ************************************************** */
const int buzzer = 6; // connect buzzer to Arduino pin 6
void setup(){
pinMode(buzzer, OUTPUT); // set the buzzer pin as an output
}
void loop(){
tone(buzzer, 440); // send 440 Hz wave to the output
delay(250); // and do it for 1 sec
noTone(buzzer); // stop frequency output
delay(250); // again for 1 sec
tone(buzzer, 880, 500); // third parameter is length in ms
delay(250); // in reality 1000 - 500
}
Obmedzenia pre Arduino[1]:
- Ak použijete funkciu tone(), tak nemôžete zároveň použiť analogWrite() na pinoch 3 alebo 11, pretože obe používajú ten istý časovač.
- Funkcia tone() nevie generovať tón s frekvenciou menšou ako 31 Hz.
- Funkcia tone() sa nedá použiť súčasne na dvoch rôznych výstupoch.
Úloha: Naprogramujte vlastnú funkciu void tone (int TONE, int DURATION);
s dvoma parametrami - TONE
je výška tónu,
pričom odporúčame zadefinovať jednotlivé tóny napr. takto
#define A4 70
// tone __| |__ value for OCR is 70
Druhý parameter, DURATION
je dĺžka trvania v ms.
Poznámky k programu pre AVR-GCC
Podla https://balau82.wordpress.com/2014/10/15/using-a-buzzer-with-arduino-in-pure-c/
V horeuvedenom príklade využívame Timer0
a jeho výstup OC0A
, ktorý je mapovaný na pin 6 portu D procesora ATmega328P, (na Arduino doske označený ako D6).
Počítadlo a časovač Timer0
má niekoľko režimov činnsotí, my sme využili režim Clear Timer on Compare Match (CTC). V tomto režime sa dá výstup pinu OC0A
ovládať frekvenciou, ktorú vieme
nastaviť pomerne presne aj s potrebnou striedou 50% (pripomínam, že výstup je obdĺžnikový, nie harmonický). Vzťah pre nastavenie frekvencie je podľa datasheetu:
Kde je frekvencia generovaného signálu, je frekvencia oscilátora (pre Arduino UNO je to 16 MHz), je preddelič a OCRnx
je príslušný Output Compare Register, v našom prípade OCR0A
, ktorý prislúcha k pinu OC0A
.
Ako príklad uvedieme výpočet hodnôt pre komorné A, teda tón s frekvenciou 440Hz. Preddelič môžeme nastaviť len na hodnoty z množiny {1; 8; 64; 256; 1024}, tak vyberieme napríklad N = 256 a k tomu dopočítame hodnotu pre register OCR0A = 70. Pre iné hodnoty nám nevyjde hodnota, ktorá by sa vošla do 8-bitového registra.
Pre výpočet sa dá použiť aj niektorá z utilitiek na internete, napríklad
AVR Calc od Brandona Robertsa
Takto vyzerá priebeh na výstupe zmeraný osciloskopom. V ľavej časti je priebeh 880 Hz signálu, v pravej je 440 Hz. Hodnoty namerané kurzormi sú v dolnej časti obrázku.
Poznámky k _delay_ms()
pozri -> Oneskorenia s AVR
Úloha:
Naprogramujte melódiu niektorej slovenskej pesničky s minimálnym počtom 15 tónov.
Komplexnejšie melódie
Ak sa nám bude chcieť, tak sem dáme aj zložitejšie programíky...
Napríklad tento odtialto https://learn.sparkfun.com/tutorials/sik-experiment-guide-for-arduino---v32/experiment-11-using-a-piezo-buzzer
/*
Connect the positive pin to Arduino digital pin 9.
Connect the negative pin to GND.
This sketch was written by SparkFun Electronics,
with lots of help from the Arduino community.
(This sketch was originally developed by D. Cuartielles for K3)
Version 2.0 6/2012 MDG */
const int buzzerPin = 6;
// We'll set up an array with the notes we want to play
// change these values to make different songs!
// Length must equal the total number of notes and spaces
const int songLength = 18;
// Notes is an array of text characters corresponding to the notes
// in your song. A space represents a rest (no tone)
char notes[] = "cdfda ag cdfdg gf "; // a space represents a rest
// Beats is an array of values for each note and rest.
// A "1" represents a quarter-note, 2 a half-note, etc.
// Don't forget that the rests (spaces) need a length as well.
int beats[] = {1,1,1,1,1,1,4,4,2,1,1,1,1,1,1,4,4,2};
// The tempo is how fast to play the song.
// To make the song play faster, decrease this value.
int tempo = 113;
void setup()
{
pinMode(buzzerPin, OUTPUT);
}
void loop()
{
int i, duration;
for (i = 0; i < songLength; i++) // step through the song arrays
{
duration = beats[i] * tempo; // length of note/rest in ms
if (notes[i] == ' ') // is this a rest?
{
delay(duration); // then pause for a moment
}
else // otherwise, play the note
{
tone(buzzerPin, frequency(notes[i]), duration);
delay(duration); // wait for tone to finish
}
delay(tempo/10); // brief pause between notes
}
while(true){} // stop here
}
int frequency(char note)
{
// This function takes a note character (a-g), and returns the
// corresponding frequency in Hz for the tone() function.
int i;
const int numNotes = 8; // number of notes we're storing
// The following arrays hold the note characters and their
// corresponding frequencies. The last "C" note is uppercase
// to separate it from the first lowercase "c". If you want to
// add more notes, you'll need to use unique characters.
// For the "char" (character) type, we put single characters
// in single quotes.
char names[] = { 'c', 'd', 'e', 'f', 'g', 'a', 'b', 'C' };
int frequencies[] = {262, 294, 330, 349, 392, 440, 494, 523};
// Now we'll search through the letters in the array, and if
// we find it, we'll return the frequency for that note.
for (i = 0; i < numNotes; i++) // Step through the notes
{
if (names[i] == note) // Is this the one?
{
return(frequencies[i]); // Yes! Return the frequency
}
}
return(0); // We looked through everything and didn't find it,
// but we still need to return a value, so return 0.
}
Literatúra
- Katalógový list piezomeniča AL-60P01
- Príklady aj s niekoľkými už predpripravenými melódiami:
- A tu je to aj s hudobnou teóriou:
- Podrobnejšie vysvetlenie časovačov https://www.avrfreaks.net/forum/tut-c-newbies-guide-avr-timers?page=all
- ↑ Referenčná príručka Arduino, dostupná na adrese https://www.arduino.cc/reference/en/language/functions/advanced-io/tone/