One commonly suggested solution to the responsiveness problem is to check your switches inside your loops and quit the loop if a switch is pressed. The switch check can be neatly combined with the delay. And the loop can be re-written to exit early.
This does make your program more resonsive, but there are a couple of fundamental problems with this approach:
- You are still using delay(), so you still can't do two (or more) patterns at once.
- And what if you don’t really want to quit? We want a way to remain responsive - without necessarily disturbing the execution of the pattern.
We learned how to use Interrupts in Part 2 of this series. But they are not the total answer to the these problems either.
With interrupts, you can eliminate the need to poll the switches. That makes the code a little neater, but it doesn't really address the rest of the problems listed above
It is possible to solve all these problems. But we will need to both ditch the delay and lose the loop. The good news is, the resulting code is surprisingly simple.
The Neopixel loop & delay problem is very similar to the servo sweep example we re-engineered in Part 1. We can apply the same state machine approach to Neopixel patterns.
The basic idea is to encapsulate the patterns in a C++ class. Capture all the state variables as member variables and move the core of the loop logic into an Update() function that uses millis() to manage the timing.
The Update function can be called from your loop() or a timer interrupt and you can update many patterns simultaneously on each pass, while monitoring user interactions at the same time.