Egy párbeszéd szintű tanulással egybekötött - ha úgy tetszik - kurzus.

Slogan barátom kedvet kapott a PIC programozáshoz. Ő eddig asm-ben tevékenykedett, viszont abban én nem igazán tudtam Neki segíteni, mert nem szívelem azt a nyelvet. Ezért elhatároztuk, hogy megpróbálom picit megtanítani a C nyelv alapjaira. Arra gondoltunk, hogy lehetne valamiféle párbeszédes formában - ketten - cikket írni: én próbálok magyarázni, Neki pedig - ha van kérdése, akkor - fel is tudja tenni egyből. Cikkírás közben skype-on tartottuk a kapcsolatot.

- Slogan: Miért is C?

Alapvetően azért mert a programozó lusta. A C nyelv használata megszabadít minket a PIC programozás rabszolga-műveleteitől: mint pl. BANK-váltás, táblázatok pozicionálása a memóriában. Engem az is az őrületbe kergetett, hogy ha egy regiszterbe konstans adatot szeretnék tölteni, azt csak kizárólag a W munkaregiszteren keresztül tehetem meg.

Lényegesen egyszerűbbé válik az osztás/szorzás elvégzése, akár tizedes törteken, de említhetném még  szövegek, több dimenziós tömbök kezelését is. A programunk sokkal átláthatóbb, mint egy ASM lista.  A C nyelvet azért is érdemes elsajátítani, mert később is hasznunkra lesz, ha egyszer PC-n szeretnénk programozni, vagy weboldalt fejleszteni (a php szintaktikája és parancsai nagyon C-szerűek), míg a PIC asm tudásunkkal más területen nem sokra megyünk, mivel elég speciális parancsai vannak ennek a kontrollernek.

Nem akarok eltántorítani senkit az ASM-től, de az alapok után szerintem célszerű átváltani valami termelékenyebb programozási nyelvre.

- Slogan: Na jó, de mi a hátránya?

Nem lenne fair elhallgatni a hátrányokat sem: C-ben megírt programunk nagy valószínűséggel több memóriát fog foglalni egy ember által ügyesen optimalizált asm kódhoz képest. Emiatt persze "lassabb"  is lesz. Azért tettem idézőjelbe, mert a kontrollerben futó programok szinte mindig várakoznak vagy a felhasználóra, vagy valamilyen eseményre, ezért valójában nem lassabb a C-ből fordított program sem, csak esetleg kevesebbet fog tudni várakozni két esemény között.

C fordítóból is létezik többféle, jelen cikkben a HI-TECH C-vel foglalkozunk, ami tulajdon képen gyári fordító lett, mióta felvásárolta a Microchip.  Így a LITE verzióhoz ingyenesen juthatunk hozzá.  Ez a verzió nem korlátoz semmiben, minden 10-es, 12-es, 16-os  típusra írhatunk vele programot, kihasználhatjuk a kontroller teljes memóriáját is. Amiben kevesebb a fizetős verzióktól, az a kód optimalizálás mértéke. Innen tölthető le:  www.microchip.com/stellent/idcplg

Tehát valamennyivel kevesebb lefordított C kódot tudunk elhelyezni a kontroller memóriájában egy teljes optimalizációval rendelkező fordítóhoz képest.

Ajánlott letölteni a legújabb MPLAB csomagot ,és teljesen feltelepíteni (install-nál a "Complete" menüpontot választva). Így feltelepül a HI-TEH C 9.83-as fordító is lite üzemmódban. De ha már fenn lenne a gépünkön az MPLAB, később is telepíthetjük külön csak a C fordítót.

A cikkben szereplő példákat Proteus áramkör szimulációban próbálhatjátok ki. A trial verzió letölthető innen. A demo verzió annyiban korlátos, hogy menteni nem lehet benne, és a PIC szimuláció is csak a mellékelt példafájlokban működik. Ezért is választottam onnan a PICDEM2+ with PIC16F877.DSN demo panelt.

Az illusztrációval ellentétben mi a 40 lábú 16F877-et fogjuk használni, az van ugyanis a működő demo file-ban. Kicsit elavult ez a PIC, de könnyen módosítható a példa program 16F887-re is, ha valaki a valóságban építené meg, és az olcsóbb utódot választaná. Aki a szimulációt választja, annak csak annyi dolga lesz, hogy megnyitja a fenti demo panelt, majd a PIC-be a saját programját tölti bele.

Vágjunk is bele, indítsuk el az MPLAB ot és kezdjünk egy új project-be!

Project menü/Project wizard. Üdvözöl minket, nyomjunk tovább-ot, majd válasszuk ki a használni kívánt PIC típust. Legyen ez most a 16F877.
Mehetünk is tovább, ha nem az lenne kiválasztva, akkor válasszuk a HI-TECH Universal Toolsuite-ot, azután tovább.
Browse gombnál válasszuk ki a mappát ahová elmentjük a project-et, és adjunk neki egy nevet is. Célszerű, amúgy rövid elérési utakkal dolgozni, és nem használni ékezeteket a file és könyvtár nevekben. Tovább.
Itt lehetne kiválasztani a forrás file-t, de most még nincs még mit hozzáadni, nem is adunk hozzá semmit, menjünk tovább, majd befejezés.

Csináljunk egy új file-t, mentsük el mondjuk cikk.c -néven, a project-ünk könyvtárába, majd adjuk hozzá a project ablakban a source files-hoz (jobb gomb/add files) az új c állományunkat. Írjuk még bele az alábbi sorokat: (a sorszámokat természetesen ne )

  1. #include <pic.h>
  2.  
  3. void main()
  4. {
  5. }


Bár ez a program még nem csinál semmit, akár le is fordíthatjuk. A fekete gombbal a toolbar-on, vagy F10-et nyomva. Az output ablakban láthatjuk a fordítás eredményét. Mennyi program és adat memóriát foglaltunk, esetleges hibaüzenetek, stb.

  1. #include <pic.h>
  2.  
  3. void main()
  4. {
  5. }

- Slogan :  ASM ben is van hasonló, de kíváncsi lennék pontosabban a dolgok nyitjára, hogy ne csak "beollózni" tudjam mintegy fejlécet, hanem értsem is!

A C fordító több file-ból is össze tudja "ollózni" a forrást fordítás előtt. Ezt hívják előfeldolgozónak (preprocessor). Az  # jelzi hogy az adott sor az előfeldolgozónak szól, nem magának a C fordítónak. Az include pedig azt jelenti hogy a megadott file-t fűzze bele az adott helyre. Fordításkor úgy fog viselkedni, mintha annak a file-nak a tartalma benne lenne a mi forrásunkban. Ez a pic.h  (azért .h a vége, mert ez egy header file) tartalmazza a pic -ekre jellemző leírásokat a C fordító részére. (pl hogy tudja hogy mi az a PORTA).

- Slogan :  Akkor ezek szerint a pic.h  file -ban állítjuk be a Code Protect-et, órajelet, stb.?Ezt a file-t nekem kell írnom?

Ez a filet jobb ha nem babráljuk, ezt a HI-TECH-es programozók írták nekünk. Mi csak felhasználjuk a programunkban. A beállításokat a saját program fájlunkba írjuk bele. (pl. cikk.c ) Megadhatnánk még a Configure/Configuration bits alatt a menüben is, de jobb ezt írásban rögzíteni a programunk első soraiban.

A pic.h -t megnyitva (C:/Program Files/HI-TECH Software/PICC9.70/include alatt található) láthatjuk, hogy ha a 16F877-et választunk, akkor ez a file további header fileokat include-ol be, mint valami "matrjoska baba", jelen esetben a pic1687x.h -t.  Ezt is nyissuk meg. Legörgetve az aljára láthatjuk, hogy hogyan nevezi el a konfigurációs biteket. Ezeket fogjuk megadni a programunk elején.

- Slogan : OK, próbálom jegyezni..... a "void main" - gondolom - a program kezdete.  De mi ez a sok "lőn", meg "vala"? Azaz mit jelentenek a zárójelek? Kerül közéjük valami? És miért áll két "szóból" (1. void ; 2. main)?

Jól sejted, valahol el kell kezdődnie a programnak. C -ben a main nevű függvény végrehajtásával kezdődik a programunk. A függvény neve előtt a void az azt jelenti hogy ez a függvény nem ad vissza értéket. Már csak azért sem, mivel nem lépünk ki belőle jó esetben soha.  A két zárójel a main után pedig a függvény paramétereinek a helye, de itt nincsenek paraméterek, mert ezt a függvényt nem hívta meg senki. Tehát nem kap paramétert, csak elindul. Később majd lesz példa, ha majd saját függvényt írunk, a visszatérő értékre is, meg paraméterekre is. A main alatt a kapcsos zárójel nyit/zár közé kerül majd a programunk.  Gépelés közben célszerű mindig leírni mind a két zárójelet és közé írni a tartalmat, mert így nem felejtjük el bezárni a kinyitott blokkot.

- Slogan : Tehát itt a "{" a START és a "}" az END-nek felel meg?

Igen. Ez közrezár egy blokkot. Tehát ami a main után a két kapcsos zárójel között van, az mind a main része.

Mielőtt elkezdenénk a programunkat, állítsuk be akkor a konfigurációs biteket. Az F11-es gombot ,megnyomva elindíthatjuk a C fordító kézikönyvét. Onnan puskázok most én is, az 52. oldalról (Configuration fuses).

Alakítsuk át a programunkat ennek megfelelően:  (a konfig bitek elnevezéseit a pic1687x.h file-ból puskázzuk)

  1. #include <pic.h>
  2.  
  3. __CONFIG(FOSC_HS & WDTE_OFF & PWRTE_OFF & BOREN_ON & LVP_OFF & CPD_OFF & WRT_OFF & DEBUG_OFF & CP_OFF );
  4.  
  5. void main()
  6. {
  7. }

- Slogan : OK. A "melyik bit mit csinál" kérdést nem teszem fel ,adatlapból kiderül általánosan/procifüggően.  Haladjunk tovább, lassan besötétedik és még mindig nem villog a LED-em

Haladjunk akkor a főprogrammal is kicsit.  Azt megbeszéltük, hogy a program futása a main-nel kezdődik. Ez most üres még, tennünk is kell valamit, mert így nem hagyhatjuk, hogy csak úgy elkóboroljon a végrehajtás a programmemóriában, mert annak megjósolhatatlan a kimenetele. Csináljunk úgy, mint ahogy asm-ben szokás, a programunk végén ugrassuk előre újból a végrehajtást, így nem tud elkóborolni. Tudom hogy C-ben nem szokás goto-t használni, de mivel most asm felől közelítünk a C felé, talán most az egyszer még megbocsájtanak az igazi C programozók. Tehát akkor egészítsük ki a programunkat (most csak a main-t részletezem, természetesen amit eddig írtunk ne töröljük ki) :

  1. void main()
  2. {
  3.  
  4. ugorjunk_ide_vissza:
  5.  
  6.  
  7. goto ugorjunk_ide_vissza;
  8.  
  9. }

Ezzel elértük, hogy ha a programunk végére ér, akkor egy goto -val visszazavarjuk az elejére, nem tud elkóborolni a fel nem töltött memória területre. A programunk majd a címke és a goto közé kerül.  Látható hogy a címke végén kettőspont van, az utasítás végén viszont pontosvessző. Ezt ne kérdezd meg hogy miért   A C fordító így szereti.

-Slogan: .....na ezt már szeretem, mikor megmondják mit kérdezhetek Erről eszembe jut az a bizonyos nyomtatott Orosz kérdőív : 1. Ki a példaképe ? 2. Miért pont Lenin ? Viccet félretéve .... Mindig a részletek érdekelnek: Tetszőleges hossza lehet a címkéknek? Lehet esetleg ékezet?

Hosszra korlátozást nem tudok, annyi viszont biztos, hogy szóköz nem lehet benne, se ékezet, és számmal se kezdődhet. A kis és a nagy betűk között viszont különbséget tesz a fordító. Ja, és nem lehet a címke azonos egy C utasítás nevével sem. Logikusan ha megegyezne egy utasítás nevével a címke akkor nem tudná eldönteni a fordító hogy ez most címke-e vagy utasítás. Továbbá csak az adott függvényen belüli címkére ugorhatunk, tehát a main -ból nem ugorhatunk goto -val át egy másik függvénybe.

-Slogan: Hol érdemes utána nézni az utasításkészletnek?

A Hi-Tech C manual 167. oldalától kezdődik a beépített C függvények leírása. (Chapter 7. Library Functions)  Csak ismétlésképp:  F11 funkciógombbal, vagy a Project menüből érhető el MPLAB alól.  A sztenderd C parancsokat viszont nem találom benne, mindenesetre itt egy kis leírás: http://tigcc.ticalc.org/doc/keywords.html

De ideje hogy valami hasznosat is csináljon a programunk. Gyújtsunk ki egy ledet. Ehhez az kell hogy a kiválasztott portot kimenetre kapcsoljuk, analóg funkciókat is lekapcsoljuk az adott lábról ha van rajta. Hasonlóan tehetjük ezt meg mintha asm ben dolgoznánk. Először beállítjuk az adott portot, ( legyen ez most a B ) kimenetre, majd a portra írjunk ki egy értéket.

  1. void main()
  2. {
  3.            TRISB=0b00000000;    // PORTB minden lába kimenet
  4.           
  5.            ugorjunk_ide_vissza:
  6.            PORTB=1;
  7.            goto ugorjunk_ide_vissza;
  8. }

Látható hogy nincs vacakolás W regiszterrel, közvetlenül megmondtuk mi legyen a tris, és a port értéke.
Több dolog is megfigyelhető a példaprogramunk aktuális változatán:

Ez a fajta tagolás segít átláthatóbbá tenni a programunkat. A C fordító amúgy nem finnyás, mindegy neki mennyi tabulátorral vagy szóközzel kezdődnek a programsorok. Egy sorba is írhatunk több utasítást pontosvesszővel elválasztva. Visszatérve a programunkra, eddig nem valami látványos, 1db ledet kapcsoltunk be. ( RB0 kimeneten )


 

-Slogan: A W regiszter ( és gondolom lesz még ilyen ) macera kihagyása és hogy nem kell bankolni mindenféle FSR eléréshez tényleg egyszerűbbé ,felhasználó-barátabbá teszi az egész programozást.Ennek örülök !A tagolási egyszerűség is tetszik ,de azért érdemes tartani valamiféle sémát.És megjegyeztem a " ; " -t .

Haladjunk tovább. Deklaráljunk egy változót. Azaz mondjuk meg a fordítónak hogy milyen tipusu változót szeretnénk, és hogy mi legyen a neve. Látható hogy itt sem kell törődnünk vele, hogy hol kezdődnek a felhasználható regiszterek. Amíg van hely a ramban, addig  a fordító elintéz mindent.

Ha már megvan a változónk,akkor egyesével növelgetve írjuk ki az értékét a B portra. Így tulajdon képen bináris formában láthatjuk ,ahogy a PIC számol felfelé, majd miután túlcsordul a 8 bites előjel nélküli számunk, kezdi elölről a számolást:

void main()
{
    unsigned char i;
   
    TRISB=0b00000000;    // PORTB minden lába kimenet
   
    ugorjunk_ide_vissza:
   
    i=i+1;
    PORTB=i;
   
    goto ugorjunk_ide_vissza;
}



-Slogan: Tehát ,ha jól értem a deklarált változó az " i ". Ezt a sort csak ott lehet elhelyezni ,vagy bárhol ?Aztán a következőkben változóhoz adod önmagát + 1-et és az eredményt kiíratod PORTD re.Az egyenlőség jelnek mi a szerepe ?A cimkére ugrást már kitárgyaltuk ,csak azt nem ,ha nem GOTO -t írnánk ,akkor mit ?

Bárhol deklarálhatod a változókat, de fontos hogy még a felhasználásuk előtt tedd meg, különben panaszkodni fog a fordító. Továbbá, a függvényen belül deklarált változók, azok lokálisak. Más függvényből nem érhetőek el. Ha globális változót szeretnél, akkor azt függvényen kívül kell deklarálni.

Az egyenlőségjel jelenti itt az értékadást. Azaz az a változó ami balra van tőle, felveszi az egyenlőségjeltől jobbra levő értéket.

Goto helyett használhatnánk while vagy for ciklusszervező utasításokat is. Majd nézünk ezekre is példát.
Viszont ami még fontos, hogy mit is jelent az unsigned char. Ez mondja meg hogy milyen méretű, memóriafoglalású, típusú legyen a változónk. A pic alapvetően 8 bites számokkal dolgozik, de a fordító elintézi nekünk hogy nagyobb 16 vagy 32 bites értékekkel is dolgozhassunk. Ezekről leírást a manual 58. oldalán a SUPPORTED DATA TYPES AND VARIABLES részben találunk.  Az unsigned az előjel nélkülit jelent. Ha nem írjuk, akkor előjeles szám lesz a változónk. ( azaz negatív számokkal is tudunk dolgozni ez esetben )

Naszóval szimulátorban nézve szépen látszik, ahogy villognak a ledek, a valóságban ebből kevés érzékelhető, mivel a PIC elég fürge kis jószág. Le kéne lassítani minden egyes lépés után hogy lássunk is valamit.


A legújabb fordítóban van már beépített delay  ( várakozást megvalósító függvény ). Használjuk is fel:

  1. #define _XTAL_FREQ 4000000
  2. #include <pic.h>
  3.  
  4. __CONFIG(FOSC_HS & WDTE_OFF & PWRTE_OFF & BOREN_ON & LVP_OFF & CPD_OFF & WRT_OFF & DEBUG_OFF & CP_OFF );
  5.  
  6. void main()
  7. {
  8.            unsigned char i;
  9.           
  10.            TRISB=0b00000000;    // PORTB minden lába kimenet
  11.           
  12.            ugorjunk_ide_vissza:
  13.           
  14.            i=i+1;
  15.            PORTB=i;
  16.  
  17.          
  18.            __delay_ms(100);
  19.  
  20.            goto ugorjunk_ide_vissza;
  21. }

-Slogan: Ennyi egy DELAY ???Ez baromi jó !Ennyit kell csak beírnom és a fordító intézi a többit ? Mekkora intervallumban állítható ? Vagy van esetleg többféle ?

Ha kevesebbet szeretnénk 1ms -nél várakozni, akkor használható még a __delay_us(x) is.

Felfedezhető még, hogy a fordítóval közölni kellett a használt órajelünket a #define _XTAL_FREQ megadásával. Ezt az értéket felhasználja az előfeldolgozó, és mindenhol ahol a forrásban _XTAL_FREQ -et írunk, kicseréli az utána beírt számra, még a fordítás előtt.
( logikusan azért van erre szükség, mivel valahonnan tudnia kell a fordítónak, hogy mennyi utasítást tud végrehajtani adott idő alatt. Miközben várakozunk, a pic tovább dolgozik, "nop" utasításokat hajtat végre vele a várakozó függvényünk)
Ezekkel a szövegbehelyettesítésekkel még szemléletesebbé, egyszerűbben módosíthatóvá  tehetjük a programunkat. ( pl ha több helyen is használjuk ugyanazt a behelyettesítést, akkor elég csak a progi elején átírni a #define -ben, és az előfeldolgozó a fordítás előtt behelyettesíti mindenhová ahol csak használtuk  )
 

Látható a példaprogramban, hogy a port regisztert mindig csak írásra veszem igénybe. Azaz nem azt olvasom ki és növelem az értékét, majd írom vissza. Hanem egy külön változót tartunk fenn erre látszólag feleslegesen. Ennek a magyarázatát olvashatjátok Potyo tollából itt: www.hobbielektronika.hu/forum/topic_hsz_458622.html

A fordító nálam 197ms -nél hosszabb késleltetést nem fordított le. Ez most kapóra is jön, legalább írhatunk egy saját függvényt.

Csináljunk egy saját függvényt, amivel akár másodperceket is várakozhatunk.

Először, még a felhasználás előtt a függvényünket be kell mutatni a fordítónak (#6), deklarálnunk kell, majd pedig leírni magát a függvényt is.(#27 - 38)

  1. #define _XTAL_FREQ 4000000
  2. #include <pic.h>
  3.  
  4. __CONFIG(FOSC_HS & WDTE_OFF & PWRTE_OFF & BOREN_ON & LVP_OFF & CPD_OFF & WRT_OFF & DEBUG_OFF & CP_OFF );
  5.  
  6. void delay_ms_uj(unsigned int mennyit);
  7.  
  8. //----------------------------------------------------------------------------
  9. //----------------------------------------------------------------------------
  10. void main()
  11. {
  12.            unsigned char i;
  13.           
  14.            TRISB=0b00000000;    // PORTB minden lába kimenet
  15.            ugorjunk_ide_vissza:
  16.           
  17.            i=i+1;
  18.            PORTB=i;
  19.            delay_ms_uj(1000);
  20.  
  21.            goto ugorjunk_ide_vissza;
  22. }
  23.  
  24. //----------------------------------------------------------------------------
  25. //----------------------------------------------------------------------------
  26.  
  27. void delay_ms_uj(unsigned int mennyit)
  28. {
  29.            unsigned int szamol;
  30.           
  31.            for (szamol=0; szamol<mennyit; szamol++)
  32.            {
  33.                __delay_us(985);
  34.               
  35.            }
  36.           
  37.            return;
  38. }

Slogan : Az "unsigned" - ha jól emlékszem - azt jelöli ,hogy  "+" egész számról beszélünk ? Viszont a többit sajnos csak kapizsgálom

Ok, akkor részletezem picit. Látható hogy a főprogramunkban a delay_ms_uj(1000); sorral hívjuk a saját új függvényünket. Mégpedig úgy, hogy paraméterként átadunk neki egy értéket. Jelen esetben az 1000-et. Ezt azért tehetjük meg, mert úgy deklaráltuk a függvényt, hogy egy 16 bites előjel nélküli számot vár paraméterként. Erre a paraméterre a függvényünkben a megadott változó néven hivatkozhatunk. (jelen esetben a mennyit néven).

Kis kiegészítés haladóknak: Ha egy változóval hívnánk meg a függvényünket, azaz a paraméter helyén egy változó neve állna, akkor a változó pillanatnyi értékével hívódik meg a függvény. Ha függvényen belül módosítjuk a paraméter értékét, akkor az nem fog visszahatni a meghívó változóra. Ha azt szeretnénk, hogy a függvény változtatni tudja a függvény paramétereként megadott változót, akkor másképp kell deklarálnunk a függvényt. Úgy hogy ne a változó értékét adja át a függvényhívás, hanem a címét. Azaz egy mutatót, ami a memóriában elfoglalt helyére mutat.

Feltűnhet még egy új utasítás:
for (inicializálás; feltétel; ciklusváltozó növelése) utasítás;

Ez úgy működik, hogy mindaddig végrehajtja a for utáni utasítást (vagy utasítás blokkot) amíg a feltétel igaz. A ciklusváltozó növelésénél is van egy érdekes operátor: ++ Ez megnöveli eggyel az adott változót. Azt is írhattam volna hogy szamol=szamol+1 . Ugyan azt a hatást érjük el vele.

Az is magyarázatra szorulhat, hogy miért csak 985us -ig várakozunk 1ms időtartam eléréséhez ? Noss azért, mert a függvényhívásnak és visszatérésnek is van időszükséglete, és szimulátorban ellenőrizve így jön ki viszonylag pontosra az 1ms várakozásunk. Ezzel ugyan pontosan időt nem lehet mérni, de minden egyéb feladatra elégséges pontosságot érhetünk el. (ledek villogtatása, léptetőmotor forgatás, karakteres lcd modul meghajtás stb)

Alakítsuk át a programot úgy hogy sorban villanjanak fel a ledek. Ez futófény kis áramköri kiegészítéssel alkalmas lehet léptető motor meghajtásra is.

  1.     ugorjunk_ide_vissza:
  2.           
  3.           
  4.            PORTB=1;
  5.            delay_ms_uj(1000);
  6.  
  7.            PORTB=2;
  8.            delay_ms_uj(1000);
  9.           
  10.            PORTB=4;
  11.            delay_ms_uj(1000);
  12.           
  13.            PORTB=8;
  14.            delay_ms_uj(1000);
  15.           
  16.  
  17.            goto ugorjunk_ide_vissza;


Ez bár működik, elég favágó megoldás, alakítsuk át valami kifinomultabb módszerre, és ha már úgyis törekszünk a kifinomultságra, akkor váltsuk ki a főprogram pörgését megvalósító goto -t is.

  1. ...
  2. void main()
  3. {
  4.            unsigned char i;
  5.           
  6.            TRISB=0b00000000;    // PORTB minden lába kimenet
  7.  
  8.           
  9.            i=1;
  10.           
  11.            do
  12.            {
  13.           
  14.                PORTB=i;
  15.                delay_ms_uj(1000);
  16.               
  17.                i=i*2;
  18.                if (i==16) i=1;
  19.           
  20.            } while (1) ;  
  21.           
  22.          
  23. }
  24. ...

Új utasítás amit megismerhetünk az if. Ez egy elágazást lehetővé tevő utasítás, ha a zárójelben megadott feltétel igaz, akkor végrehajtja a következő utasítást. ( vagy blokkot, szokás szerint). Figyeljünk arra, hogy most nem értéket akarunk adni az i változonknak, ezért nem 1db = jelet kell raknunk, hanem az egyenlőség vizsgálatot jelölő dupla jelet, azaz == -t kell írni. Tehát ha az i változónk egyenlő 16 -al, akkor átállítjuk 1-re. Ezzel elérjük, hogy a 4. led után újra az első világítson.

A másik újdonság a do ... while utasításpár. Ezzel úgynevezett hátul-tesztelő ciklusokat írhatunk. Azaz egyszer mindenképp lefut a közrezárt utasítás ( vagy blokk, ezt most írom le utoljára ) , majd miután lefutott, megnézi hogy igaz-e a zárójelben megadott logikai feltétel, és ha igaz, akkor újra végrehajtja a ciklust. Jelen állapotban a feltételünk elég egyszerű, mindig igaz. A feltétel helyére azt is írhattam volna akár hogy 1==1, vagy 4==4, ezek is mindig igazak. Azaz állandóan ebben a végtelen ciklusban fog pörögni a programunk, csakúgy mintha goto -t használtunk volna cimkével.

Nade mivan akkor ha nem valami számtanilag egyszerűen leírható sorrendben szeretnénk ha felvillannának a ledjeink ? A megoldás egyszerű, használjunk mondjuk konstans tömböt a led állapotok, vagy ha úgy tetszik animációs fázisok letárolására.

  1. #define _XTAL_FREQ 4000000
  2. #include <pic.h>
  3.  
  4. __CONFIG(FOSC_HS & WDTE_OFF & PWRTE_OFF & BOREN_ON & LVP_OFF & CPD_OFF & WRT_OFF & DEBUG_OFF & CP_OFF );
  5.  
  6. //----------------------------------------------------------------------------
  7. //----------------------------------------------------------------------------
  8. const unsigned char tomb[]={1,2,4,8};
  9. //----------------------------------------------------------------------------
  10. //----------------------------------------------------------------------------
  11. void delay_ms_uj(unsigned int mennyit);
  12. //----------------------------------------------------------------------------
  13. //----------------------------------------------------------------------------
  14. void main()
  15. {
  16.            unsigned char i;
  17.           
  18.            TRISB=0b00000000;    // PORTB minden lába kimenet
  19.            i=0;
  20.           
  21.            do
  22.            {
  23.  
  24.                PORTB=tomb[i];
  25.                delay_ms_uj(1000);
  26.               
  27.                i++;
  28.                if (i==4) i=0;
  29.           
  30.            } while (1) ;  
  31.           
  32. }
  33. //----------------------------------------------------------------------------
  34. //----------------------------------------------------------------------------
  35. void delay_ms_uj(unsigned int mennyit)
  36. {
  37.            unsigned int szamol;
  38.           
  39.            for (szamol=0; szamol<mennyit; szamol++)
  40.            {
  41.                __delay_us(985);
  42.               
  43.            }
  44.           
  45.            return;
  46. }



A cikk sorozat kis időre abbamaradt, pihent sokáig. Úgy éreztem viszont hogy lenne értelme közzé tenni az eddig elkészült részeket. Ha valaki esetleg úgy érzi segítene folytatni, átvéve Slogan barátom helyét a kérdések feltevésével, az nyugodtan keressen meg.

Folyt köv.

üdv,

Lidi