Program Latching Button Sequences and More with State Machines

By Jeremy S. Cook

Freelance Tech Journalist / Technical Writer, Engineering Consultant

Jeremy Cook Consulting

October 22, 2024

Blog

Caption: Finite state machine programming was used for the auto-beat sequence on this MIDI controller/ Image Credit: Jeremy Cook

Consider the humble normally open momentary pushbutton. Push it in, an electrical connection is made, and whatever you want to happen via that input nominally happens. What if, however, you want to use the button to advance through a series of actions? This could be as as simple as a push-on, push-off sequence, or going from state 0, to state 1, to state XYZ, and back again.

I admittedly struggled with how to do this in a recent project, and eventually found* an excellent solution in the form of the finite-state machine, or simply, state machine programming. This concept breaks programming/machine functions into discreet states that become active one state at a time by meeting certain conditions, e.g. a pressed or released button. The program can only transition from one state to another via pre-designated paths.

State machine programming allowed me to break the concept of pushing/releasing a button down to a point where I could easily perform the latching operation that I needed, without a physically latching button.

Button Push-on/Push-off State Machine

Image Credit: Jeremy Cook

In my code, the buttonState variable defines the state of the button “machine,” starting from buttonState = 0. When depressed, auxRightButton (defined as an INPUT_PULLUT) is pulled LOW to ground, advancing buttonState to state 1, while turning the beatOn variable to 1. The buttonState variable represents the state that the machine is in, and code inside the corresponding if (buttonState == x){} brackets is executed. States 2 and 3 follow a similar path, reverting back to 0 when the last condition (button released for a second time) is met.

Image Credit: Screencap

The state machine is a rather ingenious concept for breaking something down that seems simple to humans–e.g. push button to latch, push again to unlatch–and describing it programmatically. Note that while the way I set up the program (as of this writing) works well enough for my application, it would likely be better to use millis() instead of delay() to avoid blocking code. One might also consider implementing a class object for this sort of operation, especially if you need extra functionality like long-press detection.

More State Machine Fun

State machines are great for button sequences, but they can do much, much more. Transitions between states can be triggered by any number of conditions (buttons, sensors, timers, other code, etc.) and don’t necessarily have to advance in numerical order. States may nominally advance from 0 to 1, 2, 3,4, etc, and back to 0, but perhaps there is a condition in state 3 (for example) where it needs to transition directly back to 1. This is entirely possible. You can also use multiple state machines in your overall code, greatly expanding your programming possibilities.

Lots more info on the state machine concept is found in this Wikipedia article, and for more inspiration, James Bruton outlines the concept in his R6 Droid video starting at around the 7:30 mark. Bruton also uses it to cook breakfast in this video, and who knows where else he uses it, potentially making him YouTube’s preeminent state machine promoter.

Whether you’re simply toggling a process on and off via button presses, or performing more advanced computations, the state machine concept is an excellent tool to have ready to go in your programming arsenal. For more Arduino programming ideas, check out my Developing With Arduino online training series!

*or perhaps re-invented

Jeremy Cook is a freelance tech journalist and engineering consultant with over 10 years of factory automation experience. An avid maker and experimenter, you can follow him on Twitter, or see his electromechanical exploits on the Jeremy S. Cook YouTube Channel!

More from Jeremy

Categories
Open Source