Prof Creative Commons License 2017.01.07 0 1 2679

Szasztok,

 

Sploc, mielőtt óriási keveredés lenne a dologból, pár alaptétel.

 

1. Egy programon belül (Arduino 'sketch', konkrétan az Arduino keretrendszer/IDE szabályai szerint) kizárólag egy loop() ciklus lehet. Ez alap esetben végtelen számú alkalommal ismétlődik. Egy programon belül a miniális és egyben maximális követelmény is az egy darab void setup() és az egy darab void loop() megléte. A fordítást, áttöltést követően a setup() minden indítást  (reset vagy táp bekapcsolást követően) egyszer fut le, a loop () néhány speciális esetet kivéve végtelen számú alkalommal. A speciális eseteket hagyjuk egyelőre.

 

2. Léteznek olyan parancsok, amelyek valamely feladatot egy loop() futási körön belül többször futtatnak le. Jellegüket tekintve vagy magukban számolnak (például for ciklus), vagy vamely állapotot figyelnek (például while ciklus). Amikor a program futása során ezek sorra kerülnek, a szintaktika (az Arduino keretrendszer 'nyelvtana') szerinti módon a cikluson belüli utasítás vagy utasítások a megadott/tervezett számú alkalommal futnak le. Ettől a loop() ciklus futása nem változik, mindössze annyi történik, hogy a program futása az adott feltételek teljesülésének idejére csupán néhány utasításra korlátozódik.

halaloszto példája alapján a setup() az alapanyagok és eszközök előszedését jelenti (csak egyszer kell, az elején), a loop () maga az ételkészítés folyamata, a for ciklus megfelel pl. a "vágj fel 4 hagymát"-nak, egészen konkrétan "addig vagdoss hagymákat, ameddig a felvágott hagymák száma el nem éri a 4-et", a while ciklus pedig nagyjából az "addig dinszteld a hagymákat, amíg azok üvegesek nem lesznek".

 

3. Ide kívánkozik még egy rész, amit ugyan a legtöbb Arduino példa, különösen az egyszerűbbek nem érintenek, de a változók hatókörének megértéséhez fontos. Ezek a függvények. Az Arduino kód alap esetben két függvényt, a loop()-ot és a setup()-ot tartalmazza. Viszont ezen kívül végtelen számú (legalábbis a rendelkezésre álló memória erejéig) további függvényt tartalmazhat. Ezeket önálló programrészeknek kell tekinteni, amelyek akkor és csak akkor futnak le, amikor egy másik függvényből [setup(), loop() vagy másik önálló föggvény] hívás érkezik rájuk. Erre sajnos a legtöbb általam ismert oktatóanyag nem vagy nem kellő alapossággal tér ki.

 

4. Változók. Az Arduino keretrendszer alapjául szolgáló C nyelvben ez elég jól definiált dolog, ez nagyjából-egészében az Arduinora is igaz szerencsére, bár néhány dolgot jóval egyszerűbben oldottak meg (mert inkább tanulásra, oktatásra kitalált rendszerről van szó). Egy változónak alapvetően két fontos tulajdonsága van: a típusa (char, bool, int stb.), illetve a hatóköre (lokális, globális stb.). A típust kellő angol ismerettel az Arduino honlap REFERENCE szakaszában kifejtik. A hatókör már egy más kérdés. Alap esetben úgy kell elképzelni, hogy egy változó akkor foglal memóriát, ha él, egyébként nem. Ha él, van benne adat (függetlenül attól, hogy hozzárendeltél-e adatot akkor, amikor életre hívtad vagy sem), ha elpusztul, akkor az adat törlődik (egészen pontosan felszabadul az a memóriacím, amin tárolva van, ha ezt nem írja felül semmi, a memóriacímről elvileg beolvasható a régi adat). A változók életciklusa és hatóköre piszok fontos a jó programstruktúra elkészítéséhez (plusz memória-takarékossághoz stb.). Az alap tétel az, hogy egy lokális változó ott férhető hozzá, ahol létrehoztuk. Egy globális változó a programon belül mindenhol hozzáférhető. A legtöbb példában a változók deklarálása (és jó esetben a kezdeti értékek hozzárendelése) a programok legelején történik. Ezek mind globális változók, a setup() és a loop() függvényeken belül bárhol, illetve minden egyedileg létrehozott függvényen belül hozzáférhetők. A for ciklusban deklarált változó viszont lokális, ez csak ott és csak addig él, amíg a for ciklus fut, utána elpusztul (pontosabban felszabadul a memóriahely és a változó neve is "újrahasznosítható" lesz). Egy változó a hatókörén kívül nem él, nem értelmezhető, nem hozzáférhető, normális körülmények között nem írható át (erre van kivétel, de ebbe most nem megyek bele). Nagyon egyszerű példával:

int globalisValtozo = 0; //változó deklaráció a kód elején, ezek a kódon belül végig, mindenütt élnek és hozzáférhetők.

void setup()

{

int vaneGombnyomas = digitalRead(1); // ez lokális változó, csak a setup() függvényen belül él

}

void loop()

{

int loopValtozo = 42; // ez egy lokális változó, csak a loop()-on belül hozzáférhető

for (int i=0; i<10 ; i++) //az i változó csak a for cikluson belül él, csak ott hozzáférhető

{ } //ez a for ciklus parancsszakasza

int i = 21; // ez meg itt egy vicces helyet, amibe sokan belefutnak, lásd alább.

}

A változók a globálistól lefelé a lokális függvény szintű és a lokális parancs (ciklus) szintű változókig építkeznek hatókör szerint. Ennek megfelelően egy adott elnevezésű globális változóból egy programon belül csak egyetlen egy lehet. Egy függvényen belül egy adott elnevezésű változóból csak egyetlen egy lehet, de ugyanazt a változónevet létrehozhatod és használatod egy másik függvényen belül is (elvileg akkor is, ha mindkét változó egyszerre él), és a két függvényben a két teljesen azonos nevű változó teljesen eltérő értékkel bírhat. Ugyanez igaz a ciklusokra is, annyi differenciával, hogy beágyazott ciklusok ugyan vannak (cikluson belüli ciklus), de a beágyazott ciklus nem érhet véget később, mint az a ciklus, amibe beágyaztad. Plusz mivel a változók, amiket a cikluson belül deklaráltál, a cikluson belül élnek és érvényesek, ezért a ciklusba ágyazott ciklusban ugyanazt a változót még egyszer azonos néven nem hozhatod létre (for (int i....)-n belül nem lehet még egy for (int i...)). Sőt, mint a fenti példa is mutatja, ha egy változónak van egy függvényen belül érvényes változata és egy függvényen belüli cikluson belüli változata, akkor a kód fordítása sem fog már megtörténni (mivel a függvényen belül érvényes változó a függvénybe ágyazott utasításszintű változóként lenne újra létrehozva). Ez szintaktikai hiba.

 

Aztán van még a változó nevezéktan, a változótípusokkal való hatékony munka és a memóriakezelés hatékonyabbá tétele, a változók és a konstansok közötti differencia és ezek hatékony használata, és akkor még mindig nem hívtunk adatot memóriacímről. :-) Ez jó hosszú külön poszt lehetne.

 

Innentől csak a távoli jövő...No, ha ezzel így megvagyunk, akkor jön a következő csavar, hogy függvényen belül lokális változót át lehet adni másik függvénynek úgy, hogy a lokális változó tartalmát a meghívott függvényben felhasználjuk, sőt, az ottani lokális változóban meg is változtatjuk, majd ezt visszaadhatjuk egy teljesen másik változóba a hívott függvényből a hívó függvénybe. Sőt, megtehetjük azt is, hogy a függvényt kiszedjük a picsába, csinálunk belőle egy könyvtárat, amibe úgyszintén vannak lokális és (a könyvtáron belüli) globális változók, sőt, olyanok is, amik a könyvtárat használó programból is elérhetőek és megváltoztathatóak.

 

Előzmény: Sploc (2677)