Loopar

Loopar

I detta kapitel ska vi se närmare på loopar. En loop är en funktion som gör samma sak om och om igen. Vi har redan använt en loop flera gånger (funktionen som heter loop och finns i alla sketcher). For och while är två loopar som kan användas inne i loop-funktionen.

For-loop

For-loopen är en klassisk loop som finns i många programmeringsspråk. Den styrs av ett villkor och gör om samma sak till dess att villkoret inte längre är uppfyllt. For-loopen kan exempelvis användas för att loopa igenom en array. 

Vi kan lagra namn i en sträng-array (vid namn names) med följande deklaration och initiering.

String names[] = {"Alice", "Bob", "Charlie", "Dave"};


Vi skulle kunna skriva ut namnen i Serial monitor med följande kod.

Serial.println(names[0]);
Serial.println(names[1]);
Serial.println(names[2]);
Serial.println(names[3]);


Detta sätt att skriva ut namnen blir tyvärr opraktiskt om det är många namn som ska skrivas ut. Som tur är kan vi använda en for-loop för att effektivisera koden. Den kan se ut på följande vis.

  for(int i = 0; i <= 3; i = i + 1){
    Serial.println(names[i]);
  }

Inne i for-parentesen skriver vi tre saker. 

  • Den första saken är deklarationen och initieringen av int-variabeln i. Vi sätter värdet på i till 0. Detta gör vi eftersom det första namnet vi vill skriva ut ligger på plats 0 i arrayen.
  • Den andra saken är villkoret för hur länge loopen ska köras. Vi säger att den ska köras så länge i är mindre än eller lika med 3. Detta gör vi eftersom det sista namnet vi vill skriva ut ligger på plats 3 i arrayen.
  • Den tredje saken är vad for-loopen ska göra med variabeln i varje gång loopen har körts. Vi säger att i ska räknas upp med värdet 1 varje gång loopen har körts.

Sammantaget innebär detta att vår for-loop kommer köras fyra gånger. 

For-loopen ska skriva ut innehållet från names-platsen i. Eftersom i räknas upp varje gång loopen har körts kommer Arduinon första gången skriva ut names[0], andra gången names[1] och så vidare. 

Tips! I APL (och många andra språk) kan i = i + 1 förkortas till i++ (det får exakt samma innebörd). For-loopar brukar därför skivas på följande sätt.

 for(int i = 0; i <= 3; i++) {
    Serial.println(names[i]);
  }

Motsatsen till i++ är i-- som betyder i =  - 1 (alltså räkna ned värdet med 1). Det är praktiskt för att loopa igenom något baklänges. 

Följande sketch skriver ut namnen i names i både stigande ordning och fallande ordning. Eftersom de två looparna ligger i loop-funktionen kommer looparna att köras om varenda sekund (lägg märke till fördröjningen på 1000 ms). 

NamePrinter.ino

Räkneverk med fyra deltagare

Räkneverket i Funktioner byggdes för två deltagare och två korgstorlekar. Vi kan använda samma hårdvara och koppling för att bygga ett annat räkneverk för fyra deltagare och en korgstorlek. Det enda vi behöver göra hårdvarumässigt är att byta färg på två av knapparna så att även Charlie och Dave får varsin dedikerad färgknapp. 

Kopplingen för vårt räkneverk.12

Vi vill att räkneverket ska räkna upp personens värde (antalet insamlade äpplen) när han eller hon trycker på sin knapp. Arduinon ska även skicka en statussammanställning till Serial monitor varje gång någon trycker på en knapp. I statussammanställningen ska det stå hur många äpplen varje person har plockat och hur många äpplen han eller hon har kvar att plocka till sitt individuella mål. För att göra detta behöver vi skapa tre arrayer:

  • en String-array med alla namn
  • en long-array med antalet plockade äpplen per person
  • en long-array med målet för hur många äpplen varje person ska plocka.

Det gör vi med följande kod.

Del av FruitPickers5.ino

När någon trycker på sin knapp anropas funktionen updateStatus med argumenten för hur många äpplen som ska läggas till och till vems samling det ska läggas till. Sedan använder vi en for-loop för att skriva ut hur många äpplen varje person har plockat. I for-loppen har vi lagt in en if-sats för att få en korrekt utskriven statusrapport. Utan if-satsen hade vi fått negativa värden i statusrapporten när någon hade plockat fler äpplen än hans eller hennes mål.

Den färdiga sketchen ser ut på följande vis.

FruitPickers5.ino

Obs! Lägg märke till att vi har ändrat datahastigheten (från 9600 Bd till 115200 Bd) för att få bättre flyt. För att programmet ska fungera som tänkt måste detta även ändras i Serial monitor (längst ned till höger).

Kom ihåg att ändra hastigheten till 115200 Bd.

Morsealfabetet

Morsealfabetet uppfanns på 1800-talet av Samuel Morse. Det används för att kommunicera med hjälp av pulser. Det främsta användningsområdet var inom telegrafin, men Morsealfabetet kan även i modern tid användas för att sända budskap med blinkande lampor eller pipande högtalare. 

Bokstäverna i Morsealfabetet byggs upp med kombinationer av korta och långa pulser. Exempelvis är bokstaven A en kort puls följd av en lång puls. Långa pulser varar lika länge som tre korta pulser. Alla pulser skiljs åt med en paus som varar lika länge som en kort puls.

Morsealfabetet

Bokstavskombinationen SOS blev det universella nödanropet eftersom det är lätt att komma ihåg hur det skrivs med Morsealfabetet. Bokstaven S är tre korta pulser och bokstaven O är tre långa pulser. Denna kombination av tre tecken går lätt att sända kontinuerligt med hjälp av en så kallad while-loop. 

SOS med Morse

While-loop

Det går att åstadkomma samma resultat med en while-loop som med en for-loop, men while-loopen erbjuder viss utökad funktionalitet. Den kan exempelvis användas för att köra saker under tiden en knapp är intryckt.

För att demonstrera detta vill vi bygga en SOS-blinkare. När vi trycker på SOS-blinkarens knapp ska en lysdiod blinka det Morsebaserade SOS-ropet (tre korta blinkningar, följt av tre långa blinkningar, följt av tre korta blinkningar).

Illustration gjord med komponenter från Fritzing (fritzing.org). CC BY-SA 3.0

Vi använder utvecklingskortets inbyggda lysdiod (GPIO-stift 13) för att slippa koppla in en extern lysdiod. 

Vi inleder koden med att inkludera Button-biblioteket och skapa en ny knapp (kopplad till GPIO-stift 2).

Del 1/5 av Sos.ino

I setup-funktionen startar vi knappen och sätter lysdiodsstiftet som en utgång.

Del 2/5 av Sos.ino

Vi väntar med att skriva loop-funktionen och skriver tre egna funktioner först. Den första funktionen kallar vi shortBlink. Den har varken något argument eller något retur­värde. Det enda den gör är att tända lysdioden i 200 ms och därefter hålla den släkt lika länge. ShortBlink åstadkommer alltså en kort Morsepuls. 

Den andra funktionen kallar vi longBlink. Den gör samma sak som shortBlink, men håller lysdioden tänd tre gånger så länge (d.v.s. 600 ms). LongBlink åstadkommer alltså en lång Morsepuls. 

Del 3/5 av Sos.ino

Den tredje egna funktionen kallar vi morseBlink och ger argumentet character. När funktionen anropas med en bokstav som argument, kommer programmet undersöka om bokstaven finns med i switchsatsen. Om den gör det kommer programmet att anropa shortBlink- och longBlink-funktionerna för att få lysdioden till att blinka fram den önskade bokstaven.  

Del 4/5 av Sos.ino

I loop-funktionen skriver vi avslutningsvis en if-sats som körs när någon trycker på knappen. Då startar en while-loop som loopar tills knappen släpps upp. Lägg märke till hur vi har uttryckt villkoret. Utropstecknet gör att villkoret får motsatt betydelse. While-loopen körs alltså så länge som btnSos inte är släppt.

Del 5/5 av Sos.ino

Do-loop

While-loopen förekommer i en version som kallas do-loop. While-loopen börjar alltid med att undersöka om villkoret är uppfyllt och kör koden om villkoret är det. Do-loopen kör koden först och kollar villkoret efter det. Om villkoret är uppfyllt repeterar do-loopen koden igen. 

Den praktiska skillnaden mellan en while-loop och en do-loop är att koden i do-loopen alltid körs minst en gång.

Oändlig loop

Ett vanligt misstag är att skriva oändliga loopar. Det är loopar vars villkor alltid uppfylls så att de körs i all oändlighet. Dubbelchecka alltid så att variabeln som villkoret testas mot ändras någon gång i loopen. 

while (x<100) {
  Serial.println(x);
}

Oändlig loop

while (x<100) {
  Serial.println(x);
  x++;
}

Inte oändlig loop

Oändliga loopar får programmet att stanna i loopen och aldrig komma vidare. Läs mer om oändliga loopar i Programmeringslathund

Referenser

12. Illustration gjord med komponenter från Fritzing (fritzing.org). CC BY-SA 3.0

Senast ändrad: 2017-01-23