How to get out a void function?

Hello everyone,

My existing project is some kind of midi sequence player. When you press a button, arduino executes a function. This function (let's call it void play) is a series of commands that send a signal. It is coded on purpose in a way to use delays for keeping a rythm.
Now, when I want to stop playing before it ends, typically I press the reset button. In this way it stops playing, but the board starts all over again. In my final code I don't want this for many reasons. Another way to do this is using an interrupt. When the interrupt pin triggers, I can use a software reset, but it is the same as pressing reset.
Is there any way to stop playing (exit from the function) at anytime before it ends it's command sequence?

This is a very tiny version of my sketch. The actual one is 14k lines long!

void setup{
pinMode (1, INPUT);
}

void loop{

if(digitalRead(1) == HIGH){
play();
}


}

void play(){
 digitalWrite(1, HIGH);
 delay(500);
 digitalWrite(1, LOW);
 delay(1000);
 digitalWrite(1, HIGH);
 delay(500);
 digitalWrite(1, LOW);
 delay(200);
 etc...
}

The correct way would be to completely restructure your code by putting the timings and associated high/low value into an array (or similar data structure) and read through that, using millis() to implement the timing so other things could happen simultaneously.

But, you could also do it like this, retaining your original code structure, where stopFlag is set in an interrupt service routine as a result of a button press:

void play(){
 digitalWrite(1, HIGH);
 delay(500);
 if (stopFlag) return ;
 digitalWrite(1, LOW);
 delay(1000);
 digitalWrite(1, HIGH);
 delay(500);
 if (stopFlag) return ;
 digitalWrite(1, LOW);
 delay(200);
 etc...
 if (stopFlag) return ;
}

But, as you see, it is messy. Define stopFlag as volatile bool.

Thank's for reply!

Unfortunatelly due to many other things I can't use millis. Believe me I would use them if I could.
If it can be done by that single command then it's only a matter of adding some lines between LOW & HIGH as you said.

You have to handle the return to the loop() as well:

if(digitalRead(1) == HIGH && ! stopFlag ) { play() } ; // or similar

It is not necessary to have a return statement before every delay() statement. It just depends how responsive you want the stop button to be.

The “array” solution would be even easier to implement than I first suggested. The array can be 1 dimensional because this high/ low change alternately. You’d have something like:

uint16_t rhythm = {500, 1000, 500, 200 . . . } ;
Then simply iterate through that using a loop. The high/low value can be derived from the array index (high if odd, low if even). Use the value obtained from the array to set a millis based timer (or even a delay() if you must).

Unfortunatelly due to many other things I can't use millis.

What are these "other things" ?

My sequence is about 1min long, so it must be a very long array. I will try what you’re suggesting to see if it works better with my case.
The reason I want to use delays is becase there is an RTC on my board that plays another function when time gets to a certain point. Also there’s bluetooth connection and a SIMCOM module. Each of them send a commands to execute a specific sequence function. Using delays prevents every other code execution that I don’t want to run at the time play() is executing. If it’s time the RTC needs to play a function and at the same time I want to execute play() it would be a mess. What if the bluetooth/SIMCOM receive a message that needs to play their sequence function when I need to start play() or while play() is executing?

Time for you to learn about State Machines and non-blocking coding techniques.

Another trick you could do is to write a wrapper around delay(). This would first test if the ISR belonging to the button had been invoked. If so, it would do the equivalent of a delay( 0 ), otherwise it would issues a delay() with the desired wait time. Again, not a beautiful solution but may work for someone who has no alternative but to use the delay() statement.

I can't believe that the array would very long as you imply in post #5, if you go that route. Assuming the examples you gave were realistic, with delay times of 1000, 500 and 200 ms. Even if your 1 minute sound track was composed entirely of, say, 500mS parts that would be only 120 entries (or 240 bytes assuming 16 bit entries).

Elias97:
My sequence is about 1min long, so it must be a very long array. I will try what you’re suggesting to see if it works better with my case.
The reason I want to use delays is becase there is an RTC on my board that plays another function when time gets to a certain point. Also there’s bluetooth connection and a SIMCOM module. Each of them send a commands to execute a specific sequence function. Using delays prevents every other code execution that I don’t want to run at the time play() is executing. If it’s time the RTC needs to play a function and at the same time I want to execute play() it would be a mess. What if the bluetooth/SIMCOM receive a message that needs to play their sequence function when I need to start play() or while play() is executing?

You are the programmer. You are in complete control of everything your program does. If you want your board to prioritize the MIDI playing over everything else, then just choose to ignore everything else when you are playing. You’re not forced to respond to any inputs to your program, you always choose whether or not you respond.

if( SIMCOM_message && !playing )
{
  // only responds to SIMCOM message if you are not playing, dumps it otherwise.
}

Guys, thank's alot, I found a way to utilise many of your ideas. It's a bit messy though, but it's what I was after.

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