What design patterns can I use to handle user input and display updating?
The answer depends on exactly how the sketch is meant to respond to the user interaction.
External interrupts
If the interaction depends on responding very accurately to the rising or falling edge of an input event (as in your example), then an external interrupt may be the way to go, if possible.
This is particularly important if the input event might be shorter that the duration of a call to loop()
. If that happens, consecutive attempts to poll the input could completely miss the state change. It's quite rare for a user input event to be that short though, unless loop()
is quite slow to execute.
External hardware to get help that though, e.g. by having an input which latches until it is read and reset by the microcontroller.
Improving polling frequency
External interrupts often aren't possible (e.g. because the chip only supports a limited number), or they are simply overkill/unnecessary for a given application.
In those cases, it may still be possible to improve the timing precision when using polling. One option is to split up all the different parts of the main loop into separate functions. On each successive iteration of loop()
, it will call the next function, and then wrap round to the first. In between each of those functions, it can poll the button. Here's a simple example:
unsigned int g_section = 0;
void setup() { }
void pollButton()
{
//...
}
void runSection0()
{
//...
}
void runSection1()
{
//...
}
void runSection2()
{
//...
}
void loop()
{
// Poll the button on every pass:
pollButton();
// Execute the next section of the main code:
switch (g_section)
{
case 0: runSection0(); break;
case 1: runSection1(); break;
case 2: runSection2(); break;
}
// On the next iteration, run the next section:
if (++g_section > 2) g_section = 0;
}
One important issue with this approach is that it's very difficult to make each of those runSectionX()
functions take the same execution time. That can result in the button being polled inconsistently from one iteration to the next. If it's fast enough though, then it shouldn't be too big of a problem.
Display update
Updating a display is unfortunately often quite slow, compared to many other operations. That means you need to be quite careful where you do it. Inside an Interrupt Service Routine often wouldn't be appropriate, as that could introduce other timing issues in your sketch.
Realistically, you'd have to do it in the main loop. If you absolutely have to run it quickly though, then it can be included in the faster polling example I've given above -- i.e. update the display on every iteration, the same as polling. You have to be careful to avoid partial updates though.
For program control, I made something of a menu handling framework for one of my projects and shared the source on Github. Note that this is for chipKIT but the menu handling code is generic. After building my 3rd or 4th huge if-else-if and switch structure, I decided there had to be a better way. Credit for the source of the static menu structures.
I just use the main loop to check the button.
I'm wanting to say the first step is to get a TFT. If you try it, you'll never go back... I particularly love the Adafruit 1.8" TFT with joystick. Arduinos are slow enough that I cannot recall caring to debounce user input.