Fyzikální kabinet FyzKAB

Testujeme Arduino Multi-function Shield (Funduino)

1. VÝSTUPY

1.1. Signalizační LED

Ukážeme si, jak rozsvítit a zhasnout čtveřici signalizačních LED a též, jak lze jejich svit regulovat pomocí tzv. pulzní šířkové modulace (PWM).

1.1.1. Blikáme

Funkčnost signalizačních LED si vyzkoušíme pravidelným cyklickým blikáním (1 s LED svítí, 1 s budou LED zhasnuté).

Kód:
char ledPin1 = 10;              // LED na pinu 10
char ledPin2 = 11;              // LED na pinu 11
char ledPin3 = 12;              // LED na pinu 12
char ledPin4 = 13;              // LED na pinu 13

void setup()
{
      pinMode(ledPin1, OUTPUT);
      pinMode(ledPin2, OUTPUT);
      pinMode(ledPin3, OUTPUT);
      pinMode(ledPin4, OUTPUT);    // nastaveni vystupu
}

void loop()
{
      digitalWrite(ledPin1, LOW);       // rozsvit LED 1
      digitalWrite(ledPin2, LOW);       // rozsvit LED 2
      digitalWrite(ledPin3, LOW);       // rozsvit LED 3
      digitalWrite(ledPin4, LOW);       // rozsvit LED 4

      delay(1000); // cekej 1s

      digitalWrite(ledPin1, HIGH);      // zhasni LED 1
      digitalWrite(ledPin2, HIGH);      // zhasni LED 2
      digitalWrite(ledPin3, HIGH);      // zhasni LED 3
      digitalWrite(ledPin4, HIGH);      // zhasni LED 4

      delay(1000); // cekej 1s
}
Popis:

Signalizační LED jsou na shieldu připojeny na výstupy 10 – 13. V první části programu si tyto čísla nastavíme do proměnných ledPin1 – ledPin4. Typ proměnné byte znamená, že se jedná o jedno bytovou proměnou s rozsahem hodnot (0-255). To nám stačí. Možná je i volba int (integer), ale ta by zbytečně alokovala v paměti dvojnásobek místa.

V části setup nastavíme piny, ke kterým jsou připojeny signalizační LED, do režimu výstup.

Následná smyčka loop vždy rozsvítí všechny LED (hodnota LOW), vteřinu počká (1000 milisekund) a pak je zhasne (hodnota HIGH). To vše se cyklicky opakuje v sekci loop.

1.1.2. Postupné rozsvěcení (PWM - „analogový“ výstup)

Výstupní piny 10 a 11 podporují pulzní šířkovou modulaci (tzv. PWM), což je jakási digitální „náhražka“ analogového signálu. Ta v praxi funguje tak, že se rychle střídá napětí 0 V a 5 V na daném výstupu. Podle poměru časů, ve kterých je nastaveno na výstupu +5 V a 0 V, se pak odvíjí intenzita svícení zvolené LED diody.

Kód:
byte ledPin1 = 13;              // LED D1 - pin13 PWM regulace jen pro LEONARDO pro UNO bude binarni
byte ledPin2 = 12;              // LED D2 - pin12 PWM nepodporuje - bude binarni
byte ledPin3 = 11;              // LED D3 - pin11 PWM regulace
byte ledPin4 = 10;              // LED D4 - pin10 PWM regulace

void setup()
{
      pinMode(ledPin1, OUTPUT);
      pinMode(ledPin2, OUTPUT);
      pinMode(ledPin3, OUTPUT);
      pinMode(ledPin4, OUTPUT);    // nastaveni vystupu
}

void loop()
{
      for (int i = 255; i > 0; i--)
      {
             analogWrite(ledPin1, i); // rozsvit LED D1 - intenzita dle hodnoty promenne i
             analogWrite(ledPin2, i); // totez pro LED D2
             analogWrite(ledPin3, i); // totez pro LED D3
             analogWrite(ledPin4, i); // totez pro LED D4
             delay(100);              // cekej 100 ms
      }
delay(1000);        // cekej 1 s, pak znova
}
Popis:

Opět nastavíme piny 10-13, na kterých jsou připojeny signalizační LED, na stav výstupu (proměnné pinLED1-4 a blok setup).

V části loop postupně cyklem odesíláme na jednotlivé výstupy hodnoty od 255 (zcela zhasnuto) až 0 (plné rozsvícení). Každá nastavená hodnota zůstane platná 100 ms, pak je nastavena vyšší svítivost. Regulace je patrná zejména u nižší svítivosti, u vyšších hodnot již lidské oko jen velmi těžko pozná rozdíl ve světelné intenzitě.

Po „proběhnutí“ všech možných 256 intenzit, se po vteřinovém čekání vše opakuje od zhasnutí po plný svit.

POZOR, protože jsou LED na shieldu zapojeny tak, že jsou rozsvíceny při LOW a naopak zhasnuty při HIGH, je i nyní nejvyšší svit při nejnižší výstupní hodnotě.

Pokud máte shield připojený k modulu Arduino LEONARDO, bude se postupně rozsvěcet trojice LED (pin 10, 11 a 13), naopak pin 12 se bude střídat jen ve dvou stavech (svítí × nesvítí – mezní výstupní hodnota změny stavu je 128). Pokud používáte Arduino UNO, budou se postupně rozsvěcet (vliv PWM) pouze diody na pinech 10 a 11. LED na pinech 12 a 13 budou střídat jen žádný a plný svit (PWM není na těchto pinech podporováno).

1.2. Bzučák

Bzučák použitý na shieldu Funduino je pasivní – to znamená, že po připojení napětí nevydává předem zvolený tón, ale musíme si tón vygenerovat. Kupříkladu střídáním stavu HIGH a LOW výstupu 3, ke kterému je bzučák připojen. Druhou možností by mohlo být využití PWM stejně jako v předchozím příkladu u LED. Je ale otázkou, zda tím dosáhneme slyšitelné frekvence (vyzkoušejte to!). My si nejdříve vygenerujeme tón klasickým „přepínacím“ způsobem a pak to zkusíme připravenou funkcí.

1.2.1. Tón klasicky
Kód:
int buzzer = 3;     // pin bzucaku

void setup()
{
      pinMode(buzzer,OUTPUT);       // nastaveni bzucaku na vystup
}

void loop()
{
      for(int i = 0; i < 80; i++) // chvilku jedna frekvence
      {
             digitalWrite(buzzer, HIGH); // nastav HIGH
             delay(2);                   // pockej 2 ms
             digitalWrite(buzzer, LOW);  // nastav LOW
             delay(2);                   // pockej 2 ms
      }

      for(int i = 0; i < 100; i++)      // a ted zase jina frekvence
      {
             digitalWrite(buzzer, HIGH);
             delay(4);
             digitalWrite(buzzer, LOW);
             delay(4);
      }
}
Popis:

Opět nastavíme pin, ke kterému je shieldu připojen bzučák (tj. pin č. 3), na výstup. První cyklus generuje vyšší tón (čekání mezi stavy HIGH a LOW 2 ms), pak se tón změní na hlubší (druhý cyklus - čekání 4 ms).

Upřímně řečeno, ten kdo má hudební sluch možná ví, jaké to jsou tóny.

POZN: U mého shieldu je hlasitost pískání velmi malá – bzučák je slyšet až po přiložení k uchu. (předpokládám, že je to vada mého konkrétního kusu a ne obecný jen – jinak by bzučák byl dosti nepoužitelný)

1.2.2. Funkce Tone(pin, freq, [time])

Funkce Tone() slouží ke generování tónu. Má tři parametry – dva povinné (pin a freq) a jeden nepovinný (time). První z nich udává pin, na kterém je připojen pasivní bzučák (u našeho shieldu to je pin 3), druhý parametr je frekvence generovaného tónu. Nepovinným parametrem je délka tónu v milisekundách.

Hned si řekneme i o existenci funkce noTone(pin), která vypne generovaný tón na daném pinu – např. není-li stanovena délka tónu ve funkci Tone().

Kód:
int buzzer = 3;     // adresa bzucaku

void setup()
{
      pinMode(buzzer, OUTPUT);  // nastaveni bzucaku na vystup
}

void loop()
{
      tone(buzzer, 440);        // nastav komorni A
      delay(1000);               // pockej 1 s
      tone(buzzer, 1000);       // nastav technicke A
      delay(1000);              // pockej 1 s
}
Popis:

Nastavení pinu 3 na výstup je obdobné předchozímu příkladu. Ve smyčce loop pak vidíme velice jednoduchý kód. Nejdříve se nastaví výstupní frekvence 440 Hz, po vteřině se tato frekvence změní na 1 kHz. To vše se neustále opakuje.

1.3. LCD zobrazovače

Multi-function Shield je osazen čtveřicí LED segmentovými zobrazovači, které jsou řízeny dvojicí obvodů 74HC595. Jedná se o registry, do kterých se ukládá rozsvícení/zhasnutí jednotlivých segmentů daného LED zobrazovače a číslo zvoleného zobrazovače. Registry jsou na shieldu zapojeny tak, že zápis do registrů probíhá následujícím způsobem. Zahájí se nastavením výstupního pinu 4 do stavu LOW. Do registrů pak se zapisuje sériově pomocí pinu 8 s hodinovým signálem (taktem) na pinu 7. První osmice bitů volí rozsvícení LED v zobrazovači (POZOR: LOW znamená rozsvítit, HIGH znasnout), druhá osmice volí „adresu“ zvoleného zobrazovače (zajímají nás jen poslední 4 bity daného byte).

Následující obrázek zachycuje, jak odpovídají jednotlivé LED v zobrazovači bitům v bytu registru:

segmety a bity pro zobrazení
Obrázek 1 - rozložení LED v zobrazovači a jejich ovládací bity v řídicím registru
1.3.1. Světe AHOJ

Pro zjednodušení zápisu dat do registrů využijeme funkci shiftOut(dataPin, clockPin, bitOrder, data). Tato funkce má čtyři parametry: První dataPin je číslo pinu, na který budou odesílaná sériová data (v našem případě pin 8). Druhý clockPin je pin, na kterém bude generován hodinový signál (takt) pro zápis (u nás pin 7). Třetí bitOrder udává směr odesílaných bitů ze zadaného byte (konstanta MSBFIRST – nejvyšší bit jako první; opakem je konstanta LSBFIRST). Čtvrtým parametrem je samotná hodnota, která bude odeslána – my budeme hodnoty v kódu zapisovat v binární podobě, aby bylo patrné, které LED v zobrazovači chceme rozsvítit.

Budeme chtít na čtveřici zobrazovačů zobrazit nápis AHOJ. Znamená to tedy zapsat na první zobrazovač (počítáno zleva) písmeno A, na druhý H atd. Jakmile však zapíšeme do společného registru hodnoty pro druhý zobrazovač (tj. písmeno H), první zobrazovač pochopitelně zhasne (registr nyní rozsvěcí druhý zobrazovač) Stejně tomu bude při zápisu třetího a čtvrtého znaku. Musíme tedy jednotlivá písmena zobrazovat neustále dokola a to tak rychle, aby lidské oko nepostřehlo přeblikávání.

Kód:
int latchPin = 4;
int clockPin = 7;
int dataPin = 8; // data pro segmentovky

void setup()
{
      pinMode(latchPin,OUTPUT);
      pinMode(clockPin,OUTPUT);
      pinMode(dataPin,OUTPUT); // nastaveni vystupu pro segmentovky
}

void loop()

{
      digitalWrite(latchPin,LOW);                      // start zapisu
      shiftOut(dataPin,clockPin,MSBFIRST,B10001000);   // zobrazeni znaku A
      shiftOut(dataPin,clockPin,MSBFIRST,B00000001);   // adresa 1. segmentovky
      digitalWrite(latchPin,HIGH);                     // konec zapis - data jdou na vystup
      delay(5);

      digitalWrite(latchPin,LOW);
      shiftOut(dataPin,clockPin,MSBFIRST,B10001001);   // H
      shiftOut(dataPin,clockPin,MSBFIRST,B00000010);   // adresa 2. segmentovky
      digitalWrite(latchPin,HIGH);
      delay(5);

      digitalWrite(latchPin,LOW);
      shiftOut(dataPin,clockPin,MSBFIRST,B11000000);   // O
      shiftOut(dataPin,clockPin,MSBFIRST,B00000100);   // adresa 3. segmentovky
      digitalWrite(latchPin,HIGH);
      delay(5);

      digitalWrite(latchPin,LOW);
      shiftOut(dataPin,clockPin,MSBFIRST,B11100001);   // J
      shiftOut(dataPin,clockPin,MSBFIRST,B00001000);   // adresa 4. segmentovky
      digitalWrite(latchPin,HIGH);
      delay(5);
}
Popis:

Nastavení pinů 4, 7 a 8 pro výstup je pro nás již standardním postupem. Podíváme se na čtveřici odstavců v bloku loop. Každý nastavuje právě jeden zobrazovač. Přesně, jak bylo popsáno výše, dojde k nastavení pinu 4 do stavu LOW – registr je připraven pro zápis. Poté funkce shiftOut „nasype“ bity pro jednotlivé LED zobrazovače. Pro názornost ukázky je použit binární odeslané hodnoty. Např. pro písmeno A: První bit je desetinná tečka (viz obr. 1), tu chceme zhasnout – nastavena na 1, další je střední vodorovná LED, tu ve znaku A chceme rozsvítit – nastavíme na 0. Třetí je levá horní LED – chceme rozsvítit… atd… až dojdeme k binární hodnotě 10001000. V kódu ji zapíšeme jako B10001000 (aby překladač věděl, že jde o binární hodnotu).

Druhé použití funkce shiftOut určí číslo zobrazovače, pro který jsou data platné – nejnižší bit 1. zobrazovač, druhý bit = 2. zobrazovač atd.).

K zobrazení hodnoty dojde až po nastavení pinu 4 na LOW. Až nyní dojde v registru k prokopírování dat ze vstupu na výstupy.

Obdobně je tomu pro zbylé zobrazení znaky.

Tip: Zkuste zvýšit čekání mezi jednotlivými bloky pro zobrazení znaků kupříkladu na hodnotu 500 ms. Rázem se ze statického nápisu AHOJ, stanou postupně blikající a posouvající se znaky A, H, O, J. Taky hezké, ne?




2. VSTUPY

Multi-funkční Shield je pochopitelně osazen i vstupy. Nejdříve se podíváme na vstupy analogové, které ale občas použijeme i trochu „digitálně“. Nakonec si některé digitální piny nastavíme jako čistě digitální vstupy a třeba připojíme i nějakou jednoduchou „periférii“ (IR dioda, sonarové čidlo…), která však již není součástí zde popisovaného multifunkčního shieldu.

2.1. Trimr na A0

Na multifunkčním shieldu nalezneme i víceotáčkový trimr, pomocí kterého můžeme měnit vstupní napětí na jednom z analogových vstupů – zde konkrétně na vstupu A0.

Otázkou je, jak můžeme ověřit, že modul Arduino patřičnou analogovou hodnotu načetl. Ukážeme si dva příklady. V tom prvním se kromě načítání vstupní hodnoty seznámíme i s možností modulu Arduino odesílat data do PC prostřednictvím sériového portu (USB portu). V druhém příkladu si z modulu Arduino a připojeného Multi-function Shieldu vytvoříme jednoduchý digitální voltmetr.

2.1.1. Načítání A0, komunikace přes sériový port

Hodnoty odeslané do PC (připojené přes sériový port, či USB) budeme sledovat přes „Seriový Monitor“ (menu Nástroje) v prostředí určeném pro programování modulu Arduino (viz obr. 2).

Arduino - serial monitor
Obrázek 2 - Serial Monitor: zobrazení hodnot zaslaných modulem Arduino prostřednictvím sériového portu


Při otáčení trimrem uvidíme, jak se nám postupně zobrazují postupně se měnící načtené hodnoty na pinu A0.

Kód:
#define Pot A0       // nastaveni vstupu pro trimr
int PotBuffer = 0;   // hodnota na vstupu

void setup()
{
      Serial.begin(9600);   // nastaveni seriove komunkace
}

void loop()
{
      PotBuffer = analogRead(Pot);   // nacitej A/D prevodnik na A0 (trimrt)
      Serial.print("Pot = ");        // odesli do PC text: 'Pot ='
      Serial.println(PotBuffer);     // odesli hodnotu PotBuffer a pak odradkuj
      delay(500);                    // pockej 500 ms
}
Popis:

Abychom poznali i něco nového z jazyka Wiring, ve kterém se píše kód pro moduly Arduino, máme zde v uvedeném kódu hned několik „novinek“:

Hned tu první najdeme na prvním řádku. Výraz #define dělá to, že při překladu zamění dva následující výrazy – tedy narazí-li na výraz Pot, dosadí za něj konstantu A0 (tj. označení pro vstup A0, na kterém je připojen trimr). POZOR: #define ve skutečnosti není příkazem jazyka Wiring (např. jako deklarace konstanty), ale je vlastností překladače. Ten při překladu programu „podstrkává“ za výraz Pot konstantu A0. Z hlediska programu (uloženém v modulu Arduino) žádná konstanta Pot neexistuje.

Druhou novinkou je řízení komunikace modulu Arduino přes sériový port (popř. USB port, který sériový port emuluje). Funkce Serial.begin() se používá k zahájení sériové komunikace. Do závorek se píše parametr rychlosti této komunikace. Nejčastěji se používá hodnota 9600 (odpovídá počtu přenosů za sekundu). Funkce Serial.begin() se většinou volá v části setup.

Pro odeslání hodnoty do PC (či jiného zařízení) použijeme funkci Serial.print() nebo Serial.println(), která navíc na konci odeslaných dat přidá znak pro zalomení řádku.

Třetí novinkou je fakt, že blok setup vůbec neobsahuje deklaraci toho, že pin A0 má být nastaven jako analogový vstup. Přesto, když kód přeložíte, vše bude fungovat, jak má. Jak je to tedy možné? Některé piny mají svou roli tak trochu předurčenou a tak ji nemusíme (ale můžeme!) uvádět. Případem takového pinu je analogový pin A0 – pokud jej tedy budeme využívat, tak jak je předurčeno, nemusíme to v bloku setup uvádět. Ale když tak učiníte, nic tím nezkazíte!

Samotný princip načítání hodnoty na trimru (pinu A0) je jednoduchý. Program se točí ve smyčce loop, kdy pomocí funkce analogRead() načte napětí (0-5 V)* na pinu A0 do proměnné PotBuffer (hodnoty: 0-1024). Hodnota je pak sériovou linkou odeslána v podobě řetězce ‘Pot = ×××ב (kde ×××× je hodnota proměnné PotBuffer).


* Hodnota (0-5 V) referenčního napětí lze programově změnit, ale zatím se tím nebudeme zabývat!

2.1.2. Jednoduchý voltmetr

Tento příklad již není jen pouhým otestováním vstupního trimru multifunkčního shieldu, ale trochu nám ukazuje, že už jsme se naučili docela prima věci!

Pomocí trimru budeme nastavovat napětí na vstupu A0, které budeme zobrazovat na čtyřech LED zobrazovačích. Chcete-li z multifunkčního shieldu udělat skutečný voltmetr (s rozsahem 0-5 V), změňte jen v #define na první řádce A0 na A4 a na pin A4 (dostupný na konektoru pro teplotní čidlo LM35) připojte požadované měřené napětí.

Kód:
#define Pot A0                    // nastaveni vstupu pro trimr
int latchPin = 4;
int clockPin =7;
int dataPin = 8; // nastaveni pro LED zobrazovac

unsigned char Dis_table[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};  // definice cisel 0-10
unsigned char Dis_buf[]   = {0xF1,0xF2,0xF4,0xF8};  // adresy LED zobrazovacu
unsigned char disbuff[]  =  {0, 0, 0, 0};           // pole odesilanych hodnot na LED
int rT=0; // pomocna promena

void setup()
{
      pinMode(latchPin,OUTPUT);
      pinMode(clockPin,OUTPUT);
      pinMode(dataPin,OUTPUT); // nastaveni vystupu pro segmentovku
}

void display()
{
      for(char i = 0; i <= 3; i++) // probene zobrazovace a zobrazi, co je treba
      {
             digitalWrite(latchPin,LOW); // nastavi latch pro zapis
             if(i == 0)
             {
                shiftOut(dataPin,clockPin,MSBFIRST,Dis_table[disbuff[i]]&0x7F); // za prvnim cislem rozsvit i des. tecku
             }
             else
             {
                shiftOut(dataPin,clockPin,MSBFIRST,Dis_table[disbuff[i]]);
             }
             shiftOut(dataPin,clockPin,MSBFIRST,Dis_buf[i] );   // zapise adresu zobrazovace
             digitalWrite(latchPin,HIGH);    // vypni latch
             delay(2);                       // pockej 2 ms
      }
}

void loop()
{
      float vol = analogRead(Pot)*(4.97 / 1023);   // nacte dohnotu z A0 a prevede na Volty
      rT= (int) (vol*1000);      // vyrobi 4-ciferne cislo
      disbuff[0]= rT/1000;       // pocet tisicu na 1 zobrazovac
      disbuff[1]= rT%1000/100;   // pocet stovek na 2 zobrazovac
      disbuff[2]= rT%100/10;     // pocet desitek na 3 zobrazovac
      disbuff[3]= rT%10;         // pocet jednotek na 4 zobrazovac

      for(char time = 0; time < 20; time++)  // zapisovanim stejne hodnoty se to zdrzi a pritom neblikaji zobrazovace
      {
             display();
      }
}
Popis:

S většinou věcí, které jsou použity v tomto kódu, jsme se setkali. Je tu nastavení pinů pro LED zobrazovače, načítání analogového vstupu A0 atd. Za zmínku však stojí ukázka definice vlastní uživatelské procedury/funkce. Konktrétně vytvoření procedury display(). Stejně jako u jiných programovacích jazyků můžeme i v jazyce Wiring části kódu, které se opakovaně používají, „zabalit“ do svého vlastního příkazu. Zde je to obsluha LED zobrazovačů. Začíná deklarací void, pak následuje jméno procedury. Mohly by v závorce následovat parametry. Tělo funkce/procedury je uzavřeno ve složených závorkách.

Druhou novinkou oproti dosud používanému kódu, je použití datové struktury pole – zde jde o předem připravené hodnoty Dis_table pro LED zobrazovače (definice pro číslice 0, 1, 2…9), stejně tak adresy Dis_buf LED zobrazovačů. Poslední použité pole disbuff je složeno ze čtveřice hodnot, které se budou zobrazovat na prvním, druhém… LED zobrazovači.

2.2. Vstupní tlačítka

Začíná to být příliš velká divočina? Zvolníme tedy. Začneme analogové vstupy (konkrétně A1-3) používat pro zjišťování stisknutí tlačítek. Takže vlastně tak trochu „digitálně“.

2.2.1. Načítání A1: Stiskni tlačítko S1

Jak již bylo naznačeno, použijeme analogový vstup A1 pro zjištění jednoho ze dvou stavů tlačítka S1 (zapnuto/vypnuto). Stav zapnutu (stisknuto) je na desce multifunkčního shieldu řešen připojením vstupního pinu k uzemnění. Otevření (nestisknutí) tlačítka má dvě možnosti. Buď je na shieldu zkratována propojka J2 (poblíž tlačítek) – pak je na vstupní pin přes PullUp rezistor přivedeno napětí +5 V, nebo je propojka rozpojena a vstupní pin je „volný“ – není na něj připojena žádná napěťová hodnota (značně neurčitý stav)**. Následující příklad by měl dělat jen to, že po dobu stisknutí tlačítka S1 (pin A1) se rozsvítí LED 1 (pin 13).

Kód:
int ledPin = 13;    // cislo pinu LED 1
int inPin = A1;     // cislo tlacitka S1
int val;            // pomocna promena val

void setup()
{
      pinMode(ledPin, OUTPUT);   // LED jako vystup
      pinMode(inPin, INPUT);     // S1 jako vstup (zkratujte jumper J2 - jinak chybi PullUp rezistor)
}

void loop()
{
      val = digitalRead(inPin);   // nactu vstup
      if (val == LOW)             // pokud je stisknuto PAK
      {
             digitalWrite(ledPin, LOW);   // rozsvit
      }
      else  // JINAK
      {
             digitalWrite(ledPin, HIGH);  // zhasni
      }
}
Popis:

Nastavení pomocných proměnných i konfigurace pinů pro INPUT a OUTPUT je stejné jako u předešlých příkladů, kde jsme četli hodnotu vstupu A0. Načítání analogového vstupu A1 je však prováděno pomocí funkce digitalRead(). Jde o funkci, která dle napětí na vstupu vrací jen dva stavy: buď LOW, nebo HIGH.

A nyní si zkusíme následující věc: Zkuste si funkčnost našeho příkladu a pak rozpojte propojku J2 a zkuste několikrát stisknout S1 znova. A… asi je to rozbité!!! Ne, nebojte, zasuňte propojku zpět a je vše zase O.K. Proč?

Problém je právě ve stavu rozpojeného tlačítka, kdy na vstup A1 není přivedeno žádné definované napětí. Musí se to řešit buď externím PullUp rezistorem, nebo pomocí nastavení modulu Arduino, které si na vstupní pin „umí“ připojit PullUp rezistor svůj vlastní – ale musíme mu to nařídit.

To provedeme při nastavení vstupního pinu v sekci setup. Stačí jen vstupní pin místo typu INPUT změnit na INPUT_PULLUP. Patřičný řádek v bloku setup tedy bude vypadat takto:

pinMode(inPin, INPUT_PULLUP);

A je to! Zkuste nyní rozpojit propojku JP2 a stisknout tlačítko S1. Vše je O.K.

Obdobně je to i s tlačítky S2 (pin A2) a S3 (pin A3). A hned jsme si i vysvětlili, k čemu je propojka (jumper) J2 na desce Multi-function Shield.


** Jak tomu předejít si ukážeme po vyzkoušení následujícího příkladu.

2.2.2. Čítač s nulováním

Nyní si zase s modulu Arduino a Multi-function Shield postavíme jednoduchý čítač. Pomocí jednoho tlačítka (S1) budeme čítat pulzy a pomocí druhého tlačítka (S2) získanou hodnotu vynulujeme. Pochopitelně hodnota „namačkaná“ se bude zobrazovat na LED segmentech. Budiž tento příklad i ukázkou, že jsme nákupem Multi-function Shield neutratili své peníze zas tak úplně zbytečně.

Kód:
int latchPin = 4;
int clockPin =7;
int dataPin = 8;              // pro zobrazovace
int KEY_Count = A1;
int KEY_Reset = A2;           // tlacitka
unsigned char Dis_table[] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0X80,0X90}; // data pro zobrazovace
unsigned char Dis_buf[]   = {0xF1,0xF2,0xF4,0xF8};
unsigned char disbuff[]  =  {0, 0, 0, 0};
int rT = 0;               // pomocna promenna

void setup(void)
{
  pinMode(latchPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(dataPin, OUTPUT);      // nastaveni pro zobrazovace
  pinMode(KEY_Count, INPUT);     // citaci tlacitko
  pinMode(KEY_Reset, INPUT);     // tlacitko RESET
}

void display(void)
{
    for(char i = 0; i <= 3; i++)    // probehne segmenty a zobrazi hodnoty
  {
    digitalWrite(latchPin, LOW);    // zapis na latch
    shiftOut(dataPin, clockPin, MSBFIRST, Dis_table[disbuff[i]]);   // data pro zobrazovac
    shiftOut(dataPin, clockPin, MSBFIRST, Dis_buf[i] );             // adresa zobrazovace
    digitalWrite(latchPin, HIGH);        // zobraz zapsana data
    delay(2);        // cekej 2 ms
  }
}

void GetKey(void)       // nacitani tlacitek
{
  if(digitalRead(KEY_Count) == LOW)   // je prvni stisknute?
  {
    while( !digitalRead(KEY_Count) ) {display();}   // je stale dole – jen zobrazuj, nic necitej
    rT++;                     // uz je povoleno, tak zapocti
    if (rT>9999) { rT=0; }    // preteklo to hodnotu 9999

    disbuff[0]= rT/1000;      // predelej hodnoty pro zobrazovace
    disbuff[1]= rT%1000/100;
    disbuff[2]= rT%1000%100/10;
    disbuff[3]= rT%1000%100%10;
  }

   if(digitalRead(KEY_Reset) == LOW)    // stisknute nulovani
   {
      while( !digitalRead(KEY_Reset) ) {display();}   // tlacitko dole, cekej az pusti
      rT = 0;                 // vynulovani
      disbuff[0] = rT/1000;   // nova data pro zobrazovac
     disbuff[1] = rT%1000/100;
     disbuff[2] = rT%1000%100/10;
     disbuff[3] = rT%1000%100%10;
   }
}

void loop(void)
{
        display();     // zobrazovani
        GetKey();      // test tlacitek
}
Popis:

Věci kolem zobrazení číslic na LED zobrazovačích jsou zahrnuty v proceduře display, jejíž princip byl již vysvětlen dříve. Zaměříme se tedy na proceduru GetKey, která obsluhuje stisknutí jednotlivých tlačítek. Počáteční podmínka načte a otestuje tlačítko S1 (navyšování počtu kliknutí). Pokud je tlačítko stále stisknuté, zastaví se běh programu v následujícím cyklu while. Hodnota čítané proměnné se tak zvětší až při puštění tlačítka (funkce digitalRead vrátí HIGH). To je proto, aby se počítaly skutečně jednotlivá stisknutí – klidně zkuste tento cyklus vynechat a pak dlouze stisknout tlačítko. A jestliže při stisknutém tlačítku program „uvízne“ v cyklu, stalo by se, že přestanou být obsluhované zobrazovače a po dobu zmáčknutého tlačítka by náhodně svítila jen jedna číslice na čtveřici zobrazovačů. Proto je v tomto cyklu neustále na zobrazovačích zobrazována aktuální hodnota počtu pulzů – procedura display (opět pro pochopení, doporučuji z cyklu tuto proceduru dočasně vynechat a zkusit, co se stane). Projde-li program přes tento cyklus (tj. opět bylo tlačítko puštěno), dojde k navýšení proměnné rT a přepočtení číslic pro zobrazení (pole disbuff[0-3]). Přesáhne-li hodnota rT zobrazitelnou hodnotu 9999, dojde k vynulování této proměnné. Ke stejnému vynulování dojde i při stisknutí druhého tlačítka. Zobrazování číslic na zobrazovačích a test tlačítek se pak opakuje ve smyčce loop.

Závěr (?)

Výše uvedenými příklady jsme si ukázali základní použití, či otestování funkčnosti Arduino Multi-function Shield (též někdy označovaného Funduino).

Pochopitelně to není vše!

Tento shield je připraven pro připojení teplotních čidel (LM35, Dallas 18B20), modulu sonaru (HCSR04), serva či krokového motoru, radiového modulu (APC220). Ovšem tyto moduly a součástky již nejsou součástí běžného dodání modulu Multi-function Shield. Je tedy třeba si je dokoupit. A pak si zase začít „hrát“.

Ale o tom třeba zase někdy příště…

Reklama:
UPOZORNĚNÍ:
Nesouhlasíme s vyřazením Newtonových zákonů, Ohmova zákona a zákona zachování energie z učiva fyziky základních škol v České republice!