The long and short of it is I have some code that is running as intended, but I want to implement a toggle start/stop button.
So I don't want any of this code to automatically run in the main loop until toggled. So it's fine if I have to use a delay to debounce the switch in the main loop becaause nothing really happens there. But once the bulk of my code starts being executed if I want to stop all of it and exit back to the main loop I need to do that and debounce without delay. I don't know how to compare an old and new button reading with milis because the looping nature means an old button reading will be assigned a new millis every loop.
If your loop is running free, looping at any respectable frequency, just look at the button every 20 - 50 ms and act on the changes to the state of that button.
If your loop is not running free, I got nothing except to say loop() wants to and should be allowed to run free and you wouldn't have any problem debouncing a switch.
First of all, I'd use hardware debounce so no need to add any code or delay() for debouncing. Said that, if you're still stuck with software debounce, there's nothing special to do, you should just read the button state not less than every 50 mS, either via delay() or checking this interval using millis(). I don't think it's an emergency kill switch to avoid human damages, so I think 100 mS or more is enough.
To completely stop everything (I suppose you're asking this, too) you simply need to quit the loop() if the current machine status is "stopped".
I mean something like this (please check it, I haven't tested it out!):
bool Running = true; // Default state
unsigned long tmrCheck = 0;
const unsigned long CHECK_INTERVAL = 100; // Milliseconds between checks
byte PrevState = HIGH; // Previous Start/Stop button state
...
void loop() {
currentMillis = millis();
if (currentMillis - tmrCheck >= CHECK_INTERVAL) {
// It's time to check the Start/Stop button!
StartStopStatus = digitalRead(StartStopPin);
// Changed? Toggle the "Running" state
if (StartStopStatus != PrevState) Running = !Running;
// Next check
tmrCheck = currentMillis;
PrevState = StartStopStatus;
}
if (!Running) return;
// Main code here
// All current code here, except for StartStopPin
// to run only if "running" state
...
}
Yours doesn't debounce, you set the timer at the wrong place. Sry, still chasing something here.
Yours toggles on every transition, not just the press. Perhaps that was intentional.
unsigned long currentMillis = millis();
if (currentMillis - tmrCheck > CHECK_INTERVAL) { // time to look?
startStopStatus = digitalRead(startStopPin); // read the switch
if (startStopStatus != previousState) { // if it changed
if (previousState == HIGH) // and got pressed, togggle running.
running = !running;
tmrCheck = currentMillis; // always remember the last time you looked at the switch
previousState = startStopStatus;
}
}
I just had a few minutes to toss it into the wokwi, so did. Mostly to see if my reading was correct. Made it before my beach buddy called, très importante, she must not be kept waiting.
The timer, by setting it every time you look at the switch, the code will have a random reaction time based on exactly when you press the button.
If instead the timer is advanced only if a transition was detected and handled, the reaction to a button press becomes nearly instantaneous. That is the beauty of the model pattern I copy when I do switches.
This slugishness can be demonstrated (in any denounce code) by temporarily cranking up the CHECK_INTERVAL or equivalent. You will see that the code reacts "eventually" to a button pressed down, sometime right away, sometimes it takes CHECK_INTERVAL ms.
Because I have no life my ride is delayed (the irony!), I put the two versions into the wokwi.
The nice thing about good coide for the loop() (non-blocking, light on time resources) is that it is easy to let both algorithms look at the swtich and make independent use of having done.
If the weather was better, I could be mad at my friend. Maybe she just doesn't want to go... sit under the umbrella, or more accurately as is the case now, the parapluie.
The LEDs come on at "the same time". But if you play with it, you will def be able to see the instant LED come on sooner than the random LED. When it is closer to the 50 ms that it can sometimes take.