Lekce 10 - Tvorba vlastní Arduino knihovny - Třída
V předešlém cvičení, Řešené úlohy k 8.-9. lekci programovacího jazyka Arduina, jsme si procvičili nabyté zkušenosti z předchozích lekcí.
V tomto tutoriálu programovacího jazyka pro Arduino prozkoumáme základy objektově orientovaného programování v praxi. Vytvoříme třídu pro blikání LED diodou. Třídu pak díky vytvoření více instancí můžeme používat opakovaně. Právě znovupoužitelnost kódu je jednou z výhod OOP. Vykročíme tím ke tvorbě vlastní knihovny.
Objektově orientované programování
Objektově orientované programování zkráceně OOP v sobě nese základní myšlenku pohlížet na části programu jako na skutečně existující objekty. Daleko lépe se s nimi pracuje, protože obvykle odpovídají reálným objektům, které přes Arduino ovládáme (LED dioda, robotické rameno a tak dále).
Třída
Objekt určitého typu tvoříme tak, že si prvně definujeme tzv. třídu. Ta dovoluje vytvořit objekt, který se vyznačuje svým specifickým chováním a obsahuje své vlastní atributy. Navíc má i svou jedinečnou identitu. Výhodu tohoto přístupu si ukážeme na následujícím programu.
Blikačka bez třídy
Vytvoříme si funkci pro blikání se všemi třemi použitelnými LED
diodami zapojenými na desce Arduina (RX
, TX
a
L
). Nebudeme tedy potřebovat žádné schéma zapojení ani
nepájivé pole, postačí jen deska libovolného Arduina.
Kód programu je následující:
bool stav; long posledniZmena; void blikej(int pin, int interval) { if ((millis() - posledniZmena) > interval) { stav = !stav; posledniZmena = millis(); } digitalWrite(pin, stav); } void setup() { pinMode(0, OUTPUT); pinMode(1, OUTPUT); pinMode(13, OUTPUT); } void loop() { blikej(0, 125); blikej(1, 250); blikej(13, 500); }
Kód využívá funkci millis()
. Ta se od funkce
delay()
(známé z předchozích lekcí) liší tím, že se jedná
o čítač milisekund od spuštění programu, nikoliv o pauzu.
Program má blikat hned třemi LED diodami, a to každou v jiném intervalu. Aby mohly být intervaly úplně různé, každá dioda si podle aktuálního času a posledního času změny stavu zjistí, zda se má nebo nemá změnit její stav.
Vidíme, že diody na desce se chovají dosti nestabilně. Problém je v tom,
že pro všechna volání této funkce je použita vždy stejná proměnná
posledniZmena
. Ostatní volání této funkce jsou tedy
zdržované. Takhle by to nešlo.
Problém bychom určitě mohli vyřešit i bez objektů, např. vytvořit samostatnou proměnnou pro každou ledku zvlášť, či případně dát LED diody do pole. My si dnes ovšem ukážeme objektové řešení.
Třída Blikacka
Použitím třídy vytvoříme tři samostatné objekty, jeden pro každou z
LED diod, se svými vlastními proměnnými. Nejprve si deklarujeme třídu
Blikacka
. Pomocí této třídy definujeme, jaké vlastnosti (a
schopnosti) budou mít budoucí objekty blikačky.
Třída je tedy vzor, podle kterého pak lze vytvořit libovolné množství objektů, kterým říkáme instance třídy. Všechny instance budou mít ty samé proměnné a funkce, které definuje třída. Každý objekt v nich ale bude mít své vlastní hodnoty.
Deklarace metod a atributů třídy
Kód třídy bude zatím následující:
class Blikacka { public: Blikacka(int pin); void blikej(int interval); void neblikej(); private: int pin; bool stav = false; long posledniZmena; };
Za složeným blokem ohraničujícím třídu se skutečně píše středník!
Třídě jsme deklarovali několik funkcí a proměnných. Těm se nyní terminologicky správně říká metody a atributy. Patří daným instancím třídy, blikačkám, které podle třídy jako vzoru vytvoříme.
První metoda bez datového typu, Blikacka()
, je tzv.
konstruktor. Zavolá se automaticky hned po
vytvoření konkrétní nové blikačky. Konstruktor slouží k inicializaci
hodnoty atributů.
Kód metod třídy
Následně po deklaraci třídy doplníme jednotlivé metody a konstruktor
prostřednictvím kvalifikátoru "čtyřtečky" ::
(neboli
operátoru příslušnosti).
Pod deklarací této třídy program pokračuje:
Blikacka::Blikacka(int pin) { if (pin < 0 || pin > 13) pin = 13; this->pin = pin; pinMode(pin,OUTPUT); // Již nemusíme provádět inicializaci ve funkci setup() } // Metoda pro blikání LEDkou void Blikacka::blikej(int interval) { if (interval <= 0) interval = 250; if ((millis() - posledniZmena ) > interval) { stav = !stav; posledniZmena = millis(); } digitalWrite(pin,stav); } // Metoda pro přerušení blikání void Blikacka::neblikej() { digitalWrite(pin,LOW); } // Vytvoření tří instancí Blikacka X(0); Blikacka Y(1); Blikacka Z(13); void setup() { } void loop() { X.blikej(125); Y.blikej(250); Z.blikej(500); }
Metody jsou doplněny podmínkami pro omezení rozsahu užitých pinů
Arduina (0
- 13
, uvažujme základní Arduino Nano či
Uno) a intervalu - interval 0
ms a menší nedává dobrý
smysl.
Zde si všimněme několika dalších (pro nás zatím nových) výrazů.
Výraz this
a operátor
->
Jako první je výraz this->pin = pin
. Tímto říkáme
programu, že do atributu instance třídy s názvem pin
(v
privátní části) přiřadíme hodnotu parametru pin
z
konstruktoru Blikacka()
. Právě pomocí this
od sebe
odlišíme, která proměnná pin
patří které instanci. Výraz
this
je ukazatel na instanci samotnou, proto vše označené tímto
ukazatelem je vždy součástí instance.
U Arduino programů se běžně užívají pro odlišení duplicitních
názvů podtržítka. V tomto případě by tedy tento atribut pak měl tvar
_pin
. Tato praktika je sice běžná, avšak více se
upřednostňuje varianta s ukazatelem this
, která je
přehlednější. A vzhledem k tomu, že jde o ukazatel, má i tzv.
ukazatelový selektor (->
). Se selektorem se
setkáváme běžně, avšak jako s operátorem tečka (například při tisku
na sériový monitor jsme používali metodu Serial.println())
.
Případné zájemce o více informací ohledně ukazatele this
odkážeme na lekci v programovacím jazyce C++.
Modifikátory přístupu
Dalším výrazům public
a private
říkáme
modifikátory přístupu (někdy též přístupové úrovně). V podstatě nám
říkají, s čím můžeme mimo třídu pracovat, a co je naopak skryto
uvnitř.
Modifikátorem public
označujeme vše, s čím chceme, aby nám
třída dovolila nějakým způsobem veřejně manipulovat. Například volat
její metody. K takovýmto částem třídy pak přistupujeme pomocí selektoru
tečky. Například pomocí X.blikej()
voláme veřejnou metodu
blikej()
instance X
. Atributy a metody označené
modifikátorem public
nazýváme jako
veřejné.
Je dobrou praktikou označovat všechny atributy jako soukromé a jejich hodnoty měnit pouze prostřednictvím veřejných metod!
Naopak modifikátor přístupu private
označuje vše, co je
skryté, a my k tomu zvenčí nemáme přístup. Tímto modifikátorem se
nejčastěji označují ty atributy a metody, které třída využívá ke své
vlastní činnosti. Například jde o operace, do kterých není vhodné
nějakým způsobem zvenčí zasahovat. O částech třídy označené
modifikátorem private
vždy mluvíme jako o
soukromých částech třídy. K takovýmto atributům nelze
veřejně přistupovat prostřednictvím selektoru. Jejich hodnoty nicméně lze
měnit prostřednictvím veřejných metod. My hodnotu privátního atributu v
tomto případě nastavujeme v konstruktoru. Jedná se o privátní atribut
pin
.
Schválně si vyzkoušejme vypsat hodnotu atributu
posledniZmena
. Kompilátor nám nyní vynadá. Když ale atribut
označíme jako veřejný, při každé iteraci smyčky loop()
nám
bude vypsána hodnota v něm uložená.
Kromě modifikátorů přístupu public
a private
existuje ještě modifikátor protected
. Ten je podobný
privátnímu modifikátoru, avšak lze jej dědit v odvozených třídách. To
je ovšem nad rámec této lekce.
Celý program
Nyní už známe dostatečný objem teorie, abychom si naprogramovali praktickou ukázku včetně nahrání uceleného programu do Arduina:
class Blikacka { public: Blikacka(int pin); void blikej(int interval); void neblikej(); private: int pin; bool stav = false; long posledniZmena ; }; Blikacka::Blikacka(int pin) { if (pin < 0 || pin > 13) pin = 13; this->pin = pin; pinMode(pin,OUTPUT); } // Metoda pro blikání LEDkou void Blikacka::blikej(int interval) { if (interval<= 0) interval = 250; if ((millis() - posledniZmena ) > interval) { stav = !stav; posledniZmena = millis(); } digitalWrite(pin,stav); } // Metoda pro přerušení blikání void Blikacka::neblikej() { digitalWrite(pin,LOW); } // Vytvoření tří instancí Blikacka X(0); Blikacka Y(1); Blikacka Z(13); void setup() { } void loop() { X.blikej(125); Y.blikej(250); Z.blikej(500); }
To už je lepší, že ano? Třída Blikacka
je k dispozici ke
stažení níže.
V příští lekci, Tvorba vlastní Arduino knihovny - Dokončení, si vytvoříme naši plnohodnotnou Arduino knihovnu pro blikání LED.
Měl jsi s čímkoli problém? Stáhni si vzorovou aplikaci níže a porovnej ji se svým projektem, chybu tak snadno najdeš.
Stáhnout
Stažením následujícího souboru souhlasíš s licenčními podmínkami
Staženo 83x (568 B)
Aplikace je včetně zdrojových kódů