For this project, I'm using two internal pull-up resistor buttons on the Arduino Uno.
Both work in conjunction with an interrupt in order to trigger a specific function outside of the loop().
For some reason, when exiting one of those functions, programmingMode() or cleaningMode(), the program seems to
trigger that function again if I hold down the button for too long. If I press and release either button quickly,
the program functions normally.
I have two theories, although my attempts to solve either one have not solved the problem:
When either button is pressed within programmingMode() or cleaningMode(), the interrupt is called a second time.
The interrupts, although set to falling, somehow pickup the RISING action of the button as well??
Here's my code:
int programmingPin = 2;
int cleaningPin = 3;
int interruptProgramming = 0;
int interruptCleaning = 1;
volatile int programmingStatus = 0;
volatile int cleaningStatus = 0;
void setup()
{
attachInterrupt(interruptProgramming, isProgrammingMode, FALLING);
attachInterrupt(interruptCleaning, isCleaningMode, FALLING);
digitalWrite(programmingPin, HIGH);
digitalWrite(cleaningPin, HIGH);
}
void loop()
{
if (programmingStatus == 1)
{
programmingMode();
programmingStatus = 0;
}
if (cleaningStatus == 1)
{
cleaningMode();
cleaningStatus = 0;
}
}
void isProgrammingMode()
{
programmingStatus = 1;
}
void isCleaningMode()
{
cleaningStatus = 1;
}
void programmingMode()
{
for ( ; ; )
{
if (digitalRead(programmingPin) == LOW)
{
break;
}
}
}
void cleaningMode()
{
for ( ; ; )
{
if (digitalRead(cleaningPin) == LOW)
{
break;
}
}
}
Moderator edit: </mark> <mark>[code]</mark> <mark>
Have you debounced the buttons? A normal button may close-open-close-open-close, real fast when you press it. Normally in programs you may only see the first close and the program is too slow (there is a delay() some where ] ) to check the state and catch it in bouncing. Interrupts usually do catch all states. Depending on the button construction your button may not bounce as much when pushed as opposed to released.
Debouncing can be done in hardware (a simple small capacitor and resistor) or in software (ignore a button push if it is within 2 ms of the previous one).
Haven't studied your program in detail, but it seems a likely fault condition for what you describe.
While servicing and interrupt all other interrupts are disabled. If the routine takes to long this will cause problems. Some of the things which may have trouble due over long interrupt routines include serial, the servo lib, pwm.
Serial and delay can not be used in interrupt routines.
In general interrupt routines should be kept as short as possible. You cannot run other parts of a program in an interrupt routine instead you should set a flag in the interrupt routine and then check the state of the flag in loop().
Any var modified by an interrupt routine must be declared as volatile.
Adding a delay as such seems to correct the problem:
if (cleaningStatus == 1)
{
cleaningMode();
cleaningStatus = 0;
delay(500);
}
This raises another question however:
Does bouncing only occur when the button is pressed down? If bouncing were to occur when the button was released, I would still expect inconsistent behavior.
Does bouncing only occur when the button is pressed down? If bouncing were to occur when the button was released, I would still expect inconsistent behavior.
It can occur on either press or release. Only the crappiest switches bounce for 500 milliseconds. If you really need that large a value, a new switch is needed. Not that 5 cent model off ebay, either.
I usually use 5 ms for software debounce. Note that with the debounce written properly you get instant action on the push, it does not delay the program from doing other stuff.
SkiBum326:
Does bouncing only occur when the button is pressed down? If bouncing were to occur when the button was released, I would still expect inconsistent behavior.
Assume it always happens - any vibration in the metal contacts of the switch down to a scale of a few atoms across will cause
bounce.
Thanks again everyone for the great replies..I really appreciate the help.
Msquare, that article was really helpful.
I just have one final question:
As an example, when I press the programming button to cancel out of the programmingMode() function, I believe an interrupt flag is raised, such that when the program reenters the main loop, the interrupt is again triggered and the program again enters programmingMode(). I tried reseting the interrupt flags for interrupts 0 and 1 in the register as so: EIFR |= 0x03, unfortunately this doesn't seem to be working. Is there anything obviously wrong with what I am attempting here?
I dont follow your line of thought there, sorry. Post some more code.
If you want to write a bit of code where the two buttons are more or less a "start" and "stop" function, then you can do so with a handful lines of code in the loop(), and avoid all his interrupt stuff. It is not needed. Cetainly not for buttons activated by an oh-so-slow human. Interrupts make sense for a optogate that is triggered by the teeth of a rapid turning gear. On the other hand if you want to play with interrupts for the sake of doing so, then ... well, have fun