How to step back to loop() during an interrupt

Hi, I am trying to make a mood lamp with an attiny 45. I want the led to flash, then when I press a button, the intensity goes up and down as in a sine wave, then when the button is pressed again, it goes back to flashing.
This is my code:

int a=1;
void sinex(){
  for (float x=0;x<PI;x=x+0.00001){
    a=255*abs(sin(x*(180/PI)));
    analogWrite(0, a);
    // delay(30);
  }
}
void flash(){
  digitalWrite(0, HIGH);
  delay(1000);
  digitalWrite(0, LOW);
  delay(1000);
}
void inter(){
  if(digitalRead(2)==HIGH){
    while(digitalRead(2)==HIGH){
      sinex();
    }
  }
}
void setup(){

  pinMode(0,OUTPUT);
  pinMode(2, INPUT);
  digitalWrite(2, HIGH);
  attachInterrupt(0, inter, LOW);
}
void loop(){
  flash();
}

After I press the button, the led goes from flashing to sine-wave brightness. But when I press it again, nothing happens. Can anybody please tell me how to make it go back to loop()? Thanks a lot!

I wouldn't have the ISR call sinex(). Have the ISR just toggle a boolean variable, and use that variable in loop() to call either sinex() or flash(). Also rewrite flash() to work without delay().

Actually my first thought would not be to use interrupts.

Interrupts are for urgent action, arguably a human pushing a button
is never urgent (we are talking sub-millisecond really for urgent).

I see. I thought it would be easier to write the program with the interrupts. Should I stop using interrupts?

arduinohabib:
I see. I thought it would be easier to write the program with the interrupts. Should I stop using interrupts?

It can be done with or without. Should be an educational experience either way. Maybe try it both ways, with and without interrupts then decide which is easier or preferable :smiley:

You may already be aware, but the other thing to consider, regardless of how the code is written, is that switches bounce. The code will need to allow for this.

Finally, a low-level interrupt will trigger continuously as long as the pin is held low, so also consider that the typical human pushing a button is likely to generate hundreds or thousands of interrupts. I might try an edge-triggered interrupt.

Thanks.
I changed the code, without the interrupts. When I press the button, it goes from flash() to sinex(), but when I press the button again, it doesn't jump back to flash() Why is this?

boolean mode=false;
long previousMillis=0;
int state=LOW;
int a=0;
void sinex(){
  for (float x=0;x<PI;x=x+0.00001){
    a=255*abs(sin(x*(180/PI)));
    analogWrite(0, a);
  }
}
void flash(){
  unsigned long currentMillis=millis();
  if(currentMillis-previousMillis>1000){
    previousMillis=currentMillis;
    if(state==LOW){
      state=HIGH;
    }
    else{
      state=LOW;
    }
    digitalWrite(0, state);
  }
}
void setup(){
  pinMode(0,OUTPUT);
  pinMode(2, INPUT);
  digitalWrite(2, HIGH);

}
void loop(){
  if(digitalRead(2)==LOW){
    delay(20);  //debounce
    if(digitalRead(2)==HIGH){
      mode=~mode;
    }
  }
  if(mode==false){
    flash();
  }
  else{
    sinex();
  }
}

arduinohabib:
Thanks.
I changed the code, without the interrupts. When I press the button, it goes from flash() to sinex(), but when I press the button again, it doesn't jump back to flash() Why is this?

How long do you think the sinex() function takes to execute once? While it's running, the code in loop() can't monitor the button. On the other hand, the flash() function is very fast. It quickly determines if it needs to do something or not, then returns.

Some similar approach is needed for sinex().

Thank you so much, Jack
I changed sinex() to this

void sinex(){
  x+=0.00001;
  a=255*abs(sin(x*(180/PI)));
  analogWrite(0, a);
  if(x>= PI){
    x=0;
  }
}

and it's working perfectly! I'll change the flash() into something that sets the intensity according to an analogue input from a pot.
Thanks again!

and it's working perfectly!

No, it isn't.

    a=255*abs(sin(x*(180/PI)));

sin() takes a value in radians, not in degrees.

arduinohabib:
Thank you so much, Jack

You're welcome, and nice job! I would have a look at radians vs. degrees as Paul pointed out.

I might also do some additional thinking about sinex(). It's incrementing in very tiny steps (0.00001) but then the end result gets mapped to a number 0-255. So most of the time the value it uses for analogWrite() is not going to change from one call to the next -- it's burning a lot of cycles that could be used elsewhere. If it works to your satisfaction and there are no additional processing requirements, then there's no harm in leaving it as is, but I'm just saying that it could take larger steps and still make smooth enough transitions. I might look at making it time-based like flash(), i.e. only do the calculation every 100ms or whatever makes for smooth fading. As it is, the speed at which the fade happens is dependent on how many cycles don't get used elsewhere.