![]() |
||
Princíp riadenia činnosti 7-segmentového LED displeja.Cieľ lekcie 19:
V Časti III. - Úlohy praktických cvičení - sa zameriame na vyriešenie jednej úlohy
Návod na riešenie úlohy:Spoznajte - Výkonový koncový stupeň - displej.LED displej z 3 digitov obsahujúcich 7 svietiacich segmentov + 1 pre desatinnú bodku, ktorý budete používať na zobrazenie potrebujete detailne poznať. Takže prvou úlohou bude pozrieť si nápisy na ňom a vyhľadať dokumentáciu od výrobcu. Do rúk sa vám najskôr dostane typ KINGBRIGHT BC56-12GWA. Prvá úloha - nájdite ho v Internete. Možno sa dostanete k dokumentu, ktorý bude popisovať viacero podobných typov, preto sa musíte v dokumente zorientovať a nájsť najdôležitejšie informácie. Ak nenájdete pozrite si tento obrázok zapojenia súčiastky a vypíšte si dôležité informácie. Ako ovládať BC56-12GWA?Z obrázka vyplýva spôsob ako sa ovláda BC56-12GWA. Je jasné, že LED dióda svieti ak ňou tečie prúd od anódy ku katóde, t.j. anóda má vyšší potenciál a katóda nižší potenciál. Pri ovládaní ARDUINOM vyšší potenciál predstavuje logická 1 (t.j. +5V) a nižší potenciál predstavuje logická 0 (t.j. GND). Z obrázka v dokumentácii vidno, že každý digit má samostatnú spoločnú katódu pre všetky segmenty (spolu má digit 8 segmentov), ale anódy sú prepojené pre všetky digity paralelne (3 spoločné anódy na konkrétny segment). Pozrite si zapojenie ručne ovládaného displeja 3x7LED. Ak by sme uzemnili naraz všetky spoločné katódy a na anódové vstupy by sme priviedli kladný potenciál, rozsvietia sa všetky digity naraz a zobrazia to isté. Jediný spôsob ako sa teda dá niečo zobraziť pre každý digit samostatne, ja taký pri ktorom v jednom čase budú na zem (GND) napojené len katódy jediného digitu. To sa dá uskutočniť jedine DYNAMICKY v krátkych časových intervaloch . Čo to znamená? Naše oko má zotrvačnosť pri vnímaní dejov. Vďaka tomu vidíme film na obrazovke a svetlá so striedavým napájaním nám "viditeľne" neblikajú. Aby naše oko vnímalo dynamický dej spojito a neprerušovane - t.j. bez blikania - musí sa odohrávať v čase 1/100 sekundy. Algoritmus zobrazovania na displeji potom bude vyzerať takto:
Ak zabezpečíme tento dynamický princíp prepínania digitov na displeji získame pocit neprerušovane zobrazovaného súboru troch čísel. V nasledovnom programovom kóde sa bude opakovať sekvencia troch akcií, z ktorých každá sa bude trvať minimálne 10 milisekúnd. Rozanalyzujte tento jednoduchý program a vysvetlite, a experimentom odskúšajte. Budete ho potrebovať na ovládanie prepínania digitov.
unsigned long timediff;;
int cas=10;
void loop()
{
timediff=millis(); // nastav nové počítanie času
while(millis()-timediff<=cas) { AKCIA1 } // Akcia1 bude trvať "cas"
timediff=millis(); // nastav nové počítanie času
while(millis()-timediff<=cas) { AKCIA2 } // Akcia2 bude trvať "cas"
timediff=millis(); // nastav nové počítanie času
while(millis()-timediff<=cas) { AKCIA3 } // Akcia3 bude trvať "cas"
}
Zapojenie LEDNa vyriešenie projektov potrebujete zvládnuť zapojenia LED diód v klasickom obvode pozostávajúceho zo: zdroja, ochranného odporu a aktívneho prvku - LED diódy. Kombinácia napätia a ochranného odporu rozhoduje o tom či LED bude fungovať alebo sa prepáli. Zdroj v našom prípade bude nahradený koncovým stupňom na výstupe Arduina, nakoľko tieto zvládajú cca 40mA prúdy potrebné na napájanie LED diód. Čo sa týka ARDUINA sú len dve možnosti použitia vstupno/výstupných digitálnych pinov: OUTPUT (VÝSTUP) a INPUT (VSTUP). Piny DIGITAL označené na doske ARDUINA 0 až 13 predstavujú digitálne Výstupy a Vstupy. Konektor označený ANALOG IN obsahuje "analógové vstupy" 0 až 5, ale tieto sa dajú použiť aj ako DIGITAL 14 až 19. Režim pinov sa nastavuje príkazmi. Na príklade si vysvetlíme ich význam:
pinMode(13, OUTPUT); // Nastav režim Vstupno/Výstupného pinu 13 na VÝSTUP
pinMode(13, INPUT); // Nastav režim Vstupno/Výstupného pinu 13 na VSTUP
Nasledovné inštrukcie vám pomôže pochopiť animácia s doskou ARDUINA.
digitalWrite(13, HIGH); // Nastav na pine 13 logickú úroveň HIGH t.j. log1
digitalWrite(13, LOW); // Nastav na pine 13 logickú úroveň LOW t.j. log0
Pre ovládanie displeja používajúceho paralelne 7 bitový kód by bolo výhodné, aby sa spínalo súčasne 7 segmentov digitu naraz. Doteraz sme preberali len tie metódy, ktoré s bitmi portu pracovali pomocou bitových operácií. Tieto majú svoj význam v prípade, keď máme nedostatok vstupno/výstupných bitov na jedinom porte Arduina. Porty ARDUINA - možnosť paralelného zápisu kódu pre displej.Konektor Arduina označený DIGITAL (0-13) je tvorená bitmi dvoch portov PORTD (0-7) a PORTB (0-5). Konektor ANALOG IN (0-5), použiteľný aj ako DIGITAL (14-19), je tvorený bitmi PORTC (0-5). Spomenuté porty sú tvorené adresovateľnými registrami napojenými na vnútornú 8 bitovú dátovú zbernicu procesora, a súčasne na vstupno-výstupné piny (nožičky) mikropočítača. Smer prepojenia ich bitov určujú konfiguračné registre DDRB, DDRC a DDRD. Viac o portoch nájdete tu. Obsah portov sa dá zmeniť jedinou VSTUPNO-VÝSTUPNOU operáciou naraz za kratší čas než je nastavenie 1 bitu bitovou operáciou. Jediné čo nás obmedzuje pri použití 7 bitového kódu je to, že jediný PORTD, ktorý má viac ako 6 bitov, má bity 0 až 3 využité na dôležité funkcie určené na externé prerušenie (int0= bit 2 a int1= bit 3) a na sériový prenos dát sériovou linkou (Rx= bit 0 a Tx= bit 1). Ak tieto bity nechcete využívať, máte na prenos 8 bitového kódu celý PORTD. V prípade, že ovládané bity sa nachádzajú na dvoch rôznych portoch, môžeme použiť bitové operácie alebo komplikovanejšie hromadné operácie portov. Hromadné operácie portov, ktoré nastavia len časť bitov portu naraz, nesmú zasahovať do bitov určených pre iné účely. Pre naše potreby hromadného ovládania ukážeme si nastavenie 5 bitov PORTD (ktorý je za časťou konektora DIGITAL 0-7). Na hromadne zmeny časti bitov portu musíme používať konštanty (t.j. masky) a Booleovu algebru - konkrétne bitové operácie "&" (AND) a "|" (OR). Operácia sa vykonáva medzi 8 bitovými operandami (napr. maskou a obsahom registra) vždy len medzi bitmi tej istej rádovej pozície (t.j. 0 s 0, 1 s 1 atď.). Obe operácie sú v niečom "agresívne" a v niečom "pasívne". Operácia AND je "agresívna" v bitoch obsahujúcich log0. Bit v maske obsahujúci log0 zmení výsledok operácie AND vždy na log0. Naopak bit v maske obsahujúci log1 ponechá po operácii AND stav ktorý má druhý operand - nezmenený. Operácia OR je "agresívna" v bitoch obsahujúcich log1. Bit v maske obsahujúci log1 zmení výsledok operácie OR vždy na log1. Naopak bit v maske obsahujúci log0 ponechá po operácii OR stav ktorý má druhý operand - nezmenený. Ako teda zmeniť časť bitov portu paralelnou operáciou? Každá zmena časti bitov portu sa musí uskutočniť vo dvoch etapách. 1. Nulovanie s AND a 2. zápis jednotiek s OR (alebo presne naopak: jedničkovenie s OR a zápis 0 pomocou AND). Na daný port najprv aplikujeme masku obsahujúcu binárne jednotky a nuly tak, že tam, kde budeme meniť obsah nastavíme log0 a aplikujeme operáciu AND. Následne tam kde chceme nastaviť log1 nastavíme v maske log1 a aplikujeme operáciu OR. Príklad:Podrhnuté znaky v príklade sú "agresívne". Nasledovná ukážka najprv zapíše 8 bitový údaj a potom zmení horných 5 bitov bez toho aby ovplyvnil najnižšie 3 bity aplikovaním operácie AND a následne OR (zápis operácie je v skrátenom tvare A = A oper B t.j. A oper= B ):
PORTD = B10101010; // bin. maska nastaví digitálne piny 7,5,3,1 na HIGH ostatné na LOW
PORTD &= B00000111; // nastaví digitálne piny 7 až 3 na LOW ostatné ZACHOVÁ !!! 00000010
PORTD |= B01010000; // nastaví digitálne piny 6 a 4 na HIGH ostatné ZACHOVÁ !!! 01010010
DDRD je register určujúci smer prenosu pre Port D (Digitálne piny Arduina 0 až 7). Tieto bity v tomto registri riadia či piny v porte PORTD sú konfigurované ako vstupy alebo výstupy, napríklad:
DDRD = B11111110; // nastaví PORTD piny 1 až 7 ako výstup(HIGH),
// a pin 0 ako vstup(LOW)
DDRD = DDRD | B11111100; // bitová operácia OR (alebo) nastavila piny 2 až 7 ako výstupné
// ale ponechala nastavenie pinov 0 a 1 pre sériovú linku Rx,Tx
// DDRD bude B11111110
Praktiky programovania - "Konverzia hodnoty na reťazec".Ak budeme chcieť zobraziť číselný údaj, bude v počítači najskôr uložený ako binárne číslo typu int. Na displeji máme k dispozícii len 3 digity. Maximálne číslo 999. Z každého čísla vieme zobraziť len stovky, desiatky a jednotky. Ak by v údaji boli tisíce, neostáva nám nič iné - len zobraziť "Err" - chybový stav. Ne separovanie číslic z údaja nám poslúži jednoduchý program - separujJednotky(). Program používa špeciálnu premennú na ADRESOVANIE údajov typu "smerník" (angl. "pointer"). Výrazy priradené premennej pointer menia adresu na ktorú ukazuje. Ak chceme pracovať s ÚDAJOM na ktorý pointer ukazuje, potom sa pred názov pointra napíše znak * (nemýľte si ho s násobením!). Hviezdička a názov pointra spolu vytvárajú PREMENNÚ s ktorou sa narába ako s obyčajnou premennou. Nasledovný program cez parameter adrPrem získa adresu premennej (znova opakujem - ide o premennú typu pointer - resp. "ukazujúca" na adresu). Pôvodný obsah na starej adrese prepíše príkazom *adrPrem= nový_obsah; . Hviezdička pred pointrom predstavuje význam "údajové miesto ktoré adresuje pointer". Aj keď inštrukcie funkcie sú uzavreté lokálne v jej bloku, pracujú s údajom nachádzajúcim sa mimo funkciu. Názov funkcie separujJednotky() použitý v nejakom výraze, bude obsahovať návratovú hodnotu v podobe odseparovanej hodnoty jednotky z premennej, na ktorú sa aplikovala funkcia. Pôvodný obsah celočíselnej premennej, predelený 10, sa zapíše na jej pôvodné miesto. Zvyšok po delení - separovaná jednotka - sa vracia cez názov funkcie príkazom return((byte)jednotky); (Poznámka: (byte) uvedený v príkaze pretypuje výsledok int na typ byte) // originál číselného údaja 10 násobne zmenší a vráti hodnotu jednotky byte separujJednotky(int* adrPrem) // adrPrem je adresa premennej odovzdana cez parameter { int jednotky; jednotky= (*adrPrem) % 10; // odpamätaj "jednotky" z číselného údaja na adrese adrPrem *adrPrem= (*adrPrem) / 10; // celočíselný podiel pôvodnej premennej vrať na jej miesto return ((byte)jednotky); // odovzdaj separované jednotky ako návratovú hodnotu funkcie } Nasleduje príklad použitia funkcie. V globálnom priestore sa nachádzajú premenné jed, des, stov, tis a val obsahujúci číselnú hodnotu, ktorú chceme separovať na číslice. Program separuje z pôvodnej hodnoty vždy len jednotky a zvyšok vráti desaťnásobne zmenšený do pôvodnej premennej. Po separácii sa ocitnú samostatne jednotky v premennej jed, desiatky v premennej des, stovky v premennej stov a tisíce v premennej tis: int jed,des,stov,tis,val=958; enum { medzera=10, znak_E=11, znak_r=12 }; // vid kódová tabuľka void loop() { jed= separujJednotky(&val); des= separujJednotky(&val); stov=separujJednotky(&val); tis= separujJednotky(&val); if (tis) { stov=znak_E; des=znak_r; jed=znak_r; } vypisCislo(stov,des,jed,2000); } Výhoda predošlého algoritmu s pointrami je v tom, že sa dá aplikovať na ľubovoľne veľké číslo. Ak chcete obísť použitie pointrov, na separovanie "len štyroch číslic" z čísla sa dá použiť nasledovný podprogram: int jed,des,stov,tis,val=958; void separujTSDJ(int cislo) { jed=(byte)(cislo % 10); // zvyšok po delení 10 cislo=cislo/10; // t-s-d (tisice-stovky-desiatky) celočíselný podiel des=(byte)(cislo % 10); cislo=cislo/10; // t-s tisíce a stovky stov=(byte)(cislo % 10); tis=(byte)cislo/10; // t tisíce } // ... niekde v programe použijete separujTSDJ(val); // funkciu na separovanie číslic z premennej val // ... Dynamický proces zobrazovania - multiplex.Riešení úlohy, ktoré by používalo prídavné pamäte pri každom "digite" displeja, by bolo veľmi jednoduché. Pri takomto "statickom" riešení by stačilo vložiť do pamäte digitu kód a ten by nonstop zobrazoval. Obsah by sa zmenil obyčajným prepisom. Takéto riešenie sa často používa, ale je ekonomicky náročnejšie. Trochu komplikovanejšie, ale lacnejšie, je využitie vlastností displeja BC56-12GWA, ktoré statický režim ani neumožňuje. Dôvodom je fakt, že odpovedajúce segmenty (a,b,c,d,e,f,g a DT-bodka) všetkých troch digitov sú paralelne spojené a vytvárajú 8 trojíc vstupných bodov pre zobrazovaný kód. Naopak všetky katódy LED diód každého jednotlivého digitu (t.j. každý digit má 8 katód LED) sú spojené do jediného odvodu prúdu pre každý digit osobitne. Ak by potenciál na odtoku prúdu bol rovnaký ako na vstupe - stav HIGH - segment nebude svietiť. Tým že zabránime napojiť spoločné katódy digitu na GND, zabránime digitu aby svietil. Ak by sme pripojili súčasne dve spoločné katódy digitov na GND, svietil by na digitoch ten istý znak. V programe bude potrebné riešiť úlohu krátkeho cyklického prepínania katód jednotlivých digitov na potenciál GND. Toto zabezpečí logická hodnota LOW z portu ARDUINA. Tu je ukážka programu zabezpečujúceho krátky impulzu GND na prvý z digitov 3x7 LED displeja pomocou volania programu blikniDigit(dig1pin); . Ak v priebehu 4 milisekund blikneme tým istým digitom opakovane - naše oko si nevšimne žiadne zmeny! enum { dig1pin=4, dig2pin=3, dig3pin=2 }; // pridelenie spoločných katód displeja digitom void blikniDigit(int digit) { digitalWrite(digit,LOW); delay(1); // krátky záblesk zobrazovaného digitu digitalWrite(digit,HIGH); } Dostávame sa do dosť komplikovanej situácie. Spomeňme si že hlavný program má svoju cyklickú časť v ktorej musí vykonávať všetky prácu. Teraz vzniká problém, že musí obsluhovať dej prepínania jednotlivých digitov v čase menej ako 1/100 sekundy a okrem toho vykonávať ešte ďalšiu činnosť. Pri poruche tohto režimu by ste mohli zaregistrovať "kmitanie obrazu" displeja. Cyklická časť programu by mohla vyzerať nasledovne: void loop() { int scan; scan=analogRead(0); // nasnímaj hodnotu analógového senzora (0 až 1023) delay(5); // mala pauza na dokončenie merania vypis3CifCislo(scan); // zobraz údaj na displeji } V ukážke vidíte jednak snímanie hodnoty senzora a jednak zobrazovanie nasnímanej veličiny na displeji. Dej prebiehajúci 1/100 sekundy trvá 10ms. Takže všetky operácie pred a za funkciou vypis3CifCislo(scan); v cykle loop() môžu trvať maximálne 10ms ak zahrnieme aj delay(5); . Podľa rovnakých pravidiel musí fungovať samotná funkcia vypis3CifCislo(scan);. Očakávame od tejto funkcie že okrem zobrazovania bude vyhodnocovať aj maximum hodnoty, ktorú vie zobraziť na 3 miestnom displeji (t.j. 999) a pri hodote 1000 a viac vypíše hlásenie "Err" . Pozrite si nasledovný program: enum { medzera=10, znak_E=11, znak_r=12 }; // vid kódová tabuľka int vypis3CifCislo(int hodnota) { separujTSDJ(hodnota); // rozseparuj hodnotu na 4 údaje tis, stov, des a jed if (tis) // ak tis sa nerovná 0 { stov=znak_E; // budeme zobrazovať správu "Err" des=znak_r; jed=znak_r; } vypisCislo(stov,des,jed,1000); // potom budeme zobrazovať 3 digity celých 1000 milisec } Dostávame sa k jadru problému vypisCislo(stov,des,jed,1000); . Tu musíme vyriešiť problém s časom. Číslo sa bude zobrazovať 1000 milisec. Ale počas celého procesu musíme zároveň prepínať jednotlivé digity v čase maximálne 10milisec. Tu však nemôžeme použiť klasický delay(x); pretože počas celého času musia prebiehať všetky procesy v Arduine. No aj na to máme riešenie: // program bude dynamicky zobrazovať 3 digity po dobu cas // pridelenie pinov Arduina spoločným katódam displeja 3x7 LED enum { dig1pin=4, dig2pin=3, dig3pin=2 }; void vypisCislo(byte cislo1, byte cislo2, byte cislo3, int cas) { unsigned long startTime; // premenná na meranie času startTime=millis(); // nastav počiatočný stav merania času resetDisplay(dig1pin); // pin katódy pre digitC1 = zhasni resetDisplay(dig2pin); // detto digitC2 resetDisplay(dig3pin); // detto digitC3 while(millis()-startTime<=cas) // porovnaj počiatočný čas s aktuálnym či sme neprečerpali čas { setDisplay(kod7segZnaku[cislo1]);// nastav bity s kódom digitu na anodách displeja blikni(dig1pin); // blikni krátky záblesk (t.j.katoda) digitu C1 po dobu delay(1) setDisplay(kod7segZnaku[cislo2]); // detto pre digit C2 blikni(dig2pin); setDisplay(kod7segZnaku[cislo3]); // detto pre digit C3 blikni(dig3pin); } } Funkcia millis() v príklade vracia veľkú hodnotu (unsigned long) lineárne narastajúceho času v milisekundách vždy keď ju o túto hodnotu požiadame. Zmenu hodnoty poskytovaného času zabezpečuje automaticky vnútorný generátor hodín mikropočítača. V programe nájdete funkciu resetDigit(). Má za úlohu vypnúť digity LED displeja na začiatku zobrazovania. void resetDigit(int digit) { digitalWrite(digit,HIGH); //zhasni LED odpojením katódy od potenciálu 0V log0 } Premenné a dátové typy použité pre aplikáciuZnaky 7 segmentového displeja sú tvorené 7 LED diódami (Pozn.: pričom je tam aj 8. LED - bodka pri pravej päte) sa vytvárajú kombináciou 1 a 0(svieti/nesvieti). Na takomto displeji vieme zobraziť, tak aby sa dali od seba rozlíšiť, nasledovné znaky: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, b, C, d, E, F, o, r, u, n a prázdny znak (medzeru). Na uloženie 8 bitovej kódovej tabuľky máme v C jazyku k dispozícii štruktúru - pole bajtov. Vzor výberu z poľa vidíte na nasledovnej definícii premennej kod, nastavenú na konkrétnu hodnotu danú tabuľkou a indexom: byte kod=kod7segZnaku[index]; , kde kod je premenná typu byte rovnako ako prvky poľa. V hranatej zátvorke uvedený index je premenná alebo konštanta adresujúca prvok poľa počnúc hodnotou 0. Každý bajt v poli bude predstavovať 7 bitov segmentov digitu - t.j. číselného znaku (Pozn.: hexadecimálna sústava používa navyše aj digity A=10, B=11, C=12, D=13, E=14 a F=15, na zobrazovanie ktorých je 7 segmentový displej práve veľmi vhodný.). Nasleduje príklad poľa obsahujúceho kódy znakov "0" až "9", medzeru a dva znaky "E" a "r". Tie posledné použijeme na vypísanie chybového stavu "Err" od slova Error (angl. "Chyba"). Tu je vzor ako na to: // POLE KÓDOV ZNAKOV ČÍSLIC a PÍSMEN "E", "r" a MEDZERA=off t.j. vypnuté byte kod7segZnaku[13]= {// gfedcbaN - priradenie k segmentom N- nepoužitý B01111111, //0 B00001101, //1 B10110111, //2 B10011111, //3 B11001101, //4 B11011011, //5 B11111011, //6 B00001111, //7 B11111111, //8 B11011111, //9 B00000001, //10 off = všetky anódy nastav na log0 - t.j. zhasni (vypíš medzeru) B11110011, //11 E písmeno E na sedemsegmentovke B10100001 //12 r písmeno r na sedemsegmentovke }; Výhodou tohto poľa je to, že hodnota číslice zodpovedá indexu s ktorým sa údaj dá vybrať z tabuľky. Ak bity budú pekne uložené vedľa seba na porte PORTD (konektor Arduina DIGITAL 7 až 0) potom jeho použitie môže byť takéto:
PORTD=kod7segZnaku[5]; // vypíš kód znaku 5 na PORTD (DIGITAL 7-0)
Sú však prípady, keď potrebné bity nenájdete na jednom porte, ale potrebujete ich poskladať na viacerých portoch. Vtedy potrebujete separovať jednotlivé bity z kódového slova. Na to existuje viacero metód, ale teraz tu sa dozviete výnimočnú a elegantnú metódu používanú profesionálmi akými chcete byť. Celá myšlienka spočíva v tom, že na element v poli kódovej tabuľky typu byte, chceme nahliadnuť ako na ešte menšie prvky - samostatné bity, aby sme ich potom samostatne nastavovali na bitoch portov Arduina. Na tento účel vieme vytvoriť dátový objekt nazývaný štruktúrovaná premenná ktorej priradíme názov napr. POLE8BIT ktorá bude obsahovať jednobitové premenné s názvami segmentov displeja a celá štruktúra sa bude ukladať práve do 1 bajtu: // definícia TYPU 1 bajtovej štruktúrovanej premennej obsahujúca 1 bitové premenné struct POLE8BIT { byte N:1; // N ako nepoužitý byte a:1; byte b:1; byte c:1; byte d:1; byte e:1; byte f:1; byte g:1; } ; Teraz využijeme možnosť inej štruktúry v C jazyku, ktorá do jedného a toho istého dátového priestoru umiestni dve premenné tak, že sa prekryjú. Takáto štruktúra sa nazýva - union. Priradíme jej názov napr. KODY7SEGM: typedef union // definícia TYPU umožňujúca bitový aj bajtový prístup k rovnakým dátam { // union predstavuje dve premenné uložené na to isté miesto POLE8BIT segment; // premenná typu pole 8 bitov vložených do 1 bajtu byte kod8bit; // celočíselná kladná premenná veľkosti 1 bajt } KODY7SEGM; Ako vidíte premenná segment je typu štruktúry pozostávajúcej z 8 bitov a táto sa prekrýva s bajtovou premennou s názvom kod8bit. Keď zapíšeme niečo do premennej kod8bit, môžeme pristupovať k obsahu pomocou štruktúrovanej premennej segment, ktorá má podštruktúru s názvami bitov presne podľa anód sedem segmentového displeja. Štruktúrovanú premennú používate v kombinácii s podštruktúrou takto: segment.a, segment.b, ... a každý názov predstavuje jeden bit. Konečný efekt v programe bude nasledovný:
// tento program umožňuje na účely riadenia displeja použiť ľubovoľnú kombináciu bitov Arduina // pridelenie pinov Arduina anódam segmentov displeja 3x7 LED enum { segApin=12, segBpin=11, segCpin=10, segDpin=9, segEpin=8, segFpin=7, segGpin=6 }; void setDisplay(byte zobrKod) { KODY7SEGM kod; // union premenná prekrývajúca bajt kod8bit a pole bitov segment kod.kod8bit=zobrKod; // vloženie formou celého bajtu aby sa následne konal výber po bitoch digitalWrite(segApin, kod.segment.a ); // na pin konektora DIGITAL Arduina pridelený segmentu digitalWrite(segBpin, kod.segment.b ); // LED pošli bit segmentu podľa obsahu 8 bitového kódu digitalWrite(segCpin, kod.segment.c ); digitalWrite(segDpin, kod.segment.d ); digitalWrite(segEpin, kod.segment.e ); digitalWrite(segFpin, kod.segment.f ); digitalWrite(segGpin, kod.segment.g ); } void setDisplay(byte zobrKod) // alternatívny program využívajúci štandardnú funkciu bitRead(); { digitalWrite(segApin, bitRead(zobrKod,1) ); // na pin konektora DIGITAL Arduina pridelený segmentu digitalWrite(segBpin, bitRead(zobrKod,2) ); // LED pošli bit segmentu podľa obsahu 8 bitového kódu digitalWrite(segCpin, bitRead(zobrKod,3) ); digitalWrite(segDpin, bitRead(zobrKod,4) ); digitalWrite(segEpin, bitRead(zobrKod,5) ); digitalWrite(segFpin, bitRead(zobrKod,6) ); digitalWrite(segGpin, bitRead(zobrKod,7) ); } V programe vyššie máte dva spôsoby toho istého programu setDisplay(). V prvom vidíte elegantné riešenie práce s bitmi. Cely bajt najprv vložíte ako jeden kód a následne vyberáte jednotlivé bity podľa názvov segmentov. Program je čitateľný, zrozumiteľný a profesionálny! Ak ste ho pochopili pootvorili ste dvere do triedy profesionálnych programátorov. Ak navyše ovládate prácu s pointrami a objektové programovanie otvoria sa vám dvere dokorán. Druhý model setDisplay() využíva štandardnú funkciu bitRead(bajt, číslobitu); ktorá sa nachádza v štandardnej zostave knižničných funkcií C jazyka Arduina. Údaj číslobitu čísluje bity bajtu sprava doľava počnúc číslom 0. Riešenie displeja pomocou procesu bežiaceho na pozadí iných procesov.Častou potrebou je riešiť aplikáciu, ktorá využíva displej. Programátor, však nemá priestor na riešenie drajvera pre displej (obslužný program displeja) nakoľko očakáva už hotové riešenie. V tomto našom prípade odovzdá jeden proces druhému hodnotu v premennej int value; ktorý sa odseparuje do premennych int tis, stov, des, a jed; . Tam ich nájde proces ktorý sa bude nachádzať v programe specDelay() ktorý popri tom, že vytvára požadovanú pauzu v programe, navyše bude zabezpečovať užitočné služby ako napr. zobrazovanie na displeji.
/*******************************************************************************
* Načítaj údaj zo sériovej linky (SerialMonitor) a nastav čas blikania LED. *
* Celý čas zobrazuj údaj aj na 3x7LED displeji *
*******************************************************************************/
const int ledBit = 3; // výstupný pin pre LED - Aplikácia blikania
int polCas=500; // polcas blikania LED v milisec
char inByte = 0; // premenná pre prichádzajúci bajt
int value;
byte zmena=0; // sprava pre iný proces, že došlo ku zmene premennej value
void doSerial() // OBSLUHA SÉRIOVÉHO KANÁLA
{
if (Serial.available()) // Hlavný cyklus prebieha pokiaľ sa neobjaví znak
{
value=0; // priprav sa na ďalšie číslo
zmena=1;
delay(100); // v tej chvíli počká lebo predpokladá viac znakov
while (Serial.available() > 0) // a v cykle začne vyberať z buffra znak za znakom,
{
inByte = Serial.read();
value=value*10+(inByte-'0'); // extrahuj z číslice jej hodnotu pridaj jednotky
Serial.write(inByte); // vypíš na Ser.Mon.znak ktorý čítaš z buffra sériovej linky
Serial.print(".");
}
// odteraz je hodnota value nastavená
Serial.print(" Nacital ");
Serial.println(value,DEC);
}
}
void setup()
{
Serial.begin(9600); // inicializácia sériovej linky
resetDisplay(dig1pin); // pin katódy pre digit1 = zhasni
resetDisplay(dig2pin); // detto digit2
resetDisplay(dig3pin); // detto digit3
}
void specDelay(unsigned long myDelay)
{
unsigned long startTime;
startTime=millis(); // nastav nové počítanie času
while(millis()-startTime<=myDelay) // cyklus obsluhujúci služby min po dobu myDelay
{
doSerial(); // ošetrenie sériovej linky - nastaví value
if (zmena)
{
polCas=value;
separujTSDJ(value);
if (tis) // zobrazovanie tisicov vyvolá zobrazenie "Err"
{
stov=znak_E;
des=znak_r;
jed=znak_r;
}
zmena=0;
}
setDisplay(stov);
blikniDigit(dig1pin);
setDisplay(des);
blikniDigit(dig2pin);
setDisplay(jed);
blikniDigit(dig3pin);
// ... miesto pre ďalšie akcie v reálnom čase
}
}
void loop()
{
// ...
digitalWrite(ledBit,HIGH); // zapni LED
specDelay(polCas); // Počkaj
digitalWrite(ledBit,LOW); // vypni LED
specDelay(polCas); // Počkaj
// ...
}
SeriaInBlinkLED3x7displ
Vašou úlohou je teraz poskladať celú aplikáciu dokopy.
Vzorové príklady vo vývojovom prostredí Arduina ((Examples/1.Basics/... )
Kontrolné otázky
|
||
|
|
||
| Moderné vzdelávanie pre vedomostnú spoločnosť / Projekt je spolufinancovaný zo zdrojov EÚÚÚPredmet: Elektrotechnika / Autor: Ing. Jaroslav Janoušek |