V této části kurzu se budeme zabývat rozhraním UART. Jedná se o jednoduché a velmi oblíbené sériové rozhraní. Zejména při komunikaci s počítačem.
Objednejte si sadu prvků a začněte se učit v praxi! Kliknutím sem přejdete do obchodu >>
Jak funguje UART? - Trocha teorie
Jeho funkční princip je založen na sériovém přenosu posloupnosti bitů, které jsou následně spojeny do informace. Jeden rámec (zjednodušeně řečeno: bajt) je přenášen v následujícím tvaru:
Přenos začíná start bitem, který je na obrázku označen BS. Tento bit je vždy logická nula. V závislosti na konfiguraci následuje 7, 8 nebo 9 datových bitů (zde označených jako B0-B7), které představují přenášené informace. Stop bit (zde označený jako BK bit) je bit, který je logickou jedničkou – označuje konec přenosu.
Naštěstí se nemusíme starat o rozdělování dat na bity/byty/snímky. Všechny operace za nás provádí Arduino.
Při použití UART na Arduinu nás zajímají dva piny:
- Tx pro odesílání dat (pin 1 na Arduino),
- Rx pro příjem dat (pin 0 na Arduino).
Aby přenos probíhal správně, musí být na obou čipech nastavena stejná přenosová rychlost – tzv. baud rate. Určuje počet bitů přenesených za sekundu. Obvyklé hodnoty jsou: 9600 a 115200.
Zbývá komunikace přes USB. Tento úkol je bohužel poměrně obtížný. Z tohoto důvodu většina hobbyistů používá převodníky UART <-> USB, které práci značně usnadňují. S Arduino si s tím nemusíte dělat starosti. Takový převodník je již zabudován v naší desce.
Nyní se dostáváme k praktickým příkladům. První dva programy vyžadují POUZE připojení Arduino k počítači přes USB. Teprve později přidáme do našeho obvodu periferní zařízení.
Hotové sady pro kurzy Forbot
U našich prodejců si nyní můžete zakoupit sadu více než 70 elementů potřebných pro cvičení v kurzu!
Populární sada: Arduino Master – Robotics Master
První program Arduino
Úkolem následujícího programu je jednoduše pravidelně odesílat text do počítače:
void setup(){
Serial.begin(9600); //Nastavení přenosové rychlosti
Serial.println("Vítejte na Forbot!"); //Jednorázové odeslání textu
}
void loop() {
delay(5000);
Serial.println("Uplynulo 5 sekund!"); //Odesílání ve smyčce
}
Aktualizace, leden 2016 – Od aktualizace prostředí Arduino IDE se funkce označovaná zde jako Serial Port Monitor nachází pod volbou Serial Monitor. Pokud se v programu zobrazují obě možnosti, vyberte nyní možnost Serial Monitor, druhá možnost bude popsána v části 10.
Je důležité, aby terminál pracoval správnou rychlostí na portu COM, ke kterému je Arduino připojeno! Nastavení rychlosti najdete v pravém dolním rohu terminálu.
Průběh programu v praxi:
Text „Vítejte ve Forbotu!“ se zobrazí pouze jednou, protože jsme ho vložili do funkce nastavení, a jak je vidět z obrázku předchozí části kurzu – pokyny se provedou až po spuštění programu.
Lze také pozorovat funkční přenos lze také pozorovat na LED diodách zabudovaných v Arduino (označené Tx a Rx)! Rozsvítí se, když probíhá přenos dat z/do naší desky.
Domácí úkol 2.1
Zjistěte, co se stane, když v okně terminálu zvolíte jiné rychlosti, než jaké jsou nastaveny v Arduino. Kdy dochází k chybám? Jak se projevují? Jak sami uvidíte, chyby jsou zcela odlišné a je třeba je brát v úvahu.
Interakce s programem
Představme si situaci, ve které Arduino hraje roli kontrolky okna, se speciálním tlačítkem/senzorem připojeným k jeho rámu. Celý mechanismus funguje tak, že při zavřeném okně je tlačítko zkratováno na zem, jinak je obvod přerušen.
S dříve získanými znalostmi byste mohli napsat program, který při otevření okna rozsvítí barevnou LED diodu. Pokusme se však náš program rozšířit. Arduino vybavíme tlačítkem (které imituje senzor v okenním rámu) a dvěma LED diodami (zelenou a červenou).
Když je okno zavřené (stisknuté tlačítko), rozsvítí se zelená LED dioda. Pokud přerušíte obvod (přestanete mačkat tlačítko), musí se rozsvítit červená LED dioda a na terminálu se zobrazí „Pozor! Alarm! Okno není zamčené!
void setup(){
Serial.begin(9600); //Spouštíme vysílání
pinMode(8, OUTPUT); //Výstup červené diody
pinMode(9, OUTPUT); //Výstup zelené diody
pinMode(10, INPUT_PULLUP); //Tlačítko
digitalWrite(8, LOW); //Vypnutí obou diod LED
digitalWrite(9, LOW);
}
void loop() {
if (digitalRead(10) == LOW) { //Pokud je tlačítko stisknuto
digitalWrite(9, HIGH); //Zapnutí zelené diody
digitalWrite(8, LOW); //Vypnutí červené diody
} else { //Pokud tlačítko není stisknuto
digitalWrite(9, LOW); //Vypnutí zelené diody
digitalWrite(8, HIGH); //Zapnutí červené diody
Serial.println("Pozor! Alarm! Okno není zamčené!");
}
}
Podívejme se, jak program funguje! Bohužel není ideální, pokud okno není zavřené, protože informace o alarmu se odesílají trvale. Byli bychom však raději, kdyby byla odeslána pouze jednou. Máte nějaký nápad, jak to změnit? Samozřejmě pomocí smyčky while, kterou jsme používali dříve.
void setup(){
Serial.begin(9600); //Spouštíme vysílání
pinMode(8, OUTPUT); //Výstup červené diody
pinMode(9, OUTPUT); //Výstup zelené diody
pinMode(10, INPUT_PULLUP); //Tlačítko
digitalWrite(8, LOW); //Vypnutí obou diod
digitalWrite(9, LOW);
}
void loop() {
if (digitalRead(10) == LOW) { //Pokud je tlačítko stisknuto
digitalWrite(9, HIGH); //Zapnutí zelené diody
digitalWrite(8, LOW); //Vypnutí červené diody
} else { //Pokud tlačítko není stisknuto
digitalWrite(9, LOW); //Vypnutí zelené diody
digitalWrite(8, HIGH); //Zapnutí červené diody
Serial.println("Pozor! Alarm! Okno není zamčené!");
while (digitalRead(10) == HIGH) {
//Zastavíme se v prázdné smyčce, dokud se okno opět nezavře.
delay(25); //Ve smyčce zavádíme malé zpoždění 25 ms, abychom kompenzovali rušení.
}
}
}
Můžeme výše uvedený kód nějak vylepšit? Zlepšit ne, ale samozřejmě ji můžeme udělat elegantněji.
Pokyn #define
Na pomoc nám přichází direktiva #define. Umožňuje definovat symbol, který se před kompilací nahradí všude v programu. Například:
#define ledPin 8
void setup() {
pinMode(ledPin, OUTPUT); //Konfigurace pinu 8 jako výstupu
}
void loop() {
digitalWrite(ledPin, HIGH); //Zapnutí diody
delay(1000); //Čekání 1 sekundu
digitalWrite(ledPin, LOW); //Vypnutí diody
delay(1000); //Čekání jednu sekundu
}
Vložením řádku na začátek programu: #define ledPin 8, zajistíme, že každý výskyt textu ledPin bude před kompilací převeden na 8. Převedený název může být samozřejmě jiný, důležité je, aby byl jedinečný a pomohl vám při psaní dlouhých programů.
Nezapomeňte!
Za řádky začínající #define nepište středník!
Níže naleznete konečnou, revidovanou verzi našeho okenního alarmu:
#define diodaČervená 8
#define diodaZelená 9
#define senzorOkna 10
void setup(){
Serial.begin(9600); //Spouštíme vysílání
pinMode(diodaČervená, OUTPUT); //Výstup červené diody
pinMode(diodaZelená, OUTPUT); //Výstup zelené diody
pinMode(senzorOkna, INPUT_PULLUP); //Tlačítko
digitalWrite(diodaČervená, LOW); //Vypnutí obou diod
digitalWrite(diodaZelená, LOW);
}
void loop() {
if (digitalRead(senzorOkna) == LOW) { //Pokud je tlačítko stisknuto
digitalWrite(diodaZelená, HIGH); //Zapnutí zelené diody
digitalWrite(diodaČervená, LOW); //Vypnutí červené diody
} else { //Pokud tlačítko není stisknuto
digitalWrite(diodaZelená, LOW); //Vypnutí zelené diody
digitalWrite(diodaČervená, HIGH); //Zapnutí červené diody
Serial.println("Pozor! Alarm! Okno není zamčené!");
while (digitalRead(senzorOkna) == HIGH) {
//Zastavíme se v prázdné smyčce, dokud se okno opět nezavře.
delay(25); //Ve smyčce zavádíme malé zpoždění 25 ms, abychom kompenzovali rušení.
}
}
}
Od nynějška bude změna vývodu, ke kterému připojíme diodu nebo senzor, vyžadovat pouze změnu v jednom bodě programu.
Proměnné nebo "univerzální zásuvky"
Přesněji řečeno, mohou to být znaky, slova nebo čísla. Nejčastěji budeme pracovat s číselnými proměnnými. Kdy jsou proměnné nutné? Pokud chceme uložit hodnotu a provádět s ní různé operace. Stejně jako funkce může mít i proměnná specifický typ, který určuje, jaká data může uchovávat.
Zde je seznam nejdůležitějších typů dat:
Maximální hodnoty, které můžeme do proměnné zapsat, závisí na obvodu, který programujeme. Výše uvedené hodnoty jsou uvedeny pro Arduino UNO.
Zvláštní pozornost věnujte proměnným typu long a float.
boolean logika = false; //Boolean - hodnota pravda (true) nebo falsch (false)
int číslo = 30000; //Int - celková čísla v rozsahu -32,768 až 32,767 (v Arduino Uno)
long velkeČíslo = 2000000; //Long - celková čísla v rozsahu -2 147 483 648 až 2 147 483 647
float čísloProměnné = 6.28; //Float - reálná čísla zabírající v paměti 4 bajty.
char znak = 'a'; //Char - ukládá jeden znak
String věta = "Vítejte na Forbot!"; //String - řádek znaků
- boolean
- int
- string
Proměnná Int je nejčastěji používanou proměnnou pro ukládání celých čísel. Může sloužit k ukládání informací, například kolikrát bylo stisknuto tlačítko, kolikrát byla spuštěna událost nebo údaje ze snímače vzdálenosti (tomu se budeme věnovat na konci kurzu). S proměnnými lze samozřejmě provádět i matematické operace – více v praktických příkladech.
String, je řetězec, takže zjednodušeně řečeno, do proměnných tohoto typu můžeme ukládat text. Slova, věty, zprávy.
Proměnné v praxi
Název každé proměnné začíná písmenem. Číslice nesmí být na začátku. Každé prohlášení musí být učiněno následujícím způsobem:
Typ název = 0;
//nebo
Typ název;
Všimněte si, že operátor = se používá k přiřazení hodnoty proměnné a že operátor == slouží ke kontrole, zda se výraz (proměnná) rovná hodnotě.
Proměnné mají vlastnost zvanou scope. Pokud je proměnná umístěna ve funkci, proceduře nebo podprogramu, není v jiném podprogramu viditelná (nemůžeme ji použít). Několik příkladů:
int Proměnna = 0; //Globální proměnná - viditelná všude v programu
void setup() {
int Proměnna2 = 0; //Lokální proměnná - viditelná pouze ve funkci setup()
}
void loop() {
int Proměnna3 = 0; //Lokální proměnná - viditelná pouze ve funkci loop()
}
Je tu ještě jedna velmi důležitá věc – pojmenování proměnných. Nezapomeňte dát proměnným názvy, které označují jejich účel. Takže například místo od:
string xx = "Damian"; //Proměnná ukládající jméno
měla by být vytvořena proměnná:
string jméno = "Damian"; //Proměnná ukládající jméno
Problém může nastat, pokud je účel proměnné složitější. Nebojte se však názvů, jako jsou např.:
int rychlostLevehoMotoru = 100; //Rychlost levého motoru
Nejdůležitější je, aby byl program čitelný.
Názvy proměnných samozřejmě nesmí obsahovat mezery!
Použití proměnných - čítače
Teorii máme za sebou – nyní je čas na praxi. Začněme něčím velmi jednoduchým. Nejprve necháme náš program v každé smyčce vypsat hodnotu proměnné, kterou chceme zvýšit.
int čítač = 0; //Deklarace proměnné
void setup() {
Serial.begin(9600); //Inicializace připojení PC
}
void loop() {
Serial.println(čítač); //Odeslání hodnoty proměnné čítač
čítač = čítač + 1; //Zvýšení čítače o 1
delay(100); //Zpoždění pro zviditelnění efektu
}
Deklarace globální proměnné je samozřejmě na samém začátku. To znamená, že k nim můžeme přistupovat odkudkoli z programu. Následně se převodovka spustí jako obvykle. Naše hlavní smyčka loop() provede 3 akce.
- Přistupujeme k paměťovému místu, které jsme deklarovali jako proměnnou čítače, a poté odešleme hodnotu, kterou jsme tam našli, prostřednictvím UART.
- Aktuální hodnotu proměnné čítače zvýšíme o 1.
- Počkáme 100 ms (pro lepší efekt) a vrátíme se na začátek smyčky.
Bod 2, tj. zvýšení počtu proměnných, může vyžadovat vysvětlení. Používá se následující zápis:
čítač + čítač + 1; //Zvýšení čítače o 1
Z matematického hlediska, kde znaménko „=“ znamená rovnost, by výše uvedený řádek neměl fungovat. V programování však znaménko „=“ znamená přiřazení. V praxi by se výše uvedený kód měl chápat jako následující operace:
- Převezměte hodnotu proměnné čítače,
- přidat 1,
- uložit výslednou hodnotu do proměnné čítače.
Nahrajte program do Arduina a zkontrolujte, zda funguje správně. Abyste viděli účinky, musíte samozřejmě spustit monitor na sériovém rozhraní (terminálu).
Domácí úkol 2.2
Co se stane, když deklaraci proměnné čítače přesuneme do smyčky loop()?
Domácí úkol 2.3
Jak již bylo zmíněno, proměnné mají svá omezení. Změňte deklaraci proměnné čítače z int na byte, která může obsahovat čísla v rozsahu 0-255. Co se stane, pokud je tato hodnota překročena? Pozorně sledujte zobrazené výsledky!
Obousměrný přenos pomocí Arduino
Úkolem prvního programu bude „naslouchat“ našemu jménu. Po odeslání by nás Arduino mělo přivítat zprávou „Hello name!“, přičemž se samozřejmě vloží dříve odeslané jméno.
Nejprve deklarujeme proměnnou přijatáData, do které se zkopíruje řetězec přijatých znaků. Seznámíme se s novou funkcí: Serial.available(). Tato funkce vrací počet bajtů, které byly přijaty a čekají na zpracování přes Arduino.
Pokud jsou data k dispozici (více než 0), zapíší se do proměnné přijatáData. K tomu slouží funkce Serial.readStringUntil(terminator), která kopíruje data z vyrovnávací paměti, dokud nenastane ukončovací znak (v tomto případě „\n“ – tj. přerušení řádku).
String prijataData = ""; //Prázdný řádek přijatých dat
void setup() {
Serial.begin(9600); //Zahájení komunikace
}
void loop() {
if(Serial.available() > 0) { //Přijalo Arduino data
prijataData = Serial.readStringUntil('\n'); //Pokud ano, přečtěte je až po znak konce řádku a uložte je do proměnné receivedData.
Serial.println("Ahoj" + prijataData + "!"); //Zobrazte zprávu
}
}
Interakce s obvodem - ovládání diod přes UART
K ovládání LED diod využijeme možnost posílání textu do Arduino. Za tímto účelem připojte dvě diody podle obrázku níže (diody na pinech 8 a 9).
Úkolem našeho programu je rozsvítit zelenou nebo červenou LED diodu na 1 sekundu, když je do Arduino odeslán příslušný příkaz. Hotový program vypadá takto:
#define zelená 8
#define červená 9
String prijataData = ""; //Prázdný řádek přijatých dat
void setup() {
Serial.begin(9600); //Zahájení komunikace
pinMode(zelená, OUTPUT); //Konfigurace výstupu
pinMode(červená, OUTPUT);
digitalWrite(zelená, LOW); //Vypnutí diod
digitalWrite(červená, LOW);
}
void loop() {
if(Serial.available() > 0) { //Přijato Arduino data
//Pokud ano, přečtěte je až po znak konce řádku a uložte je do proměnné prijataData
prijataData = Serial.readStringUntil('\n');
if (prijataData == "zelená") { //Pokud příjato slovo "zelená"
digitalWrite(zelená, HIGH); //To zapne zelenou diodu
delay(1000);
digitalWrite(zelená, LOW);
}
if (prijataData == "červená") { //Pokud příjato slovo "červená"
digitalWrite(červená, HIGH); // To zapne červenou diodu
delay(1000);
digitalWrite(červená, LOW);
}
}
}
Nyní si rozebereme, jak program funguje. Na začátku jsou definována čísla pinů LED diod a je deklarována proměnná, do které se kopírují přijatá data. Poté ve smyčce zkontrolujeme, zda Arduino data přijalo. Pokud ano, zkontrolujeme, zda tento údaj odpovídá jedné z barev. Následně se zapnou příslušné diody.
Aby výše uvedený program fungoval, musí být odeslány znaky konce řádku, které lze automaticky připojit k zadanému řetězci znaků. Za tímto účelem vyberte příslušnou možnost z rozevírací nabídky v monitoru sériového rozhraní.
Domácí úkol 2.4
Přepracujte výše uvedený program tak, aby v případě nesprávné barvy odeslal prostřednictvím terminálu odpovídající zprávu.
Domácí úkol 2.5*
Obtížnější úkol s hvězdičkou. Napište program, který v okamžiku, kdy je diodě vyslána barva, změní její stav na opačný. Když je dioda zapnutá, je vypnutá a naopak. Tip: Nezapomeňte použít další proměnné typu bool pro uložení aktuálního stavu LED diod.
Shrnutí
Nezapomeňte, že kompletní sada potřebná pro všechna cvičení je k dispozici u společnosti Botland. Zakoupením souprav podpoříte budoucí vydání kurzu Forbot!
Proměnné je programovací prvek, který se bude objevovat stále a opakovaně! UART budeme také často používat k zobrazení shromážděných informací a ke změně nastavení našeho programu. Bude také velmi užitečný při hledání chyb v našich kódech!
Objednejte si sadu prvků a začněte se učit v praxi! Kliknutím sem přejdete do obchodu >>