Cvičenie je zamerané na prácu s vývojovou doskou Arduino. Cvičenie je orientované na základné programovanie mikroprocesora. V rámci cvičenia budú demonštrované spôsoby obsluhy tlačidiel, sériovej linky, analógových a digitálnych vstupov a piezoelektrických akustických meničov. Po osvojení si učiva, študent dokáže realizovať základné zapojenia s využitím vývojovej dosky Arduino, skúšobného poľa a pasívnych elektronických prvkov (rezistor, dióda, a pod.). Študent dokáže napísať jednoduchý zdrojový kód pre obsluhu mikroprocesora Atmega328P.
|
Odporúčaná literatúra a dôležité odkazy[1] KPI-FEI-TUKE: Arduino UNO [2] KPI-FEI-TUKE: Traffic Lights Controlled by Arduino [3] Arduino.cc: Language Reference [4] Unciarobotics.com: Arduino Push Button Debounce using Millis Function |
Ako už bolo na predchádzajúcom cvičení a tiež aj na prednáške, Arduino Uno obsahuje 14 digitálnych pinov zvyčajne označených ako D0 - D13. Tiež bolo povedané, že aj analógové piny A0 - A5, ktoré primárne slúžia ako analógový vstup je možné použiť ako digitálne. Pri práci s digitálnym pinom je potrebné si osvojiť minimálne tieto príkazy:
Je potrebné si uvedomiť, že zle nastavený režim pinMode() môže spôsobiť nesprávne chovanie sa zariadenia a vo špecifických prípadoch aj jeho zničenie!
Nasledujúci príklad simuluje situáciu kedy je Arduino použité na monitorovanie či slučka obvodu nie je prerušená. Napríklad si môžeme predstaviť bezpečnostný snímač na okne či dverách. Ak sú dvere otvorené, tento sa rozpojí a preruší sa kontrolovaný obvod.
Pre pochopenie a správnu prácu s analógovým vstupom je nutné porozumieť tomu ako vlastne tento vstup dokáže merať hodnotu napätia. Nechceme a ani nemôžeme ísť do detailov problematiky, ale určite musíme skonštatovať, že vo vnútri procesora Atmel ATMega328p je integrovaný Analógovo Číslicový Prevodník ( Analog Digital Coverter - ADC). Existuje viacero typov prevodníkov ale v ATMege je takzvaný Successive Approximation Register Analog to Digital Converter (SAR ADC) s rozlíšením 10 bitov. Rozlíšenie 10 bitov znamená, že hodnotu meraného napätia dokáže rozlíšiť na 1023 úrovní. Tomuto procesu sa tiež hovorí kvantizácia, o ktorej sa budete učiť neskôr. Ďalším dôležitým parametrom pri analógovom vstupe je referenčné napätie. Toto napätie môžeme priviesť na pin Aref ale tiež ho na tomto pine môžeme aj namerať. Arduino má toto napätie vnútorne nastavené na +5V ale programovo ho môžeme meniť príkazom analogReference(). Rôzne vývojové dosky majú rôzne možnosti voľby úrovne tohto napätia. Pre Arduino UNO a Nano sú nasledovné: 5V a 1.1V a prípadne ľubovoľná externá hodnota (z rozsahu 0 - 5V) privedená na pin Aref. Pre Arduino Uno hodnotu referenčného napätia nastavíme takto:
Nastavením referenčnej hodnoty určíme v akom rozsahu chceme napätie merať. Toto je napríklad výhodné vtedy ak vieme, že budeme merať hodnoty napätia, ktoré nebudú prevyšovať hodnotu 1.1V. Vtedy je rozumné nastaviť referenciu na 1.1V. Získame tak oveľa presnejšie meranie. Ako už bolo uvedené vyššie. Vieme merať s presnosťou na 10 bitov. To znamená, že najmenšie možné napätie, ktoré vieme zmerať je rovné Aref/1023. Teda pre 1.1V/1023 = 0,0011V a pre 5V to bude 0,0049V.
Ďalej musíme poznamenať, že vnútorné referenčné napätie nemusí byť vždy identické s katalógovou hodnotou. Môže sa trochu líšiť a to môže zásadne ovplyvniť presnosť merania. Preto si pri návrhu zariadenia musíme odmerať skutočnú hodnotu referenčného napätia na pine Aref a vo výpočtoch potom používať túto hodnotu. Na Analógový a referenčný vstup nesmie byť pripojené napätie vyššie ako 5.5V dôjde k jeho zničeniu!
Príklad: Pomocou analógového vstupu A1 odmerajte hodnotu naň pripojeného napätia. Ak toto napätie prevyšuje 3V rozsvieti sa LED dióda pripojená k pinu D13.
void setup() { // Pin 13 bude výstup, lebo na neho pripojíme LED diódu, ktorú potrebujeme napájať pinMode(13, OUTPUT); // Zvolili sme referenčnú hodnotu napätia na +5V analogReference(DEFAULT); // Aby sa inicializovala referenčná hodnota je potrebné urobiť jeden analogRead. // Hodnota nás nezajíma ide len o to, aby sa nastavila referenčná hodnota analogRead(15); } void loop() { float Aref = 5.0; // Hodnotu napätia vo voltoch získame tak že meranú hodnotu z ADC predelíme hodnotou // 1023 a tento výsledok vynásobíme hodnotou Aref. Musí sa to pretypovať na float! // A1 je na pine č. 15, mohla by sa to zapísať aj ako A1. float voltage = (float) Aref*analogRead(15)/1023; if(voltage > 3.0) digitalWrite(13,HIGH); else digitalWrite(13,LOW); } |
Ešte si ukážme príklad kedy sa zvolí vonkajšie referenčné napätie. Referenčné napätie bolo získané pomocou napäťového deliča, ktorý je vyhotovený pomocou potenciometra (pokojne aj 5kohm). V kóde vpravo došlo len k malej zmene. Takto nastavená referenčná hodnota umožňuje merať napätie z rozsahu 0-4V. Vyššie pripojené napätie na analógovom vstupe bude stále vyhodnotené ako 4V. Presnosť merania je teraz približne 0.004V.
Na záver je potrebné poznamenať, že ADC môže zavádzať rôzne nelinearity, offset a tiež šum. Tieto nedostatky sa odstraňujú kalibráciou, ktorá však nie je náplňou predmetu Programovanie.
void setup() { pinMode(13, OUTPUT); // Zvolili sme referenčnú hodnotu napätia z vonkajšieho zdroja analogReference(EXTERNAL); // Aby sa inicializovala referenčná hodnota je potrebné urobiť jeden analogRead. // Hodnota nás nezajíma ide len o to, aby sa nastavila referenčná hodnota analogRead(15); } void loop() { float Aref = 4.0; float voltage = (float) Aref*analogRead(15)/1023; if(voltage > 3.0) digitalWrite(13,HIGH); else digitalWrite(13,LOW); } |
PULL UP
void setup() { pinMode(13, OUTPUT); pinMode(6, INPUT); } void loop() { if(digitalRead(6) == 0) digitalWrite(13, HIGH); else digitalWrite(13, LOW); } |
PULL DOWN
void setup() { pinMode(13, OUTPUT); pinMode(6, INPUT); } void loop() { if(digitalRead(6) == 1) digitalWrite(13, HIGH); else digitalWrite(13, LOW); } |
INTERNAL PULL UP
void setup() { pinMode(13, OUTPUT); pinMode(6, INPUT_PULLUP); } void loop() { if(digitalRead(6) == 0) digitalWrite(13, HIGH); else digitalWrite(13, LOW); } |
Doposiaľ sme uvažovali o ideálnych podmienkach a ideálnych súčiastkach. Problém však je ten, že nič nie je ideálne. Tlačidlá sú známe tým, že po stlačení dochádza k zákmitu (rýchle zopnutie a rozopnutie) to pri rýchlom Arduine znamená to, že v podstate to zaregistruje, že tlačidlo bolo stlačené mnohokrát. Riešiť sa to môže hardvérovo, pripojením kondenzátorov a podobne ale skôr sa stretneme so softvérovým riešením. To spočíva v tom, že po tom ako je prvý krát zachytené stlačenie tlačidla na nejakú dobu sa prestane sledovať jeho stav. Zvyčajne sa to robí veľmi zle cez funkciu delay(). Túto iba pre ukážku použijeme v nasledujúcom príklade. Pritom uvažujeme zapojenie s PULL DOWN rezistorom, ale v princípe sa to robí rovnako pre každý spôsob zapojenia tlačidla. To ako to urobiť elegantne s využitím funkcie milis() [4] si ukážeme na ďalšom cvičení.
void loop() { if(digitalRead(6) == 1) { digitalWrite(13, HIGH); delay(50); } else digitalWrite(13, LOW); } |
Častokrát je potrebné aby zostavené zariadenie vydávalo zvuky. Hlavne sa so zvukmi stretávame vo forme rôznych pípaní pri stlačení tlačidiel, zvučiek pri štarte alebo vypnutí zariadenia a podobne. K Arduinu je možné pripojiť takzvaný piezoelektrický menič - bzučiak. Tento sa pripája k portom, ktoré podporujú PWM. Na doske Arduino Uno sú označené symbolom '~'. Na týchto portoch je možné generovať tóny s frekvenciou od 31Hz do 65kHz (ľudské ucho počuje v závislosti od jedinca maximálne do 20kHz). Bzučiak sa pripája cez maličký cca 100 Ohm rezistor. V kóde môžeme použiť funkcie tone() a noTone().
Veľmi dôležitou súčasťou vývoja hardvéru a softvéru je aj jeho komunikácia s ostatnými zariadeniami. Medzi počítačom a Arduinom je táto komunikácia zabezpečená pomocou sériovej linky. Komunikácia cez sériovú linku je zabezpečená cez niekoľko príkazov, ktoré si ukážeme na príklade. Nakoľko ArduinoIDE neposkytuje možnosť ladenia kódu, sériová linka je veľmi výhodná. Detaily o protokole, ktorý sa používa pri sériovej komunikácii sa budete učiť až v druhom ročníku. Na predmete Programovanie sa máte hlavne naučiť sériovú linku použiť.
Príklad.
Vytvorte program, ktorý čaká na príkazy z PC a na základe týchto príkazov do PC zašle údaje o hodnotách na jeho digitálnych portoch D2 -D13 (príkaz S) a informáciu o sebe (príkaz I). Informácia o stave na portoch bude zaslaná v nasledujúcom formáte: "Z,1,1,0,1,0,0,0,0,0,0,0,0,K" a informácia o Arduine bude vyzerať nasledovne "ARD001".
Sériovú komunikáciu v prostredí ArduinoIDE vyvoláte kliknutím na ikonku lupy vpravo hore. V prostredí Tinkercad je dole tlačidlo pre "Serial monitor"
Príkazy ktoré budeme potrebovať:
Existuje viac príkazov, ktoré sa môžu hodiť. Tieto ale necháme na samoštúdium [3].
int A[14]; void setup() { Serial.begin(9600); // inicializacia seriovej komunikacie for(int i=2;i<14;i++) // Hromadne nastavenie pinov na INPUT { pinMode(i,INPUT); digitalWrite(i,HIGH); } } void loop() { int i; for(i=2;i<14;i++) // Prečítanie hodnoty pinov A[i-2] = digitalRead(i); // Arduino počúva na sériovej linke a reaguje na 2 príkazy // I - zašle svoj identifikátor // S - zašle hodnoty na portoch if(Serial.available()>0) // Ak je niečo na sériovej linke tak // sa skontroluje či ide o správne príkazy { char r = Serial.read(); if( r == 'I') // mód identifikácie { Serial.print("ARD001\n"); } if( r == 'S') // mód zaslania hodnôt portov { Serial.print("Z,"); for(i=0;i<12;i++) { Serial.print(A[i]); Serial.print(","); } Serial.println("K"); } } } |
Úloha 1.
Napíšte program pre Vývojovú dosku Arduino, ktorý bude cez sériovú linku prijímať číslice od 0 do 9 a tieto potom zobrazí na 7 segmentový displej (spoločná katóda). Tento displej bude pripojený k pinom D6- D12. Jednotlivé segmenty sa budú spínať sekvenčne, ale veľmi rýchlo (povedzme 10ms na jeden segment). Vytvorte vlastnú funkciu, ktorá bude prevádzať dekadickú hodnotu na kód pre ovládanie 7 segmentového displeja.
Deklarácia funkcie Dec2Seven() je zobrazená nižšie. Skúste sa vyhnúť globálnej premennej, nie je to ale povinnosťou. Jednotlivé bity kódu uloženého v 1R poli - seven sa zapíšu na príslušné piny D6 - D12.
Napr. Ak má svietiť číslo 7, tak sú zapnuté segmenty - A, B a C, ktoré sú pripojené na piny 11, 12 a 6. Nezabudnite na 220 Ohm rezistor, ktorý je spoločný pre všetky diódy. Stačí iba jeden nakoľko sa to spína sekvenčne. Odporúčam to spraviť na reálnom Arduine, aby bolo aj vidieť keď zvolíte nízku obnovovaciu frekvenciu
void Dec2Seven(int cislo) // S globálnou void Dec2Seven(int cislo, int* seven) // bez globálnej { /* [C D E G F A B ]Segmenty displeja [6 7 8 9 10 11 12] Piny Arduina [0 1 2 3 4 5 6 ] Index prvku poľa seven 1 - [1 0 0 0 0 0 1 ] Hodnoty poľa seven 2 - [0 1 1 1 0 1 1 ] 3 - [... */ |
Úloha 2.
pozrite si náplň cvičenia na [2] a vypracujte úlohy, ktoré tam sú zverejnené.