UART Metronóm: Rozdiel medzi revíziami
Zo stránky SensorWiki
| (3 medziľahlé úpravy od rovnakého používateľa nie sú zobrazené.) | |||
| Riadok 8: | Riadok 8: | ||
Cieľom projektu je vytvoriť jednoduchý elektronický metronóm riadený mikrokontrolérom AVR. Program komunikuje s používateľom prostredníctvom rozhrania UART, cez ktoré je možné zadať hodnotu BPM (beats per minute/počet úderov za minútu). Zadaná hodnota určuje rýchlosť metronómu. | Cieľom projektu je vytvoriť jednoduchý elektronický metronóm riadený mikrokontrolérom AVR. Program komunikuje s používateľom prostredníctvom rozhrania UART, cez ktoré je možné zadať hodnotu BPM (beats per minute/počet úderov za minútu). Zadaná hodnota určuje rýchlosť metronómu. | ||
[[Obrázok: | [[Obrázok:Normal_metronome_picture.webp|400px|thumb|center]] | ||
| Riadok 75: | Riadok 71: | ||
| | ||
Po uplynutí tohto intervalu sa aktivuje funkcia tick(), ktorá na krátky čas zapne výstup Timer0 a tým vytvorí zvukový impulz na bzučiaku. | |||
| Riadok 267: | Riadok 263: | ||
[[Category:AVR]] [[Category:MIPS]] | [[Category:AVR]] [[Category:MIPS]] | ||
Aktuálna revízia z 23:20, 22. máj 2026
Záverečný projekt predmetu MIPS / LS2026 - Karol Kilian
Zadanie
UART Metronóm
Cieľom projektu je vytvoriť jednoduchý elektronický metronóm riadený mikrokontrolérom AVR. Program komunikuje s používateľom prostredníctvom rozhrania UART, cez ktoré je možné zadať hodnotu BPM (beats per minute/počet úderov za minútu). Zadaná hodnota určuje rýchlosť metronómu.

Analýza a opis riešenia
Projekt bol realizovaný pomocou mikrokontroléra ATmega328P, ktorý zabezpečuje spracovanie vstupných údajov z počítača a generovanie zvukového signálu pre metronóm. Používateľ zadáva hodnotu BPM cez sériovú komunikáciu UART pomocou terminálu v počítači. Program následne vypočíta časový interval medzi jednotlivými údermi a v pravidelných intervaloch aktivuje bzučiak.
Komunikácia medzi počítačom a mikrokontrolérom prebieha pomocou rozhrania UART s prenosovou rýchlosťou 9600 baudov. Používateľ zadá číselnú hodnotu BPM do terminálu a po potvrdení klávesom Enter sa hodnota odošle do mikrokontroléra. Program prijaté znaky uloží do poľa znakov (buffer) a následne ich pomocou funkcie atoi() prevedie na celé číslo. Ak je hodnota v povolenom rozsahu, nastaví sa ako nová hodnota BPM.
Na generovanie zvuku bol použitý hardvérový časovač Timer0 v režime CTC (Clear Timer on Compare Match). Výstup OC0A automaticky prepína svoj stav pri zhode časovača s hodnotou registra OCR0A, čím vzniká obdĺžnikový signál vhodný na ovládanie piezoelektrického bzučiaka. Zvuk metronómu vzniká krátkym zapnutím generovania signálu na približne 50 ms, čím sa vytvorí krátke „tiknutie“.
Čas medzi jednotlivými tiknutiami sa vypočíta podľa vzťahu:
t = 60000/BPM
kde: t je interval medzi údermi v milisekundách, BPM je počet úderov za minútu.
Napríklad pri hodnote 120 BPM bude interval medzi jednotlivými údermi:
t = 60000/120 = 500 ms
Program neustále kontroluje prítomnosť nových dát na UART rozhraní. Táto kontrola je realizovaná neblokujúcim spôsobom pomocou príznaku RXC0 v registri UCSR0A, takže metronóm môže pokračovať v činnosti aj počas čakania na nový vstup od používateľa.
Použité komponenty:
1.Piezoelektrický bzučiak: Piezoelektrický bzučiak slúži na generovanie zvukového signálu metronómu. Je pripojený na výstup OC0A mikrokontroléra (pin PD6). Mikrokontrolér generuje obdĺžnikový signál, ktorý spôsobuje vibrácie piezoelektrického prvku a tým vznik zvuku.
2. Časovač Timer0: Timer0 je 8-bitový hardvérový časovač zabudovaný v mikrokontroléri ATmega328P. V projekte bol použitý na generovanie obdĺžnikového signálu pre bzučiak.
Použité nastavenia:
-režim CTC, -prepínanie výstupu OC0A pri zhode, -prescaler 256.

Schéma zapojenia a opis obvodu
Zapojenie metronómu je založené na mikrokontroléri ATmega328P, ktorý je napájaný napätím +5 V. Napájanie je privedené na piny VCC a AVCC, pričom oba piny sú pripojené na rovnaký zdroj napätia.
Reset pin je pripojený cez pull-up rezistor (10 kΩ) na +5 V, čím sa zabraňuje nechcenému resetovaniu mikrokontroléra.
Zvukový výstup metronómu je realizovaný pomocou piezoelektrického bzučiaka, ktorý je pripojený na pin PD6 (OC0A). Tento pin je riadený hardvérovým časovačom Timer0, ktorý generuje obdĺžnikový signál. Bzučiak je druhým vývodom pripojený na zem (GND).
Komunikácia s počítačom prebieha prostredníctvom rozhrania UART. Piny PD0 (RX) a PD1 (TX) sú pripojené na USB–UART prevodník, ktorý zabezpečuje prenos dát medzi mikrokontrolérom a terminálom v počítači. Používateľ tak môže zadávať hodnotu BPM v reálnom čase.

Algoritmus a program
Algoritmus programu je založený na neustálom cyklickom vykonávaní dvoch hlavných činností: spracovaní vstupu z UART rozhrania a generovaní pravidelného zvukového signálu metronómu.
V prvej časti program kontroluje, či boli prijaté nové dáta cez sériovú komunikáciu UART. Ak je detegovaný prichádzajúci znak, program ho načíta a postupne ukladá do textového bufferu. Po prijatí ukončovacieho znaku (Enter) sa celý reťazec prevedie na celočíselnú hodnotu pomocou funkcie atoi(). Táto hodnota predstavuje nové BPM (beats per minute), ktoré sa následne nastaví ako rýchlosť metronómu.
Druhá časť algoritmu zabezpečuje generovanie rytmických „tikov“. Na základe aktuálnej hodnoty BPM sa vypočíta časový interval medzi jednotlivými údermi podľa vzťahu t = 60000/BPM
Po uplynutí tohto intervalu sa aktivuje funkcia tick(), ktorá na krátky čas zapne výstup Timer0 a tým vytvorí zvukový impulz na bzučiaku.
#define F_CPU 16000000
#define BAUD 9600
#define BAUD_PRESCALE (((F_CPU / (BAUD * 16UL))) - 1) // vypocet pre UART podla datasheetu
#include <util/delay.h>
#include <avr/io.h>
#include "uart.h"
#include <stdio.h>
#include <stdlib.h> // pre atoi() - prevod textu na cislo
// makra na nastavenie a vymazanie bitov
#define set_bit(ADDRESS,BIT) (ADDRESS |= (1<<BIT))
#define clear_bit(ADDRESS,BIT) (ADDRESS &= ~(1<<BIT))
// prepojenie printf a getchar na UART
FILE uart_output = FDEV_SETUP_STREAM(uart_putc, NULL, _FDEV_SETUP_WRITE);
FILE uart_input = FDEV_SETUP_STREAM(NULL, uart_getc, _FDEV_SETUP_READ);
// funkcia na oneskorenie v milisekundach (lebo _delay_ms ma obmedzenie)
void delay_ms(int ms)
{
for (int i = 0; i < ms; i++)
_delay_ms(1);
}
// funkcia ktora vytvori kratky "tick" zvuk
void tick(void)
{
TCCR0A |= (1 << COM0A0); // zapne generovanie signalu na vystupe OC0A
delay_ms(50); // dlzka kliknutia (50 ms)
TCCR0A &= ~(1 << COM0A0); // vypne signal
}
int main(void)
{
uart_init(); // inicializacia UART komunikacie
stdout = &uart_output; // presmerovanie printf na UART
stdin = &uart_input; // presmerovanie getchar z UART
DDRD |= (1 << PD6); // nastavenie pinu PD6 (OC0A) ako vystup
// nastavenie Timer0:
TCCR0A = (1 << COM0A0) | (1 << WGM01); // CTC rezim + toggle vystupu
TCCR0B = (1 << CS02); // prescaler 256
OCR0A = 70; // hodnota pre frekvenciu zvuku
int bpm = 120; // predvolena hodnota beats per minute
char buffer[10]; // pole na ulozenie prijateho cisla ako text
int index = 0; // aktualna pozicia v bufferi
printf("Enter BPM:\n"); // vyzva pre pouzivatela
while (1)
{
// kontrola ci prisli data cez UART (neblokujuca kontrola)
if (UCSR0A & (1 << RXC0)) // ak je prijaty znak
{
char c = getchar(); // nacitanie znaku
// ak bol stlaceny ENTER (koniec vstupu)
if (c == '\r' || c == '\n')
{
buffer[index] = '\0'; // ukoncenie retazca
int new_bpm = atoi(buffer); // prevod textu na cislo
// kontrola ci je hodnota v rozumnom rozsahu
if (new_bpm > 0 && new_bpm < 300)
{
bpm = new_bpm; // nastavenie noveho BPM
printf("BPM set to %d\n", bpm);
}
else
{
printf("Invalid BPM\n"); // chybny vstup
}
index = 0; // reset bufferu pre dalsi vstup
}
else if (index < 9)
{
buffer[index++] = c; // ulozenie znaku do bufferu
}
}
// vypocet intervalu medzi tickmi (v ms)
int interval_ms = 60000 / bpm;
tick(); // prehranie kliknutia
delay_ms(interval_ms - 50); // pockanie do dalsieho ticku
}
}
#ifndef UART_H_
#define UART_H_
void uart_init( void );
void uart_putc( char c );
void uart_puts( const char *s );
char uart_getc( void );
#endif /* UART_H_ */
#define F_CPU 16000000
#define BAUD 9600
#include <avr/io.h>
#include "uart.h"
#include <util/setbaud.h>
void uart_init( void )
{
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
#if USE_2X
UCSR0A |= _BV(U2X0);
#else
UCSR0A &= ~(_BV(U2X0));
#endif
UCSR0C = _BV(UCSZ01) | _BV(UCSZ00); /* 8-bit data */
UCSR0B = _BV(RXEN0) | _BV(TXEN0); /* Enable RX and TX */
}
void uart_putc(char c)
{
if (c == '\n')
{
uart_putc('\r');
}
loop_until_bit_is_set(UCSR0A, UDRE0); /* Wait until data register empty. */
UDR0 = c;
}
void uart_puts(const char *s)
{
/* toto je vasa uloha */
}
char uart_getc(void) {
loop_until_bit_is_set(UCSR0A, RXC0); /* Wait until data exists. */
return UDR0;
}
Zdrojový kód: Projekt_metronom_Kilian.zip
Overenie
Funkčnosť programu bola overená praktickým testovaním v reálnych podmienkach. Používateľ zadával rôzne hodnoty BPM prostredníctvom UART rozhrania v sériovom termináli a následne bola kontrolovaná správnosť generovaného rytmu.
Overenie prebiehalo tak, že po zadaní konkrétnej hodnoty BPM (napr. 60, 120, 180) bol čas medzi jednotlivými „tikmi“ meraný pomocou stopiek. Namerané hodnoty boli následne porovnané s teoretickými intervalmi.
Týmto spôsobom bola overená správna funkcia výpočtu časovania aj samotného generovania signálu.
Pri testovaní sa zároveň overilo, že zmena BPM počas behu programu sa okamžite prejaví na rýchlosti metronómu bez nutnosti reštartu zariadenia. Program sa správal stabilne aj pri opakovaných zmenách vstupnej hodnoty.
Okrem bežných hodnôt bolo vykonané aj testovanie krajných a nesprávnych vstupov. Boli skúšané veľmi nízke hodnoty (napr. 1–10 BPM) a aj vyššie hodnoty (napr. 200–250 BPM), pri ktorých metronóm pracoval na hranici použiteľnosti. V prípade neplatného vstupu (napr. nulová hodnota, záporné číslo alebo nečíselný vstup) program správne reagoval vypísaním hlásenia „Invalid BPM“ do sériového terminálu a hodnota BPM nebola zmenená.
Na používanie aplikácie je potrebný iba sériový terminál v počítači a základné pripojenie zariadenia, pričom celý proces ovládania je realizovaný zadaním číselnej hodnoty BPM.

Video:
Čo by som urobil inak
Pri spätnej analýze riešeného problému sa ukázalo, že základná funkčnosť metronómu a UART komunikácie funguje správne. Napriek tomu sa počas práce objavil menší problém v spôsobe komunikácie s používateľom v sériovom termináli.
Program priebežne vypisuje text „Enter BPM:“ do terminálu, čo spôsobuje, že pri zadávaní hodnoty BPM nie je vždy prehľadne viditeľný samotný vstup používateľa. Terminál je tak čiastočne zahltený opakovanými výpismi, čo znižuje komfort ovládania.
V budúcej verzii by bolo vhodné upraviť spôsob práce s terminálom tak, aby sa výpisy zobrazovali prehľadnejšie, napríklad formou jednoduchšieho textového menu alebo jednorazovej výzvy na zadanie hodnoty BPM bez opakovaného vypisovania. Tým by sa zvýšila čitateľnosť a používateľská prívetivosť celej aplikácie.