Serial input issue with switch case - loop terminating after one interation

Hi guys,

This is my first serious project I’m building with the arduino and I am having a tough time understand what’s going on .
My program asks a user to enter a number between 1 - 4 in the serial monitor to select a mode for the led to operate on. Namely auto mode, blink, on or off.

When I enter the number 3 or 4 to turn the led on or off. It works perfectly however when I enter 2 the led blinks once then goes off permanently. It should blink continuously.

Auto mode uses an LDR to sense how bright is the environment, after a certain point when it becomes dark the led automatically turns on.

The problem is in the main loop, I can’t seem to call the 1st and 2nd function to run over and over again until the user enters another number.

I’m sure this isn’t too difficult a problem (except for me). Please could somebody help me out. Thanks !

//Declare variables here 
int val ;             // variable to store entered number
int ldr = 0;             //analog pin to which LDR is connected
int lightValue = 0;        //variable to store LDR values
int ledPin = 13;           // LED connected to pin 13 and ground
unsigned int lightThreshold = 550;       // Decrease for LED to turn on in brighter conditions or increase for the opposite (Range 0 - 1023 )


// ----------- SETUP LOOP ---------------------------This loop is compulsory DO NOT DELETE. It sets up the program.
void setup()     {            
  Serial.begin(9600);      //start the serial monitor
  Serial.println("Welcome ! ");
  Serial.println(" Select which mode you want to choose ");
  Serial.println("1 - Auto   ");                                    
  Serial.println("2 - Blink ");
  Serial.println("3 - ON");
  Serial.println("4 - OFF"); 
  Serial.println("");
  Serial.println("Enter the number for the mode you wish to choose followed by the return key: ");
}


//----------- MAIN LOOP ------------------------------ This loop is compulsory DO NOT DELETE. 
void loop() {
         if(Serial.available()>0) {
            val = Serial.read();   
       switch (val) {  
         case '1': ledAuto(); break;
         case '2': ledBlink(); break;
         case '3': ledON(); break;
         case '4': ledOFF();break;
        
        }
           
         } 
         
           

          
         
        } 
         
// --------------------- END OF MAIN LOOP----------------------------


//------------------- Create functions below----------------------





void ledAuto()
{
  lightValue = analogRead(ldr);          //reads the LDR values
   Serial.println(lightValue);        //prints the LDR values to serial monitor every 50ms
  delay(50);                           // Uncomment for serial debugging
 
      if(lightValue > lightThreshold ) {         //if value of LDR is higher than lightThreshold turn LED ON else keep OFF                 
       digitalWrite(ledPin,HIGH);                //   delay ( 2 seconds) is added to prevent led from turning on and off too much 
       delay(2000);                     
    } else {
       digitalWrite(ledPin,LOW);
       delay(2000);
    }  
          
}


void ledON() {
 digitalWrite(ledPin,HIGH);             
}


void ledOFF() {
  digitalWrite(ledPin,LOW);
}


void ledBlink() {                     // Blinks the led every one second 
   digitalWrite(ledPin,HIGH);
   delay(1000);                       // Change the value of the delay (in milliseconds ) to speed up / slow down the frequency of blinking 
   digitalWrite(ledPin,LOW);          
   delay(1000);                                          
}

LED_control_3.ino (2.69 KB)

It only works once because you have the call inside the if(serial.available()) test.

Next time loop executes there is no character available so the switch doesn't get run. Try moving the switch out of that test block

void loop() {
        if(Serial.available()>0) {
            val = Serial.read();   
        }
        switch (val) {  
            case '1': ledAuto(); break;
            case '2': ledBlink(); break;
            case '3': ledON(); break;
            case '4': ledOFF();break;
            default : Serial.println("Enter a valid number !");
        } 
}

Mind you if they enter a bogus number you are going to get a lot of "Enter a valid number !" messages :slight_smile:


Rob

Initialize Val = 0 every-time you enter the loop()... so you are sure about the reading

Also use flush() to clear... when done executing one of your functions

Sorry but that wouldn't work because let's say I want the LED to blink over and over again until I enter another number (e.g 4 which turns it off). val will keep resetting to zero at the beginning of the loop. I want val = 2 until a new value is entered. Hope you get what I mean. :~

Use flush() then, if you want to read a new value...

Thanks for telling me about flush(). But my main concern is getting the ledBlink and ledAuto loop to keep repeating itself. It would be really helpful if you could help me modify the code for the main loop. I still don't fully understand everything. Sorry I'm just starting out. Cheers.

Use flush() then, if you want to read a new value…

?

void loop() {
        if(Serial.available()>0) {
            val = Serial.read();   
        }
        switch (val) {  
            case '1': ledAuto(); break;
            case '2': ledBlink(); break;
            case '3': ledON(); break;
            case '4': ledOFF();break;
            default : Serial.println("Enter a valid number !");
        } 

       Serial.flush();
}

This should be fine…

Why bother waiting for the serial transmit buffer to empty?

You can use Serial.readBytes() and use Serial.readBytesUntil(timeout)

Serial.setTimeout() would also help

Moderator edit: name-check removed

I see no reason to flush the Tx buffer, apart from anything else there's no characters being transmitted.

I also see no reason to reset val if you want the action to continue until told to do another action.

OP, does my code example work or not? If not we'll think of something else, if so we're done :slight_smile:


Rob

Thanks for the help guys. @ jainvikas8 I don't think I want a timeout for my project so Serial.readBytesUntil(timeout) isn't necessary. And I'm really sorry @Graynomad your code seems to have the same result as my one. I suggest you plug in an LED and test the code for function 2. FYI I have tried blinkwithoutdelay but that doesn't really make a difference.

Can you post your code as it is now, and describe what it does, and what it doesn't do but that you expect it to?

Looking at the code, the fundamental problem appears to be that loop() reads one character, and if that character is a 2, calls ledBlink(). The ledBlink() function turns the LED on for a second, then off for a second, then terminates. Then we go back to loop(), which is waiting for another character to be available in the serial buffer. There's nothing to make ledBlink() repeat, so the LED doesn't blink continuously.

Ah i get it... it might one those issues...

Where delay() calls the loop() to pass the time....?

If so solution is simple... flag ...

flag = true; //global variable

void loop()
{
if (flag == true)
{
flag = false;
//code
flag = true;
}

}