From what I've read, the solution to my problem is to use an interrupt, but if I understand them correctly, I cant use a delay in the routine that gets called by the interrupt. I've got a large pushbutton led switch. I want it to have a heartbeat while sitting idle, but once its pushed, stay green and execute code. I can break the heartbeat() if I push the buttons enough times (I assume getting the state change at just the right time as it finishes a loop of the heartbeat), but I'm stuck on how to make it work on the first click. Is there an alternative way to do what I'm attempting?
void loop(){
heartbeat(); //make led beat
buttonVal = digitalRead(buttonPin); //check the button
if (buttonVal != buttonState) { //if the button state changed
if (buttonVal == HIGH){ //check if the button is pressed
analogWrite(greenPin, 255); //button stays green once pushed
functionA //has some delays in it
functionB //has some other delays
}
}
}
void heartbeat(){
for(i = 0; i < pmw; i++) {
analogWrite(greenPin,i);
delay(((60000/rate)*.1)/pmw);
}
for (i = pmw; i > 0; i--){
analogWrite(greenPin,i);
delay(((60000/rate)*.2)/pmw);
}
for(i = 0; i < pmw; i++) {
analogWrite(greenPin,i);
delay(((60000/rate)*.1)/pmw);
}
for (i = pmw; i > 0; i--){
analogWrite(greenPin,i);
delay(((60000/rate)*.6)/pmw);
}
}
Apologies. I guess after rereading my initial post, it was a bit obtuse.
My problem is not with the blinking itself (that parts works quite well) but the fact that the button push doesnt interrupt the heartbeat() and proceed to the rest of the code which is the actual action of the button push. (functionA and B which utilize delays). I assume I need an interrupt to break the heartbeat action?
Although rereading the blink without delay, I may be able to use these to get rid of the delays in function A and B. I'll need to think on that.
An interrupt is just that - a brief distraction.
Imagine you're reading a book, and the doorbell rings.
You go and answer it, then go back to baking your cake.
No.
Imagine you're reading a book, and the doorbell rings.
You go and answer it, then go back to baking your cake.
I don't think that's quite how an interrupt works. It does seem more like what OP wants, though. He/she apparently wants the code with the delay()s (reading a book) to be interrupted, and then some other code (baking a cake) to be performed. But, of course, that's not (directly) possible.
My problem is not with the blinking itself (that parts works quite well) but the fact that the button push doesnt interrupt the heartbeat() and proceed to the rest of the code which is the actual action of the button push. (functionA and B which utilize delays). I assume I need an interrupt to break the heartbeat action?
Yes your problem is with your heartbeat as it uses delay() and therefore your program won't do anything until the delay() is completed. Even an interrupt would not help as you can see the result of the interrupt is complete.
Got it figure out. Interrupt was the only way, but shuffling code and how I watch for the button push eliminates the need to modify any of the other functions to remove delays, including those delays in the hearbeat(). Thought I'd share. Works like a charm.
volatile int buttonFlag = 0;
void setup(){
attachInterrupt(0, bISR, RISING);
}
void loop(){
if (buttonFlag ==0){
heartbeat();
}
else {
analogWrite(greenPin, 255); //button stays green once pushed
function stuff;
buttonFlag = 0;
}
}
void bISR(){
buttonFlag = digitalRead(buttonPin);
}
I'm working on a project where I need to detect button presses. Short and long. Tempted as I was to use interrupts (after all I have a lengthy web page on how to use them) I found it was just as simple to test the button in "loop", and notice when it was pressed. You can check also for it to be released (that is two transitions to look for: high/low and low/high) and work out how long it was held down.
Since no interrupts were involved the issue of being "stuck in an interrupt" doesn't arise.
that is two transitions to look for: high/low and low/high
Actually detecting the transition is a matter of the current state not matching the previous state. Once you've detected a transition, the current state tells you whether the transition was to pressed or to released. So, it's not any extra code. Just a matter of using nested ifs rather than compound ifs:
if(currState != prevState)
{
// A transition occurred
if(currState == LOW)
{
// To pressed, assuming the use of a pullup resistor
}
else
{
// To released
}
}
I prefer interrupts: it makes the code far more modular, more reliable and lessons the cpu load.
The other approach that I provided earlier is essentially polling. It runs on mcus without interrupts, or where you don't want to muddle up the isr more (a mcu without a vectored interrupt for example).
Interrupts are great, as they provide priorities over different tasks.
dhenry:
I prefer interrupts: it makes the code far more modular, more reliable and lessons the cpu load.
Interrupts are fine when you need to do something with very low scheduling latency that is decoupled from the main code. But here, there are no latency requirements and the event is directly coupled to the main code - in effect, you'd be trading polling an input with polling a flag set by the interrupt handler; given that you still have to deal with any timing/debouncing issues, I don't see that the interrupt has given you any benefit at all, and at the same time it introduces a whole new set of potential bugs in any data or code shared between the interrupt and the main code.
My advice is to use interrupts only where necessary. Problems like this can be solved in a very simple and straight forward way without using interrupts.