delay | probleem | ingrijpen | voorwaardelijk ingrijpen |
Delay |
Na deze les hoor je te weten:
In het vorige hoofdstuk hebben we de sketch Blink gebruikt. Deze sketch is hieronder verkort weergegeven met een langere wachttijd. In deze sketch gaat het lampje ieder 5 seconden aan dan wel uit. De timing wordt hier gedaan met de delay functie. We hebben voor het aan en uitzetten een functie schakel ingezet.
|
Opdracht |
|
Probleem | ProbleemHet probleem met delay als timing is tweeledig. Het belangrijkste probleem is dat de Arduino niets anders kan doen tijdens een delay. Stel je wilt tijdens de aan en uit cyclus hierboven snel kunnen reageren op de status van een knop. Als de knop wordt ingedrukt moet er een tweede lamp gaan branden terwijl het knipperen van de eerste lamp gewoon doorgaat. Voor we hiervoor een sketch ontwikkelen vermelden we nog het tweede probleem. In de Blink sketch hierboven lijkt het erop of onze cyclus 10 seconden duurt. Omdat digitalWrite een heel snelle instructie is zal dit ook wel bijna 10 seconden duren. Als echter een functie wordt uitgevoerd die veel meer tijd kost (zeg 1 seconde) dan is de tijd van de cyclus langer dan 10 seconden (10 + 2 × 1 = 12). We beginnen met een eerste poging waarin we reageren op een knop. Voeg een led en een knop toe. De knop sluit je aan volgens het schema hier onder.
|
Opdracht |
|
Terug naar de sketch waar slechts 1 lamp knippert, maar nu met een andere manier van wachten. Lees de code aandachtig door. Run de code en observeer.
|
|
Opdracht |
|
Ingrijpen | IngrijpenIn de de twee knipper voorbeelden zien we het zelfde. Het lampje wisselt iedere 5 seconden van status. In de Arduino is er dan wel wat anders aan de gang. Vergelijk het met de situatie van een wekker versus alleen een klok. Met een wekker kun je je ogen even toe doen terwijl je eitje aan het koken is. Heb je alleen een klok dan moet je de tijd zelf constant in de gaten houden. Maar ja als je eenmaal aan het kijken bent kun je net zo goed andere wijzertjes in de gaten houden en daar op reageren. Hier onder vind je een code met een timer en een knop waarbij de Arduino direct reageert op de knop. Behalve constant de tijd bijhouden gaat de Arduino nu ook constant kijken of er iets aan de toestand van een knop is veranderd.
|
Opdracht |
|
Je ziet wel heel vaak dezelfde uitvoer. We willen dit eigenlijk alleen zien als er wat verandert in de toestand van de knop. We gaan een toestand voor de knop toevoegen.
|
|
Opdracht |
|
Voorwaardelijk ingrijpen | Voorwaardelijk ingrijpenIn de sketch hierboven hebben we tijdens het knipperen een ander lampje bediend. Wat als we met de knop juist de status van de eerste lamp willen beïnvloeden? In het vorige hoofdstuk heb je als opdracht twee verkeerslichten moeten aansturen met de Arduino voor een hoofdweg met een zijweg. Als de zijweg nu heel weinig wordt gebruikt en de hoofdweg juist heel, is het slimmer om de zijweg alleen op groen te zetten als er verkeer komt. We nemen nu even aan dat de zijweg een fietspad is met een drukknop bij het verkeerslicht. Het hoofdweg - zijweg probleem uit het vorige hoofdstuk heb je opgelost met delay instructies tussen de verschillende toestanden. De wachttijden tussen die toestanden hebben we nog steeds nodig. Een fietser moet nu door het indrukken van de knop groen licht gaan krijgen. Dat kan natuurlijk niet gelijk. Eerst moet de hoofdweg oranje krijgen voor dat het verkeerslicht op rood staat om het verkeer op de hoofdweg veilig te kunnen laten stoppen. Er is dus een opeenvolging van toestanden waarvan de meeste niet onderbroken mogen worden en in dit geval slechts één wel (groen op de hoofdweg met rood op het fietspad) We moeten dus een aantal dingen voor een toestand vast gaan leggen: Hoelang duurt de toestand, wat moet er gebeuren, en mag de toestand worden onderbroken. Er zijn verschillende mogelijkheden om dit te doen. Wij gebruiken hier een datastructuur in c++ struct genoemd, waarmee je op eenvoudige manier gegevens groepeert. Het begrip struct is de voorloper van het begrip class dat gebruikt wordt in object georiënteerd programmeren. Wat we nu gaan doen hadden we iets ingewikkelder met classes kunnen doen. De struct die we gaan maken noemen we toestand die we een duur, een actie en een vlag bevat om aan te geven of de toestand te verstoren is: struct toestand { unsigned long duur; // duur in miliseconden int actie; // nummer van de actie bool te_storen; // toestaan (true) of niet toestaan false }; Hiermee maken we een array met alle gewenste toestanden: #define TOESTANDEN 6 toestand toestand_reeks[TOESTANDEN]={ {10000,1,true}, // groen rood {500,2,false}, // geel rood {500,3,false}, // rood rood {5000,4,false}, // rood groen {500,5,false}, // rood geel {500,3,false} // rood rood }; We moeten bijhouden welke toestand er gaat komen, of de knop is ingedrukt of niet en of we in de reeks moeten ingrijpen. unsigned long volgend_moment; // wanneer moet de volgende toestandsovergang plaatsvinden int volgende_toestand=0; // welke toestand wordt dit bool interupted = false; // moet in de toestandreeks ingegrepen worden bool knopstatus = false; // is de knop ingedrukt of niet Hieronder vind je de volledige schets. Jouw taak is om het geheel verder te begrijpen aan de hand van de opdrachten er onder. #define HoofdwegRood 13 #define HoofdwegGeel 12 #define HoofdwegGroen 11 #define ZijwegRood 10 #define ZijwegGeel 9 #define ZijwegGroen 8 #define AAN true #define UIT false #define TOESTANDEN 6 #define KNOP 3 struct toestand { unsigned long duur; int actie; bool te_storen; }; toestand toestand_reeks[TOESTANDEN]={ {10000,1,true}, // groen rood {500,2,false}, // geel rood {500,3,false}, // rood rood {5000,4,false}, // rood groen {500,5,false}, // rood geel {500,3,false} // rood rood }; unsigned long volgend_moment; // wanneer moet de volgende toestandsovergang plaatsvinden int volgende_toestand=0; // welke toestand wordt dit bool interupted = false; // moet in de toestandreeks ingegrepen worden bool knopstatus = false; // is de knop ingedrukt of niet void setup() { // Initialiseer de digitale pin als uitvoer. pinMode(HoofdwegRood, OUTPUT); pinMode(HoofdwegGeel, OUTPUT); pinMode(HoofdwegGroen, OUTPUT); pinMode(ZijwegRood, OUTPUT); pinMode(ZijwegGeel, OUTPUT); pinMode(ZijwegGroen, OUTPUT); pinMode(KNOP, INPUT); Serial.begin(115200); volgend_moment=millis(); } void loop() { controleerToestand(); controleerKnop(); // verstoor eventueel de reeks toestanden } void controleerToestand() { // controleer of de sequentie moet worden onderbroken if(interupted) { // is de huidige toestand te verstoren? Zo niet dan gaat de huidige toestand // gewoon door Serial.println("Inbreken gewenst"); if(toestand_reeks[(volgende_toestand-1)%TOESTANDEN].te_storen) { // wel te verstoren // zet de vlag voor verstoring weer uit. Serial.println("Ingebroken"); interupted=false; // vervroeg het moment naar de volgende toestand volgend_moment=millis(); } } // controleer of er iets moet gaan gebeuren if( millis() >= volgend_moment) { doeActie(toestand_reeks[volgende_toestand].actie); volgend_moment += toestand_reeks[volgende_toestand].duur; volgende_toestand+=1; volgende_toestand%=TOESTANDEN; } } void controleerKnop() { int status=digitalRead(KNOP); if(status != knopstatus) { knopstatus = status; interupted |= true; Serial.print("Status:"); Serial.println(status?"aan":"uit"); } } void doeActie(int actie) { Serial.print("Actie: "); Serial.println(actie); switch(actie) { case 1: lichten(UIT,UIT,AAN,AAN,UIT,UIT); break; // groen rood case 2: lichten(UIT,AAN,UIT,AAN,UIT,UIT); break; // geel rood default: case 3: lichten(AAN,UIT,UIT,AAN,UIT,UIT); break; // rood rood case 4: lichten(AAN,UIT,UIT,UIT,UIT,AAN); break; // rood groen case 5: lichten(AAN,UIT,UIT,UIT,AAN,UIT); break; // rood geel } } void lichten(bool hr,bool hg, bool hgr, bool zr, bool zg, bool zgr) { digitalWrite(HoofdwegRood, hr); digitalWrite(HoofdwegGeel, hg); digitalWrite(HoofdwegGroen, hgr); digitalWrite(ZijwegRood, zr); digitalWrite(ZijwegGeel, zg); digitalWrite(ZijwegGroen, zgr); } |
Opdracht |
|