Aborting a loop sequence mid-run with the same input

I have a single input pulse that comes into pin A0 via a button press. When it's activated (analogRead >= 521), it triggers a 5 second sequence where:

A tone is played, there is a short delay, and then lights begin to flash in four steps (high lux, low lux, high lux, low lux).

If the button is pressed again while the lights are flashing, I want the loop to abort immediately and not to continue with the flashing light sequence.

Is this possible? If it is, what is the best way to code this? I've tried multiple approaches and they don't seem to work & I'm probably too novice to understand why.

Any help would be greatly appreciated. :slight_smile:

Welcome to the forum

Please post your current sketch, using code tags when you do

In my experience the easiest way to tidy up the code and add the code tags is as follows
Start by tidying up your code by using Tools/Auto Format in the IDE to make it easier to read. Then use Edit/Copy for Forum and paste what was copied in a new reply. Code tags will have been added to the code to make it easy to read in the forum thus making it easier to provide help.

Thanks for the welcome to the forum, UK HeliBob.

My basic code is:

// DEFINE OUTPUT PINS

#define Speaker 12
#define LED 11

// VARIABLES

int tonePause = 500;
int toneFreq = 2500;
int toneDuration = 500;

int brightness_A = 200;
int brightness_B = 50;
int flashDuration = 1000;
int lightOff = 0;

void setup () {
pinMode(Speaker, OUTPUT);
pinMode(LED, OUTPUT);
pinMode(A0, INPUT);
}

// MAIN LOOP

void loop() {
int trigger = analogRead(A0);

if (trigger >= 521)
{
// Play tone
tone(Speaker, toneFreq);
delay(toneDuration);
noTone(Speaker);

// Pause after tone
delay(tonePause);

// Flash high lux
analogWrite(LED, brightness_A);
delay(flashDuration);

// Flash low lux
analogWrite(LED, brightness_B);
delay(flashDuration);

// Flash high lux
analogWrite(LED, brightness_A);
delay(flashDuration);

// Flash low lux
analogWrite(LED, brightness_B);
delay(flashDuration);

// Turn off light
analogWrite(LED, lightOff);
}
}

My question is whether pressing the button input (to A0) again during the light flashing part of the void loop (first "// Flash high lux" comment onwards) can immediately abort the loop.

Thank you for your initial reply! :slight_smile:

Yes somethjng like that can be done...
You cannot leave loop.
So in loop you need to make a while(True) loop. You can leave that while loop with
if (someTrigger) break;

But: you will first need to rewrite your code to non-blocking code. Otherwise your program cannot redpond to your button press.
There are several good tutorials on this matter available in this forum.

Do you mean loop can't be left because the way that the loop code has been written, or do you mean that using 'return' in loop() can't be done?
I don't see a problem with the latter.

If you use return in the loop function, you will leave the loop function...
It may end your program or it may lead to undefined behaviour. Message is simple: do not leave loop...
If you want to stop your program add:
while (True) ;

It will do neither. It will return to the main() function which will then call the loop() function again

Of course, this may not be what you want to do ...

Thanks so much for your comment, build_1971. I managed to successfully code what I wanted to achieve by applying your suggestions.

I simplified the loop for testing, so that it now does:

1s low freq tone -> 1s delay -> 1s high freq tone -> 1s low freq tone -> 1s high freq tone -> 1s low freq tone

I also added a step to confirm that it's been 2 seconds since the last activation of A0 before the initial loop is able to be triggered again. I'll provide the successful code below in case anyone else has a similar issue.

// DEFINE OUTPUT PINS
#define Speaker 12

// VARIABLES
int tonePause = 1000;
int toneFreq1 = 2500;
int toneFreq2 = 6000;
int toneDuration = 1000;
unsigned long startTime;
unsigned long lastActivationTime = 0;
bool tonePlaying = false;
int step = 0;

void setup() {
  pinMode(Speaker, OUTPUT);
  pinMode(A0, INPUT);
  startTime = millis();
}

void loop() {
  int trigger = analogRead(A0);
  unsigned long currentTime = millis();

  if (trigger >= 521 && !tonePlaying && (currentTime - lastActivationTime >= 2000)) {
    tonePlaying = true;
    startTime = currentTime;
    step = 0;
  }

  if (tonePlaying) {
    if (currentTime - startTime >= 6000) {
      tonePlaying = false;
      noTone(Speaker);
      lastActivationTime = currentTime;
    } else if (trigger >= 521 && currentTime - startTime >= 1000) {
      tonePlaying = false;
      noTone(Speaker);
      lastActivationTime = currentTime;
    } else {
      switch (step) {
        case 0:
          tone(Speaker, toneFreq1);
          if (currentTime - startTime >= toneDuration) {
            noTone(Speaker);
            startTime = currentTime;
            step++;
          }
          break;
        case 1:
          if (currentTime - startTime >= tonePause) {
            tone(Speaker, toneFreq2);
            startTime = currentTime;
            step++;
          }
          break;
        case 2:
          if (currentTime - startTime >= toneDuration) {
            noTone(Speaker);
            tone(Speaker, toneFreq1);
            startTime = currentTime;
            step++;
          }
          break;
        case 3:
          if (currentTime - startTime >= toneDuration) {
            noTone(Speaker);
            tone(Speaker, toneFreq2);
            startTime = currentTime;
            step++;
          }
          break;
        case 4:
          if (currentTime - startTime >= toneDuration) {
            noTone(Speaker);
            tone(Speaker, toneFreq1);
            startTime = currentTime;
            step++;
          }
          break;
        case 5:
          if (currentTime - startTime >= toneDuration) {
            noTone(Speaker);
            tonePlaying = false;
            lastActivationTime = currentTime;
          }
          break;
      }
    }
  }
}

Well done!

To be honest I thought that this would cost a few more posts!

2 Likes

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.