Operácie

Akordy s procesorom AVR: Rozdiel medzi revíziami

Z SensorWiki

(21 medziľahlých úprav od rovnakého používateľa nie je zobrazených.)
Riadok 6: Riadok 6:
 
Naprogramujte nejakú pesničku aj s akordmi (využite skutočnosť, že procesor má až tri nezávislé časovače).
 
Naprogramujte nejakú pesničku aj s akordmi (využite skutočnosť, že procesor má až tri nezávislé časovače).
  
[[Obrázok:ard.jpg|400px|thumb|center|Vývojová doska ACROB.]]
+
[[Obrázok: UNO_schema_na_zaciatok_stranky.jpg|700px|thumb|center|Vývojová doska Arduino UNO]]
  
 
'''Literatúra:'''  
 
'''Literatúra:'''  
Riadok 25: Riadok 25:
 
Počítadlo T0 je 8-bitové. Cez registre TCCR0A a TCCR0B (Timer/Counter control register) možno nastaviť jeho preddeličku, PWM mód a hlavne režim generovania priebehu. Do TCCR0A a TCCR0B ide číslo ktorým nastavujeme počítadlo (8-miestny kód v binárnej sústave alebo to isté číslo prepočítané do inej sústavy). Viem, že potrebujem pre počítadlo nastaviť:
 
Počítadlo T0 je 8-bitové. Cez registre TCCR0A a TCCR0B (Timer/Counter control register) možno nastaviť jeho preddeličku, PWM mód a hlavne režim generovania priebehu. Do TCCR0A a TCCR0B ide číslo ktorým nastavujeme počítadlo (8-miestny kód v binárnej sústave alebo to isté číslo prepočítané do inej sústavy). Viem, že potrebujem pre počítadlo nastaviť:
  
- Toggle OC0A on compare match – oživiť register OC0A
+
<nowiki>- Toggle OC0A on compare match – oživiť register OC0A</nowiki>
- Normal port operation, OC0B disconnected – register OC0B nechať vypnutý
+
 
- CTC – režim počítadla Clear Timer on Compare Match
+
<nowiki>- Normal port operation, OC0B disconnected – register OC0B nechať vypnutý</nowiki>
- Preddelička 256 – ako “rýchlo“ má počítať
+
 
 +
<nowiki>- CTC – režim počítadla Clear Timer on Compare Match</nowiki>
 +
 
 +
<nowiki>- Preddelička 256 – ako “rýchlo“ má počítať</nowiki>
  
  
 
V tabuľkách DataSheetu dohľadám ako treba nastaviť podregistre COM0A1, COM0A0, COM0B1, COM0B0, WGM02, WGM01, WGM00, CS02, CS01, CS00 a zadám ich dokopy do registrov TCCR0A a TCCR0B podľa rozloženia: (obrázok)
 
V tabuľkách DataSheetu dohľadám ako treba nastaviť podregistre COM0A1, COM0A0, COM0B1, COM0B0, WGM02, WGM01, WGM00, CS02, CS01, CS00 a zadám ich dokopy do registrov TCCR0A a TCCR0B podľa rozloženia: (obrázok)
  
[[Obrázok:TCCR0_registre_na_nastavenie_pocitadla_T0.jpg|700px|center|Forma rozpoloženia podregistrov v registroch TCCR0A a TCCR0B.]]
+
[[Obrázok:TCCR0_registre_na_nastavenie_pocitadla_T0.jpg|700px|thumb|center|Forma rozpoloženia podregistrov v registroch TCCR0A a TCCR0B.]]
 +
 
 +
Pre počítadlo T0 majú byť TCCR registre nastavené nasledovne:
 +
TCCR0A = 0b01000010;
 +
TCCR0A = 0b00000100;
 +
Register OCR0A je priamo napojený na katódu (pozitívnu nožičku) pasívneho meniča. Anóda meniča je pripojená na zem. Do registra OCR0A však nemôžem v AVR kóde napísať skutočnú frekvenciu zvuku ako mechanického vlnenia v prírode, ale treba ju prepočítať. Tento prepočet je daný jednoduchým vzťahom:
 +
 
 +
[[Obrázok:vzorec_na_vypocet_frekvencie_tonu_v_AVR.png|200px]]
 +
 
 +
Kde platí:
 +
 
 +
- fOCnx je skutočná frekvencia zvuku (napr. komorné “a“ = 440Hz)
 +
 
 +
- fclkIO je frekvencia oscilátora procesora – v prípade Arduina UNO (procesor ATmega328P) je to 16MHZ
 +
 
 +
- N je preddelička – 256
 +
 
 +
- OCRnx je hľadaná hodnota reprezentujúca skutočnú frekvenciu, pri konkrétnej preddeličke skompilovateľná cez AVR
 +
 
 +
Tento prevod za mňa dokáže urobiť jednoduchý, šikovný program AVRcalc (https://sourceforge.net/projects/avrcalc/). Stačí vybrať hore v záložkách 8-bit Timer, Mode nechať na Clear Timer on Compare Match, Prescaler zmeniť na 256, Clock zadať ako 16 000 000 a hýbať so sliderom v riadku Compare kým v riadku Frequency nebude moja želaná frekvencia. Hodnota v riadku Compare ide do registra OCR0A.
 +
 
 +
[[Obrázok:AVRcalc_obrazok_na_ukazku_vypoctu_440_Hz.jpg|400px|center]]
 +
 
 +
Aby boli tieto tóny čitateľné pre ľudí na začiatku programu som im pridelil formou makier korešpondujúce mená tónov v štandardnom notopise
 +
 
 +
<tabs>
 +
<tab name="AVR C-code"><source lang="c++" style="background: LightYellow;">
 +
#define C4 118
  
  
[[Súbor:ledRGB.jpg|400px|thumb|center|RGB LED.]]
+
</source></tab>
 +
</tabs>
  
 +
Dĺžku tónov viem ovládať v main() programe funkciou delay(), ktorá zamrzne procesor na danú dobu v milisekundách a teda bude tú dobu hrať jeden tón, a potom prepísať OCR0A na iný tón.
  
Nezabudnite doplniť schému zapojenia!
+
Na ukážku funkčnosti tohto projektu som si vybral pieseň Happy Birthday. Je to jednoduchá kozonantná skladba ktorej som pre limitácie zvukovej kvality buzzerov musel pomeniť harmóniu. Finálne noty vyzarajú takto:
 +
 
 +
[[Obrázok:Happy_Birthday_noty_fotka.jpg|700px|center]]
 +
 
 +
Schéma zapojenia:
 +
 
 +
[[Obrázok:schema_zapojenia_3_speakre_s_rezistormi.png|300px|center]]
 +
 
 +
Repráčiky na pinoch D9 a D11 majú sériovo pred sebou zapojený rezistor (R = 220 Ω) aby ich zvuk bol o trošku tichší. Na pine D6 je pripojený repráčik, ktorý hrá hlavnú melódiu a na D9, D11 repráčiky, ktoré hrajú sprievodnú harmóniu (akordy), čiže potrebujem aby boli trošku komplimentárne, tichšie voči D6 a prepojím ich signál cez rezistor. Projekt funguje aj bez rezistorov napojením repráčikov priamo na signál, ale potom to znie akoby sa repráčiky prekrikovali.
  
[[Súbor:schd.png|400px|thumb|center|Schéma zapojenia LCD displeja.]]
 
  
  
Riadok 51: Riadok 90:
 
<tabs>
 
<tabs>
 
<tab name="AVR C-code"><source lang="c++" style="background: LightYellow;">
 
<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 <avr/io.h>
 +
#include <util/delay.h>
 +
 +
#define O0 50000000000 // toto neexistuje teda nehra nic
 +
// melodia:
 +
#define C4 118
 +
#define D4 106
 +
#define E4 94
 +
#define G4 79
 +
#define A4 70
 +
#define H4 62
 +
#define C5 59
 +
#define D5 52
 +
#define E5 46
 +
#define F5 44
 +
#define G5 39
 +
 +
// bass:
 +
#define A3 141
 +
#define G3 158
 +
#define F3 178
 +
#define E3 189
 +
#define D3 213
 +
#define C3 238
 +
#define H2 252
 +
  
int main(void)
+
void delay(int delay)   // vlastna funkcia, lebo inak je max 16ms
 
{
 
{
   unsigned int measuredValue;
+
for (int i=1; i <= delay - 2; i++){
 +
_delay_ms(1);
 +
}
 +
 
 +
OCR0A = O0; // malinka pauza za kazkou notou melodie
 +
    for (int i=1; i <= 2; i++){ // ... ked za sebou idu dve rovnake noty aby nezneli
 +
  _delay_ms(1); // ako jedna spojita
 +
}
 +
}
 +
 
 +
void InitTimer0(){
 +
  DDRD  |= (1 << PD6);            // port D.6 pin ako vystup
 +
 
 +
  TCCR0A = 0b01000010;
 +
  TCCR0B = 0b00000100;
 +
    
 +
  OCR0A = 70;
 +
 
 +
}
 +
 
 +
void InitTimer1(){
 +
DDRB  |= (1 << PB1);            // port D.9 pin ako vystup
 +
 
 +
TCCR1A = 0b01000000;
 +
TCCR1B = 0b00001100; // preddelicka 256
 +
 +
OCR1A = 70;
 +
 
 +
}
 +
 
 +
void InitTimer2(){
 +
DDRB  |= (1 << PB3);            // port D.11 pin ako vystup
 +
 
 +
  TCCR2A = 0b01000010;
 +
  TCCR2B = 0b00000110;
 +
 
 +
  OCR2A = 70;
 +
 
 +
}
 +
 
 +
void speaker0(vyska_tonu0){
 +
OCR0A = vyska_tonu0;
 +
}
  
  while (1)
+
void speaker1(vyska_tonu1){
  {
+
OCR1A = vyska_tonu1;
    /*  relax  */
+
TCNT1 = 0x00; // resetovanie pocitadla T1 aby nesekalo
  }
+
}
  
  return(0);
+
void speaker2(vyska_tonu2){
 +
OCR2A = vyska_tonu2;
 
}
 
}
  
</source></tab>
 
<tab name="filename.h"><source lang="c++" style="background: LightYellow;">
 
#include <avr/io.h>
 
  
void adc_init(void);                                   // A/D converter initialization
+
int main(void)
 +
{
 +
InitTimer0();
 +
InitTimer1();
 +
InitTimer2();
 +
 
 +
int tempo = 250;
 +
 +
while(1){
 +
// ------------------------ Happy birthday ------------------------ //
 +
 +
// 1 takt
 +
speaker0(G4); speaker1(O0); speaker2(O0); delay(tempo); // ha-
 +
speaker0(G4); delay(tempo); // -ppy
 +
speaker0(A4); speaker1(G3); speaker2(C3); delay(tempo*2); // Birth-
 +
speaker0(G4); delay(tempo*2); // -day
 +
 +
// 2 takt
 +
speaker0(C5); speaker1(O0); speaker2(O0); delay(tempo*2); // to
 +
speaker0(H4); speaker1(G3); speaker2(H2); delay(tempo*4); // you
 +
 +
// 3 takt
 +
speaker0(G4); speaker1(O0); speaker2(O0); delay(tempo); // ha-
 +
speaker0(G4); delay(tempo); // -ppy
 +
speaker0(A4); speaker1(G3); speaker2(H2); delay(tempo*2); // Birth-
 +
speaker0(G4); delay(tempo*2); // -day
 +
 +
// 4 takt
 +
speaker0(D5); speaker1(O0); speaker2(O0); delay(tempo*2); // to
 +
speaker0(C5); speaker1(G3); speaker2(C3); delay(tempo*4); // you
 +
 +
// 5 takt
 +
speaker0(G4); speaker1(O0); speaker2(O0); delay(tempo); // ha-
 +
speaker0(G4); delay(tempo); // -ppy
 +
speaker0(G5); speaker1(C4); speaker2(E3); delay(tempo*2); // Birth-
 +
speaker0(E5); delay(tempo*2); // -day
 +
 +
// 6 takt
 +
speaker0(C5); speaker1(O0); speaker2(O0); delay(tempo*2); // dear
 +
speaker0(H4); speaker1(C4); speaker2(F3); delay(tempo*2); // Ji-
 +
speaker0(A4); delay(tempo*2); // -mmy
 +
 +
// 7 takt
 +
speaker0(F5); speaker1(O0); speaker2(O0); delay(tempo); // Ha-
 +
speaker0(F5); delay(tempo); // -ppy
 +
speaker0(E5); speaker1(C4); speaker2(E3); delay(tempo*2); // birth-
 +
speaker0(C5); delay(tempo*2); // -day
 +
 +
// 8 takt
 +
speaker0(D5); speaker1(G3); speaker2(D3); delay(tempo*2); // to
 +
speaker0(C5); speaker1(G3); speaker2(C3); delay(tempo*4); // you
 +
 +
}
 +
 
 +
 
 +
}
 +
 
  
unsigned int adc_read(char a_pin);
 
 
</source></tab>
 
</source></tab>
 
</tabs>
 
</tabs>

Verzia zo dňa a času 21:03, 7. máj 2024

Záverečný projekt predmetu MIPS / LS2024 - Kristián Pauliny


Zadanie

Naprogramujte nejakú pesničku aj s akordmi (využite skutočnosť, že procesor má až tri nezávislé časovače).

Vývojová doska Arduino UNO

Literatúra:


Analýza a opis riešenia

Opíšte sem čo a ako ste spravili, ak treba, doplňte obrázkami...

Zapojenie, vypracovanie je inšpirované cvičením 5 – Generovanie tónov, kde sme dostali funkčný program, v ktorom stačilo len “naprogramovať melódiu“.

Hranie tónov cez AVR je založené na vstavaných perifériách – počítadlá v stave CTC (Clear Timer on Compare Match). Budem používať všetky 3 nezávislé počítadlá (T0, T1, T2) – konkrétne ich výstupy OC0A, OC1A, OC2A (Output Compare Register) na riadenie výšky tónov. Nastavenie počítadiel vysvetlím konkrétne ako pre počítadle T0 – po pochopení jedného sa proces dá zopakovať aj pri ostatných.

Počítadlo T0 je 8-bitové. Cez registre TCCR0A a TCCR0B (Timer/Counter control register) možno nastaviť jeho preddeličku, PWM mód a hlavne režim generovania priebehu. Do TCCR0A a TCCR0B ide číslo ktorým nastavujeme počítadlo (8-miestny kód v binárnej sústave alebo to isté číslo prepočítané do inej sústavy). Viem, že potrebujem pre počítadlo nastaviť:

- Toggle OC0A on compare match – oživiť register OC0A

- Normal port operation, OC0B disconnected – register OC0B nechať vypnutý

- CTC – režim počítadla Clear Timer on Compare Match

- Preddelička 256 – ako “rýchlo“ má počítať


V tabuľkách DataSheetu dohľadám ako treba nastaviť podregistre COM0A1, COM0A0, COM0B1, COM0B0, WGM02, WGM01, WGM00, CS02, CS01, CS00 a zadám ich dokopy do registrov TCCR0A a TCCR0B podľa rozloženia: (obrázok)

Forma rozpoloženia podregistrov v registroch TCCR0A a TCCR0B.

Pre počítadlo T0 majú byť TCCR registre nastavené nasledovne: TCCR0A = 0b01000010; TCCR0A = 0b00000100; Register OCR0A je priamo napojený na katódu (pozitívnu nožičku) pasívneho meniča. Anóda meniča je pripojená na zem. Do registra OCR0A však nemôžem v AVR kóde napísať skutočnú frekvenciu zvuku ako mechanického vlnenia v prírode, ale treba ju prepočítať. Tento prepočet je daný jednoduchým vzťahom:

Vzorec na vypocet frekvencie tonu v AVR.png

Kde platí:

- fOCnx je skutočná frekvencia zvuku (napr. komorné “a“ = 440Hz)

- fclkIO je frekvencia oscilátora procesora – v prípade Arduina UNO (procesor ATmega328P) je to 16MHZ

- N je preddelička – 256

- OCRnx je hľadaná hodnota reprezentujúca skutočnú frekvenciu, pri konkrétnej preddeličke skompilovateľná cez AVR

Tento prevod za mňa dokáže urobiť jednoduchý, šikovný program AVRcalc (https://sourceforge.net/projects/avrcalc/). Stačí vybrať hore v záložkách 8-bit Timer, Mode nechať na Clear Timer on Compare Match, Prescaler zmeniť na 256, Clock zadať ako 16 000 000 a hýbať so sliderom v riadku Compare kým v riadku Frequency nebude moja želaná frekvencia. Hodnota v riadku Compare ide do registra OCR0A.

AVRcalc obrazok na ukazku vypoctu 440 Hz.jpg

Aby boli tieto tóny čitateľné pre ľudí na začiatku programu som im pridelil formou makier korešpondujúce mená tónov v štandardnom notopise

#define C4 118

Dĺžku tónov viem ovládať v main() programe funkciou delay(), ktorá zamrzne procesor na danú dobu v milisekundách a teda bude tú dobu hrať jeden tón, a potom prepísať OCR0A na iný tón.

Na ukážku funkčnosti tohto projektu som si vybral pieseň Happy Birthday. Je to jednoduchá kozonantná skladba ktorej som pre limitácie zvukovej kvality buzzerov musel pomeniť harmóniu. Finálne noty vyzarajú takto:

Happy Birthday noty fotka.jpg

Schéma zapojenia:

Schema zapojenia 3 speakre s rezistormi.png

Repráčiky na pinoch D9 a D11 majú sériovo pred sebou zapojený rezistor (R = 220 Ω) aby ich zvuk bol o trošku tichší. Na pine D6 je pripojený repráčik, ktorý hrá hlavnú melódiu a na D9, D11 repráčiky, ktoré hrajú sprievodnú harmóniu (akordy), čiže potrebujem aby boli trošku komplimentárne, tichšie voči D6 a prepojím ich signál cez rezistor. Projekt funguje aj bez rezistorov napojením repráčikov priamo na signál, ale potom to znie akoby sa repráčiky prekrikovali.


Algoritmus a program

Algoritmus programu je....


#define F_CPU 16000000UL  // toto je lepsie vlozit do parametrov pre kompilator

#include <avr/io.h>
#include <util/delay.h>

#define O0 50000000000		// toto neexistuje teda nehra nic
// melodia:
#define C4 118
#define D4 106
#define E4 94
#define G4 79
#define A4 70
#define H4 62
#define C5 59
#define D5 52
#define E5 46
#define F5 44
#define G5 39

// bass:
#define A3 141
#define G3 158
#define F3 178
#define E3 189
#define D3 213
#define C3 238
#define H2 252


void delay(int delay)   // vlastna funkcia, lebo inak je max 16ms
{
	for (int i=1; i <= delay - 2; i++){
		_delay_ms(1);
	}

	OCR0A = O0;						// malinka pauza za kazkou notou melodie 
    for (int i=1; i <= 2; i++){		// ... ked za sebou idu dve rovnake noty aby nezneli
	  _delay_ms(1);					// ako jedna spojita
	}
}

void InitTimer0(){
  DDRD   |= (1 << PD6);            // port D.6 pin ako vystup
  
  TCCR0A = 0b01000010;
  TCCR0B = 0b00000100;
  
  OCR0A = 70;
  
}

void InitTimer1(){
	DDRB   |= (1 << PB1);            // port D.9 pin ako vystup
  
	TCCR1A = 0b01000000;
	TCCR1B = 0b00001100;			// preddelicka 256
	
	OCR1A = 70;
  
}

void InitTimer2(){
 DDRB   |= (1 << PB3);            // port D.11 pin ako vystup
  
  TCCR2A = 0b01000010;
  TCCR2B = 0b00000110;
  
  OCR2A = 70;
  
}

void speaker0(vyska_tonu0){
	OCR0A = vyska_tonu0;
}

void speaker1(vyska_tonu1){
	OCR1A = vyska_tonu1;
	TCNT1 = 0x00;					// resetovanie pocitadla T1 aby nesekalo
}

void speaker2(vyska_tonu2){
	OCR2A = vyska_tonu2;
}


int main(void)
{	
	InitTimer0();
	InitTimer1();
	InitTimer2();

	int tempo = 250;
		
	while(1){
		//	------------------------ Happy birthday ------------------------ //
		
		// 1 takt
		speaker0(G4);	speaker1(O0); speaker2(O0);			delay(tempo);			// ha-
		speaker0(G4);										delay(tempo);			// -ppy
		speaker0(A4);	speaker1(G3); speaker2(C3);			delay(tempo*2);			// Birth-
		speaker0(G4);										delay(tempo*2);			// -day
		
		// 2 takt
		speaker0(C5);	speaker1(O0); speaker2(O0);			delay(tempo*2);			// to
		speaker0(H4);	speaker1(G3); speaker2(H2);			delay(tempo*4);			// you
	
		// 3 takt
		speaker0(G4);	speaker1(O0); speaker2(O0);			delay(tempo);			// ha-
		speaker0(G4);										delay(tempo);			// -ppy
		speaker0(A4);	speaker1(G3); speaker2(H2);			delay(tempo*2);			// Birth-
		speaker0(G4);										delay(tempo*2);			// -day
		
		// 4 takt
		speaker0(D5);	speaker1(O0); speaker2(O0);			delay(tempo*2);			// to
		speaker0(C5);	speaker1(G3); speaker2(C3);			delay(tempo*4);			// you
		
		 // 5 takt
		speaker0(G4);	speaker1(O0); speaker2(O0);			delay(tempo);			// ha-
		speaker0(G4);										delay(tempo);			// -ppy
		speaker0(G5);	speaker1(C4); speaker2(E3);			delay(tempo*2);			// Birth-
		speaker0(E5);										delay(tempo*2);			// -day
		
		// 6 takt
		speaker0(C5);	speaker1(O0); speaker2(O0);			delay(tempo*2);			// dear
		speaker0(H4);	speaker1(C4); speaker2(F3);			delay(tempo*2);			// Ji-
		speaker0(A4);										delay(tempo*2);			// -mmy
		
		// 7 takt
		speaker0(F5);	speaker1(O0); speaker2(O0);			delay(tempo);			// Ha-
		speaker0(F5);										delay(tempo);			// -ppy
		speaker0(E5);	speaker1(C4); speaker2(E3);			delay(tempo*2);			// birth-
		speaker0(C5);										delay(tempo*2);			// -day
		
		// 8 takt
		speaker0(D5);	speaker1(G3); speaker2(D3);			delay(tempo*2);			// to
		speaker0(C5);	speaker1(G3); speaker2(C3);			delay(tempo*4);			// you
		
	}


}

Pridajte sem aj zbalený kompletný projekt, napríklad takto (použite jednoznačné pomenovanie, nemôžeme mať na serveri 10x zdrojaky.zip:

Zdrojový kód: zdrojaky.zip


Overenie

Na používanie našej aplikácie stačia dve tlačítka a postup používania je opísaný v sekcii popis riešenia. Na konci uvádzame fotku záverečnej obrazovky pred resetom. Vypísaný je tu priemerný čas a najlepší čas.

Aplikácia.

Video:

Kľúčové slová 'Category', ktoré sú na konci stránky nemeňte.