scrumfled:
I've been dabbling with frankensteins creation for a while now and Im about to get rid of the bodged menu it has and move to something a bit more extensive. There seem to be a bewildering array of option for menu libraries out there, but i wonder which is generally seen as the current best option, in as much as its easy to use, doesnt chew up resources (memory) and is adaptable.
Currently I navigate with a single button tied to three events (click, double click and long click) for navigate, select and confirm. I activate the menu system by watching button activity, outside of those times the system is either active or asleep.
Over to you guys! 
To use a single button, you need to detect something. The only things you can detect are:
- Is the button pressed?
- Was the button pressed before?
- How long is the button pressed?
Depending on the PREVIOUS button press, the next one does something else.
The simplest example is a toggle. If "something" is ON, the next press turns it OFF. If it was OFF, the next press turns it ON.
You can also use time. For example, short button presses can mean "select next" while a long press means "enter or accept".
Double clicks are tricky for the user to get right. As you know, the double click timeout for a PC is user settable because different people "double click" at different speeds. Stay away from double click detection if you can.
You could have a hypothetical menu that monitors a motor. You want to select any ONE of several readings:
- RPM
- VOLTS
- AMPS
- TEMPERATURE
- CANCEL
So, a LONG button press would mean "Bring up the menu"
Once the menu is up (showing the 4 options), a short press cycles through them 1..2..3..4,5...1 (rolls around from the end back to the beginning).
Let's say you wanted to monitor "Amps". You would press and hold the button until the menu popped up, At this point, "RPM" would be highlighted (bold font, reverse colors, depending on your display).
Then, one short press selects "Volts". Next press selects "Amps". This is the one you want, so now you press AND HOLD the button. After the "long" time passes, the display reverts to "run mode" and displays AMPS.
Of course, you always need a "Cancel" option in the menu in case you got into it by mistake and don't want to change anything.
The idea is that you detect a button press and grab the current millis() value, then wait until the button is released.
The elapsed time is "millis() - start". If the elapsed time is, say, less than 1000 (1 second), it's considered a "short" press". If it's longer than 1000, then it's a "long" press and your code acts accordingly.
Note that you also need to debounce the button. A mechanical button, when pressed, "bounces" and goes open-closed-open-closed several tens of times in the course of a millisecond or so (and the microcontroller can detect each one!)
Therefore your code has to work like this:
uint8_t check_button (uint8_t port)
{
pinMode (port, INPUT_PULLUP);
if (digitalRead (port) == HIGH) {
return 0;
}
uint16_t timeout = 1000; // change this if necessary
while (timeout--) {
if (digitalRead (port) == HIGH) {
timeout = 1000; // button bounced, reset countdown
}
}
return 1; // we got 1000 successive contacts, therefore button is no longer bouncing
}
The above code simply gets you a clean button detection. Then you have to time how long it remained pressed.
You put in your pin number connected to the button, then read a "0" if it's not pressed or a "1" if it is.
Hopefully this is enough to get you started. Good luck!