MarkC:
I'm basing this idea on something I read, which appears to have been recommended by various users.
Indeed. There is the typical "internet" problem - lots of "helpful" articles, written by enthusiastic hobbyists who have cleverly discovered how to do a particular thing. And many of them are extremely helpful, but some are not, and that is why I tend to be strident about such things, to get people to sit up and think. I hope.
MarkC:
I'm honestly confused here - the author makes it sound as if it's a great idea to use interrupts to sense button presses.
Well, to be fair, he uses it as an example. He refers to "a project that relies on very precise timing or needs to react quickly to an input", and therein is the confusion. A pushbutton is - as i mentioned - simply not something that requires a quick response in microcontroller terms of microseconds. Some things however are, for example a hard disk spinning 120 times a second with hundreds of sectors of information on each track, or a serial interface receiving 153,600 bits per second.
MarkC:
He states "Let’s implement this using a simple example: detecting when a pushbutton has been pressed, and performing an action based on that press."
Actually, a very poor example however, and herein is the problem. Strictly, he is correct - "performing an action based on that press" - given that that action is complete within the interrupt (as he also specifies). For example (and again, a very bad example because of the more pragmatic consideration of debouncing), switching on a LED on a single port pin.
MarkC:
To me, this sounded ideal: the LCD screen would continue to post messages until someone pressed a button, and then the program would move to the rotation, etc.
But you have mis-read him, and that was my point. As he says: "Once triggered, an interrupt pauses the current activity and causes the program to execute a different function. This function is called an interrupt handler or an interrupt service routine (ISR). Once the function is completed, the program returns to what it was doing before the interrupt was triggered."
So that is clearly not what you want at all. (But I can see the confusion - you may think that after you have performed your pushbutton work, you do want to go back to the LCD animation, but this is not something you do inside the interrupt where no other functions including timing, are possible!)
MarkC:
I just don't get it. Why is he wrong?
He isn't entirely wrong, except in suggesting that interrupts are appropriate for pushbuttons.
It's just that in the excitement of describing how to implement interrupts, he fails to properly describe where and why they are actually needed.
MarkC:
I wasn't clear. This device will be placed in a lobby, where I don't know exactly when the next user arrives. So I want the LCD "advertising" to run until someone presses the button. They shouldn't have to push it more than once, or wait to push it.
There is no problem. You write the code to interleave between checking the pushbutton and performing successive steps in the LCD "animation". This is what the " loop" is for, not for repeating the overall sequence of the animation. Here is some (untested) code I posted to an earlier question:
const int buttonPin = 7;
const int ledPin = 11;
const int ledPin2 = 10;
const int ledPin3 = 9;
int ledState = HIGH;
int buttonState;
int lastButtonState = HIGH;
long lastDebounceTime = 0;
long debounceDelay = 10;
void setup() {
pinMode(buttonPin, INPUT);
digitalWrite(buttonPin, HIGH); // sets pull-up
pinMode(ledPin, OUTPUT);
pinMode(ledPin2, OUTPUT);
pinMode(ledPin3, OUTPUT);
}
void loop() {
int reading = digitalRead(buttonPin);
if (reading != lastButtonState) {
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
if (reading != buttonState) {
buttonState = reading;
if (buttonState == LOW) {
ledState = !ledState;
}
}
}
if (ledState) {
analogWrite(ledPin, random(120)+135);
analogWrite(ledPin2, random(120)+135);
analogWrite(ledPin3, random(120)+135);
delay(random(100));
}
else {
analogWrite(ledPin, 0);
analogWrite(ledPin2, 0);
analogWrite(ledPin3, 0);
}
lastButtonState = reading;
}
It flickers some LEDs when - and while the button is pressed.
And another example:
// seed counter
/* This program should count seeds as they drop
and track how many have been planted */
const byte seedPin_1 = 2; // sensor pin - active LOW
const byte ledPin = 13; // LED indicator
unsigned long seedCount; // actual seed count
byte seedState_1; // sensor status
byte lastseedState_1; // previous sensor status
byte bounce_1; // debounce counter
long lasttime; // clock
void setup()
{
pinMode(seedPin_1, INPUT); // seedState as an input
digitalWrite(seedPin_1, HIGH); // pullup enabled (reliable way!)
pinMode(ledPin, OUTPUT); // LED as an output
digitalWrite(ledPin, LOW);
Serial.begin(9600); // serial communication
seedCount = 0;
seedState_1 = HIGH;
lastseedState_1 = HIGH;
bounce_1=10; // Bounce time >= 10 ms
Serial.println("on");
}
void loop() {
if (millis() > lasttime) { // next clock tick
lasttime = millis();
if (digitalRead(seedPin_1) == seedState_1)
{ // if the state is same
bounce_1 = 10; // nothing to bounce
}
else if (--bounce_1 == 0) { // if we hit zero, we act:
seedState_1 = digitalRead(seedPin_1); // update the saved
bounce_1=10; // Bounce time reset
if (seedState_1 == LOW) { // If input now active
seedCount++; // increment the counter
Serial.print("seeds planted: ");
Serial.println(seedCount);
}
}
if (seedState_1 % 100 == 0)
{
digitalWrite(ledPin, HIGH);
}
else
{
digitalWrite(ledPin, LOW);
}
}
}
based on my generic description of debouncing.