Czech English

4. Blikáme LEDkou 2

aneb trocha matematiky nikoho nezabije

Arduino je přeci počítač a ten by měl umět počítat. V dnešní lekci se tedy podíváme na čísla, proměnné a počítání s nimi. Abychom viděli co se uvnitř mikrokontroleru děje, použijeme opět led, ale tentokrát větší počet.



Zapojení

Nejprve si tedy připojíme k arduinu několik led (alespoň 4). Na schématu a v dalším textu budeme předpokládat připojení 7 kusů led na piny 1 - 7.
Zapojení led
Zapojení led


Datové typy (konstanty a proměnné)

Abychom mohli v programu počítat, musíme trochu poznat tzv. datové typy. Stejně jako matematici rozdělují čísla na různé typy - přirozená, celá, zlomky, ..., tak i v počítači se používají různé typy čísel. Dnes si z nich vybereme jen několik:
bool  ... logická hodnota (0/1)
byte  ... nezáporné číslo v rozsahu 8b (0 - 255)
char  ... celé číslo v rozsahu 8b (-128 - 127)
int   ... celé číslo v rozsahu 16b (-32768 - 32767)
long  ... celé číslo v rozsahu 32b (-2^31 - 2^32-1)
V programu používáme konstanty, tj. přímé vyjádření číselné hodnoty, které jsme je již v programu používali. Např. číslo pinu (2), délka časové prodlevy (500), ... Jak už víme, konstantu můžeme zapsat přímo v daném místě programu nebo si zadefinovat symbolické jméno (využitím příkazu preprocesoru), které číselnou hodnotu zastupuje.
#define LED        2
#define TLACITKO   5
Mimo konstant v programu používáme proměnné. Proměnná je vyhrazené místo v paměti mikrokontroleru, na které se odkazujeme jeho jménem (stejně jako existuje proměnná v matematice).
Každou proměnnou musíme tzv. deklarovat (vytvořit) - říci překladači jakého je typu (určuje velikost paměti pro proměnnou) a její jméno. Pojmenování proměnné může být téměř jakékoliv, může obsahovat písmena, číslice a některé další znaky (např. _), nesmí však číslicí začínat. Pozor, stejně jako u klíčových slov, kompilátor rozlišuje malá a velká písmena (proto jména proměnných Pokus a POKUS nejsou stejná).
Příklad deklarace proměnných:
bool Start;         // vytvoření logické proměnné se jménem "Start"
byte i;             // vytvoření číselné proměnné (0 - 255) se jménem "i"
int  x1;            // vytvoření číselné proměnné (16b) se jménem "x1"

Výrazy

Konstanty a proměnné můžeme pomocí matematických operací a funkcí spojovat do výrazů. Výsledkem vyhodnocením výrazu při běhu programu je číslo, proto můžeme matematický výraz použít všude, kde se v programu očekává číselná hodnota.
Základní matematické operace:
+   ... sčítání
-   ... odčítání
*   ... násobení
/   ... dělení
!   ... negace (logická operace 0 -> 1, 1 -> 0)

Přiřazení

Pro vložení požadované hodnoty do proměnné, použijeme přiřazovací příkaz. Na levé straně příkazu je jméno proměnné, to následuje znak = a na pravé straně je konstanta, proměnná nebo libovolný matematický výraz.
x = 10;         // vložení hodnoty 10 do proměnné x
y = x;          // vložení hodnoty proměnné x do proměnné y (opět 10)
z = 2 * x + 3;  // vložení hodnoty výrazu do proměnné z (2*10+3, tj. 23)

Příklad č. 1

Sestavte program pro postupné rozsvětcování a zhasínání led zleva doprava. Po doběhnutí se celý cyklus opakuje ("běžící had"). Každá led svítí vždy 0,5s.

Řešení 1:

Tuto úlohu bychom samozřejmě zvládli i s tím co už jsme se naučili v minulých lekcích. Program by mohl vypadat např. takto:
#define PRODLEVA   500

void setup()
{   
  pinMode(1, OUTPUT);             // nastaveni pinu 1 jako vystup
  pinMode(2, OUTPUT);             // nastaveni pinu 2 jako vystup
  pinMode(3, OUTPUT);             // nastaveni pinu 3 jako vystup
  pinMode(4, OUTPUT);             // nastaveni pinu 4 jako vystup
  pinMode(5, OUTPUT);             // nastaveni pinu 5 jako vystup
  pinMode(6, OUTPUT);             // nastaveni pinu 6 jako vystup
  pinMode(7, OUTPUT);             // nastaveni pinu 7 jako vystup
}

void loop()
{
  digitalWrite(1, HIGH);          // rozsviceni led na pinu 1
  delay(PRODLEVA);                // casova prodleva
  digitalWrite(1, LOW);           // zhasnuti led na pinu 1
  
  digitalWrite(2, HIGH);          // rozsviceni led na pinu 2
  delay(PRODLEVA);                // casova prodleva
  digitalWrite(2, LOW);           // zhasnuti led na pinu 2
  
  digitalWrite(3, HIGH);          // rozsviceni led na pinu 3
  delay(PRODLEVA);                // casova prodleva
  digitalWrite(3, LOW);           // zhasnuti led na pinu 3
  
    .
    .
    
  digitalWrite(7, HIGH);          // rozsviceni led na pinu 7
  delay(PRODLEVA);                // casova prodleva
  digitalWrite(7, LOW);           // zhasnuti led na pinu 7
}

Řešení 2:

Tento program je funkční, ale je už poměrně dlouhý a hlavně pokud budeme chtít udělat nějakou změnu, tak už i méně přehledný.
Můžeme si všimnou, že celý program je tvořen sedmi opakujícími se částmi, které se liší pouze hodnotou pinu, na kterém je připojena led. Místo konstanty zde můžeme použít proměnnou, a tak celý program podstaně zkrátit.
#define PRODLEVA   500

byte i;         // deklarace promenne i (cislo 0 - 255)
            
void setup()
{   
  pinMode(1, OUTPUT);             // nastaveni pinu 1 jako vystup
  pinMode(2, OUTPUT);             // nastaveni pinu 2 jako vystup
  pinMode(3, OUTPUT);             // nastaveni pinu 3 jako vystup
  pinMode(4, OUTPUT);             // nastaveni pinu 4 jako vystup
  pinMode(5, OUTPUT);             // nastaveni pinu 5 jako vystup
  pinMode(6, OUTPUT);             // nastaveni pinu 6 jako vystup
  pinMode(7, OUTPUT);             // nastaveni pinu 7 jako vystup
  
  i = 1;                          // vlozeni hodnoty 1 do promenne x (prvni led)
}

void loop()
{
  digitalWrite(i, HIGH);          // rozsviceni led na pinu i
  delay(PRODLEVA);                // casova prodleva
  digitalWrite(i, LOW);           // zhasnuti led na pinu i

  i = i + 1;                      // zvetseni hodnoty promenne i o 1 (posun na dalsi led)
  if (i == 8) i = 1;              // pokud i je 8, vloz hodnotu 1 (vrat se na prvni led)  
}
Tento program je podstatně kratší. Nyní upravte program tak, aby svítící had běžel opačným směrem. (Nápověda: stačí hodnotu proměnné i snižovat o jedničku a upravit test, kdy je nutné přeskočit znovu na druhou stranu).

Příklad č. 2

Sestavte program pro postupné rozsvětcování a zhasínání led zleva doprava. Po doběhnutí na konec se směr otočí a světélko běží zase zpět, celý cyklus opakuje. Každá led svítí vždy 0,5s.

Řešení 1:

Stačí nepatrně upravit program z předchozí úlohy. Po doběhnutí světla na led 7 musíme začít hodnotu proměnné i snižovat o 1 a po doběhnutí na led 1 opět zvyšovat. Na to použijeme druhou proměnnou, ve které si budeme pamatovat jestli se světlo pohybuje jedním nebo druhým směrem. Program by mohl vypadat např. takto:
#define PRODLEVA   500

byte i;         // deklarace promenne i (cislo 0 - 255)
bool smer;      // deklarace logicke promenne pro urceni smeru pohybu
            
void setup()
{   
  pinMode(1, OUTPUT);             // nastaveni pinu 1 jako vystup
  pinMode(2, OUTPUT);             // nastaveni pinu 2 jako vystup
  pinMode(3, OUTPUT);             // nastaveni pinu 3 jako vystup
  pinMode(4, OUTPUT);             // nastaveni pinu 4 jako vystup
  pinMode(5, OUTPUT);             // nastaveni pinu 5 jako vystup
  pinMode(6, OUTPUT);             // nastaveni pinu 6 jako vystup
  pinMode(7, OUTPUT);             // nastaveni pinu 7 jako vystup
  
  i = 1;                          // vlozeni hodnoty 1 do promenne x (prvni led)
  smer = 1;                       // 1 - pohyb dopredu, 0 - pohyb zpet
}

void loop()
{
  digitalWrite(i, HIGH);          // rozsviceni led na pinu i
  delay(PRODLEVA);                // casova prodleva
  digitalWrite(i, LOW);           // zhasnuti led na pinu i

  if (i == 7) smer = 0;           // pokud i je 7 ~ jsme na konci, nastav smer zpet   
  if (i == 1) smer = 1;           // pokud i je 1 ~ jsme na zacatku, nastav smer vpred   

  if (smer == 1)                  // kdyz pohyb vpred
    i = i + 1;                    // zvetseni hodnoty promenne i o 1
  else                            // jinak (pohyb zpet)
    i = i - 1;                    // zmenseni hodnoty promenne i o 1
}

Řešení 2:

Jde to i trochu elegantněji. Pokud pro sledování směru nepoužijeme logickou proměnnou, ale číselnou (se znaménkem), může ji použít přímo pro změnu honoty proměnné i (tedy čísla led).
#define PRODLEVA   500

byte i;         // deklarace promenne i (cislo 0 - 255)
char smer;      // deklarace číselné promenne pro urceni smeru pohybu
            
void setup()
{   
  pinMode(1, OUTPUT);             // nastaveni pinu 1 jako vystup
  pinMode(2, OUTPUT);             // nastaveni pinu 2 jako vystup
  pinMode(3, OUTPUT);             // nastaveni pinu 3 jako vystup
  pinMode(4, OUTPUT);             // nastaveni pinu 4 jako vystup
  pinMode(5, OUTPUT);             // nastaveni pinu 5 jako vystup
  pinMode(6, OUTPUT);             // nastaveni pinu 6 jako vystup
  pinMode(7, OUTPUT);             // nastaveni pinu 7 jako vystup
  
  i = 1;                          // vlozeni hodnoty 1 do promenne x (prvni led)
  smer = 1;                       // 1 - pohyb dopredu, -1 - pohyb zpet
}

void loop()
{
  digitalWrite(i, HIGH);          // rozsviceni led na pinu i
  delay(PRODLEVA);                // casova prodleva
  digitalWrite(i, LOW);           // zhasnuti led na pinu i

  if (i == 7) smer = -1;          // pokud i je 7 ~ jsme na konci, nastav smer zpet   
  if (i == 1) smer = 1;           // pokud i je 1 ~ jsme na zacatku, nastav smer vpred   

  i = i + smer;                   // uprava hodnoty promenne i
                                  // pokud je smer = 1, hodnota i se zvetsi o 1
                                  // pokud je smer = -1, hodnota i se zmensi o 1
}

Úkoly na samostatnou práci

1. Sestavte program pro běh dvou světýlek proti sobě (jedno běží zleva a druhé zprava). Tedy dva světelní hadi z úlohy 1 proti sobě. Po doběhnutí se celý cyklus opakuje. Každá led svítí vždy 0,5s.
2. Sestavte program pro běh světelného hada z úlohy 1 upravený tak, že nesvítí jen jedna led, ale vždy dvě sousední led (na konci svítí první a poslední led současně).