Další část pokračování stránek o základech programování. Po nastudování této stránky by Vám mělo být jasné jedno z několika možných připojení (a samozřejmě ovládání) sedmisegmentové číslicovky k procesoru typu x51, její programové obsloužení a zároveň s tím i použití některých nových instrukcí.

     Protože z minulé stránky již něco umíme, a umíme již "dostat" program do mikroprocesoru, naučíme se, jak sdělit výsledky našeho snažení okolí. V dnešní době inteligentních displejů LCD s integrovaným řadičem se mohou zdát sedmisegmentové zobrazovače již minulostí, ale naopak pro jednoduché aplikace mají své nezastupitelné místo, jak svojí cenou, tím, že je seženete takřka na každém rohu, tak i svým jasem a výběrem z množství rozměrů. Naopak mínusem a to pro některé aplikace značným je spotřeba. Takže s chutí do toho.

Jak tedy pomocí mikroprocesoru rozsvítit nějaké číslo na sedmisegmentovce, případně si vytvořit vlastní znak ?


     Nejjednodušší (a je to opravdu příklad, neboť málokdy budeme připojovat pouze jedno číslo) je zapojit sedmisegmentovku segmenty přímo k jednomu portu. Má to jednu velikou výhodu týkající se software, kterou Vám prozradím o kousek dál. Pokud se podíváme na obrázek, zjistíte, že jeden každý segment je připojen k jednomu bitu portu.

     Nyní poněkud odbočím. Pro pochopení funkce budeme uvažovat, že pro rozsvícení jednoho některého segmentu nastavíme vývod do logické úrovně H. Je to lepší pro pochopení, prostě úroveň log. H na vývodu = segment svítí. Abych Vás nezmátl, ve skutečnosti je situace poněkud komplikovanější, má to souvislost s konstrukcí výstupních budičů portu procesoru, ale o tom až později, až si osvojíte toto jednoduché připojení.
     Označme si jednotlivé segmenty písmeny podle abecedy a budeme pro začátek uvažovat o zobrazovací jednotce se společnou katodou. Jestliže tedy přivedeme na segment a úroveň log. H, segment se rozsvítí. A totéž platí i pro ostatní. Nyní, chceme-li rozsvítit například číslo 1, které je zde na příkladu zobrazeno, musíme nastavit do úrovně log. H segment b a c, a naopak ostatní ponechat v log. úrovni L. Tak tedy rozsvítit jednotlivé segmenty umíme, to není problém, v programu bychom pro rozsvícení znaku pro jedničku prostě napsali:
;--------------------
CLR	P2.0		;zhasne segment A
SETB	P2.1		;rozsvítí segment B
SETB	P2.2		;rozsvítí segment C
CLR	P2.3		;zhasne segment D
CLR	P2.4		;zhasne segment E
CLR	P2.5		;zhasne segment F
CLR	P2.6		;zhasne segment G
CLR	P2.7		;zhasne segment H (des. tecka)
;--------------------
ALE - jistě sami uznáte, je to možná přehledné, ale zcela jistě dlouhé (představte si takto vypisovat všechny kombinace pro číslice od 0 do 9, pro některá písmena a ještě se na ně odkazovat), zabere to zbytečně mnoho paměti a v programu nanejvýš nepraktické, a proto se takovýto přístup k ovládání kupodivu nepoužívá a ani na to tady nenajdete příklad .
      Na jiný, troufám si říci správný (nejsem dokonalý, kdyžtak mne opravte) přístup se podíváme dál. Tahle kapitolka měla jen nastínit, jak segmentovku připojit, a jak rozsvítit jednotlivé segmenty.


     Podstatně jednodušší postup, jak vypisovat čísla (případně znaky) je, posílat kombinaci svítících a zhasnutých segmentů na port jednou instrukcí. Pro pochopení budeme muset trochu zabrousit zpět do číselných soustav. Port má 8 vývodů (pinů), označených 0 až 7. Byte má osm bitů. Každý bit v byte má nějakou váhu (ne na kg, ale hodnotu). Jestliže zavzpomínáme na dvojkovou (binární) soustavu, víme, že hodnotu můžeme vyjádřit kombinací nul a jedniček. To znamená, že pro "naplnění" jednoho byte odpovídá kombinace jeho bitů hodnotě 11111111. Takže například vyjádření 01010101B (binárně) odpovídá číslu 85D (dekadicky). Rozepsáno to znamená:
01010101B (binárně)
0x128+1x64+0x32+1x16+0x8+1x4+0x2+1x1

      A nyní celé to kouzlo spočívá v tom, že si dáme dohromady (samozřejmě v hlavě) port a byte. Jednotlivé piny výstupního portu jsou ony váhy s tím, že nejvyšší váha (128) odpovídá bitu s označením 7 (P1.7, P2.7 nebo P3.7), nejnižší váha odpovídá bitu s označením 0 (P1.0, P2.0, P3.0). Jasně vše ukazuje obrázek sedisegmentovky výše.
Tím pádem jestliže na port pošleme například výše zmíněnou binární kombinaci (01010101B), stane se to, že se bity portu nastaví do následujícího stavu:

0 1 0 1 0 1 0 1 B (binárně)
Px.7 Px.6 Px.5 Px.4 Px.3 Px.2 Px.1 Px.0 Bity portu (P0 až P3)
L H L H L H L H Logické úrovně
128 64 32 16 8 4 2 1 Váhy bitů

      Jestliže si tedy zrekapitulujeme vše předchozí, pak pro rozsvícení čísla 1 na sedmisegmentovém zobrazovači pošleme na port číslo 6H (segment b = 2, a k němu segment c = 4). Takže prostě v programu bychom mohli provést instrukci MOV P2,#06H. (Píši mohli provést, neboť o kousek dále si vysvětlíme, proč to ještě takto snadno nejde), a na sedmisegmentovce na portu 2 se rozsvítí znak symbolizující číslo 1.
      Teď byste již měli principu zobrazení rozumět. Pro příklad si ještě můžete vyzkoušet převést následující znaky do jejich HEXA reprezentace, kterou je nutno pro jejich rozsvícení "poslat" na port.

23 E 0 0 s tečkou
91D / 5BH79D / 4FH 121D / 79H 63D / 3FH 191D / BFH


Nyní by již mělo zase být poněkud více jasné, jak "to" udělat. Nastává čas, osvětlit několikrát zmiňovanou větu "ale takhle jednoduše to nejde" .
      Vše má těsnou souvislost s hardwarem - jedná se o konstrukci portů u procesoru typu x51 (pokud jste pozapomněli, podívejte se na stránku portů a vraťte se sem zpět). Totiž všechny porty kromě portu P0 jsou pseudoobousměrné, a ne plnohodnotné obousměrné porty. Port je schopen "stáhnout" úroveň na pinu k zemi, ale protože výstupní tranzistor pinu (je vidět na obrázcích na odkazované stránce) - opět kromě P0, má kolektor připojen k Vcc přes ošetřovací rezistor relativně velké hodnoty, není schopen, dodat vývodem výstupní proud směrem ven (řečeno laicky).
      Pro nás jako návrháře z toho tedy vyplívá, že pokud chceme připojit k pinu portu například LED, pro jejíž rozsvícení již potřebujeme pinem portu nechat procházet relativně velký proud (10 mA), musíme LED zapojit anodou na +Vcc, a katodou na pin portu - samozřejmě přes rezistor. No a pokud budeme chtít LED rozsvítit, musíme pin nastavit překvapivě do úrovně logické L.
      Toto pravidlo platí všeobecně, proto je dobré si jej zapamatovat, prostě u ATMELa zapojovat vše tak, aby aktivní úroveň byla logická nula (tedy L). I výstupy, které jsou posíleny tranzistory zapojuji s tranzistory typu PNP (až na pár vyjímek).


     Takže, jestliže se chceme konečně dopracovat ke skutečnému a funkčnímu zapojení, na kterém si vše odzkoušíme, musíme VŽDY připojit sedmisegmentovku se společnou anodou připojenou na +Vcc, a jednotlivé vývody katod připojené k pinům portu. Nyní se změní samozřejmě i hodnota zasílaná na port, a to tak, že musíme jednotlivé bity negovat, jinak by segmenty, které chceme mít zhasnuté svítili a naopak. K tomu je určena instrukce negace - CPL. Nejlépe si vše objasníme na opět velmi jednoduchém konkrétním funkčním příkladu programu. Toto zapojení jsem kdysi dělal do jednoho soutěžního vozu, pro signalizaci zařazeného rychlostního stupně, a nyní nám poslouží jako triviální příklad. Takže opět si zapojte vše podle schématu (schéma ke stažení ve větším rozlišení naleznete na konci stránky, a taktéž jak zdrojový tak i přeložený soubor příkladu). A nyní se podíváme na vlastní zdrojový kód programu. V něm se mimo jiné naučíme použití několika dalších instrukcí, testování vstupů a také si vysvětlíme pojem podprogram (rutina, subrutina). K tomuto příkladu již nebudu malovat vývojový diagram, vše si popíšeme slovně. Než začneme, bylo by vhodné, popsat, jak program pracuje.
     Program neustále testuje tlačítka připojená na portu P1. Jestliže zjistí, že je některé z tlačítek stisknuté, rozsvítí na displeji odpovídající číslo (nebo znak), které zůstává svítit až do stisku dalšího tlačítka. Pro signalizaci polohy neutrál je zvolen znak pomlčka a pro zpětný chod (zpátečku) je použit znak C (velké písmeno C). V programu není ošetřován kolizní stav stisknutí více tlačítek najednou, neboť to v reálné konstrukci (řazení v automobilu - jde zařadit vždy jen pouze jedna rychlost) bylo ošetřeno mechanicky. Ale upozorňuji na to, neboť je třeba se vždy u programu snažit eliminovat co nejvíce chybových stavů, způsobených uživatelem. Což platí všeobecně pro všechny počítačové programy, rozhodně uznejte, je lepší, když program zahlásí, že je vloženo např. neplatné číslo, než aby se buď zhroutil sám (v lepším případě), nebo aby dokonce dokázal zhroutit celý systém.
;********************************************************************
$MOD51
$TITLE(BYTE SIGNED MULTIPLY)
$PAGEWIDTH(132)				;HLAVICKA
$DEBUG
$OBJECT
$NOPAGING
;********************************************************************

ORG 0
	MOV P1,#0FFH		;aktivace portu pro cteni vst. hodnot
	MOV A,#080H
	ACALL displej

smyc1:	JNB P1.0,jedna		;testuj stavy mikrospinacu a pri  
	JNB P1.1,zpatecka	;aktivite posli cislo na displej
	JNB P1.2,neutral
	JNB P1.3,pet
	JNB P1.4,ctyri
	JNB P1.5,tri
	JNB P1.6,dva
	SJMP smyc1

jedna:  MOV A,#6H		;reprezentave	cisla 1
	ACALL displej	
	SJMP smyc1

dva:	MOV A,#05BH		;reprezentave	cisla 2
	ACALL displej	
	SJMP smyc1

tri:	MOV A,#04FH		;reprezentave	cisla 3
	ACALL displej
	SJMP smyc1

ctyri:	MOV A,#66H		;reprezentave	cisla 4
	ACALL displej
	SJMP smyc1

pet:	MOV A,#06DH		;reprezentave	cisla 5
	ACALL displej
	SJMP smyc1

neutral:MOV A,#40H		;reprezentave	pomlcky 
	ACALL displej
	SJMP smyc1

zpatecka:MOV A,#39H		;reprezentave	znaku C
	ACALL displej
	SJMP smyc1

;********************************************************************
displej:CPL A		;provede negaci a posle ven
	MOV P2,A
	RET	

        END
;********************************************************************
      Na začátku je jako vždy nejprve hlavička zdrojového souboru. Direktivou ORG0 nastavíme počáteční adresu programu na adresu 0. Nyní zápisem hodnoty 0FFH zapíšeme do výstupního registru portu P1 jedničky, tím jej nastavíme do vstupního režimu. Nyní vložíme do Akumulátoru (již známe z minula) hodnotu 80H. Proč ? To si za chvilku povíme.
      Následující instrukcí je instrukce ACALL. Tuto instrukci ještě neznáme. tak se na ni podíváme podrobněji. Tato instrukce provede volání podprogramu ležícího na adrese uvedené za touto instrukcí. V praxi to znamená, že se uloží návratová adresa do zásobníku, provede se skok na podprogram, a po jeho vykonání se instrukcí RET na konci podprogramu vyzvedne návratová adresa ze zásobníku a zavede se do programového čítače (Program counter - PC). Prostě a jednoduše instrukcí RET se vrátíme z podprogramu zpět na instrukci následující za instrukcí volání podprogramu. Pro naprosté pochopení můžeme opět sáhnout po staré dobré kuchařkové analogii. V receptu máme např. rozklepněte vejce, a vložte na pánev. Takže co uděláme ? Po přečtení rozklepněte vejce "bude zavolán podprogram" který zajistí dojít do lednice, rozklepnout vejce a uklidit skořápku. Po návratu z tohoto podprogramu se bude pokračovat dalším krokem - vložte na pánev.
      Protože hledání adresy, na kterou skočit je nemyslitelné, opět použijeme nám již známé návěští, kterým je libovolné slovo, pro lepší orientaci jsem zvolil slovo displej. Takže volání ACALL displej provede skok na adresu s tímto návěštím. Jestliže se podíváme na samý konec prográmku, na rutinu "displej" zjistíme, že provede následující kroky: instrukcí CPL A neguje všechny bity akumulátoru - to je nutné kvůli hardwarovému připojení displeje - aktivní jsou bity v log. L.
      Další instrukce (MOV P2,A) provede odeslání hodnoty na port procesoru, a v tomto okamžiku se tedy rozsvítí ty segmenty, kde je na portu log. úroveň L, naopak zůstanou zhasnuté ty, kde je log. úrpveň H. Poslední instrukcí této rutinky je RET, která zajistí návrat z tohoto podprogramu na instrukci následující za instrukci ACALL.

     Ptáte se, v čem je hlavní kouzlo podprogramů ? Představte si, že místo každého volání "ACALL displej" budete muset vložit obsah této rutiny. Jsou to sice jen 2 řádky, použitím podprogramu máme ušetřeno cca 7 řádek kódu, ale vezměte si např. rutinu vícebytového dělení, která má kolem 100 řádek kódu. To je již značná úspora (času, paměti, nervů, račte doplnit další ...), pokud místo každého vypisování rutiny pouze zapíšete ACALL, nebo LCALL s návěštím dělení.
     Protože jsme po zapnutí vložili do akumulátoru hodnotu 80H, následným zavoláním rutiny displej dojde k rozsvícení desetinné tečky na segmentovce. Chtěl jsem tuto signalizaci, aby po zapnutí bylo ihned vidět, že zařízení "žije". Po návratu z rutiny displej pokračujeme dále instrukcí JNB P1.0,jedna. Opět nová instrukce, opět popis. Jde o velice jednoduchý test stavu vývodu, jistě z překladu Jump Not Bit poznáte, o co jde. Tato instrukce provede skok na relativní adresu (návěští) uvedenou za ní, pokud je testovaný bit v log.L. Pokud je v log. H, pokračuje se následující instrukcí. Opakem této instrukce je JB xx,xx, která naopak skočí na adresu (návěští), pokud je testovaný bit nastaven (log. H).
      Ale zpět k programu. Takto testujeme všechny připojené vstupy, a pokud je na některém log. úroveň L (pamatujete ? nejprve jsme na celý port zapsali log.H), znamená to stisknuté tlačítko. Takže pro příklad bude stisknuté tlačítko na P1.3. Program testuje P1.0, ten je v log. H, čili pokračujeme následující instrukcí. Port 1.1 také H, jedeme dál, P1.2 taktéž, znovu pokračujeme, P1.3 - log.L. Zde tedy program skočí na návěští "pet". POZOR PRO ZAČÁTEČNÍKY - nepleťte si skok a volání podprogramu, u obojího se skáče, ale pokaždé jinak. Na návěští "pet" se do akumulátoru zadá hodnota 06H, což je hodnota, která zaslaná na port způsobí rozsvícení segmentů, odpovídající číslu 6. Když máme hodnotu uloženu v akumulátoru, následuje volání podprogramu "displej", který zajistí negaci a odeslání na port. Po návratu z podprogramu je následující instrukcí SJMP smyc1. Tato instrukce zajistí (Small JuMP) skok na počátek programu, na návěští "smyc1". A opět pokračujeme testy znovu. Pokud není žádné tlačítko stisknuto, samozřejmě zůstává na displeji svítit poslední zobrazované číslo. A to je celé. Pokud budete chtít, můžete si podle níže uvedené tabulky vyzkoušet změnit některá čísla - hodnoty posílané na port (displej).

Odpovídající reprezentace3FH06H5BH4FH66H6DH7DH7H7FH6FH40H0H80H
Zobrazený znak012 3 4 5 6 78 9 - prázdny znaktečka

Žlutě označené znaky jsou již použity.

Jen na doplnění, pokud chcete, aby u čísla svítila i desetinná tečka, prostě přičtete její bit o váze 128 ke zbytku čísla. Např. pro rozsvícení čísla 6 a tečky zašleme na port hodnotu 7DH (šestka) + 80H (tečka) = FDH (253D).

     Takže teď jen zbývá podle návodu na předchozí stránce přeložit buď stažený zdrojový kód, a naprogramovat s ním procesor, nebo naprogramovat rovnou soubor ve formátu *.hex pro ověření funkce. Doporučuji Vám "pohrát" si se zdrojovým kódem a vyzkoušet si změnit hodnoty, případně si vytvořit popsaným postupem vlastní znaky nebo písmena. Zkoušením se naučíte víc, než pouhým kopírováním.




Ke stažení jsou tyto soubory:


Velikost 60 kByte  Příklady - ASM i HEX soubor a schéma v plné velikosti

Vím, že tento příklad nedokáže zobrazit žádný výsledek výpočtu a podobně, ale je prostě nutné nejdříve pochopit základ a pak můžeme pokračovat dál. Pokud Vás ani tato stránka od Vašeho přání naučit se programovat neodradila, pak Vám gratuluji. Chcete-li, můžete pokračovat další stránkou popisující kouzlo multiplexu.


Vytisknout stránku

Zpátky Zpátky
© DH servis 2002 -