Softver

Autor:  Golubović Dragan, dipl. ing.

 

 

 

ARB PIC16C84

U svom dosadašnjem predstavljanju programska biblioteka ARB je bila namenjena programiranju za mikrokontrolere iz Intel-ove serije kompatibilne sa 8051. Od ovog broja idemo korak dalje: dokazaćemo svrsishodnost primene ovog objektno orijentisanog interfejsa na slučaju popularnog mikrokontrolera PIC16C84, a u perspektivi i na ostalim mikrokontrolerima iz poznate Microchip-ove serije.


Svesni rizika da ponavljamo izvesne napomene iz izlaganja vezanog za Intelove mikrokontrolere, u ovom delu ćemo se podsetiti osnovnih postavki programske biblioteke ARB. Ukratko: ARB je softverski alat koji po našem mišljenju bitno olakšava proces programiranja za odgovarajući mikrokontroler. Polazeći od saznanja da ljudi koji se bave elektronikom i koji u svoje uređaje ugrađuju neki osmobitni mikroprocesor, mikrokontroler gotovo uvek koriste asembler kao jezik u kome se ogleda arhitektura tog mikroprocesora odnosno mikrokontrolera. Kao odgovor zašto ne upotrebljavaju neki viši programski jezik (C ili bejzik na primer), pomoću koga bi sa lakoćom rešili veoma složene probleme, oni sa pravom ukazuju da u tim jezicima ne raspoznaju svojstva arhitekture svog mikrokontrolera kao i to da raspoloživi kros-kompajleri generišu relativno glomazan kod. Dakle prvi princip ARB programiranja glasi:

Nijedan programer u asembleru ne može da stvori optimalniji izvršni kod od ARB programera ili drugačije rečeno svaka programska linija asemblerskog programa sadrži odgovarajući ekvivalent u ARB programu.
 

S druge strane programiranje u asembleru je u osnovi mukotrpan posao, sa povećanjem programa slabi programerska produktivnost. Takođe, programeri se vezuju za određeni set instrukcija i otežano prelaze na neki drugi mikrokontroler, što u uslovima gotovo svakodnevnog nastanka nekog novog mikrokontrolera treba uzeti u obzir. Prema tome drugi princip ARB programiranja bi mogao da glasi:

Usvojiti takvu programersku notaciju koja je mnogo bliža prirodnom načinu razmišljanja i koja je čak razumljiva i onima koje se ne bave dotičnim mikrokontrolerom ili uopšte mikrokontrolerima. 


Već je pomenut problem “programerske produktivnosti”. Asemblerski programeri se svakako ne mogu time pohvaliti. Isto tako se nedovoljno efikasno koriste stari programi, stari problemi, upotreba čestih programskih rutina nije najbolje rešena a o stvaranju novih objekata, čijom ugradnjom bi se znatno uvećala produktivnost, nema ni govora. Ovoga su svesni tvorci pojedinih asemblera ( kao što je Microchip-ov MPASM) pa su u njega ugradili izvesne elemente preuzete iz viših programskih jezika kao što su direktive za kontrolu toka programa, makroi, deklaracija varijabli itd. Međutim, ni ovim nisu u potpunosti rešeni svi problemi. I dalje sa povećanjem programa postaje otežano njegovo održavanje, proces ispravljanja greški je takođe usporen, a najteži problemi nastaju kod ( inače česte ) potrebe modifikacije programa. Stoga polako dolazimo do sledećeg principa ARB programiranja:

Omogućiti programiranje u objektno orijentisanom okruženju, proces stvaranja novih objekata od početka do kraja prepustiti programeru koji će ih u pravom momentu i na najbolji način upotrebiti u skladu zahtevima koji mu se postavljaju.


Realizacija poslednjeg načela je ujedno i najveći izazov budućim ARB programerima. Njime ova programska biblioteka dobija neslućena svojstva. Od ovog broja časopisa “Mikroelektronika” imaćemo priliku da se uverimo tačnost izrečenih tvrdnji. 

Biblioteka ARB nije ni poboljšani asembler niti nova varijanta C kros-kompajlera. Ona svakako nije C++ kros-kompajler kako bi to neko možda pomislio. 

Šta je zapravo biblioteka ARB biće jasnije iz daljeg teksta.


ARB i PIC16C84


Set naredbi ovog Microchip-ovog mikrokontrolera a uzimajući u obzir njegovu RISC (Reduced Instruction Set Computer) arhitekturu, sastoji se od svega 35 instrukcija. Prvi skup instrukcija zajedno sa svojim ARB ekvivalentima je predstavljen Tabelom 1.

Instrukcija Odredište w Odredište f
addwf f,d w+f f+w
andwf f,d w&f f&w
clrf f - f=0
clrw - w=0 -
comf f,d w<~f `f
decf f,d w<--f --f
decfsz f,d Skip(w<--f,!w) Skip(--f,!f)
incf f,d w<++f ++f
incfsz f,d Skip(w<++f,!w) Skip(++f,!f)
iorwf f,d w|f f|w
movf f,d w=f f=f
movwf f - f=w
rlf f,d w<Rot(f(c),LEFT) Rot(f(c),LEFT)
rrf f,d w<Rot(f(c),RIGHT) Rot(f(c),RIGHT)
subwf f,d w-f f-w
swap f,d w<f,Swapf() f,Swapf()
xorwf f,d w^f f^w
Tabela 1.

Površnim pogledom na neku od kolona Tabele 1 uočavamo značenje iznetih načela. Svakoj instrukciji, kako je već rečeno, odgovara jedna programska linija. Dok u asembleru odredišni registar specificiramo argumentom d (0 ili 1), ARB podržava pravilo “levog operanda”. To zapravo znači da se rezultat određene operacije smešta u levi operand odgovarajućeg izraza. Na primer: rezultat operacije w+f biva prosleđen akumulatoru, fČw registru f itd. Ukoliko se, međutim, radi o unarnim operacijama kao što su inkrementiranje, dekrementiranje, komplementiranje i dr. rezultat biva prosleđen registru na koji se odnosi ta operacija. To praktično znači da se rezultati operacija ++f,—f, f.Swapf() smeštaju u registre f. Kada jasno želimo da naglasimo odredišni registar, a to nije moguće implicitno iz izraza onda pozivamo u pomoć operator odredišta ‘<’ (videti drugu kolonu Tabele 1!). Interesantno je zapaziti da, na primer, izraz oblika w<++portA biva protumačen kao jedna instrukcija incf f,0 dok linija w=++portA biva protumačena kao dve incf f,1; movf f,0 ! Izlaganje o ovom delu završićemo kratkom programskom sekvencom koja će sve ovo ilustrovati:

portB=(w&portA)+(loc+w); // addwf loc,f 
// andwf portA,w
// addwf loc,w
// movwf portB

Sledeća grupa instrukcija se odnosi na manipulacije sa bitovima. Microchip-ovi projektanti predvideli su četiri sledeće instrukcije ( Tabela 2 ).

Instukcija ARB PIC 16C84
bcf f,b f(b)=low
bsf f,b f(b)=high
btfsc f,b Skip(!f(b))
btfss f,b Skip(f(b))

Tabela 2.

Resetovanje nekog bita u registru obavlja se prostim izrazom f(b)=low; (na primer portB(1)=low ili bcf portB,1), a testiranje bita izrazom Skip(). Na ovom mestu treba zapaziti višeznačnost ovog izraza: naime, ovaj izraz egzistira i u prvoj grupi instrukcija (Tabela 1).

Smatramo da ne treba posebno objašnjavati značenje ovih izraza, osim što treba još jednom podsetiti da se značenja upotrebljenih operatora u potpunosti poklapaju sa značenjem koja oni imaju u programskom jeziku C. 

Instrukcija

ARB PIC 16C84

addlw k w+k
andlw k w&k
call k Call *
clrwdt - Clrwdt()
nop Nop()
goto k Jump **
iorlw k w|k
movlw k w=k
retfie - Retfie()
retlw k Retlw(k)
return - Return()
sleep - Sleep()
sublw k w-k
xorlw w^k

Tabela 3.

Na kraju nam ostaju instrukcije koje se odnose na manipulacije sa akumulatorom, instrukcije grananja, poziva potprograma i dr. ( Tabela 3 ).

Napomena: izrazi Call * i Jump ** biće podrobno objašnjeni u posebnom poglavlju i poglavlju o blokovima. 

Sledeći već predstavljenu logiku, jasno je kako su ove instrukcije implementirane u biblioteci ARB PIC16C84. Vredi napomenuti da u ovom skupu instrukcija ostaju instrukcije kod kojih primena C operatora ne bi bila svrsishodna ( Clrwdt(),Retfie(),Retlw(k) itd. )

pa se u tim slučajevima pristupilo zadržavanju originalnih Microchip-ovih mnemoničkih oznaka. Pored toga, kod izraza ‘w op k’ ( op – operator ) ARB dozvoljava predstavljanje broja k u decimalnom, heksadecimalnom i binarnom obliku. Kada je reč o ovom poslednjem to se izvodi na sledeći način:

w=”11001110”;
w+”01010101”;

itd.

Tipovi podataka u ARB PIC16C84

Osnovna klasa u ARB PIC16C84 je klasa reg. Klase direct, sfr, gpr i flag su izvedene iz osnovne klase. Ove klase pokrivaju objekte tipa registar i bit. Pored ovih klasa nezaobilazno mesto u ARB programiranju zauzima klasa block pomoću koje u našim programima realizujemo instrukcije grananja i poziva potprograma.

Kada su u pitanju tzv. registarske klase, najčešće ćemo biti u prilici da koristimo objekte tipa gpr (General Purpose registers) i flag. Kao što se već naslućuje upotrebom klase gpr stičemo mogućnost definisanja i deklarisanja registarskih varijabli čije su lokacije u okvirima istoimene banke registara. Objekte flag koristimo kada se ukaže potreba za deklaracijum bit-varijabli. Jedini objekat klase reg jeste akumulator w i zato ovu klasu koristimo znatno ređe ( u slučajevima kada želimo da preimenujemo akumulator kao i kod deklaracija pojedinih funkcija čiji je parametar objekat tipa reg, ili funkcija koje vraćaju objekat reg). Varijable tipa sfr (Special Function Registers) su već definisane (videti zaglavlje pic16c84.h ) i njihova ponovna definicija nije neophodna. Promenljive tipa block zaslužuju posebno razmatranje i one neće biti predmet izlaganja ovog poglavlja. No, vratimo se varijablama tipa gpr i flag

Postoje dva oblika deklaracije ovih promenljivih. To su:

gpr loc1;
gpr loc2(pos);

‘pos’ je celobrojna vrednost, koja označava poziciju registra u memorijskoj banci. Varijablu flag deklarišemo na sledeće načine:

flag mark1;
flag mark2=temp(pos);


‘pos’ celobrojna vrednost između 0 i 7.
temp – bit adresabilni registar; 
‘pos’ pozicija bita u registru

Ostaje pitanje koju poziciju u memorijskoj banci odnosno koju poziciju u registru sadrže varijable loc1 i mark1. 
Odgovor je: nulta pozicija. Ovaj način je posebno pogodan u nekim situacijama kao što su deklaracije složenih tipova podataka: strukture, klase, deklaracije funkcija itd. Dodeljivanje pozicije se vrši odloženo, primenom operatora ‘<<’ kao u sledećim primerima:

gpr x;
x<<0x0f;
// posle ovoga x dobija adresu 0x0f
flag y;
y<< portA(3);
// posle ovoga bit y postaje bit portA(3) 


Varijable tipa block


Ovde dolazimo do verovatno najinteresantnijeg dela priče o biblioteci ARB. Osnovna namena ovih promenljivih bila je dodeljivanje onih svojstava biblioteci ARB koje ima asembler posedovanjem labela. I zaista, blokovi su prvenstveno zamena za labele. Međutim, tu se ne završava priča o ovim varijablama. Naime, svaki blok u ARB programu ima svoj početak i kraj. Po pravilu, blok započinje levom velikom zagradom, deklaracijom bloka,zatim sledi telo bloka i na kraju desna velika zagrada. Ukoliko se blok nalazi unutar velikih zagrada ( što je najčešće slučaj ), varijabla block se sa stanovišta C/C++ tretira kao lokalna promenljiva i njoj je nemoguće pristupiti ( navođenjem imena varijable ) izvan velikih zagrada! Zbog toga je i uveden pojam imenovanog bloka tj. bloka deklarisanog sa celobrojnim identifikatorom.

Zahvaljujući tome moguće je uskakanje na početak bloka, ( Jump ) i pozivanje ( Call ) određenog bloka sa mesta koje se nalazi izvan granica bloka.

Naziv funkcije pridružen objektu block

ImeBloka.Again()

ImeBloka.Break()

ImeBloka.Jump(IDD)

ImeBloka.Call(IDD)

ImeBloka(IDD)

Tabela 4.

Sa mesta koja se nalaze unutar bloka, moguće je postaviti naredbu ponovnog izvršenja bloka (ImeBloka.Again()), iskakanja iz bloka (ImeBloka.Break()) kao i grananja na i pozivanje podblokova (ImeBloka.Jump(IDD) i ImeBloka.Call(IDD) ) (videti Tabelu 4).

Treba naročito obratiti pažnju na okolnost da se radi o funkcijama koje su pridružene klasi block što praktično znači da se ispred poziva neke od funkcija obavezno navodi ime varijable block. Čest oblik deklaracije promenljive block izgleda ovako:

{
block s(NAME_BLOCK); 

celobrojnu promenljivu NAME_BLOCK treba unapred definisati (NAME_BLOCK>10)

linija 1; 
linija 2;
……..
linija n
// poslednja linija bloka 
}

Skok na blok s ili pozivanje bloka s obavlja se isključivo samostalnim funkcijama Jump(NAME_BLOCK) odnosno Call(NAME_BLOCK). 
Ponekad je pogodnija deklaracija tzv. razbijenog bloka:

{
enum loop{LOOP1=100,LOOP2,…LOOPn};
block s;
s(LOOP1);
//početak prvog segmenta
linija 11;
linija 21;
……….
linija m1
s(LOOP2);
//početak drugog segmenta
linija 12;
linija 22;
……….
linija m2;
…………
…………
s(LOOPn);
//početak n-tog segmenta
linija n1;
linija n2;
……….
linija mn;
}

Iz jednog segmenta ( na primer s(LOOP4) ) moguće je grananje na neki drugi segment (na primer s(LOOP2) ) navođenjem funkcije s.Jump(LOOP2). To se isto odnosi i na pozivanje pojedinog segmenta ( primer: s.Call(LOOP1) ). O funkcijama Break() i Again() ne treba posebno trošiti reči. Njihova upotreba je krajnje jednostavna i umećemo ih na ona mesta u programskom bloku odakle želimo da bezuslovno napustimo izvršenje tog bloka odnosno ponovimo njegovo izvršenje. 

Napomena: primetna je dvostruka upotreba funkcija Jump() i Call()! U prvom slučaju, kako je već rečeno, radi se o tzv. samostalnim funkcijama što znači da je njihovo pozivanje oblika Jump(NAME_BLOCK) tj. Call(NAME_BLOCK) (nema varijable block ispred imena funkcija). U drugom slučaju je reč o pridruženim funkcijama pa je navođenje imena block varijable ispred imena funkcija neophodno (s.Jump(LOOP2)). Ovde, međutim, nije kraj vratolomija sa funkcijama Jump() i Call(). 


Dodatne mogućnosti funkcija Jump() i Call()


Da ne bi došlo do zabune, prikazaćemo sve moguće oblike upotrebe ovih funkcija.( videti Tabelu 5 )

Jump Call Napomena
ImeBloka.Jump(IDD) ImeBloka.Call(IDD) upotreba u razlomljenim blokovima
Jump(IME_BLOKA) Call(IME_BLOKA) upotreba kod imenovanih blokova
Jump(ImeFunkcije) Call(ImeFunkcije) deklaracija: void ImeFunkcije(void)

Tabela 5.

Prva dva načina su donekle već predstavljena ( u narednim primerima biće više reči o njima). Treća upotreba Jump() i Call() u načelu nije vezana za blokove ili segmente blokova. Ovaj način dolazi do izražaja kod grananja i pozivanja delova programa smeštenom u klasične C procedure definisane kao void ImeFunkcije(void). U nekim slučajevima ovaj način nudi određene pogodnosti koji prva dva načina nemaju. Svesrdno preporučujemo ovu upotrebu funkcija Jump() i Call(). ( više o ovome u primerima koji predstoje ).

Instalacija i pokretanje ARB PIC16C84

ARB PIC16C84 je C++ biblioteka klasa što znači da je neophodna prethodna instalacija odgovarajućeg C++ kompajlera. Instalacija se obavlja jednostavnim kopiranjem sledećih datoteka u novoformirani direktorijum arb:

- arb.bat
- pic16c84.h
- pic16c84.lib

U editoru napravimo izvornu datoteku ( na primer test.cpp ) a zatim iz DOS-a izvršimo sledeću naredbu: <arb test>
Ukoliko je sve urađeno ispravno na ekranu će biti ispisane poruke kompajlera i linkera a potom poruka o broju programskih reči programa, broj grešaka i ime odredišne datoteke (ovo ime specificiramo funkcijom Choice() ). U protivnom biće ispisane poruke o greškama od prevodioca ili od programske biblioteke ARB u zavisnosti od prirode nepravilnosti programa. Naime, postoji mogućnost da je program sintaksno nekorektan sa stanovišta C++, pa se u tom slučaju oglasi kompajler sa svojim porukama o greškama. Tada treba pristupiti otklanjanju nepravilnosti i ponoviti prevođenje sve dok se ne pojavi ispisana poruka o uspešnom prevođenju i povezivanju. Ukoliko, međutim, program sadrži greške sa stanovišta ARB sintakse, na ekranu će se pojaviti odgovarajuće poruke o tome i što je najvažnije, neće biti generisan fajl u intel-hex formatu koji je neophodan za dalju obradu. 

ARB Studio – Win95 razvojno okruženje


Ljubiteljima Windows okruženja biće isporučen program ARB Studio koji u mnogome olakšava rad sa ovom programskom bibliotekom. Osnovna ideja ovog programa je u tome da automatizuje poslove vezane za upotrebu biblioteke ARB, objedini više mikrokontrolera u isto programsko okruženje, kao i olakša proces izrade nove ARB aplikacije.

6s151.jpg (11490 bytes)
Slika 1.

Posle aktiviranja programa pojavljuje se dijalog-prozor prikazan na Slici 1. Postojeće datoteke se mogu otvoriti eksplicitno: navođenjem imena datoteke u liniji za editovanje ili otvaranjem tzv. FileOpen dijaloga kako je to već postalo uobičajeno u mnogim Windows programima. Prikazivanje i modifikovanje izvornog koda omogućava obavezni Windows editor – Notepad. Klikom na dugme ARB pokreće se C++ kompajler. Treba naglasiti da je korisnik sve vreme u Windows okruženju raspolažući svim pogodnostima koje ono omogućava. 
Posebno je interesantna opcija New. Njenim aktiviranjem pojavljuje se prozor prikazan na Slici 2

6s152.jpg (14872 bytes)
Slika 2.

U edit kontroli Name unosimo ime programa ( primer:Novi ) čime određujemo imena odgovarajućih cpp i hex datoteka. U listi Microcontroller vršimo izbor mikrokontrolera ( što je od značaja ukoliko imamo više tipova mikrokontrolera ), a zatim pređemo na generisanje kostura novog programa pritiskom na dugme OK. Ova pogodnost koju pruža ARB Studio je od posebnog značaja jer nas oslobađa pisanja onih delova koda koji su obavezni i koji se javljaju u svim programima. Izgled osnove novog programa ( sa komentarima ) generisanog na ovaj način predstavljen je na slici br.3.

6s153.jpg (10058 bytes)
Slika 3.

Naravno, ovako generisan izvorni kod podleže daljim izmenama, dodavanjima i brisanjima. U našem slučaju, izbor je pao na mikrokontroler PIC16C84 pa je u kod ugrađeno odgovarajuće zaglavlje (pic16c84.h ). Ova mogućnost otvara nove perspektive ovog softvera u pogledu izrade programa za različite mikrokontrolere istom programskom sintaksom. 

ARB PIC16C84 na delu

Primerima koji slede želimo potkrepiti tvrdnje i principe izložene na početku ovog članka. Ono što posebno naglašavamo je činjenica da su svi izloženi primeri potvrđeni u praksi, a da je pritom korišćen Borland-ov kompajler C++ 5.0 . Prvi primer demonstrira primenu biblioteke ARB na jednostavnom slučaju kakav je periodično aktiviranje pojedinih LED dioda čime se stvara utisak “šetajuće” diode. Istovremeno, biće još jednom objašnjeni pojmovi kao što su promenljive block , funkcije Jump i Call. Drugi primer se bavi ispisivanjem niza znakova na LCD-u i on bi trebalo da predstavlja presek najvažnijih pojmova, metoda i tehnika koji nalaze primenu kod biblioteke ARB. 

LISTING: program diode
#include <stdio.h>
#include "pic16c84.h"
#include "pause.h"
const int TABLE=10;
main()
{
Choice("diode.hex",INTEL_HEX);
gpr index(0x0f);
     LC=0;
     rp0=high; // banka 1
     trisB=0; // portB je izlazni port
     rp0=low; // banka 0
     index=w=0;
     {
     block m;
     Call(TABLE); // poziv rutine TABLE
     portB=w;
     Call(Pause); // kasnjenje
     w=++index; // uvecanje brojaca
     Skip(index(3));// preskok ako je index>7
     m.Again(); // opet blok m
     index=w=0; // postavljanje brojaca
     m.Again(); // opet blok m
     }
     {
     block table(TABLE);
     pcl+w;
     Retlw("00000001");
     Retlw("00000010");
     Retlw("00000100");
     Retlw("00001000");
     Retlw("00010000");
     Retlw("00100000");
     Retlw("01000000");
     Retlw("10000000");
     }
return 0;
}

Izvršenjem programa LEDiode aktiviraju se naizmenično jedan po jedan izlaz na portu B pa ukoliko su na ovaj port spojene LEDiode stiče se utisak cikličnog pomeranja jedne sveteleće diode. Ovaj program je između ostalog poučan zato što razotkriva način upotrebe funkcije Call . Na jednoj strani imamo Call(TABLE) tj. poziv imenovanog bloka odnosno programskog bloka koji je sastavni deo glavnog programa (videti listing) a na drugoj Call(Pause) gde je Pause ime rutine void Pause(void) deklarisane u zaglavlju pause.h. Zaglavlje pause.h ovde nije predstavljeno i osim procedure Pause sadrži i druge kojima se realizuju određena vremenska kašnjenja. (datoteku pause.h moguće je dobiti kod autora članka ) Vidimo da upotrebom Call(ImeFunkcije) i Jump(ImeFunkcije) stičemo mogućnost korišćenja ranije napisanih procedura koje su definisane u drugim datotekama.

LISTING:   funkcija void Pause(void)
void Pause(void)
{
enum loop{LOOP1=100,LOOP2};
gpr cnt1(0x0c),cnt2(0x0d),cnt3(0x0e);
     cnt1=w=5;
     block delay; // pocetak bloka 'delay'
     Nop();
     cnt2=w=0xff;
     delay(LOOP1); // labela LOOP1
     Nop();
     cnt3=w=0xff;
     delay(LOOP2); // labela LOOP2
     Nop();
     Skip(--cnt3,!cnt3);
     delay.Jump(LOOP2); // skok na LOOP2
     Skip(--cnt2,!cnt2);
     delay.Jump(LOOP1); // skok na LOOP1
     Skip(--cnt1,!cnt1);
     delay.Again(); // skok na pocetak bloka
     Return(); // izlaz iz potprograma
}

Da bismo ilustrovali i treći oblik implementacije ovih funkcija pozabavićemo se upravo procedurom void Pause(void) koja se koristi u prethodnom ali i sledećem primeru. Ova procedura je interesantna zbog primene tzv. razlomljenog bloka, što je tehnika koja ima veliku primenu u ARB programiranju. Za one koji imaju iskustva u programiranju za PIC16C84 ili neki drugi, kod ove funkcije je razumljiv. Radi se o tri ciklusa ( ugnježdene petlje ) čijim se izvršenjem stvara određena vremenska zadrška. 
Mada se funkcijama Break() i Again() postiže efekat rada sa elementima strukturnog programiranja, s obzirom na prvi princip od koga smo pošli u izlaganju da ARB programeru omogućimo stvaranje maksimalno optimizovanog koda, u praksi se došlo do saznanja da sama primena ovih funkcija ne daje uvek dobre rezultate. Pridruženim funkcijama block.Jump() i block.Call() omogućava se grananje i pozivanje pojedinih delova bloka, u našem slučaju bloka delay. Naglašavamo obavezu da kod pozivanja ovih funkcija ispred imena stavimo ime bloka ( delay ). Izostavljanje ovoga dovelo bi do javljanja poruke o grešci. Druga važna pojedinost jeste u pridruživanju svakom segmentu bloka (podbloku ili labeli svejedno) jedinstvenih celobrojnih identifikatora koji moraju biti veći od 100 (linija enum loop(LOOP1=100,LOOP2)). Po pravilu pojedini segment bloka nemoguće je pozvati izvan opsega bloka, što na izvestan način obezbeđuje “privatnost” delova bloka ( doduše, postoje tehnike kojima bi se “probila” ova barijera ali o tome u nekom drugom nastavku ).

Verujemo da su ovi primeri dovoljni da se shvate osnovni elementi ARB programiranja za mikrokontrolere, bar što se tiče blokova kao i raznovrsne upotrebe funkcija Jump() i Call(). Verujemo, takođe, da su izloženi principi ARB programiranja ( prva dva pogotovo ) kroz predhodne primere postali mnogo jasniji ali ipak ostaje utisak da još ništa nismo rekli o “teškoj artiljeriji” ovog softvera. Kako to obično biva radi se o najmoćnijem ali i najkompleksnijem segmentu ove programske biblioteke čijim se razumevanjem dostižu novi programerski prostori nedostupni onima koji se u svom radu služe nekim drugim softverskim oruđem. Kroz primer o ispisivanju znakova na LCD i klasi ‘LCDstring’ započećemo priču o stvaranju korisnički orijentisanih objekata. Pretpostavimo da treba da napravimo program za PIC16C84 gde je ovaj mikrokontroler spregnut sa LCD-om. Asembler je dobro rešenje ukoliko se radi o jednom programu i jednom tipu uređaja što je, moramo priznati, malo verovatno. Želimo li da jednom stvorene programske rutine ( ili bolje reći principe ) iskoristimo uvek kada se javi problem ispisivanja teksta na LCD i da pritom raspolažemo očiglednom notacijom, onda je ARB najbolje rešenje. Heder datoteka LCD.h sadrži nacrt klase ‘LCDstring’ kao i deklaracije pomoćnih funkcija koje se pozivaju od pridruženih funkcija (metoda) ove klase. 

LISTING: datoteka LCD.h
#include <string.h>
flag rs=portB(2);
flag e=portB(3);
const int TABLE=10;
void Page(int p);
void SendCmd(void);
void SendChar(void);
void LowBit5x7(void){w=0x28;Call(SendCmd);}
void DisplayOnCursorOff(void){w=0x0c;Call(SendCmd);}
void DisplayOnCursorOn(void){w=0x0f;Call(SendCmd);}
void DisplayClear(void){w=0x01;Call(SendCmd);}
void IncrementModFreezDisplay(void){w=0x03;Call(SendCmd);}
void InitLCD(void);
void Delay();
void DelayLong();
class LCDstring {
static int num;
int tab;
public:
LCDstring(void){tab=TABLE+num;++num;}
void Assign(char * pString);
void TextOutUp();
void TextOutUp(gpr a);
void TextOutDown();
void TextOutDown(gpr a);
};

Prikazivanje koda svih funkcija bi nam oduzelo puno prostora (autor članka će rado ustupiti kompletnu datoteku LCD.h svim zainteresovanim) no za razumevanje rada ove klase to čak i nije neophodno. Recimo samo da su asemblerski kodovi rutina SendChar() i SendCmd() kao i slanje teksta na LCD detaljno obrađeni u broju 5 časopisa. Metode TextOutUp() i TextOutUp(gpr a) zadužene su za ispisivanje niske karaktera na gornji red LCD-a. Analogno, sledeće dve funkcije TextOutDown() i TextOutDown(gpr a) obavljaju ispisivanje stringova u donji red LCD-a. Ukoliko se opredelimo za varijantu ovih funkcija sa predajnim parametrom (gpr a) ispisivanje niske ne počinje od prvog znaka već od n-tog znaka gde je n broj prosleđen funkciji preko registra a. Na ovaj način stičemo mogućnost izrade raznih efekata.

LISTING: funkcija void Assign(char *)
void LCDstring::Assign(char * pString)
{
block t(tab);
int cnt=strlen(pString); // uzimamo duzinu niza
pcl=pcl+w;
for(int i=0;i<cnt;i++) // pomocu for petlje
     Retlw(pString[i]); // smestamo znak po znak
Retlw(0); // niz zavrsavamo nulom
}

Funkcijom Assign(char * pString) vršimo smeštanje niza znakova u programsku memoriju mikrokontrolera (videti listing o funkciji Assign(char * pString)).
Zahvaljujući ovoj funkciji vrlo jednostavno možemo smestiti u kod različite niske karaktera prostim pozivanjem ove funkcije kao u sledećem primeru: ImeVarijable.Assign(“probni tekst”); 
Uostalom, pogledajmo kako izgleda program lcd_test koji demonstrira mogućnosti klase ‘LCDstring’. 

LISTING: datoteka lcd_test.cpp
#include <stdio.h>
#include "pic16c84.h"
#include "pause.h"
#include "LCD.h"
main()
{
Choice("lcd_test.hex",INTEL_HEX);
     LC=0;
     Page(1);
     trisB=0;
     Page(0);
     portB=0;
     InitLCD(); // inicijalizacija LCD-a
     LCDstring s1,s2; // stvaranje objekata LCDstring
     {
     block m(MAIN);
     s1.TextOutUp(); // ispisivanje prvog teksta
     Call(Pause); // pauza
     s2.TextOutUp(); // ispisivanje drugog teksta
     Call(Pause); // pauza
     m.Again(); // opet na pocetak bloka 'm'
     }
     s1.Assign(" ARB"); // u programski kod ugraditi
     s2.Assign(" PIC16C84"); // stringove " ARB" i "PIC16C84"
return 0;
}

Izvršenjem programa lcd_test stvara se utisak naizmeničnog ispisivanja prvog (“ARB”) pa drugog teksta (“PIC16C84”) sa određenom pauzom između ispisivanja na LCD. Klasa ‘LCDstring’ dopušta i pravljenje atraktivnijih efekata, ali važnije od toga je saznanje da nam ova klasa može priskočiti u pomoć uvek kada se javi potreba da naši uređaji sadrže LCD. Naravno, postoji mogućnost dogradnje ove klase i drugim funkcijama, ali ovde je bilo najvažnije da izložimo osnovne principe objektno-orijentisanog programiranja za mikrokontrolere i prednosti koje ono pruža. 

Pročitajte više o ovoj temi
Biblioteka klasa i funkcija za 8051 
Funkcije u ARB 8051
Klase u ARB 8051 
Povezivanje LCD-a 
Step motor i PIC 
Programator za PIC16F84 
PIP02 
Portovi 

C o p y r i g h t  1998 mikroElektronika. All Right Reserved. Za sva pitanja obratite se redakciji