A while-ciklus

Lassan az egész C nyelv összes utasítását megismered (van vagy 10 belőle)! A ciklus, mint már tudod, arról szól, hogy ismételjünk dolgokat.

A for-ciklust általában úgy használjuk, hogy valamit megadott számúszor ismételjünk meg. Azonban sokszor jó lenne, ha nem kellene megadni azt, hogy hányszor ismételjen, mert:

Lássunk erre egy példát! A 0-ás portra tegyél egy gombot (az előző oldalon is ott volt). A feladat egyszerű: amíg a gombot nyomva tartják, addig villogjon a led!

Sajnos bárhogy agyalsz rajta, ezt if-el csak igen esetleges módon lehet megoldani (persze pont ezt a példát még lehet oldani if-el, de a többit már nem). Ehhez olyan ciklus kell, ami addig ismétel, amíg valami feltétel teljesül.

const int ON=1;
const int OFF=0;

void setup() {
    pinMode(13, OUTPUT);
    pinMode(0, INPUT_PULLUP);
}

bool buttonPressed() {
    if (digitalRead(0)==LOW) { // azaz a a gomb meg van nyomva
        return true; // most meg van nyomva
    }
    else {
        return false; // most nincs megnyomva
    }
}

void led(int state) {
    digitalWrite(13,state);
}

void loop() {
    while(buttonPressed()) {
        led(ON);
        delay(100);
        led(OFF);
        delay(100);
    }
}

Hogy is van ez? Egyszerűen! A while ismétli az utána írt utasításblokkot, amíg a feltétel igaz, azaz amíg a gomb meg van nyomva.

Végtelen while-ciklus

Mire jó a végtelen ciklus? Arra, hogy valamit végtelenül sokáig ismételj. Például egy SOS-t morzézó vészjelzőt célszerű úgy csinálni, hogy ahelyett, hogy diszkréten nyom egy SOS-t aztán kikapcsol, ahelyett folyamatosan nyomja hogy SOS, amíg csak tart benne az elem.

Az A-starban a loop() függvényt is egy végtelen ciklusban hívja az Arduino rendszer, így amit oda írsz, azt folyamatosan ismételgeti.

Hogyan lesz egy ciklus végtelen? Hát úgy, hogy a ciklusban maradás feltétele mindig igaz. Például, while (1==1) az remek kezdet, hiszen mióta felfedezték a számokat, 1 értéke mindig egyenlő 1-el.

Ettől kulturáltabb a while (true), hisz ahogy az előző részben láttad, az 1==1 értéke valójában egy összehasonlítás, aminek az értéke egy logikai érték, mégpedig true (azaz "igaz").

Szóval egy örökké menő ciklus ilyen lenne:

while(true) {
    led(ON);
    delay(100);
    led(OFF);
    delay(100);
}

Gomb és while-ciklus

Sokszor jó lenne a gomb megnyomását és elengedését is külön érzékelni. Csináljunk egy olyan lámpát, ami egy gombnyomással bekapcsol, és a következő gombnyomással kikapcsol!

No de ha csak arra figyelünk, hogy a gombot megnyomták-e, akkor állandóan be-ki-be-ki fogunk kapcsolgatni, hiszen az ember leggyorsabban elengedve is 0.1 másodpercig nyomja azt a gombot, ennyi idő alatt a programunk meg már sokezerszer lefut.

Csinálhatunk egy olyan while-ciklust, ami addig ismételget, amíg a gombot megnyomták, így nem megy tovább a progi amíg a gombon taposunk:

while(buttonPressed()) {
    // nem csinálunk semmit
    // és a semmit ismételjük
}

Tehát, amíg a gomb meg van nyomva, ismételjük a semmit - magyarul várunk, hogy elengedjék a gombot.

Szerencsére a semmit nem feltétlen kell leírni, ha olyan ciklust akarunk ami a semmit ismétli, az üres utasításblokk kihagyható:

// vár, amíg nyomják a gombot 
while(buttonPressed());

Az előző részben megtanultál egy csomó összehasonlító műveletet, amik számokkal működnek. A logikai (bool) értékekhez is van egy csapat művelet:

Mivel a buttonPressed egy függvény, ami logikai értéket ad vissza, ezért az eredménye megetethető mondjuk a ! műveleti jellel, így lehet gomb megnyomására, és gomb elengedésére váró ciklusunk:

// vár, amíg nyomják a gombot 
while(buttonPressed());

// vár, amíg nem nyomják meg a gombot 
while(!buttonPressed());

Tegyük akkor össze! Tehát a következő a cél:

Valahogy így:

const int ON=1;
const int OFF=0;

void setup() {
    pinMode(13, OUTPUT);
    pinMode(0, INPUT_PULLUP);
}

bool buttonPressed() {
    delay(100);
    if (digitalRead(0)==LOW) { // azaz a a gomb meg van nyomva
        return true; // most meg van nyomva
    }
    else {
        return false; // most nincs megnyomva
    }
}

void led(int state) {
    digitalWrite(13,state);
}

void loop() {
    while(!buttonPressed()); // várunk amíg megnyomják
    led(ON);
    while(buttonPressed());  // várunk amíg elengedik

    while(!buttonPressed()); // várunk amíg megnyomják
    led(OFF);
    while(buttonPressed());  // várunk amíg elengedik
}
Mi az a delay a buttonPressed-ben? Amikor egy gombot megnyomnak vagy elengednek, akkor a gomb nem hirtelen bekapcsol vagy kikapcsol, hanem egy picit ide-oda kapcsolgat. Ezt a jelenséget úgy nevezik, hogy "prell". Az Arduino annyira gyorsan futtatja a programunkat, hogy simán észreveszi ezeket a nem kívánatos prelleket. A delay(100) egyszerűen megvéd minket ettől: hiszen emiatt a delay miatt a program lassabban fog futni.

Feladat

Csinálj három-fényű lámpát! Az analogWrite-al kezeld a led fényerejét, és minden gombnyomásra kicsit erősebb legyen a fény: 0%, 50%, 100% között. (Ne feledd, hogy az 50%-os fényhez picit kisebb értéket kell használni az analogWrite-ban, mert az ember szeme nem arányosan érzékeny a fényre.)

Nekem ilyen lett:

const int MAX=255;
const int MID=50;
const int OFF=0;

void setup() {
    pinMode(13, OUTPUT);
    pinMode(0, INPUT_PULLUP);
}

bool buttonPressed() {
    delay(100);
    if (digitalRead(0)==LOW) { // azaz a a gomb meg van nyomva
        return true; // most meg van nyomva
    }
    else {
        return false; // most nincs megnyomva
    }
}

void led(int state) {
    analogWrite(13,state);
}

void loop() {
    while(!buttonPressed());
    led(MAX);
    while(buttonPressed()); 

    while(!buttonPressed());
    led(MID);
    while(buttonPressed()); 

    while(!buttonPressed()); 
    led(OFF);
    while(buttonPressed()); 
}

Csináld meg, hogy minden gombnyomásra csippantson! Sőt, más-mást csippantson az egyes fényerők bekapcsolásakor!