Delays are bad
Probably the first Arduino sketch you’ve seen is the ‘blink’ sketch. It’s a nice and short piece of code to explain the basic workings of Arduino without scaring you with loads of new things to learn. Unfortunately in terms of everything else, especially user interaction, it’s absolutely terrible. The culprits are these two lines:
If you’ve played some amount of video games in your lifetime, you probably know what FPS (frames per second) are and what influence they have on user interaction. They indicate how many times a second your button presses are checked and the action on screen is updated. So, what’s a desirable number of FPS?
- 60 FPS and above: Perfectly fluent interaction. Very fun.
- 30 FPS: Still very fun, but noticeable differences to 60FPS.
- 20 FPS: Playable, but no fun at all.
- Under 20 FPS: Agony.
While the responsiveness of games is measured in FPS, the responsiveness of Arduino Code should be measured in LPS, aka how many times the loop section of your code is completed in one second. So, how many LPS does the blink sketch have?
- 0.5 LPS. That’s bad.
If we want to fit at least 60 loops into one second, the entire delay time in the sketch should not exceed 16ms. Delay() is not a great tool for timing, so we need something different.
The blink sketch has no user interaction at all, so it’s not really an exciting example for this tutorial. Instead, we are going to code the most useless lamp ever created: One that turns itself off exactly one second after it was turned on. You’ll need a button, a led and any Arduino board.
Pretty much all we are going to do revolves around one new Arduino function: millis(). So what does it do?Inside every Arduino, there’s a little counter that simply counts the milliseconds since the Arduino has been turned on. With millis() we can retrieve the current amount of milliseconds and save them in a variable.
A word on ‘unsigned long’: Maybe you’re wondering, why we don’t use the traditional ‘int’ to initialize our variable. An int cannot contain an infinitely large number, it only covers an area from around -32000 to +32000. Since were measuring time in milliseconds and time only marches forward, we can only fit 32 seconds into one int. ‘Unsigned long’ on the other hand goes from 0 to around 4.3 billion or nearly 50 days in milliseconds. So we’re a lot more flexible in terms of timing.
Let’s go back to our useless lamp and look at it on the timeline. At some point in time the button will be pressed and the light will turn on. We’ll call this the ‘Trigger-Event’. Then, exactly 1000ms later, the lamp will be turned off again. We’ll call this the ‘Response Event’.
The Trigger Event
Let’s focus on the trigger event first. If the button is pressed, we should do two things:
1. Turn the led on
2. Save the time the event occurred in another variable.
In code, it looks like this:
The response event
The response event itself is pretty simple: Just turn the led off. But we need to define very specifically when this event should occur. We want the Response to happen exactly one second after the Trigger. We only have the current time and the last time a Trigger-Event happened to work with. So this is what we do:
1. We need to know how much time has passed since the last Trigger, so we subtract our Trigger-Time from our Current Time.
2. We need to know if enough time has passed for the Response to happen, so we check if the time passed is bigger than 1000ms
In Code, it looks like this:
And that’s it. Exactly one second after each Trigger Event, the Response Event happens. Our useless lamp is complete and we’ve learned the fundamental technique to get rid of delays in your code.
1. There are always two events, we need to code.
2. In the Trigger event we need to save the time it happened.
3. For the Response Event we compare the current time minus the saved time to our delay time.