Hoe maak ik een timer in de Arduino
Als functies vaker uitgevoerd moeten worden zal dit in de Loop procedure geregeld moeten worden. In tegenstelling tot de Setup procedure die slechts één keer bij opstart aangeroepen wordt zal de Loop procedure door de Arduino kernel zo vaak als mogelijk is worden. Hoe vaak dat is hangt o.a. af van de snelheid van de processor en wat er intern nog te doen is. In orde van grootte zal toch wel ca. elke milliseconde Loop worden aangeroepen. Alle code in Loop wordt achter elkaar uitgevoerd (single threat). Dit betekent dat er niets tussen door kan gebeuren, behalve als er interrupt procedures actief zijn. Een interrupt procedure kan gekoppeld worden aan een gebeurtenis van buiten zoals het veranderen van één van de ingangen. Dit pas ik hier niet toe omdat synchronisatie met de rest van de code het wat lastiger maakt. Een ander manier is vaak kijken of een ingang veranderd is (pollen). Bij de software voor het inlezen van de DCC commando's wordt wel van interrupts gebruik gemaakt omdat anders het meten van de pulsbreedte van het signaal (micro seconden) niet mogelijk is.
De vraag is hoe dan wel een timer te makken. Voor een simpele test wordt vaak de functie Delay(x ) gebruikt. In dat geval wacht de software x ms. Dus Delay(1000) is 1 seconde. Het vervelende is dat er dan ook niets anders gebeurt, de processor wacht gewoon totdat de tijd verstreken is. Je kan dan bv. niet tegelijk een LED laten knipperen, etc.
De oplossing is simpel, maak gebruik van de millis() functie. Intern houdt de processor een milliseconde timer bij. De millis() functie leest deze timer uit. Door dit regelmatig in de Loop procedure te doen en te kijken hoeveel ms er verstreken zijn kan je allerlei timer functies realiseren. Dit is de manier die ik altijd gebruik. Hieronder een voorbeeld uit de software voor de keerlusmodule.
void loop()
{
CurrentMillis = millis(); // neem eerst een sample van de millis timer
if ((CurrentMillis - BasicTimer) > BasicTimerValue)
{
BasicTimer = CurrentMillis; // Restart timer
HandleBasicTimer();
HandleOnStateTimers();
}
if ((CurrentMillis - ActionTimer) > ActionTimerValue)
{
ActionTimer = CurrentMillis; // Restart timer
HandleActionTimer();
}
if ((CurrentMillis - KnipperTimer) > KnipperTimerValue)
{
KnipperTimer = CurrentMillis; // Restart timer
HandleKnipperTimer();
}
}