Bevezető
Az Arduino egy szabad szoftveres, nyílt forráskódú elektronikai fejlesztőplatform, arra tervezve, hogy a különböző projektekben az elektronikus eszközök könnyebben hozzáférhetőek, kezelhetőek legyenek. Széles tömegek számára elérhető, mivel olcsó, könnyen beszerezhető, egyszerűen programozható, és csatlakoztatható más eszközökhöz.
Az Arduino eszközöket a saját programnyelvén az Arduino-n és többek között a GIM által kifejlesztett Ganzduino grafikus nyelven lehet programozni. Bár az Arduino nyelv nagyon ahsonló a C++-hoz, pár különbség mégis van. Ennek a segédletnek a célja, hogy az mindkét nyelv és függvénykészlet alapvető elemeit bemutassa.
A segédlet végén összegyűjtöttünk pár valós alakalmazásokra hasznos kódpéldát ill. egyszerű, komplett programokat, amelyek azonnal kipróbálhatóak és (remélhetőleg) megkönnyítik az Arduino felprogramozását.
A segédletet a Ganz Ifjúsági Műhely készíti és teszi nyilvánossá. A segédletet szerkeszti: Kimmel Gábor.
A tartalomhoz hozzájárultak:
- Kimmel Gábor (kimmelgabor@gmail.com)
- Kiss Attila (werdase@gmail.com)
Eszközbemutató
Az összes Arduino (és a velük kompatibilis egyéb eszköz, pl. az ESP32) mikrokontrollerekre épül. Ezek gyakorlatilag mini-számítógépek, processzorral és memóriával. Egy asztali PC-hez vagy egy okostelefonhoz kéepst nagyon lassúak, de nagyon olcsóak is, ezért egyszerűbb feladatokra, ahol programozni kell sokkal alkalmasabbak kisebb költségü és helyigényük miatt.
Az Arduinók négyféle módon tudnak a külvilággal kommunikálni. Az egyik a számítógéphez csatlakoztatott USB/soros kommunikáció. A második és harmadik a digitális és analóg portok, a negyedik egyéb, a soroshoz hasonló kommunikációs interfészek.
Digitális portból a legalapabb Arduino paneleken 14 darab található, ezekből általában 12 szabadon felhasználható (a 0 és 1 lábakat a PC-s kommunikáció használja). Ezek az Arduino szemszögéből lehetnek bemenetek (inputok) és kimenetek (outputok) is. Ha kimenet pl. ledeket lehet vele villogtatni, ha bemenet pl. kapcsolók, nyomógombok értékeit lehet vele megnézni.
A digitális eszközök két értéket tudnak felvenni. Ezeket többféleképpen is hívják, az egyik esetben nincsen feszültség, a másikban van.
Nincs feszültség | Van feszültség |
logikai 0 | logikai 1 |
0 V | 5 V |
alacsony | magas |
low | high |
Az analóg portok csak bemenetek tudnak lenni. Ellentétben a digitális portokkal amiknek csak kétfaja értékük lehet, 0 és 5 volt között több mint 1000 különböző értéket tudnak felvenni. 0 volt esetén az értékük 0, 5 volt esetén 1023 lesz. Az arudinók egy különlegessége, hogy az A0, A1, A2, A3, A4, A5 analóg portokra 14, 15, 16, 17, 18, 19 portszámokkal is tudunk hivatkozni.
Kommunikációs protokollokat kezdőként aránylag ritkán használunk, de a leggyakoribbak amiket Arduinón keresztül elérünk az SPI és az I2C.
Alapszabályok
Pár egyszerű szabály betartásával már el tudjuk kezdeni az Arduino nyelven írt programunk írását:
GanzDuino | Arduino/C++ |
Egy parancsanak egy blokk felel meg: | A parancsokat pontosvessző zárja -
|
Blokkokat vagy egymás mögé vagy egymás mellé lehet csatlakoztatni: | Egy sorba több parancs is írható -
|
A több blokkot fogadni képes blokkok elfordított "U" alakúak: |
Parancsblokkot { és } karakterekkel tudunk írni. |
Elágazás egy ha és egy ha-különben blokk áll rendelkezésre: |
Elágazásra az if, else és switch parancsokat tudjuk használni. |
Ciklusokhoz két blokk áll rendelkezésre, az egyik egy feltételt vizsgál a másik adott számszor ismétel: |
Ciklusokhoz a while, és for parancsokat használhajtuk. |
Az Arduino programnak legalább a két következő blokkot kell tartalmaznia: |
Az Aurduino programnak előre definiált struktúrája van: |
Az Aurduino rendszernek van egy nagy halmaz előre elkészített függvénykészlete. | |
Kommentet az erre speciális blokkal lehet létrehozni: |
Kommentsort a // jelekkel lehet írni, komment-blokkot a /* karakterekkel kezdünk és */ karakterekkel zárunk. -
|
Jót teszünk magunknak és másoknak, ha a következő tanácsokat is betartjuk:
- A változónevek legyenek mindig egyértelműek.
- Mindig használjunk kommenteket. Nem muszáj minden sort kommentelni, de az összetartózó részek legyenek leírva, hogy mi mit csinálnak.
- Ha gyakran ismétlünk bizonyos részeket, törekedjünk arra, hogy metódusba szervezzük ezeket a részeket - NE a kódrészletet másoljuk le többször!
Nyelvi elemek listája
Jel | Magyarázat |
---|---|
; | Parancs végét jelző karakter |
' | Karakter írására alkalmas jel |
|| | Logikai VAGY |
&& | Logikai ÉS |
| | Bitenkénti VAGY |
& | Bitenkénti ÉS |
>>, << | Bitek eltolása |
== | Egyenlőségvizsgálat |
!= | Egyenlőtlenségvizsgálat |
= | Értékedás |
+=, -=, /= *= | Értékmódosítás |
++, -- | Eggyel növelés ill. csökkentés |
Változók, típusok
Típusok
A számítógép memóriája szigorúan véve csak egész számokat tud tárolni, de okos tervezéssel tudunk törtszámokat, karaktereket, szöveget, sőt, ennél összetettebb adatfajtákat is használni.
Logikai típusok
Egy darab logikai típus létezik:
GanzDuino | Arduino/C++ | |
bool |
Igaz vagy hamis. |
Számszerű típusok
A számszerű típusok a következők:
GanzDuino | Arduino/C++ | |
--- | short |
Egy egész szám -32,768 és 32,767 között. |
int |
Egy egész szám -32,768 és 32,767 között. | |
--- | long |
Egy egész szám -2,147,483,648 és 2,147,483,647 között. |
--- | unsigned short |
Egy egész szám 0 és 65,535 között. |
--- | unsigned int |
Egy egész szám 0 és 65,535 között. |
--- | unsigned long |
Egy egész szám 0 és 4,294,967,295 között. |
float |
Tört szám, pl. 6.34 |
Karakteres típusok
GanzDuino | Arduino/C++ | |
char |
Egy darab betűt (karaktert) tárol. | |
String |
Egy szöveget tárol. |
Változók
Egy program alapvetően parancsok egymás utáni végrehajtása, de hamar eljutunk odáig, hogy bizonyos értékeket, adatokat, állapotokat tudnunk kéne elmenteni és később hozzáférni. Tehát egy program - amíg csak megírjuk - addig parancsok egy sorozata, viszont amikor már futtatjuk, használjuk, igazából parancsok és adatok egy csoportja.
Adatok tárolására változókat tudunk használni. Ezek egyfajta "címkék", amik megmondják, hogy egy edott nevű adat hol helyezkedik el a számítógép memóriájában. Ha tárolni vagy elkérni akarjuk az adott változóját akkor elég csak a címke helyén megnézni mi van a mamóriában.
Változókat nekünk kell kézzel létrehozni ha használni akarjuk őket. Először meg kell adni a típusukat, utána az azonosítójukat vagy nevüket. Egyből ezután érdmes nekik értéket is adni (ld Értékadás). A legjobb olyan értéket adni, amiről tudjuk, hogy az az alapértelmezett érték, tehát "valós" körülmények között nem fordulhat elő. Ha pl. 0-5 közötti számokat akarunk a változóba írni, egy jó alapértelmezett érték a -1.
GanzDuino | Arduino/C++ |
Hozzuk létre a változót a "Változó létrehozása"" gombbal: Adjuk meg a nevét és típusát a felugró ablakban: |
|
Attól függően, hogy hol hozzuk létre a változót beszélhetünk globális és lokális változókról.
GanzDuino | Arduino/C++ |
A Ganzduino-ban minden változó globális! |
|
A fenti Arduino programban lérehoztunk egy globális és lokális változót. A globális értéke folyamatosan nőni fog, míg a lokálisé ugyanaz marad. Miért?
A lokális változók "megsemmisülnek", amint a blokk, amiben létrehoztuk őket véget ér. A globális változónkat egyből a program elején hoztuk létre, tehát "örökéletű" marad. Lokális változót olyan helyen érdemes használni, ahol csak ideiglenesen van szükségünk egy plusz tárolóhelyre, globálsiat pedig ott, ahol az egész programot befolyásoló adatokat akarunk tárolni.
Tömbök
A tömbök ugyanolyan típusú változóknak a csoportja. Tömböt bármilyen típusból létre lehet hozni. Hasznuk abban van, hogy ugyanazzal a névvel tudunk az összes elemre hivatkozni, de egy kiegészítő címmel, ún. indexszel. Ez egy sima szám.
GanzDuino | Arduino/C++ |
Ganzduino programnyelvben nincsenek tömbök! |
Itt lérehoztunk egy 3 méretű tömböt. A különböző elemekhez az indexeren keresztül tudunk hozzáférni amit a szögletes zárójelek jeleznek.. Az indexek mindig 0-tól kezdődnek.
|
A tömbök különösen hasznosak, ha ciklusokban tudjuk őket használni!
Műveletek
Értékadás
Egy változót nem elég csak létrehozni, értéket is kell adni neki, hogy használható legyen. Egy változó értéke többféleképpen módosítható.
A legegyszerűbb értékadás, amikor egyértelműen megadjuk a változó értékét
GanzDuino | Arduino/C++ |
|
Ha egy változót csak egy egyszerű számmal szeretnénk módosítani, használhatjuk a négy alapműveletet egyszerűsítő értékadásokat is.
GanzDuino | Arduino/C++ |
A Ganzduino összetett értékedást nem támogatja. |
|
Különleges művelet az inkrementálás és a dekrementálás. Ez esetben pontosan 1-el tudjuk növelni vagy csökkentei egy változó értékét.
GanzDuino | Arduino/C++ |
A Ganzduino az inkrementálást/dekrementálást nem támogatja. |
|
Aritmetikai műveletek
Az aritmetikai műveletek olyan műveletek, amiket számokon lehet használni. Mivel az Arudino nyelvben a legtöbb adat amivel dolgozunk számszerű, ezért a legtöbb változón használhatóak. Eredményük mindig egy igaz-hamis érték lesz. Leginkább fletételek írására használhatjuk ezeket a műveleteket.
A kettő legfontosabb ilyen művelet az egyenlőség- és különbözőségvizsgálat. Két további ilyen művelet a nagyobb- illetve kisebb vizsgálat.
int a = 10; //hamis
int b = 15; //igaz
int c = -3; //igaz
int d = 10; //igaz
int q = a == d; //egyenlőségvizsgálat - igaz
int r = b != d; //különbözőségvizsgálat - igaz
int s = b > c; //relációs vizsgálat - igaz
int t = d < c; //relációs vizsgálat - hamis
Logikai műveletek
Az Arduino nyelv egy erősen kapcsolásokhoz kapcsolódó nyelv. Emiatt logikai függvényeket is lehet vele írni.
A logikai függvények alapvetően három műveletet ismernek
- ÉS (AND)
- VAGY (OR)
- NEM (NOT)
Ezekből lehet további műveleteket lérehozni
- ÉS-NEM (NAND)
- VAGY-NEM (NOR)
- EGYENLŐ (EQU)
- KÜLÖNBÖZŐ (XOR)
Érdekes módon az Arduino (és C++) nyelvben nincs logikai változótípus. Helyette használható bármelyik szám, ahol a 0 a hamis, bármelyik másik érték (pl. 1) az igaz értéket jelenti. Így már lehet írni logikai kifejezéseket is. Ezeket több jel feldolgozására, vagy feltételek írására lehet használni. Érdemes viszont mindig egy igaz értéket használni, mert az EGYENLŐ és KÜLÖNÖZŐ műveletek számszerű egyenlőséget vizsgálnak!
A nyelvben a három alapvető, ill. az egyenlőség és különbözőség-vizsgálatra beépített parancsok vanak. A NAND és NOR kifejezéseket ezekből lehet létrehozni.
int a = 0; //hamis
int b = 1; //igaz
int c = 3; //igaz
int d = -5; //igaz
int q = 0;
q = a && b; //ÉS
q = a || c; //VAGY
q = !a //NEM
q = b == d; //EGYENLŐ
q = a != c; //KÜLÖNBÖZŐ
q = !(a && d) //ÉS-NEM
q = !(b ||c) //ÉS-VAGY
Mint a NAND és NOR kifejezéseken látható, a logikai műveletek szabadon kominálhatóak egymással. A műveletek sorrendje balról jobbra halad, zárójelekkel viszont vezérelhető melyik művelet fusson le előbb (hasonlóan a matematikai kifejezésekhez),
q = !(d || (c && a) && b == d) //igaz, ha d igaz vagy c és a igaz, és d és d egyenlő
Bitműveletek
Mivel a mikrokontroller digitális lábait felfoghatjuk biteknek is (0 és 1 értékeik lehetnek), ezért a mikrokontrollereknél kiemelkedően fontos műveletek a bitek manipulálása. Sok esetben kisebb és gyorsabb kód írható, ha jól tudunk bárrni a bitek alacsony szintű kezeléséhez való eszközökkel
Két számot nem csak matematikailag lehet kombinálni, hanem bitentént is - ÉSelni és VAGYolni.
int i = 1; //00000001
int j = 8; //00001000
int k = 248; //11111000
i = i | j; //00001001, i=9
k = k & i; //00001000, k=16
Ennél még hasznosabb, ha egy változó bitjeit tudjuk eltolni. Ez, ha számszerűen nézzük a változókat teljesen véletlenszerű eredményeket ad, de ha bitenként nézzük, akkor nehéznek gondolt feladatokat lehet meglepően egyszerűen megcsinálni.
int i = 1; //00000001
i = i << 3; //00001000, i=8
i = i >> 2; //00000010, i=2
Egy nagyon egyszerű Knight-Rider kódrészlet például valahogy így nézne ki (ld. Elágazáskezelés):
int i = 1;
int irany = 0;
...
if(i == 1) //00000001
{
irany = 0;
}
else if(i == 128) //10000000
{
irany = 1;
}
if(irany == 0)
{
i = i << 1;
}
else
{
i = i >> 1;
}
PORTD = i; //PORTD az 1-8 lábakat fogja össze, erről bővebben az oktatóktól!
delay(200);
Elágazáskezelés
Ha meg akarunk vizsgálni egy változót, hogy mi az értéke, vagy attól függően, hogy mi az értéke, más és mást akarunk csinálni az if, else, és switch parancsokat használhatjuk.
If és else
A következő kód egy villogót valósít meg. Ha az i változó értéke 1, akkor világít a led, ha 0 nem. A következő lépshez megcseréljük az értékét a változónak és várakozunk.
GanzDuino | Arduino/C++ |
|
Switch - többirányú elágazás
Ha több irányba akarunk elágazni használhatunk sok ife-else-t de erre jobb megoldás a switchek használata
GanzDuino | Arduino/C++ |
A Ganzduino a többirányú elágazást nem támogatja. |
|
Ciklusok
A programozás egy másik alapja, hogy bizonyos műveletek egymás után többször, adott esetben ismeretlen sokszor kell ismételnünk.
GanzDuino | Arduino/C++ |
|
Honnan tudhatjuk, hogy 3-zor kell villogtatni a ledet? Lehet, hogy a felhasználó akarja beállítani, hogy hány villogás legyen. Egyszerű kódisméléssel erre már nem tudunk felkészülni. Erre és hasonló feladatokra valóak a ciklusok.
While ciklus
Tegyük fel, hogy soros porton akarunk beolvasni adatot. Ehhez először küldünk egy olvasási kérelmet, és ezután megvárjuk, hogy megérkezzen az adat. Hogyan kezeljük, ezt a várakozást?
GanzDuino | Arduino/C++ |
|
Ezzel a megoldással két baj van: ha gyorsan megjö az adat, akkor hiába vártunk 1 másodpercet. Másrészt semmi garancia nincs rá, hogy 1 másodperc alatt megjön az adat. Szerencsére a soros portnak van egy available metódusa, ami a még be nem olvasott karakterek számát jelzi. Tehát addig kell csinálnunk a semmit, amíg nincs mit beolvasni. Ezt a while paranccsal tudjuk megtenni.
Serial.begin(9600);
Serial.write('keres');
while(Serial.available() == 0)
{
}
char c = Serial.read();
A while parancs hasonlóan működik mint az if, azzal a különbséggel, hogy egészen addig fogja ismételni a benne lévő parancsokat, amíg a megadott feltétele igaz.
A while ciklusnak vagy egy ritkábban használt változata, a do-while. Ez egyszer mindenképpen lefut, utána pedig a feltételtől függően még többször (vagy másodszor már nem). Általában nem ajánlott használni, ezért ebbe a segédletbe nem kerül be.
For ciklus
A for ciklus alapvetően nem sokban különbözik a while ciklustól. Igazából csak egy rövidítés, de nagyon hasznos tud lenni, mert rövidebbé és olvashatóbbá teszi a kódot
//For ciklusfelépítés
for(kezdes; feltetel; modositas)
{
...
}
//Ugyanez a ciklus while-al
kezdes;
while(feltetel)
{
...
modositas;
}
A fenti két ciklus megegyezik. A for ciklus egyszerűen használható pl. olyan ciklusokban, ahol sorszámokra van szükségünk:
int i;
for(i = 0; i < 10; i++)
{
Serial.write(i);
delay(200);
}
Ez sorrendben ki fogja írni 0-9 számokat és mindössze 5 sor kód. Ha az első 100 számot szeretnénk kiíratni - egy hosszú, de ismétlődő folyamat - akkor is ugyanígy nézne ki a kód, csak a feltétel részt kéne átírni. Ez sokkal átláthatóbb, mint 100 sorban ugyanazt minimális változtatással leírni.
Ahogy volt már róla szó, tömböket kifejezetten hasznos a ciklusokkal, egész pontosan a for ciklussal használni. Nagyon egyszerű pl. n darab elem kezelése (keresés, sorbarendezés, sorban kiírás stb.).
int[] tomb = int[10]; //Létrehozunk egy 10 elemű tömböt
for(i = 0; i < 10; i++)
{
tomb[i] = i * 2; //Egy sor kódból értéket adtunk 10 különböző változónak!
}
Metódusok
Sokszor hasznos tud lenni, ha egy adott kódrészletet többször is fel tudunk használni. Például ha egy programban valami tevékenységet akarunk jelezni, villogtathatjunk egy ledet:
digitalWrite(LED, HIGH);
delay(500);
digitalWrite(LED, LOW);
Az előző kódrészlettel azonban van egy nagy probléma: minden egyes villagtatási helyre be kell másolni. Ha utólag rájövünk, hogy pl. más sebességgel akarunk villogtatni, akkor ezt aránylag sok helyen kell módosítanunk. Ehelyett létrehozhatunk metódusokat:
void villog(int ido, int szam) //visszatérési érték, név, paraméterek
{
int i; //
for(i = 0; i < szam; i++) //
{ //
digitalWrite(LED, HIGH); // Metódustörzs
delay(ido); //
digitalWrite(LED, LOW); //
} //
}
Egy metódusnak van neve, amivel hovatkozhatunk rá, törzse ahova a kódot írjuk, paraméterei és visszatérési értéke. Ennek a metódusnak a neve villog, visszatérési értéke void, van két paramétere (ido, és szam, mindkettő egy int), törzse pedig a blokkban található. Az ismert setup és loop szintén metódusok (void visszatérési érték, paraméter nélkül). Ezeket, mint már megtanultuk, muszáj definiálni.
Most egy olyan metódust hoztunk létre, amelynek nincs visszatérési értéke. Létrehozhatunk olyan metódusokat is, amelyek valamilyen értéket adnak vissza:
int negyzet(int a)
{
return a * a;
}
Ez a metódus egy int értéket ad vissza (a void egy speciális visszatérési értéket, a semmilyen értéket jelöli). A metódusban használhatunk változókat, elégazásokat és ciklusokat is, de egy nem-void metódusnak mindig vissza kell adnia egy értéket a return paranccsal. A megírt metódusokat így használhatjuk:
int i;
...
void loop()
{
...
if(negyzet(i) == 25)
{
villog(300, 1);
}
else
{
i = negyzet(10); //i = 100
villog(i, 3);
}
...
}
Voltaképpen ha belegondolunk, az alapprogramunk is pont így működik, a setup és loop metódusokat így használjuk:
GanzDuino | Arduino/C++ |
|
Fejlett kezelés
Mutatók
A mutatók, vagy más néven pointerek - ahogy nevük is mutatják - a memória egy bizonyos részére mutatnak. Nehéz elképzelni? itt egy kis magyarázat.
Bármilyen számítógép memóriája voltaképpen egy nagyon hosszú tömb. Ebbe a tömbe tudunk változókat létrehozni, amelyeknek innentől kezdve a számítógép nyelvén lesz egy memóriacíme. Például ha létrehozunk egy alma változót, az például kerülhet a 12-es helyre:
Változó alma ▼ Érték | │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘ Cím 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
Ennek a változónak aztán tudunk egy értéket is adni, pl. ez az érték legyen 40.
Változó alma ▼ Érték | | | | | | | | | | | | | 40 | | | | └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘ Cím 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
Maga a számítógép az alma névről sosem fog tudni. Neki csak úgy lesz ismert, mint a valami ami a 12-es helyen van.
A pointer is egy sima egyszerű változó. Ha létrehozzuk a mutat mutatónkat, ugyanúgy egy memória-helyre fog kerülni és ugyanúgy lehet neki értéke, pl. 12
Változó *mutat alma ▼ ▼ Érték | │ │ │ 12 │ │ │ │ │ │ │ │ │ 40 │ │ │ │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘ Cím 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15
Ha most lefuttatnánk a következő kódot valami nagyon érdekes történne:
int korte = mutat; //korte = 40
Mi is történt? Az korte nevű változó értéke 40 lett - pedig a mutat változóé csak 12!
Pointerekben ugyanis mindig egy memóriacímet tárolunk. A változó értéke azért lett 30, mert a mutatóban tárolt érték - 12 - memóriacímen éppen ez az érték volt.
Változó korte *mutat alma ▼ ▼ ▼ Érték | 40 │ │ │ 12 │ │ │ │ │ │ │ │ │ 40 │ │ │ │ └────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┴────┘ Cím 00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 ▲│ ▲│ ▲│ │└─────────────┘└───────────────────────────────────────────┘│ └────────────────────────────────────────────────────────────┘
Portok
Bár az Arudino környezet nagyon megkönnyíti a digitális ki- és bemenetek kezelését (ld. digitalWrite), a Arduino nem más, mint egy túlhype-olt mikrokontroller. Leggyakrabban egy Atmel gyártmányú ATMega 32.
A mikrokontrollereknél szinte kivétel nélkül a legkisebb be- és kiviteli egység a port. Ezek általában 8 lábat fognak össze, mivel a mikrokontroller által lezelt legkisebb adatmennyiség 8 bit, azaz 1 bájt. Ez ugye felvet pár kérdést, például valószínűleg a legfontosabb ezek közül:
Hogyan tudok akkor csak egyetlen lábat állítani?
Egyszerű: bitműveletekkel. Leggyakrabban ún. maszkolást szoktunk használni. Ennek lényege, hogy a hozzáadott értéket vagy hozzá VAGY-oljuk vagy ÉS-eljük a meglévő értékhez.
char port = 0x00010010
char mask = 0x10000000
PORTB = port | mask; //0x10010010
Az Arduino portjait a PORTA, PORTB, PORTC és PORTD változókkal lehet elérni. Ezeket az Arduino rendszer előre létrehozza, nekünk nem kell (és nem is lehetésges) definiálni.
PORTA | PORTB | PORTC | PORTD |
---|---|---|---|
8 9 10 11 12 13 |
A0 A1 A2 A3 A4 A5 |
0 1 2 3 4 5 6 7 |