NOVINKA - Online rekvalifikační kurz Java programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
NOVINKA – Víkendový online kurz Software tester, který tě posune dál. Zjisti, jak na to!

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ů

 

Předchozí článek
Řešené úlohy k 8.-9. lekci programovacího jazyka Arduina
Všechny články v sekci
Arduino - Programovací jazyk
Přeskočit článek
(nedoporučujeme)
Tvorba vlastní Arduino knihovny - Dokončení
Článek pro vás napsal Vašek Doškář
Avatar
Uživatelské hodnocení:
33 hlasů
Autor pracuje jako pedagog v oblasti elektroniky, elektrotechniky a programování. Rád tvoří appky všeho druhu. Má přehled v jazycích C#, Java, Kotlin, Javascript, Python a Rust
Aktivity