Před čtením se ujistěte, že znáte základy popsané v předchozích částech našeho bezplatného kurzu Arduino!
Objednejte si sadu prvků a začněte se učit v praxi! Kliknutím sem přejdete do obchodu >>
Zobrazení čísel v terminálu
Ve třetí části kurzu jsme ke komunikaci s počítačem použili rozhraní UART. Tam jsme používali funkce pro odesílání a přijímání informací. Tehdy jsem však neprobíral všechny možnosti, které zdánlivě jednoduchá funkce println nabízí. V dosavadních příkladech byl použit ve své nejjednodušší podobě, tj. s jediným argumentem – číslem nebo znakovým řetězcem, který se má odeslat.
Informace viditelné na terminálu jsou čitelné pro člověka, protože Arduino je převádí na kódy ASCII. Sudá čísla se odesílají jako text.
Všechny odeslané hodnoty v úlohách, které jsme provedli, jsme zobrazili v desetinném tvaru. Co kdybychom například chtěli reprezentovat čísla ve formátu binárním? Musíme vytvářet vlastní funkce pro převod reprezentace hodnot do jiných systémů? Ne!
Na tomto místě je vhodné připomenout, že počítače používají především binární soustavu, takže jakákoli jiná soustava (včetně naší, desítkové) je uměle vynucená.
Knihovny Arduino naštěstí obsahují řadu nástrojů pro koncové uživatele. To zahrnuje podporu různých systémů zobrazování čísel. Pokud odešleme hodnotu pomocí println, můžeme rozhodnout, jak se má zobrazit na počítači:
[...]
int číslo = 2345;
Serial.println(číslo); //Zobrazení v desítkové soustavě
Serial.println(číslo, DEC); //Zobrazení v desítkové soustavě
Serial.println(číslo, HEX); //Zobrazení v hexadecimální soustavě
Serial.println(číslo, OCT); //Zobrazení v oktalové soustavě
Serial.println(číslo, BIN); //Zobrazení v binární soustavě
[...]
Jak ukázaly pokusy v předchozích částech, čísla se ve výchozím nastavení zobrazují v desítkové soustavě, ale můžete si také vybrat mezi hexadecimální, oktalovou a binární reprezentací. V praxi se bude pravděpodobně nejčastěji používat standardní desítková reprezentace a binární reprezentace.
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
Přesnost čísel s pohyblivou řádovou čárkou
Jak již bylo řečeno v předchozích částech kurzu, je také možné deklarovat proměnnou pro uložení čísla s pohyblivou řádovou čárkou, např. 3.141592: 3.141592 Takovými příklady jsme se zatím nezabývali, protože se ukázalo, že je dobré se na mikrokontrolérech vyhýbat číslům s desetinnými místy.
Takové operace jsou pro počítače poměrně náročné a vyžadují více času.
Předpokládejme však, že takové číslo chceme bezpodmínečně zobrazit. K tomu lze použít následující velmi krátký program:
void setup() {
float čísloPI = 3.1415; //Deklarace proměnné
Serial.begin(9600); //Inicializace UART
Serial.println(čísloPI, 4); //4 místa za desetinnou čárkou
Serial.println(čísloPI, 0); //0 míst za desetinnou čárkou
Serial.println(PI); //Hádanka
}
void loop() {
}
Spuštění výše uvedeného programu by mělo mít následující účinky:
Jak vidíte, při přenosu čísla může být dalším parametrem číslice, která určuje přesnost, s jakou mají být hodnoty zobrazeny. Je důležité si uvědomit, že proměnné typu float se zobrazují až se 7 číslicemi – bez ohledu na to, kolik číslic je za nebo před desetinnou čárkou. Například:
- float number1 = 0.123456 – správně
- float number2 = 12345.6 – správně
- float number3 = 123,456 – správně
- float number4 = 1234567.8 – false
Pro vyšší přesnost (15 číslic) použijte dvojité proměnné!
Vraťme se krátce k výše zmíněnému programu, zejména k záhadné linii:
Serial.println(PI); //Hádanka
Proč je výsledkem tohoto příkazu hodnota 3,14? Takovou proměnnou jsme nikde nedeklarovali. Hodnota čísla Pí se používá tak často, že v mnoha jazycích existují hotové konstanty, které se číslu Pí také přibližují. V tomto případě se jedná o PI, které je někde v programu převedeno na odpovídající hodnotu.
Ale POZOR: můžete se zde vystavit velmi vážným rizikům!
Pokud například usilujeme o vysokou přesnost našeho programu, můžeme vyvolat tuto funkci:
Serial.print(PI, 25);
K naší radosti se pak na displeji zobrazí velmi přesná hodnota:
3.1415927410125732421875
Pokud se však vrátíme zpět do paměti k maximální přesnosti, kterou nabízejí mikrokontroléry, ukáže se, že konstanta PI má vlastnosti proměnné typu float, tj. potřebuje pouze 7 číslic! Více než to je špatně, protože nejpřesnější reprezentace hodnot s plovoucí desetinnou čárkou ve dvojkové soustavě neumožňuje získat odpovídající „pravé Pí“. Více informací najdete v této speciální kalkulačce.
Následující složení je naše zobrazené číslo a skutečné číslo Pí:
3.14159274101257324218750
3.14159265358979323846264
Výše uvedené příklady ukazují, že byste se měli vyhnout číslům s pohyblivou desetinnou čárkou, kdykoli je to možné (v 99 % případů se bez jejich pomoci obejdete). Pokud je přesto používáme, pak se zdravým rozumem a s vědomím jejich omezené přesnosti!
Vše v nové řadě?
Má přesně stejné hodnoty jako dříve používaná funkce println. Jediným rozdílem je, že každá odeslaná hodnota se zobrazí na novém řádku. Příklad:
void setup() {
Serial.begin(9600); //Inicializace UART
}
void loop() {
Serial.print("Vítejte v kurzu na Forbot.com! "); //Zobrazení textu
delay(1000); //Zpoždění pro větší pohodlí
}
Program neohromí svými schopnostmi, ale předvádí to podstatné („žádný nový řádek“):
Jak mohu přepnout na nový řádek na určité pozici? Třemi způsoby:
Serial.print("První řádek");
Serial.println();
Serial.print("Druhý řádek");
NEBO
Serial.println("První řádek");
Serial.print("Druhý řádek");
NEBO
Serial.print("První řádek \n Druhý řádek");
Existují nějaké další užitečné symboly tohoto typu? Ano! Použití tabulátorů (odrážek, širokých mezer) může být stále užitečné pro formátování zobrazeného textu. Chceme-li posunout text doprava, použijeme symbol \t – Tab místo těžkopádného zadávání několika mezer.
Nové informace o UART v praxi
Na začátku je třeba zapojit jednoduchý obvod. Ke změně napětí jsem použil potenciometr. Můžete však také instalovat dělič napětí s fotorezistorem. Pokud si nemůžete vzpomenout, jak to udělat, podívejte se na 4. část kurzu.
Doufám, že vám předchozí informace nezpůsobily příliš mnoho problémů, a proto bych vám chtěl rovnou ukázat hotový program. Samozřejmě byste měli analyzovat, jak to funguje, a napsat podobný program sami!
void setup() {
Serial.begin(9600); //Inicializace UART
}
void loop() {
int potenciometr = analogRead(A5); //Načtení hodnoty ADC
Serial.print("Čtení: ");
Serial.print(potenciometr, DEC);
Serial.print("[DEC]\t");
Serial.print(potenciometr, HEX);
Serial.print("[HEX]\t");
Serial.print(potenciometr, OCT);
Serial.print("[OCT]\t");
Serial.print(potenciometr, BIN);
Serial.print("[BIN]\n");
delay(1000); //Zpoždění pro pohodlí
}
Po spuštění programu byste měli v terminálu vidět pěkně naformátované hodnoty ADC v různých číselných reprezentacích:
Rád bych vás povzbudil, abyste sami experimentovali. Je to také ideální příležitost k procvičení ručního převodu čísel do různých soustav. Tím končí část o UART, je čas pokračovat.
Domácí úkol 6.1
Napište program, který přečte informace ze dvou fotorezistorů a potenciometru. Pokud je následně stisknuto tlačítko připojené k zařízení Arduino, je jednou odeslán řádek s informacemi:
„Fotorezistor 1: XXX, fotorezistor: XXX, potenciometr: XXX, tlačítko stisknuto XX krát“.
Místo X se samozřejmě zobrazí správné hodnoty.
Pokyny pro ovládání přepínače
Pro pochopení příkazu switch použiji příklad, který je pak řešen dvěma způsoby – tradičně a pomocí nové metody. Předpokládejme tedy, že chceme napsat program, který přečte hodnotu ADC a pak nám ji pošle zpět jako desítkové, šestnáctkové, osmičkové nebo dvojkové číslo. Vše záleží na naší volbě.
S našimi současnými znalostmi bychom mohli napsat program, který používá podmínky:
String prijataData = ""; //Prázdný řetězec přijatých dat
void setup() {
Serial.begin(9600); //Inicializace UART
}
void loop() {
int potenciometr = analogRead(A5); //Načtení hodnoty ADC
if(Serial.available() > 0) { //Přijalo Arduino data
prijataData = Serial.readStringUntil('\n'); //Pokud ano, přečtěte je až po značku konce řádku
}
if (prijataData == "d") {
Serial.println(potenciometr, DEC);
} else if (prijataData == "h") {
Serial.println(potenciometr, HEX);
} else if (prijataData == "o") {
Serial.println(potenciometr, OCT);
} else if (prijataData == "b") {
Serial.println(potenciometr, BIN);
}
delay(1000); //Zpoždění pro pohodlí
}
Je to proveditelné? Ano. Pohodlné? Průměrné, zvláště pokud by se objevilo více podmínek nebo by se podmínky musely náhle změnit. Nový pokyn k ovládání spínací skříňky je užitečný. Vypadá to takto:
switch (HodnotaDoKontroly) {
case Hodnota_1:
//Kód, který se provede, pokud je splněna podmínka
break;
case Hodnota_2:
//Kód, který se provede, pokud je splněna podmínka
break;
[...]
default:
//Kód, který se provede, pokud není splněna žádná podmínka
break;
}
Na začátku napíšeme klíčové slovo switch a do kulatých závorek uvedeme proměnnou, kterou chceme kontrolovat. V příkladu podobném předchozímu s if by to bylo takto:
switch (prijataData) {
Pokud je podmínka splněna, provede se kód od podmínky až po další slovo break, které celý přepínač ukončí. Pokud podmínka není splněna, část kódu je ignorována a mikrokontrolér pokračuje v kontrole další podmínky (case).
Pro připomenutí!
Příkaz „switch-case“ je velmi užitečný, pokud chcete zkontrolovat, zda jsou hodnoty stejné!
Nakonec můžeme volitelně umístit kód mezi default a break. Tato funkce se provede, pokud není splněna žádná z předchozích podmínek. Vím, že to zní složitě, a proto nyní přejdeme k praktickému příkladu a zrevidujeme předchozí program.
Kromě toho se data načítají místo dříve používané funkce:
prijataData = Serial.readStringUntil('\n');
Používá se jednodušší verze funkce, která čte pouze první bajt (znak) dat:
int prijataData = 0; //Prázdný řetězec přijatých dat
void setup() {
Serial.begin(9600); //Inicializace UART
}
void loop() {
int potenciometr = analogRead(A5); //Načtení hodnoty ADC
if(Serial.available() > 0) { //Přijalo Arduino data
prijataData = Serial.read(); //Pokud ano, přečtěte 1 znak
}
switch (prijataData) {
case 'd':
Serial.println(potenciometr, DEC);
break;
case 'h':
Serial.println(potenciometr, HEX);
break;
case 'o':
Serial.println(potenciometr, OCT);
break;
case 'b':
Serial.println(potenciometr, BIN);
break;
}
delay(1000); //Zpoždění pro pohodlí
}
prijataData = Serial.read(); //Pokud ano, přečtěte 1 znak
To nám umožnilo porovnat odeslané příkazy a provést odpovídající operace. Doufám, že se vám návod na přepínání stane ještě jasnější, až provedeme další praktické příklady.
Domácí úkol 6.2
Vraťte se k domácímu úkolu 2.4, který byl ve třetí části kurzu Arduino a tentokrát jej proveďte pomocí instrukce switch.
Servomechanismus v praxi - Světelný indikátor
Některé hodnoty, jako je teplota, intenzita světla atd., se však lépe zobrazují na tradičních analogových displejích. Tedy ty, které mají ukazatel:
Montážní plán hotového spotřebiče je následující:
Je to trochu složitější, ale ve skutečnosti se skládá ze dvou jednoduchých schémat. První je připojení serva spolu s napájením ze stabilizátoru. Kromě toho se přímo vedle tohoto regulátoru napětí objevují dva kondenzátory. Podobné schéma lze nalézt v předchozí části kurzu Arduino.
Při připojování serva a baterie buďte opatrní, abyste nic nepoškodili!
Druhá část schématu spočívá v propojení rezistoru a fotorezistoru do děliče napětí. Podrobnější informace naleznete v části o ADC v Arduino.
Mechanická část projektu
O „profesionálním“ ciferníku a ručičkách se vyplatí přemýšlet hned. Ciferník jsem vyrobil z několika nalepených vizitek a vytištěné stupnice. Ukazatel byl vyroben podobným způsobem. Ke spojení dílů doporučuji použít horké lepidlo (z pistole) nebo oboustrannou lepicí pásku.
Pokud použijete superlepidlo, hrozí nebezpečí, že se pohyblivé části serva slepí k sobě, což je pak vhodné pouze k vyhození!
Kvalita konstrukce není nejlepší, ale jsou to jen pokusy a důležitý je efekt:
Program je poměrně jednoduchý. Jeho úkolem je cyklicky měřit světlo dopadající na fotorezistor a řídit nastavení serva. K tomu sloužily především již naučené funkce:
#include //Knihovna odpovědná za servopohony
Servo servomechanismus; //Vytvoříme objekt, abychom se mohli na servo odkazovat.
byte pozice = 0; //Aktuální poloha serva 0-180
int predchoziPozice = 0;
void setup() {
servomechanism.attach(11); //Servo připojené na pin 11
Serial.begin(9600);
}
void loop()
{
int cteniSenzoru = analogRead(A5); //Načtení hodnoty ze snímače
pozice = map(cteniSenzoru, 0, 900, 0, 180); //Nahradíme ji polohou serva.
if (abs(pozice-predchoziPozice) > 5) { //Zkontrolujeme, zda se polohy liší o více než 5 stupňů.
servomechanism.write(pozice); //Provedeme krok
predchoziPozice = pozice; //Pamatujeme si aktuální pozici jako předchozí
}
Serial.println(cteniSenzoru); //Odesláme hodnotu do terminálu
delay(300); //Zpoždění pro lepší efekt
}
V tomto programu také ukládáme aktuální polohu serva do globální proměnné PreviousPosition. Tím je zajištěno, že v dalším cyklu smyčky provedeme pohyb pouze v případě, že dojde k velké změně intenzity světla. Jinak by náš ukazatel mohl oscilovat. Doporučuji experimentovat s hodnotou, ze které pohyb provádíme.
Každý by si měl systém kalibrovat podle vlastních podmínek!
(popis níže)
Program je velmi jednoduchý, takže neobsahuje žádné automatické kalibrační mechanismy. Proto posílá aktuální hodnotu snímanou světelným senzorem do počítače prostřednictvím UART. Nejrychlejší kalibrací by mohlo být převzetí nejnižší a nejvyšší hodnoty pozorované při zakrytém a osvětleném senzoru. Ty by pak měly být zohledněny v tomto řádku:
Doporučuji změnit nastavení a vyzkoušet nové programy. Doporučuji však nepohybovat servem příliš rychle. To může vést k problémům nebo poškození relativně citlivého motoru. Doporučuji, abyste v tomto řádku nepřekračovali hodnotu 100 ms:
delay(300); //Zpoždění pro lepší efekt
Domácí úkol 6.3
Zpřesněte obvod pomocí analogového displeje. Zkuste přidat kalibrační mechanismus. Najděte další praktické využití takového obvodu!
Shrnutí
Nezapomeňte, že kompletní sada komponentů potřebných pro všechna cvičení je k dispozici u společnosti Botland. Zakoupením sad podpoříte další vydání kurzu Forbot!
Objednejte si sadu prvků a začněte se učit v praxi! Kliknutím sem přejdete do obchodu >>
Další části kurzu jsou ukázkou používání textového displeje, který je součástí sady.