May 062013
 

Vidimo da smo se ovde “borili” softverskim metodama protiv jednog problema kojeg su konstruktori PIC kontrolera odlučili da reše na hardverskom nivou pa su dodali mogućnost čitanja stanja sa izlaza leča. Leč možemo da shvatimo kao memorijski element koji pamti jedan bit, i kod koga stanje na izlazu zavisi od stanja na ulazu.

PIC_port_2

Na slici je prikazan uprošćeni prikaz jednog pina PIC kontrolera sa koje se vidi da se ovde kao leč koristi D flip-flop (pravouganik ispod koga piše “Data Register”). Kada čitamo stanje sa porta, signal ide putanjom crvene boje obeležene brojem 1, tj, ide od pina (predstavljen precrtanim kvadratom ispod koga piše I/O pin) preko logičkog I kola kroz bafer (predstavljen trouglom) na sabirnicu podataka (“Data Bus”).
Kada čitamo stanje iz leča, signal sada ide putanjom crvene boje obeležene brojem 2, tj. ide od izlaza leča (obeležen slovom “Q”) preko bafera na sabirnicu podataka, a pošto je izlaz leča odvojen od pina baferom, vidimo da preopterećenje pina neće da dovede do promene stanja na Q izlazu tako da će uvek da bude pročitano upravo ono stanje koje je i upisano u leč, a ne aktuelno stanje na pinu.

Da bismo mogli da čitamo stanje leča, konstruktori su dodali SFR registre koji su označeni sa LATX, gde X pedstavlja naziv porta, tj. za PIC koji koristimo to su registri LATA i LATB tako da bi naš program iz primera 6 sada izgledao ovako:

Tutor10.bas

Sa slike se vidi da su upisi u port i u leč potpuno ista stvar, ali zbog principa čitaj-izmeni-upiši, koji funkcioniše i pri izmeni LATX registra, ne može da dodje do lažnog očitavanja ako je pin preopterećen pa nema potrebe za bilo kakvom zadrškom izmedju dve uzastopne izmene dva pina istog porta.

Pa dobro, ako postoje LATX registri, zašto smo potrošili nekoliko lekcija na obradu problema preopterećenog pina? Najpre zato što LATX registre nemaju svi PIC-evi; ako se budete ozbiljno bavili konstrukcijom uredjaja, koristićete razne PIC kontrolere i pre ili kasnije naići ćete na neki koji nema te registre pa treba da znate kako da se izborite sa potencijalnim problemom.

Medjutim, čitanje stanja direktno sa pina može da bude korisno u nekim situacijama jer možete da utvrdite da li se stanje na izlazu slaže sa postavljenim i na osnovu toga možete, recimo, da detektujete neki problem ili preopterećenje.

Veličina iskompajliranog programa: 82 Word-a

May 062013
 

Pisanje više asemblerskih naredbi korišćenjem znaka @ može da bude malo naporno i nepraktično, i zato postoje naredbe za blok asemblerskih komandi čija sintaksa glasi ovako:

ASM
asemblerske instrukcije
ENDASM

Ovo zapravo i nisu PDS naredbe već pseudonardbe pošto ne proizvode nikakav kod već obaveštavaju PDS kompajler da ono što sledi nisu njegove naredbe i ne treba da ih prevodi pa će sav kod izmedju njih samo preneti dalje asembleru. Maksimalna veličina teksta tog bloka, uključujući i komentare, ne može da bude veća od 8 KB pa ako je taj tekst veći, jednostavno ga podelite u više ASM … ENDASM blokova.

Kao i znak @, ASM postavlja banku na 0 pa pre ENDASM morate da je vratite opet na 0 ako ste je menjali u tom bloku. Takodje ni reč ENDASM ne sme da se nadje nigde u tom bloku asemblerskih naredbi kao komentar jer će PDS to da shvati kao kraj bloka.

Sada naš program iz prethodnog primera može da izgleda ovako:

Tutor9.bas

Tako smo uz pomoć asemblerske naredbe rešili problem kratke vremenske zadrške za kapacitivna opterećenja; to rešenje možemo da primenimo i u drugim slučajevima kada nam je potrebna pauza kraća od minimalne koju nam omogučava PDS naredba DelayUs.

Ako u praksi naidjete na problem kapacitivnog opterećenja, odredjivanje potrebne zadrške može da se uradi samo praktično tj. sistemom probe. Moglo bi i uz malo matematike, ali je tu nekoliko nepoznanica koje prosečan korisnik ne može da zna niti da izmeri.

Veličina iskompajliranog programa: 86 Word-a

May 062013
 

Tvorci PDS-a su omogućili ubacivanje asemblerskih naredbi u BASIC što i ne čudi jer je potpunu kontrolu nad MCU-om moguće ostvariti jedino pomoću asemblera. Postoje dve naredbe, jedna za ubacivanje samo jedne asemblerske naredbe, i druga za blok naredbi.

Sintaksa za prvu je:

@ asemblerska_naredba

Kada se znak @ upotrebi na početku linije, to znači da iza mora da sledi jedna asemblerska naredba. Ono što je bitno da zapamtite je da upotreba znaka @ postavlja banku na 0 i da ovu naredbu ne koristite za promenu banke, mada vam to za sada ne znači mnogo, ali trebaće kasnije. Iskoristićemo ovu naredbu da napravimo kratku pauzu u našem prethodnom primeru od svega jedne µs:

Tutor8.bas

Asemblerska naredba NOP je skraćenica od “No OPeration”, u prevodu “nema operacije”, tj. ova naredba ne radi baš ništa! Pa čemu onda služi uopšte? Korisna je upravo za ovakve stvari gde je potrebno napraviti neku pauzu koja neće da promeni baš ništa, ni jedan jedini bit bilo kog registra. Pošto PBP nema instrukciju koja ne radi ništa, u ovakvim situacijama primorani smo da upotrebimo ovu asemblersku instrukciju. Njeno izvršenje traje 1 mašinski ciklus što je u našem slučaju tačno 1 µs što bi moglo da bude prekratka pauza da se napuni kondenzator pa možemo da stavimo više ovih naredbi uzastopno.

Ako želimo da napravimo pauzu od 4 µs, treba da stavimo 4 ove naredbe i tada bi deo programa izgledao ovako:

pocetak:
    portb.4=1               ;uključi LED povezanu na pin 4 porta B (D5)
@   nop                     ;napravi pauzu od 1 mikrosekunde
@   nop                     ;napravi pauzu od 1 mikrosekunde
@   nop                     ;napravi pauzu od 1 mikrosekunde
@   nop                     ;napravi pauzu od 1 mikrosekunde
    portb.5=1               ;uključi LED povezanu na pin 5 porta B (D6)
   delayus 500               ;napravi pauzu od 500 milisekundi

Veličina iskompajliranog programa: 80 Word-a

May 062013
 

Da bismo rešili problem koji nam pravi kapacitivno opterećenje, očigledno je da moramo da napravimo vremensku zadršku izmedju dva uzastopna menjanja pinova istog porta kako bi kondenzator imao vremena da se napuni. Jedan od načina je da reorganizujemo program kako ne bismo ubacivali dodatne instrukcije koje bi trošile programsku memoriju. Pretpostavimo da deo programa izgleda ovako:

    portb.4=1
    portb.5=1
    sekunda=sekunda + 1
    if sekunda=60 then
      sekunda=0
    endif

Vidimo da posle naredbe “portb.5=1” imamo nekoliko naredbi čije izmeštanje ne dovodi ni do kakvih promena koje bi nam remetile rad programa tako da možemo da ih premestimo čime bi se pojavila odredjena zadrška izmedju dva uzastopna postavljanja stanja B porta koja bi omogućila da se kondenzator napuni, pa bi program izgledao ovako (naredbu “if … then … endif” objasnićemo drugi put):

    portb.4=1
    sekunda=sekunda + 1
    if sekunda=60 then
      sekunda=0
    endif
    portb.5=1

Medjutim, u našem programu iz primera 6 nemamo nikakve naredbe koje bi mogli da premestimo, a da ne poremetimo logiku i rad programa pa je potrebno da na neki drugi način ubacimo pauzu. Jedan od načina je naredba PAUSEUS, koja slično naredbi PAUSE pravi pauzu time što se zaustavlja izvršavanje programa, a čija sintaksa glasi ovako:

DelayUs period

gde ‘period’ označava vreme u mikrosekundama i može da se kreće od 1 do 65535

Tutor7.bas

Problem kod upotrebe ove naredbe je što ona sama zauzima odredjeni broj lokacija programske memorije, i što za ovaj PIC pri frekvenci od 4 MHz pauza ne može da bude manja od 24 us (mikrosekunde) što može da bude previše vremena za punjenje kondenzatora. Nije probem u tome što će kondenzator duže da se puni, njemu to ne smeta, kada se napuni punjenje će da se prekine samo pošto je to osobina kondenzatora, ali 24 us može da bude u nekim situacijama nepotrebno gubljenje vremena jer je moguće da se kondenzator već napunio. Zato ćemo u pomoć da pozovemo jednu asemblersku instrukciju kako bi napravili kraću zadršku.

 Veličina iskompajliranog programa: 84 Word-a

May 062013
 

Postoje situacije u kojima ne treba da menjamo stanje celog porta odjednom već pojedinačne bitove kako nebismo poremetili već postavljena stanja. Recimo da treba da trepere LED D5 i D6 dok su D1 i D2 uključene, a D3, D4, D7 i D8 isključene. Taj primer bi izgledao ovako:

Tutor6.bas

Međutim, u ovom programu se krije jedna zamka koja se, doduše, ovde neće “aktivirati”, ali kada bismo umesto LED D5 imali neko kapacitivno opterećenje, mogli bismo da imamo problem, kao što sam ga ja imao u jednom uredjaju koji sam pravio. O čemu se radi?

Ako se vrše dva uzastopna postavljanja pinova jednog porta, može da dođe do nepravilnog postavljanja novog stanja jer se svaki pristup portovima vrši u 3 koraka: čitaj-izmeni-upiši (na engleskom: read-modify-write) što konkretno znači da se kod upisa novog stanja na port zapravo prvo preuzme stanje direktno sa pinova u interni registar, zatim se izmeni sadržaj tog registra i na kraju se njegovo stanje prosledi na port. Ako se na jednom od pinova nalazi neko kapacitivno opterećenje ili je pin strujno preopterećen, velike su šanse da će druga izmena porta da poništi prvu jer strujno preopterećen pin ima manji napon koji se onda tumači kao logička 0 umesto 1.

Pojasnićemo to na našem primeru: zamislimo da je na RB4 priključen kapacitivni potrošač kome je potrebno neko vreme da se napuni i stabilizuje napon, a na RB5 neki drugi potrošač. Pojašnjenje za početnike: kod priključenja napona na kapacitivno opterećenje prvo se javlja protok struje koja puni kondenzator, dok je napon na njegovim izvodima 0 volti i zatim se povećava, tako da tek nakon izvesnog vremena dostigne nivo koji može da se “protumači” kao visok logički nivo.

Pogledajmo deo ovog primera:

portb=%00000011         ‘ postavi početno stanje na port B, tj. uključi D1 i D2

pocetak:
    portb.4=1                ‘ uključi LED povezanu na pin 4 porta B (D5)
    portb.5=1                ‘ uključi LED povezanu na pin 5 porta B (D6)

Naredba “portb.4=1” treba da postavi bit 4 porta B na logičko 1, tj. na napon napajanja. Zbog principa čitaj-izmeni-upiši biće pročitano stanje sa pinova u interni registar koji će da sadrži vrednost %00000011 jer smo pre toga postavili to stanje na port B, a zatim će biti setovan četvrti bit, i to novo stanje vraćeno na port, tj. na port će biti poslato %00010011. Kod sledeće naredbe “portb.5=1”, takodje će prvo da bude pročitano stanje sa pinova B porta, ali pošto je na pin 4 priključeno kapacitivno opterećenje, stanje na njemu će da bude i dalje logička nula (jer se kondenzator nije napunio) pa će umesto %00010011 biti pročitano 00000011, zatim će biti setovan peti bit i takvo stanje vraćeno na port pa će na kraju umesto 00110011 na pinovima biti %00100011. Ovo može da se prevazidje na nekoliko načina, a kako, videćemo u sledećim primerima.

Veličina iskompajliranog programa: 78 Word-a

May 062013
 

Tutor5.bas

Obzirom da uključujemo svih 8 LED na portu B iskoristićemo mogućnost da postavimo stanje celog registra odjednom umesto pojedinačnih bitova, kako na TRISB registru, tako i na PORTB registru i time značajno skratimo program. U naredbi ‘trisb=%00000000’ ne koristimo više tačku koja je označavala da radimo sa jednim bitom, što znači da radimo sa celim registrom odjednom, sa svih 8 bitova. Broj %00000000 napisan je u binarnom obliku i mogao je da bude napisan i kao 0, ali se na ovaj način veoma lepo i jasno vidi vrednost za svaki pojedinačni bit – krajnja desna cifra predstavlja bit 0, a krajnja leva, uz znak %, predstavlja bit 7. Isto važi i za naredbu ‘portb=%11111111’; mogla je da bude napisana sa brojem u decimalnom obliku i tada bi glasila ‘portb=255’, ali se u binarnom obliku jasno vidi da su svi bitovi postavljeni na logičko 1, što znači da su sve LED uključene.

Primetićete i da se veličina iskompajliranog programa smanjila 🙂

Veličina iskompajliranog programa: 75 Word-a

May 062013
 

Sada ćemo da izmenimo Lekciju2 koja uključuje i isključuje svih 8 LED odjednom na isti način kao što smo izmenili malo pre primer 1, izbeći ćemo naredbe ‘high’ i ‘low’ i koristićemo direktno izmene na TRISB registru, pa da vidimo koliku ćemo uštedu da ostvarimo kada je u pitanju programska memorija.

Tutor4.bas

Ovde nema naredbi koje već nismo koristili, samo smo proširili akciju na sve pinove B porta. Na početku, posle labele ‘Inicijalizacija’, nalazi se blok sa naredbama koje podešavaju oscilator i digitalnu funkciju B porta, i koje menjaju TRISB registar jedan po jedan bit, odn. koje postavljaju sve pinove B porta kao izlazne i taj deo se izvrši samo jednom pri uključenju, posle toga se više nikada ne izvršava. To podešavanje početnih vrednosti raznih registara koje se obavlja samo jednom na početku programa naziva se inicijalizacija i ubuduće ćemo se stalno sretati sa time. Labela ‘inic’ ovde nema nikakvu praktičnu vrednost jer ne postoji naredba skoka koja upućuje na nju, ali smo hteli da se jasno zna da je to inicijalni blok, a biće primera gde će nam ona trebati, pa je vreme da se navikavamo na to.

Veličina iskompajliranog programa: 95 Word-a

May 062013
 

Vratićemo se prvom primeru, koji uključuje i isključuje jednu LED, ali ovoga puta ćemo to da uradimo na nešto drugačiji način.

Tutor3.bas

Prva PDS naredba ‘trisb.0=0’ postavlja nulti bit TRISB registra na logičku 0 čime, kao što smo objasnili, postavlja pin 0 porta B kao izlazni (postavljanje odredjenog I/O pina kao ulaznog ili izlaznog naziva se još i odredjivanje smera tog pina). Posle labele ‘Pocetak’ sledi naredba ‘portb.0=1’ koja postavlja nulti bit B porta na logičko 1 i time uključuje LED, pa zatim posle već dobro poznate pauze od pola sekunde, naredba ‘portb.0=0’ postavlja taj isti pin na logičko 0, i posle još jedne pauze od pola sekunde naredba ‘GoTo Pocetak’ vraća program na naredbu posle labele ‘Pocetak’. Kao što vidimo, naredba ‘trisb.0=0’ se više nikada ne izvršava jer za tim nema potrebe. Na ovaj način program se brže izvršava, a zahvaljujući nekorišćenju naredbi ‘high’ i ‘low’ program je nešto kraći.

Treba još imati na umu da se prilikom priključenja PIC-a na napajanje svi bitovi TRISA i TRISB registra postavljaju na 1, što znači da su svi pinovi oba porta postavljeni kao ulazi, dok PORTA i PORTB zauzimaju proizvoljno, nepoznato stanje.

Veličina iskompajliranog programa: 73 Word-a

May 062013
 

Ovim primerom uključivaćemo i isključivati svih 8 LED odjednom koje su priključene na port B, umesto samo jedne. Pretpostavljam da ste i sami dobili ideju kako da se to uradi – isto kao u prethodnom primeru, samo ponovimo iste komande za svaki pin pojedinačno. Ne zaboravite da pre samog programa napišete linije u kojima su definisane konfiguracije i frekvenca oscilatora.

Tutor2.bas

Vidimo da posle podešavanja registra OSCCON imamo novu liniju koja takodje služi za podešavanje hardvera. Oba porta imaju mogućnost rada sa analognim modulima koji su ugradjeni u PIC i povezani sa portovima. Proizvodjač je podesio da se pri uključenju PIC-a aktiviraju analogne funkcije I/O portova, a nama su ovde, za sada, potrebne digitalne pa moramo sami da isključimo analogne. Registri zaduženi za to su ANSELA za port A i ANSELB za port B, a pošto mi za sada radimo samo sa B portom, izmenili smo samo ANSELB. Kada je neki bit tog registra postavljen na 1, tada odgovarajući pin ima analognu funkciju što znači da moramo sve bitove da postavimo na 0 kako bi svi pinovi imali digitalnu funkciju. Mogli smo da napišemo i binarni oblik %00000000 kako bi smo videli vrednost za svaki pojedinačni bit, ali pošto su ionako svi bitovi 0, dekadni oblik je sasvim prikladan.

Naredbe koje slede su nam već poznate s tim što se menja argument uz naredbe High i Low; prvo uključimo svih 8 LED jednu po jednu, bit po bit, pa napravimo pauzu od 500 milisekundi, zatim isključimo svih 8 LED, ponovo napravimo pauzu od 500 milisekundi pa se naredbom GoTo vratimo na labelu Pocetak čime se program vraća na početak i tako vrti u krug.
Kao što se primetili, bitovi su obeleženi brojevima od 0 do 7, a ne od 1 do 8 kako bi bilo logičnije na prvi pogled. To je uradjeno zbog binarnog brojnog sistema o kome je Siniša već ranije pisao.

Veličina iskompajliranog programa: 132 Word-a

May 062013
 

Počećemo sa veoma jednostavnim primerom:
Treptaćemo LED na pinu 0 porta B sa pauzom od pola sekunde između. Ovaj primer se u svetu korisnika mikrokontrolerra još i naziva “Hello World”, što poznavaocima programiranja na računarskim platformama sigurno zvuči poznato 🙂

LED je skraćenica za “Light Emithing Diode”, odn. za diodu koja emituje svetlost; koristi se kao i svaka dioda i kada je polarisana direktno, tj. kada kroz nju protiče struja ona svetli nekom bojom koja zavisi od materijala od koga je izrađen poluprovodnik. Još je bitno napomenuti da se LED napaja strujno, a ne naponski, a za standardnu LED je potrebno ograničiti struju na 15 do 20 mA. To se radi vezivanjem otpornika na red sa LED, a otpornik se proračunava prema padu napona na LED. Na MINI PIC 1 razvojnom sistemu se već nalazi otpornik, ali ćemo radi vežbe da uradimo jedan proračun.

Za crvenu, pri struji od oko 20 mA, pad napona je približno 2 volta pa ćemo prema omovom zakonu da izračunamo vrednost otpornika tako što od napona napajanja oduzmemo pad napona na LED. U našem slučaju napon napajanja je 5V, pad napona na LED je 2V pa je vrednost za otpornik:

R=U/I = (5 – 2) / 0,02 = 3 / 0,02 = 150 oma. To je vrednost koja postoji u standradnoj ponudi, a ako se desi da ne postoji, uzima se prva sledeća veća vrednost. Ako se koristi LED sa visokim sjajem, taj otpornik može da se poveća ako je sjaj prejak.

Tutor1.bas

Kao što vidimo, prva linija programa počinje nečim što nije naredba i završava dvotačkom, tj. labelom ‘Pocetak:’. Pre nego što objasnimo šta je labela, vratićemo se malo unazad, u prve dane BASIC-a.

U prvim verzijama BASIC-a programi su na početku svake linije imali broj koji je služio za identifikaciju i omogućavao da se program po potrebi preusmeri na odredjenu liniju naredbom GOTO ili GOSUB. Pokazalo se da je to veliki izvor grešaka jer je moguće pogrešiti pri kucanju i umesto jednog broja otkucati drugi pri čemu program nastavlja na pogrešnom mestu i ne radi kako treba. Kada bi ovaj program bio pisan na taj način, izgledao bi ovako:

10 high portb.0
20 pause 500
30 low portb.0
40 pause 500
50 goto 10

Ako u poslednjoj naredbi greškom otkucamo

50 goto 20

program će samo u prvom prolazu da uključi LED i više nikada neće doći na liniju 10 tako da će LED stalno biti isključena. U ovako kratkom programu i nije problem uočiti grešku, ali zamislite program sa više stotina, ili čak hiljada linija u kojima postoji greška u broju linije!
Zato su uvedene labele odn. oznake, čime je mogućnost greške drastično smanjena. Labela se, slično broju, postavlja pre neke instrukcije, ali ne i pre svake, čime se mogućnost greške drastično smanjuje. Labela u PDS-u može da sadrži cifre, slova i donju crtu, ali ne može da počne cifrom, a obavezno završava dvotačkom (samo kod definisanja, ne i kada je argument komande). Dužina je praktično neograničena, ali PDS uzima u obzir samo 32 karaktera ako je naziv labele duži. Sasvim je svejedno da li je labela pisana velikim ili malim slovima, to znači da se labele ‘POcetAK ‘ i ‘pocEtaK ‘ tretiraju kao da su iste. Moguće je u istoj liniji staviti i labelu i PDS naredbu

Pocetak:  High portb.0

mada je praksa da se radi preglednosti koda labele stavljaju u zasebne linije.

Veličina iskompajliranog programa: 72 Word-a