interrupt alternatives?

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);
    }
 }

Interrupts are not necessarily the answer.
Have you looked at the blink without delay example?
If not, then you should.

You don't say what the problems your having is. But it is probable that its your use of delays. Take a look at blink without delay.

Mark

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.

Hopefully this is a little more clear

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.

You do need to get rid of the delays.

Fairly easy:

  1. you can rewrite delay() to make it interruptable. Like this:
void mydelay(unsigned int dly) {
  while (dly--) {
    delay(1); //delay some time
    if (key_pressed()) break;
  }
}

So for each delay(1) it will test for the key and get out if the key is pressed

2: use an interrupt. You can then test for a flag in the heartbeat() routine to stop it or to reset it.

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.

I don't think that's quite how an interrupt works.

I know that, that's why I wrote "no" after the "explanation".

@OP

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.

Mark

PS You need to look at de bouncing your button.

M

I know that, that's why I wrote "no" after the "explanation".

Such a little word that I missed it completely. Sorry about that.

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);
}

Interrupt was the only way

No.

This will work as well:

volatile int buttonFlag = 0;

void setup(){
//attachInterrupt(0, bISR, RISING);
}

void mydelay(unsigned short dly) {
  while (dly--) {
    buttonFlag = digitalRead(buttonPin);
    delay(1); //or anything sufficiently quick
  }
}

void loop(){
  
  if (buttonFlag ==0){
    heartbeat(); //use mydelay() instead
  }
  else {
      analogWrite(greenPin, 255);                       //button stays green once pushed
      function stuff;
      buttonFlag = 0;
   }
}

Is there an advantage to one over the other dhenry? Now that I've passed the point of making it happen, I'm curious to learn more

Josh

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
   }
}

Is there an advantage to one over the other

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.