Switch-case problem: exit from case during it's running time

Hi everybody,
I need some help about a doubt i have. This is my code:

char ch=0;

void setup() {
  Serial.begin(9600);
  delay(200);
}

void loop(){
  if(Serial.available()){
    ch=Serial.read();
  }
  switch(ch)
  {       
  case '1': 
    firstcase();
    break;

  case '2': 
    Serial.println("I'm case 2");
        delay(1000);
    break;
  
  case '3':
    Serial.println("I'm case 3");
        delay(1000);
    break;

  default:
    Serial.println("Default case");
    delay(1000);
    break;
  }   
  Serial.flush();
}

void firstcase(){
 Serial.println("first case");
 delay(4000);
 Serial.println("Again first case");
 delay(4000);
 Serial.println("Again Again first case"); 
 delay(4000);
 Serial.println("Again Again Again first case");
  delay(4000);
 Serial.println("Again Again Again Again first case");
}

Sorry for this silly code, but it's just an example. All works properly. But the problem is I would like to exit from case '1' during its execution (for example sending '0' char through Serial channel) and before it finish its running time (in this case almost 16 seconds). Is it possible?? How can i do it??
Thank You very much for your help.

Get rid of the "delay()"s - it's the only sensible way you're going to do it.

If you are using delays in your real code, they halt your Arduino until the time out has been reached. In between each delay you can check for a 0.

The usual advice is to try understand the 'blink without delay' tutorial.

pYro_65:
If you are using delays in your real code, they halt your Arduino until the time out has been reached. In between each delay you can check for a 0.

The usual advice is to try understand the 'blink without delay' tutorial.

Hi! Thank you very much for your super-fast reply! But I can't apply this example to my code. Can you kindly help me again??

Imagine your function "firstcase" written without using "delay".
Instead you'd use code similar to the blink-without-delay example to progress from one state to another, where each state prints out message, and progresses to the next state, possibly even setting a different interval (there's a variable called that in the example) each time.
The time you save by not calling "delay" is used to check for incoming characters.

AWOL:
Imagine your function "firstcase" written without using "delay".
Instead you'd use code similar to the blink-without-delay example to progress from one state to another, where each state prints out message, and progresses to the next state, possibly even setting a different interval (there's a variable called that in the example) each time.
The time you save by not calling "delay" is used to check for incoming characters.

The problem is I need to control various servomotor and various sensor and I need doing it at precise moments: this is the reason I've used various delay in my code and open this tread. If I'd use the blink-without-delay example, should I initialize many "long millis_vars" as there are delay() between the various "serial.print" instructions (as written in my first post)? Should the variables be initialized inside the setup()?

Imagine "firstcase written as a "switch/case" and called repeatedly, rather than once.
Each "case" is a different action, and advances the state variable to the next state when the action has be initiated.
A simple static state integer variable within "firstcase" tells you what the next action to be performed is, and another static variable "previousTime" (or whatever) tells you when the last event occurred.

"millis" returns an unsigned long, which is the datatype you should use for any variables assigned from the return value of "millis"

I don't understand what you mean by "exit from case '1' ".

When case '1' occurs, you call that firstcase() function, and then the switch statement ends. That's what the
"break;" after firstcase() does. It ends the switch, for this instance of loop().

If you mean, you want to end the firstcase() function "early", then just put in a return; statement in firstcase()
where you want the function to end.

AWOL:
Imagine "firstcase written as a "switch/case" and called repeatedly, rather than once.
Each "case" is a different action, and advances the state variable to the next state when the action has be initiated.
A simple static state integer variable within "firstcase" tells you what the next action to be performed is, and another static variable "previousTime" (or whatever) tells you when the last event occurred.

"millis" returns an unsigned long, which is the datatype you should use for any variables assigned from the return value of "millis"

Sorry but I can't understand what you've wrote. Or better I think I've understand, but I can't "translate" it into code. It should be something like:

char ch=0;
long time;
void setup() {
  Serial.begin(9600);
  delay(200);

}

void loop(){
  if(Serial.available()){
    ch=Serial.read();
  }
  switch(ch)
  {       
  case '1': 
    firstcase();
    break;

  case '2': 
    Serial.println("case 2");
    delay(1000);

    break;

  default:
    Serial.println("default cause");
    delay(1000);
    break;
  }   
  Serial.flush();
}

char firstcase(){
   time=millis();
   switch(state)
   {
     case 0:
        Serial.println("....");
        break;
     case 1:
        Serial.println("....");
        break;
     case 2:
        Serial.println("....");
        break;
     case 3:
        Serial.println("....");
        break;
   }
}

I can't imagine the "switch" conditions using millis(). I feel so donkey! =(

michinyon:
I don't understand what you mean by "exit from case '1' ".

When case '1' occurs, you call that firstcase() function, and then the switch statement ends. That's what the
"break;" after firstcase() does. It ends the switch, for this instance of loop().

If you mean, you want to end the firstcase() function "early", then just put in a return; statement in firstcase()
where you want the function to end.

Simply I would sent '0' char through serial to stop case 1 execution early. Delay functions doesn't allow serial reading during its execution and so I must wait the case 1 finish to exit it.

I can't imagine the "switch" conditions using millis().

You don't need to, because it doesn't (and shouldn't).

char firstcase(){  
   static byte state;   // initialised to zero
   static unsigned long previousTimetime;  // initialised to zero
   static unsigned long interval = 1000; //whatever
   unsigned long nowTime =  millis();
   char inputChar;
   if (Serial.available () > 0) {
     inputChar = Serial.read ();
     if (inputChar == some_terminating_value) {
       // maybe some tidying up for next time around...
       return inputChar;
     }
   }
     

   if (nowTime - previousTime >= interval)
   {
     switch(state)
     {
       case 0:
        Serial.println(F("...."));
        state = 1;  // don't change "interval"
        break;

     case 1:
        Serial.println(F("some other string"));
        state = 2;  // don't change "interval"
        break;

AWOL:

I can't imagine the "switch" conditions using millis().

You don't need to, because it doesn't (and shouldn't).

char firstcase(){  

static byte state;   // initialised to zero
  static unsigned long previousTimetime;  // initialised to zero
  static unsigned long interval = 1000; //whatever
  unsigned long nowTime =  millis();
  char inputChar;
  if (Serial.available () > 0) {
    inputChar = Serial.read ();
    if (inputChar == some_terminating_value) {
      // maybe some tidying up for next time around...
      return inputChar;
    }
  }

if (nowTime - previousTime >= interval)
  {
    switch(state)
    {
      case 0:
       Serial.println(F("...."));
       state = 1;  // don't change "interval"
       break;

case 1:
       Serial.println(F("some other string"));
       state = 2;  // don't change "interval"
       break;

ehm... this doesn't seems to work properly for me. As I wrote before, i control the serial port in the loop(); you insert another control for serial ("if (Serial.available () > 0)") inside firstcase(). Is it correct?

It was generic example - I'm not tailoring it to your specific problem, just showing how a simple state machine might be implemented.

AWOL:
It was generic example - I'm not tailoring it to your specific problem, just showing how a simple state machine might be implemented.

However it doesn't work for me. Below follows what I've done, but it still doesn't work...

char firstcase(){
  long prevtime=0;
  long nowtime=millis();
  Serial.println("first print");
  delay(1000);
  Serial.println("second print");
  if(nowtime-prevtime>10000){
    Serial.println("third print");
    delay(1000);
    if(Serial.available()){
      ch=Serial.read();
    }      
    return ch;
  }
  prevtime=0;
  nowtime=millis();
  if(Serial.available()){
    ch=Serial.read();
  }
  if(nowtime-prevtime>5000){
    Serial.println("fourth print");
    delay(1000);
    if(Serial.available()){
      ch=Serial.read();
    }
    return ch;
  }
  return ch;
}

Did you read what I said about the return type of "millis"?
Did you read what I said about static variables?
Did you read what I said about getting rid of "delay"?

Replace "nowtime-prevtime" with "millis() - nowtime"

Replace "nowtime-prevtime" with "millis() - nowtime"

Normally, I'd disagree (call "millis" once and assign the value to a variable), but here "nowtime" is at least a second in the past...

AWOL:
Did you read what I said about the return type of "millis"?
Did you read what I said about static variables?
Did you read what I said about getting rid of "delay"?

The code below, exit after "second print". I've used delay to make an useless experiment..
I've found in google that millis() has some problem when it's called inside functions and outside loop(). Is it true??

char firstcase(){
  static byte state;
  static unsigned long prevtime=0;
  static unsigned long nowtime=millis();
  Serial.println("first print");
  Serial.println("second print");
  char inputChar
  if(nowtime-prevtime>10000){
    Serial.println("third print");
    if(Serial.available()){
      inputChar=Serial.read();
    }      
    return inputChar;
  }
  if(Serial.available()){
    ch=Serial.read();
  }
  if(nowtime-prevtime>5000){
    Serial.println("fourth print");
    if(Serial.available()){
      inputChar=Serial.read();
    }
    return inputChar;
  }
  return inputChar;
}

I've found in google that millis() has some problem when it's called inside functions and outside loop().

That's a new one to me.
You can't (shouldn't) use it to initialise static or global variables, but I'm not aware of doing that here.

AWOL:

I've found in google that millis() has some problem when it's called inside functions and outside loop().

That's a new one to me.
You can't (shouldn't) use it to initialise static or global variables, but I'm not aware of doing that here.

Did You test the code you've post before? As you post it (even two braces are missing in the end) it does not work.