Prehrávač melódie s ovládaním: Rozdiel medzi revíziami
Zo stránky SensorWiki
| Riadok 62: | Riadok 62: | ||
<tabs> | <tabs> | ||
<tab name="AVR C-code"><syntaxhighlight lang="c++" style="background: LightYellow;"> | <tab name="AVR C-code"><syntaxhighlight lang="c++" style="background: LightYellow;"> | ||
#define F_CPU 16000000UL | |||
#include <avr/io.h> | #include <avr/io.h> | ||
#include <util/delay.h> | |||
#define C5 59 | |||
#define D5 52 | |||
#define E5 46 | |||
#define F5 44 | |||
#define G5 39 | |||
#define A5 35 | |||
#define H5 31 | |||
#define C6 29 | |||
#define D6 26 | |||
#define E6 23 | |||
#define G6 19 | |||
// Melódie | |||
int s0_t[] = {G5, G5, A5, G5, C6, H5}; | |||
int s0_c[] = {300, 300, 300, 300, 300, 500}; | |||
int s0_len = 6; | |||
int s1_t[] = {C6, D6, E6, G6, E6, D6, C6}; | |||
int s1_c[] = {200, 200, 200, 400, 200, 200, 400}; | |||
int s1_len = 7; | |||
int s2_t[] = {E5, E5, E5, E5, E5, E5, E5, G5, C5, D5, E5}; | |||
int s2_c[] = {200, 200, 400, 200, 200, 400, 200, 200, 200, 200, 600}; | |||
int s2_len = 11; | |||
// Premenné | |||
int aktualna_pesnicka = 0; | |||
int aktualny_ton = 0; // Index tónu, v ktorom sme prestali | |||
int hra_sa = 1; // Po zapnutí Arduina rovno hrá | |||
void hraj_ton(int hodnota, int trvanie) { | |||
if (hodnota == 0 || hra_sa == 0) { | |||
TCCR0A &= ~(1 << COM0A0); | |||
} else { | |||
OCR0A = hodnota; | |||
TCCR0A |= (1 << COM0A0); | |||
} | |||
// Čakanie s kontrolou tlačidiel | |||
for (int i = 0; i < trvanie / 10; i++) { | |||
_delay_ms(10); | |||
// Kontrola tlačidla STOP | |||
if (!(PIND & (1 << PD2))) { hra_sa = 0; break; } | |||
// Kontrola tlačidla PLAY | |||
if (!(PIND & (1 << PD3))) { hra_sa = 1; break; } | |||
// Kontrola tlačidla NEXT | |||
if (!(PIND & (1 << PD4))) { | |||
_delay_ms(200); // debounce | |||
aktualna_pesnicka = (aktualna_pesnicka + 1) % 3; | |||
aktualny_ton = 0; // Pri NEXT hráme novú melódiu od začiatku | |||
break; | |||
} | |||
} | |||
TCCR0A &= ~(1 << COM0A0); | |||
_delay_ms(20); | |||
} | |||
int main(void) { | |||
DDRD |= (1 << PD6); | |||
DDRD &= ~((1 << PD2) | (1 << PD3) | (1 << PD4)); | |||
PORTD |= (1 << PD2) | (1 << PD3) | (1 << PD4); | |||
TCCR0A = (1 << WGM01); | |||
TCCR0B = (1 << CS02); | |||
while (1) { | |||
// Kontrola Play tlačidla, ak sme v stave STOP | |||
if (!(PIND & (1 << PD3))) { | |||
_delay_ms(50); | |||
hra_sa = 1; | |||
} | |||
if (hra_sa == 1) { | |||
// Výber pesničky a prehratie jedného tónu na pozícii 'aktualny_ton' | |||
if (aktualna_pesnicka == 0) { | |||
hraj_ton(s0_t[aktualny_ton], s0_c[aktualny_ton]); | |||
aktualny_ton = (aktualny_ton + 1) % s0_len; // Posun na ďalší tón | |||
} | |||
else if (aktualna_pesnicka == 1) { | |||
hraj_ton(s1_t[aktualny_ton], s1_c[aktualny_ton]); | |||
aktualny_ton = (aktualny_ton + 1) % s1_len; | |||
} | |||
else if (aktualna_pesnicka == 2) { | |||
hraj_ton(s2_t[aktualny_ton], s2_c[aktualny_ton]); | |||
aktualny_ton = (aktualny_ton + 1) % s2_len; | |||
} | |||
} else { | |||
// Ak nehrá, odpojíme bzučiak a len čakáme na Play/Next | |||
TCCR0A &= ~(1 << COM0A0); | |||
// Aj v stop stave vieme prepnúť na Next melódiu | |||
if (!(PIND & (1 << PD4))) { | |||
_delay_ms(300); | |||
aktualna_pesnicka = (aktualna_pesnicka + 1) % 3; | |||
aktualny_ton = 0; | |||
} | |||
} | |||
} | |||
} | } | ||
Verzia z 08:43, 8. máj 2026
Záverečný projekt predmetu MIPS / LS2026 - Miroslav Klein
Zadanie
Cieľom tohto zadania je realizácia mikropočítačového prehrávača melódií. Toto zadanie vyžaduje kontrolované prehrávanie melódií z poľa, čo znamená že k zariadeniu sú pripojené aj tri tlačidlá Play/Stop/Next pre obsluhu. Zadanie slúži na demonštráciu práce s časovačmi, generovanie signálu a spracovanie vstupov od používateľa.

Literatúra:
Analýza a opis riešenia
Opíšte sem čo a ako ste spravili, ak treba, doplňte obrázkami... Podrobne opíšte použité komponenty (okrem základnej dosky s ATmega328P procesorom), pridajte linky na datasheety alebo opis obvodu.
Pre správnu funkciu je nutné použiť pasívny bzučiak (reproduktor bez vlastného oscilátora). Aktívny bzučiak obsahuje vlastný generátor frekvencie a neumožňuje riadenie výšky tónu z mikrokontroléra. Pasívny bzučiak vyžaduje sériový rezistor na obmedzenie prúdu cez výstupný pin mikrokontroléra.

Nezabudnite doplniť schému zapojenia! V texte by ste mali opísať základné veci zo zapojenia, samotná schéma nie je dostačujúci opis.

Algoritmus a program
Algoritmus programu využíva toto a toto, základné funkcie sú takéto a voláma ich tuto...
Projekt je realizovaný na vývojovej doske Arduino Uno s mikrokontrolérom ATmega328P. Mikrokontrolér pracuje s frekvenciou 16 MHz, čo je definované makrom F_CPU 16000000UL na začiatku programu. Táto hodnota je kľúčová pre všetky časové výpočty v projekte, najmä pre generovanie zvukových frekvencií a oneskorenia.
Pre generovanie hudobných tónov sa využíva 8-bitový časovač Timer0 v režime CTC. Tento režim je nastavený bitom WGM01 v registri TCCR0A (WGM01=1, WGM00=0). V CTC režime sa časovač TCNT0 zvyšuje každý takt hodinového signálu po aplikácii preddeličky. Keď hodnota časovača dosiahne hodnotu uloženú v registri OCR0A, dôjde k zhode, časovač sa automaticky vynuluje a zároveň sa môže vykonať akcia na výstupnom pine PD6.
Preddelička: V registri TCCR0B je nastavený bit CS02, čo znamená preddeličku 256. Timer0 sa teda zvyšuje každých 256 taktov CPU.
Výstupný pin a signál: Výstupný pin je PD6. Bit COM0A0 v registri TCCR0A zapína režim toggle – pri každej zhode sa logická úroveň pinu PD6 prepne (z 0 na 1 alebo z 1 na 0). Tým sa generuje obdĺžnikový signál s presnou frekvenciou určenou hodnotou OCR0A.
Štruktúra melódií Každá melódia je definovaná pomocou troch premenných – dvoch polí a jednej konštanty: Pole sX_t[] obsahuje hodnoty OCR0A, ktoré určujú výšku jednotlivých tónov Pole sX_c[] obsahuje trvanie jednotlivých tónov v milisekundách Premenná sX_len udáva celkový počet tónov v melódii Táto štruktúra umožňuje jednoduché pridávanie nových melódií bez nutnosti zásahu do hlavného algoritmu prehrávania. V projekte sú definované tri melódie: s0, s1 a s2.
Pre ovládanie prehrávača slúžia tri tlačidlá pripojené na port D mikrokontroléra. V programe sú zapnuté interné pull-up rezistory príkazom PORTD |= (1 << PD2) | (1 << PD3) | (1 << PD4). Bez stlačenia tlačidla sú piny vďaka pull-upu v stave HIGH (5V). Stlačením tlačidla sa pin pripojí k zemi (GND) a program detekuje stav LOW.
Funkcia hraj_ton(int hodnota, int trvanie) realizuje tri kľúčové úlohy. 1. Nastavenie frekvencie a zapnutie výstupu: Ak je parameter hodnota nenulový a prehrávanie je povolené, nastaví sa register OCR0A na požadovanú hodnotu a zapne sa toggle mód na pine PD6. Ak je hodnota nulová alebo prehrávanie je zastavené, výstup sa vypne. 2. Čakanie s kontrolou tlačidiel: Namiesto jedného dlhého oneskorenia sa používa cyklus s krokmi 10 ms. Celkové trvanie tónu sa rozdelí na intervaly po 10 ms, pričom v každom kroku sa skontroluje stav tlačidiel. 3. Debouncing a detekcia tlačidiel: V cykle sa kontroluje stav tlačidiel STOP, PLAY a NEXT. Pri detekcii stlačenia sa vykoná príslušná akcia Výpis kódu je nižšie...
#define F_CPU 16000000UL
#include <avr/io.h>
#include <util/delay.h>
#define C5 59
#define D5 52
#define E5 46
#define F5 44
#define G5 39
#define A5 35
#define H5 31
#define C6 29
#define D6 26
#define E6 23
#define G6 19
// Melódie
int s0_t[] = {G5, G5, A5, G5, C6, H5};
int s0_c[] = {300, 300, 300, 300, 300, 500};
int s0_len = 6;
int s1_t[] = {C6, D6, E6, G6, E6, D6, C6};
int s1_c[] = {200, 200, 200, 400, 200, 200, 400};
int s1_len = 7;
int s2_t[] = {E5, E5, E5, E5, E5, E5, E5, G5, C5, D5, E5};
int s2_c[] = {200, 200, 400, 200, 200, 400, 200, 200, 200, 200, 600};
int s2_len = 11;
// Premenné
int aktualna_pesnicka = 0;
int aktualny_ton = 0; // Index tónu, v ktorom sme prestali
int hra_sa = 1; // Po zapnutí Arduina rovno hrá
void hraj_ton(int hodnota, int trvanie) {
if (hodnota == 0 || hra_sa == 0) {
TCCR0A &= ~(1 << COM0A0);
} else {
OCR0A = hodnota;
TCCR0A |= (1 << COM0A0);
}
// Čakanie s kontrolou tlačidiel
for (int i = 0; i < trvanie / 10; i++) {
_delay_ms(10);
// Kontrola tlačidla STOP
if (!(PIND & (1 << PD2))) { hra_sa = 0; break; }
// Kontrola tlačidla PLAY
if (!(PIND & (1 << PD3))) { hra_sa = 1; break; }
// Kontrola tlačidla NEXT
if (!(PIND & (1 << PD4))) {
_delay_ms(200); // debounce
aktualna_pesnicka = (aktualna_pesnicka + 1) % 3;
aktualny_ton = 0; // Pri NEXT hráme novú melódiu od začiatku
break;
}
}
TCCR0A &= ~(1 << COM0A0);
_delay_ms(20);
}
int main(void) {
DDRD |= (1 << PD6);
DDRD &= ~((1 << PD2) | (1 << PD3) | (1 << PD4));
PORTD |= (1 << PD2) | (1 << PD3) | (1 << PD4);
TCCR0A = (1 << WGM01);
TCCR0B = (1 << CS02);
while (1) {
// Kontrola Play tlačidla, ak sme v stave STOP
if (!(PIND & (1 << PD3))) {
_delay_ms(50);
hra_sa = 1;
}
if (hra_sa == 1) {
// Výber pesničky a prehratie jedného tónu na pozícii 'aktualny_ton'
if (aktualna_pesnicka == 0) {
hraj_ton(s0_t[aktualny_ton], s0_c[aktualny_ton]);
aktualny_ton = (aktualny_ton + 1) % s0_len; // Posun na ďalší tón
}
else if (aktualna_pesnicka == 1) {
hraj_ton(s1_t[aktualny_ton], s1_c[aktualny_ton]);
aktualny_ton = (aktualny_ton + 1) % s1_len;
}
else if (aktualna_pesnicka == 2) {
hraj_ton(s2_t[aktualny_ton], s2_c[aktualny_ton]);
aktualny_ton = (aktualny_ton + 1) % s2_len;
}
} else {
// Ak nehrá, odpojíme bzučiak a len čakáme na Play/Next
TCCR0A &= ~(1 << COM0A0);
// Aj v stop stave vieme prepnúť na Next melódiu
if (!(PIND & (1 << PD4))) {
_delay_ms(300);
aktualna_pesnicka = (aktualna_pesnicka + 1) % 3;
aktualny_ton = 0;
}
}
}
}
#include <avr/io.h>
void adc_init(void); // A/D converter initialization
unsigned int adc_read(char a_pin);
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
Ako ste overili funkciu, napríklad... 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 hotového zariadenia.

Video:
Čo by som urobil inak
Zamyslite sa spätne nad problémom, ktorý ste riešili a napíšte, čo sa vám nepodarilo a nabudúce by ste spravili inak.
Kľúčové slová 'Category', ktoré sú na konci stránky nemeňte.