Arduino - LED looplicht
In dit project sluiten we een serie LEDs aan op de Arduino en laten die in verschillende patronen knipperen. De aandacht gaat daarbij vooral uit naar het programma dat diverse vormen van lussen bevat.
Lessen:
- Meer programmeren
- Seriele communicatie helpt bij debugging
Contents
De schakeling
Extra benodigdheden (naast natuurlijk de Arduino, een USB kabel, je breadboard en wat aansluitdraadjes):
- 8 LEDs
- 8 weerstanden van 180Ω-220Ω
De LEDs sluiten we met hun lange pootje aan op pins 2 tm 9 van de Arduino. De korte pootjes van de LEDs sluiten we via een weerstand aan op de nul-regel van het breadboard die vervolgens wordt verbonden met de GND ingang van de Arduino.
|
| Verbindingen in het breadboard |
Als een van de LEDpins hoog wordt, en dus 5 Volt spanning voert, gaat er stroom door de LED lopen die via de weerstand naar de nul gaat. Vervolgens hebben we 8 LEDs die we met het programma gaan aansturen voor leuke licht-effecten.
Het programma uploaden
Hieronder staat weer het programma. Kopieer het naar de Arduino omgeving en upload het.
int base = 2 ; // aansluitpin van de eerste LED
int num = 8; // aantal LEDs
int wait = 200; // wachttijd
void setup()
{
for (int i = base; i < base+num; i++)
pinMode(i, OUTPUT);
Serial.begin(9600); // set baud rate at 9600
Serial.println("Klaar met setup()");
}
void loop()
{
for (int i = base; i < base+num; i++)
{
digitalWrite(i, HIGH);
delay(wait);
}
for (int i = base; i < base+num; i++)
{
digitalWrite(i, LOW);
delay(wait);
}
}
Een andere versie van de loop() functie staat hieronder. Dit laat een wat ander patroon zien.
void loop()
{
for (int i = base; i < base+num; i++)
{
digitalWrite(i, HIGH);
delay(wait);
}
for (int i = base+num-1; i >= base; i--)
{
digitalWrite(i, LOW);
delay(wait);
}
}
Uitleg van het programma
Tot nu toe bestaand onze programma's steeds uit drie delen. Eerst worden variabelen gedefinieerd, daarna komt de setup() functie en tenslotte de loop() functie. Ondanks dat we 8 LEDs gaan aansturen hebben we in dit programma we maar drie variabelen: base, num en wait. De LED-pins worden niet een voor een gedefinieerd, maar als reeks. De eerste LED-pin is base (=2), de volgende is dan 3, 4, en zo voort tot we num LEDs hebben. Met base en num leggen we dus de pins vast van alle 8 LEDs. Variabele wait wordt gebruikt bij de delay's.
In de setup() functie kunnen we nu niet meer de led-pins van de Arduino op de gebruikelijke manier op OUTPUT instellen. Dat doen we nu met een for-loop.
for (int i = base; i < base+num; i++)
pinMode(i, OUTPUT);
Een for-loop is een stukje programma dat een aantal keer wordt doorlopen. In de for-loop wordt een nieuwe variabele i gebruikt. Deze is van het type int (gehele getallen) en begint bij waarde base. Zoals we weten geldt base=2, dus i krijgt met waarde 2. Na de puntkomma staat de voorwaarde van de loop: i < base+num. Het < 'teken betekent kleiner dan. De herhaling gaat door zolang aan deze voorwaarde wordt voldaan. Omdat num=8 geldt base+num=10. Dit alles betekent dat zolang i<10 de loop doorgaat. Het derde deel dat de for-loop definieert is nogal cryptisch: i++. In deze programmeertaal betekent dit dat i elke ronde van de loop een hoger wordt. Als i eerst twee is, wordt hij daarna dus 3, daarna 4, en tenslotte 10. Maar als i de waarde 10 krijgt wordt de loop niet meer uitgevoerd omdat 10 niet kleiner is dan 10. De laatste waarde waarvoor de loop wordt uitgevoerd is dus 9. Het statement
pinMode(i, OUTPUT);
wordt dus uitgevoerd voor waarden i=2, 3, 4, 5, 6, 7, 8, en 9. En dat zijn precies de pins waar de LEDjes aan zitten. Zo kunnen we in twee regels code 8 pins op OUTPUT instellen. natuurlijk is het hiervoor wel noodzakelijk opeenvolgende pootjes te gebruiken.
Als we nu nog even naar de loop() functie kijken, dan zien we daar dezelfde structuur:
for (int i = base; i < base+num; i++)
{
digitalWrite(i, HIGH);
delay(wait);
}
Het enige verschil is dat binnen de loop niet een maar twee statements worden uitgevoerd. In het bovenstaande stukje van het programma wordt de betreffende pin op HIGH gezet (waardoor de LED aan gaat) en wordt er 200ms gewacht voor de volgende LED aangezet zal worden. De loop die daarna komt zet alle LEDjes in dezelfde volgorde weer uit.
Het alternatieve patroon bevat ook nog een interessante loop.
for (int i = base+num-1; i >= base; i--)
{
digitalWrite(i, LOW);
delay(wait);
}
Als je het bovenstaande begrepen hebt snap je dat i hier begint met waarde base+num-1=9 en gaat de loop zolang door als i>=2. Het derde deel van de for-loop definitie bevat nu i--. Dit betekent dat de waarde van i elke ronde van de loop een lager wordt. In dit geval begint i dus bij 9 en loopt dan af tot en met 2.
Beetje spelen
- Dat die lampjes steeds met hetzelfde ritme bewegen is toch een beetje saai. Kun jij het zo maken dat de eerste lampjes langzaam gaan en dan steeds sneller tot het einde?
- In de eerste versie van het programma gaan eerst alle lampjes aan en daarna, vanaf dezelfde kant weer uit. Je kunt eens nadenken of je iets kunt verzinnen waarmee de eerste lampjes al uitgaan terwijl de laatste nog aan gaan. Zo'n schema zou ook verder door kunnen lopen: nadat het laatste lampje is aangezet, wordt de eerste, die nu uit is, ook weer aangezet. Het is goed om hier even over na te denken, maar je zult merken dat dit nog vrij lastig is en dat je er misschien wel niet uit komt. Hier is een oplossing. Bekijk het maar eens goed en zie hoe gemakkelijk het kan zijn!
- Op het eerste gezicht werkt het laatste programma prima. Maar als je het programma lang genoeg aan laat staan blijkt dat er toch een probleempje is. De ingebouwde teller lednr is van het type int. Bij dit type gaat het om positieve en negatieve gehele getallen tussen -32768 en 32767. Grotere getallen passen niet in het type int. Maar na verloop van tijd wordt lednr natuurlijk toch groter! Het vreemde is nu dat als je 1 optelt bij 32767, je zonder waarschuwing uitkomt bij -32768 !! De berekening van de pins is vanaf dat moment helemaal fout omdat de modulus berekening met negatieve getallen ook uitkomt op een negatief getal. Dus (-12%8=-4). Jammer maar helaas dus. Daarna moet lednr eerst weer helemaal van -32768 tot nul tellen voor het programma weer normaal werkt. Voor we echter bij 32767 zijn duurt wel even. Als wait=200 (ms), zal het programma de teller elke seconde met 5 ophogen. Dat betekent dat het 6553 seconden duurt voor het probleem zichtbaar wordt. Dat komt neer op 01:49 uur. En dan nog eens 01:49 uur voor lednr weer bij zijn positieven is en het programma weer normaal werkt. Je kunt voor een test het proces natuurlijk behoorlijk versnellen door wait te verkleinen, maar maak het niet te klein, want dan zie je niks meer. Zou je dit probleem zelf hebben ontdekt met de Serial Monitor? Snap je dat er bijvoorbeeld in de ruimtevaart wel eens iets mis gaat door een software probleem?
