if statement logical test with Serial input (solved)

Hello, I’m quite new to programming and I’m trying to make a menu in one of my sketches.

I tried to make relevant debugging prints and eventually understood that the error was coming from my if() conditions, but I don’t know how to fix it.

Here is a simplified version of my code with some comments to explain the issue in more details:

void printing_on_LCD(){

for(int index2P = 0; index2P <= strlen(wind2P) - 16; index2P++){
        if(menu_check()==0)break;
        print_scrolling_line(index2P, wind2P);
        if(index2P==0)delay(1000);
    }
}

int menu_check(){

  if(digitalRead(menu_button)>0){ // uses hardware button to switch to the next data display (works fine)
    menu += 1;
    if(menu > 3)menu=1;
    return 0;
  }
  else if (Serial.available()>0){ // everything in this loop also seems to work
    Serial.print("Serial.available() > 0 recData == ");
    recData = Serial.read();
    Serial.println(recData);
    newData = true;
    Serial.end();
    Serial.begin(9600);
  }
  if(newData == true){ // seems to work as well
      Serial.println("newData == true");
      newData = false;

/* The following part is the one causing the issue. What I want is: if the Serial.read() function gives a value
   that is anything different to 1, 2 and 3, the menu goes to the next data display. However, if the value is 
   1, 2 or 3, then the menu goes to the corresponding data display.
   However, what's happening currently is that the menu goes to the next data display each time (menu+=1)
   and doesn't car about if recData== 1, 2 or 3*/

      if((recData != 1) && (recData != 2) && (recData != 3)){ 
          menu += 1;
          if(menu > 3)menu=1; Serial.println("recData != 1 && != 2 && != 3 --> return 0"); return 0;
      }
      else {
         if(recData==menu){Serial.println("recData = 1 || =2 || =3\nrecData == menu --> return 1"); return 1;}
         else {menu = recData; Serial.println("recData = 1||2||3\nrecData != menu --> return 0"); return 0;};
      }
  }
  else {Serial.println("newData == false --> return 1"); return 1;}
}

Thank you in advance for any advice you could give me!

PS: I also tried to use the following but it doesn’t work either.

if(newData == true){
    Serial.println("newData == true");
    newData = false;
    
    if((recData == 1) || (recData == 2) || (recData == 3)){
      if(recData==menu){Serial.println("recData = 1 || =2 || =3\nrecData == menu --> return 1"); return 1;}
      else {menu = recData; Serial.println("recData = 1||2||3\nrecData != menu --> return 0"); return 0;};
    }
    else {
      menu += 1;
      if(menu > 3)menu=1; Serial.println("recData != 1 && != 2 && != 3 --> return 0"); return 0;
    }
  }

Please post the complete program.

If you are getting a compiler error please post it.

if the program is working, but not the way you want then please tell us in detail what it actually does and what you want it to do that is different.

...R

I do not get any compiler error. This is the program that doesn’t work the way I want it to work.

The whole thing is quite long (more than the 9000 characters limit), but here you have it. I tried to structure it the way I could, but this is my first “real scale” project… hope you understand without too much troubles.

The issue occurs in the function menu_check(). What I want is:
(a) If the Serial.read() function gives a value to recData that is anything different of 1, 2 and 3, the menu displayed on the LCD screen goes to the next data display. (There are 3 different printing functions that are what I call the different “printing/data displays”).

(b) However, if the value of recData is 1, 2 or 3, then the menu should go to the corresponding data display.

But, what’s happening currently is that the menu goes to the next data display each time (case (a)) and doesn’t care about the lines

 if((recData == 1) || (recData == 2) || (recData == 3)){
      if(recData==menu){Serial.println("recData = 1 || =2 || =3\nrecData == menu --> return 1"); return 1;}
      else {menu = recData; Serial.println("recData = 1||2||3\nrecData != menu --> return 0"); return 0;};
    }

Here is the first half

/****************************************************************/
  /************/  /// SETUP LCD DISPLAY /// /************/
/****************************************************************/

  #include <LiquidCrystal.h>
  const int rs = 2, en = 3, d4 = 4, d5 = 5, d6 = 6, d7 = 7;

  LiquidCrystal lcd(rs, en, d4, d5, d6, d7);
  
/****************************************************************/
  /************/  /// PRINTING FUNCTIONS /// /************/
/****************************************************************/

  void print_scrolling_line(int*,char*);
  void print_inside_ambiance();
  void print_outside_ambiance();
  void print_anemometer_sensor();

/****************************************************************/
  /************/  /// SETUP ANEMOMETER ///  /************/
/****************************************************************/

  int windSensor = A5;    // Defines the pin that the anemometer output is connected
  
    /// Anemometer Technical Variables  ///

  float voltageMin = .4;    // Mininum output voltage from anemometer in mV
  float windSpeedMin = 0;   // Wind speed in meters/sec corresponding to minimum voltage

  float voltageMax = 2.0;   // Maximum output voltage from anemometer in mV
  float windSpeedMax = 32;  // Wind speed in meters/sec corresponding to maximum voltage
  
    /// Calculation variables ///
  
  int sensorDelay = 1000; // Measures every 1000 ms
  int readingIndex = 1;
  float totalWind = 0;    // Used to calculate averageWindSpeed
  
    /// Anemometer Function ///
    
void anemometer_sensor(float*, float*, float*);

/****************************************************************/
  /************/  /// SETUP T° SENSORS /// /************/
/****************************************************************/

  int tempSensorIn  = A3; // Set sensorPin to A1
  int tempSensorOut = A1; // Set sensorPin to A2
  
void temperature_sensor_in(float*);
void temperature_sensor_out(float*);
  
/****************************************************************/
  /************/  /// SETUP LIGHT SENSORS /// /************/
/****************************************************************/

  int lightSensorIn  = A4; // Set sensorPin to A
  int lightSensorOut = A0; // Set sensorPin to A0
  
  char lightLvlTxt[5][12] = {"Dark","Dim","Light","Bright","Very bright"};

void light_sensor_in(int*);
void light_sensor_out(int*);

/****************************************************************/
  /*************/  /// OTHER SETUPS ///  /*************/
/****************************************************************/

  /******************/  // MENU // /*******************/

  int menu = 1;
  const int menu_button = 12;

  char recData;
  boolean newData = false;

  /*****************/  // AWNING // /******************/

  const int led = 13;

/****************************************************************/
  /*************/  /// VOID SETUP ///  /*************/
/****************************************************************/

void setup() {

  pinMode (menu_button, INPUT);
  pinMode (led, OUTPUT);
  
  Serial.begin(9600);     // Start the serial connection
  
  char startMessage1[]="Loading ...";
  char startMessage2[]="Project started!";
  
  lcd.begin(16,2);lcd.clear();lcd.cursor();

  for(int i=0 ; i<11 ; i++){
      lcd.setCursor(i+1,0);
      lcd.print(startMessage1[i]);
      delay(120);
    }
  delay(500);lcd.clear();delay(400);
  
   for(int i=0 ; i<16 ; i++){
      lcd.setCursor(i,0);
      lcd.print(startMessage2[i]);
      delay(80);
    }
  lcd.noCursor();delay(800);lcd.clear();
  
  Serial.println("\t<< Menu: Send any value in the serial port or press the button to switch to the next data display, or send a number from 1 to 3 to switch to a specific data display: >>\n\t_________________________________________________________________________________________________________________________\n\n\t\t1. Inside ambiance\n\t\t2. Outside ambiance\n\t\t3. Anemometer sensor");
  delay(500);  
}

/****************************************************************/
  /************/  /// MAIN LOOP /// /************/
/****************************************************************/

void loop() {

  
  float wSpeed,mWind,aWind;
  anemometer_sensor(&wSpeed,&mWind,&aWind);
  
  float temperatureIn, temperatureOut;
  temperature_sensor_in(&temperatureIn);
  temperature_sensor_in(&temperatureOut);
  
  int nbrLightLvlIn, nbrLightLvlOut;
  light_sensor_in(&nbrLightLvlIn);
  light_sensor_out(&nbrLightLvlOut);
  
  if(mWind < 30 && nbrLightLvlIn >= 3 && nbrLightLvlOut == 4 && temperatureIn > 20 && temperatureOut > 20)digitalWrite(led, HIGH);
  else digitalWrite(led, LOW);
  if(menu==1){
    print_inside_ambiance();
  }
  else if(menu==2){
    print_outside_ambiance();
  }
  else if(menu==3){
    print_anemometer_sensor();
  }
}

/****************************************************************/
  /************/  /// PRINTING FUNCTIONS /// /************/
/****************************************************************/

  /**********/  // PRINTING INSIDE AMBIANCE // /**********/
 
  void print_inside_ambiance(){
   
  char lighLvlIn[12], tmpStr1[7], tmpBright[13] = "Brightness: ", tmpTemp[17] = " - Temperature:";
    char in2P[50] = "";
   
    float temperatureIn;
    temperature_sensor_in(&temperatureIn);
    dtostrf(temperatureIn,6,1,tmpStr1);
 
    int nbrLightLvlIn;
    light_sensor_in(&nbrLightLvlIn);
    strcpy(lighLvlIn,lightLvlTxt[nbrLightLvlIn]);
 
    strcpy(in2P,tmpBright);
    strcpy(&in2P[strlen(in2P)],lighLvlIn);
    strcpy(&in2P[strlen(in2P)],tmpTemp);
    strcpy(&in2P[strlen(in2P)],tmpStr1);
   
    char titleI[17] = {"Inside ambiance "};
 
    for(int i=0 ; i<16 ; i++)
    {
        lcd.setCursor(i,0);
        lcd.print(titleI[i]);
        delay(80);
    }
    delay(500);
   
    for(int index2P = 0; index2P <= strlen(in2P) - 16; index2P++) //From 0 to upto n-16 characters supply to below function
    {
      if(menu_check()==0)break;     
      print_scrolling_line(index2P, in2P);
      if(index2P==0)delay(1000);  // freezes the printing at the begining and the end of the array.
    }delay(1000);lcd.setCursor(0,1);lcd.print("                ");delay(300);
  }

  /**********/  // PRINTING OUTSIDE AMBIANCE // /**********/
 
  void print_outside_ambiance(){
   
  char lighLvlOut[12],tmpStr1[7], tmpBright[13] = "Brightness: ", tmpTemp[17] = " - Temperature:";
    char out2P[50] = "";
   
    float temperatureOut;
    temperature_sensor_out(&temperatureOut);
    dtostrf(temperatureOut,6,1,tmpStr1);
 
    int nbrLightLvlOut;
    light_sensor_out(&nbrLightLvlOut);
    strcpy(lighLvlOut,lightLvlTxt[nbrLightLvlOut]);
 
    strcpy(out2P,tmpBright);
    strcpy(&out2P[strlen(out2P)],lighLvlOut);
    strcpy(&out2P[strlen(out2P)],tmpTemp);
    strcpy(&out2P[strlen(out2P)],tmpStr1);
   
    char titleO[17] = {"Outside ambiance"};
 
    for(int i=0 ; i<16 ; i++)
    {
    lcd.setCursor(i,0);
        lcd.print(titleO[i]);
        delay(80);
    }
    delay(500);
   
    for(int index2P = 0; index2P <= strlen(out2P) - 16; index2P++) {
    if(menu_check()==0)break;       
    print_scrolling_line(index2P, out2P);
    if(index2P==0)delay(1000);
    }
  delay(1000);lcd.setCursor(0,1);lcd.print("                ");delay(300);
  }

Here is the second half.

  /**********/  // PRINTING ANEMOMETER SENSOR // /**********/

  void print_anemometer_sensor(){
    
    float wSpeed, mWind, aWind; // Wind speed in meters per second, average & maximum over the last measurementsStored
    char tmpStr3[6], tmpStr4[6], tmpStr5[6], tmpWind[] = "Wind Speed:", tmpAvrg[] = " - Average:", tmpMax[] = " - Max:";

    anemometer_sensor(&wSpeed,&mWind,&aWind);

    char wind2P [50] = "";
  
    dtostrf(wSpeed,5,1,tmpStr3);
    dtostrf(aWind, 5,1,tmpStr4);
    dtostrf(mWind, 5,1,tmpStr5);
  
    strcpy(wind2P,tmpWind);
    strcpy(&wind2P[strlen(wind2P)],tmpStr3);
    strcpy(&wind2P[strlen(wind2P)],tmpAvrg);
    strcpy(&wind2P[strlen(wind2P)],tmpStr4);
    strcpy(&wind2P[strlen(wind2P)],tmpMax);
    strcpy(&wind2P[strlen(wind2P)],tmpStr5);
  
    char titleA[17] = {"Anemometer [m/s]"};
  
    for(int i=0 ; i<16 ; i++){
        lcd.setCursor(i,0);
        lcd.print(titleA[i]);
        delay(80);
    }
    delay(500);
  
    for(int index2P = 0; index2P <= strlen(wind2P) - 16; index2P++){
        if(menu_check()==0)break;
        print_scrolling_line(index2P, wind2P);
        if(index2P==0)delay(1000);
    }
    delay(1000);lcd.setCursor(0,1);lcd.print("                ");delay(300);
  }

  /************/  // PRINT SCROLLING LINE // /************/

void print_scrolling_line(int startIndex, char array2P[50]){
  
  lcd.setCursor(0, 1);
  for (int index2P = startIndex; index2P <= startIndex + 15; index2P++) // Print only 16 chars in Line #2 starting 'startLetter'
  {
    lcd.print(array2P[index2P]);
  }
  delay(300);
}

  /************/  // PRINT SCROLLING LINE // /************/

int menu_check(){

  if(digitalRead(menu_button)>0){
    menu += 1;
    if(menu > 3)menu=1;
    return 0;
  }
  else if (Serial.available()>0){Serial.println("Serial.available() > 0");
    recData = Serial.read();
    newData = true;
    Serial.flush();
  }
  if(newData == true){Serial.println("newData == true");
    if(recData == 1 || recData == 2 || recData == 3){
      menu = recData;
      newData = false;
      if(recData==menu){Serial.println("recData = 1||2||3\nrecData == menu --> return 1"); return 1;}
      else {Serial.println("recData = 1||2||3\nrecData != menu --> else return 0"); return 0;};
    }
    else {menu += 1; if(menu > 3)menu=1; newData = false; Serial.println("recData != 1||2||3 --> return 0"); return 0;}
  }
  else {Serial.println("newData == false --> return 1"); return 1;}
}

  
/****************************************************************/
  /************/  /// FUNCTION ANEMOMETER /// /************/
/****************************************************************/  

void anemometer_sensor(float *windSpeed, float *maxWindSpeed, float *averageWindSpeed){

    /// Other Variables ///
  
  int sensorValue = 0;    // Variable stores the value direct from the analog pin
  float sensorVoltage = 0;  // Variable that stores the voltage (in Volts) from the anemometer being sent to the analog pin
  float voltageConversionConstant = .004882814; // This constant maps the value provided from the analog read function, which ranges from 0 to 1023, to actual voltage, which ranges from 0V to 5V
  
  int i, j, k, l;

    /// Basic anemometer calculations ///
    
    sensorValue = analogRead(windSensor);   // Get a value between 0 and 1023 from the analog pin connected to the anemometer
    
    sensorVoltage = sensorValue * voltageConversionConstant;
    
    if (sensorVoltage <= voltageMin)  // Convert voltage value to wind speed using range of max and min voltages and wind speed for the anemometer
    {
        *windSpeed = 0;           // Check if voltage is below minimum value. If so, set wind speed to zero.
    }
    else *windSpeed = (( sensorVoltage - voltageMin ) * windSpeedMax / ( voltageMax - voltageMin )) * 2.232694;  // For voltages above minimum value, use the linear relationship to calculate wind speed.
    
  
    if(readingIndex == 100)   // Max number of windSpeeds kept in the totalWind variable. Used to define how long the time frame of the average is.
    {
        totalWind = *averageWindSpeed;
        readingIndex = 2;
        *maxWindSpeed = *averageWindSpeed;
    }
  
    /// Total wind ///

  totalWind = totalWind + *windSpeed;  
  
    /// Average wind speed ////
  
  *averageWindSpeed = totalWind / readingIndex;
  readingIndex++;
  
    /// Max wind speed calculation ///

    if (readingIndex == 1)*maxWindSpeed = *windSpeed;
    
    if (*windSpeed > *maxWindSpeed)
    {
        *maxWindSpeed = *windSpeed;
    }
}

/****************************************************************/
  /************/  /// FUNCTION T° INSIDE ///  /************/
/****************************************************************/

void temperature_sensor_in(float *tempI){
  
  float voltage = analogRead(tempSensorIn) * 4.8828125; // = * 5000/1024
  voltage = voltage - 500;
  *tempI = voltage / 10;
}

/****************************************************************/
  /************/  /// FUNCTION T° OUTSIDE /// /************/
/****************************************************************/ 

void temperature_sensor_out(float *tempO){
  
  float voltage = analogRead(tempSensorOut) * 4.8828125; // = * 5000/1024
  voltage = voltage - 500;
  *tempO = voltage / 10;
}

/****************************************************************/
  /*********/ /// FUNCTION LIGHT LVL INSIDE /// /*********/
/****************************************************************/ 

void light_sensor_in(int *nbrLightLvlIn){
  
  float analogValue = analogRead(lightSensorIn);
  
  if(analogValue < 200)*nbrLightLvlIn = 0;
  else if(analogValue >= 200 && analogValue < 400)*nbrLightLvlIn = 1;
  else if(analogValue >= 450 && analogValue < 600)*nbrLightLvlIn = 2;
  else if(analogValue >= 600 && analogValue < 800)*nbrLightLvlIn = 3;
  else if(analogValue >= 800)*nbrLightLvlIn = 4;
  else(Serial.print("Sensor error"));
}

/****************************************************************/
  /*********/ /// FUNCTION LIGHT LVL OUTSIDE ///  /*********/
/****************************************************************/ 

void light_sensor_out(int *nbrLightLvlOut){
  
  float analogValue = analogRead(lightSensorOut);
  
  if(analogValue < 200)*nbrLightLvlOut = 0;
  else if(analogValue >= 200 && analogValue < 400)*nbrLightLvlOut = 1;
  else if(analogValue >= 400 && analogValue < 600)*nbrLightLvlOut = 2;
  else if(analogValue >= 600 && analogValue < 800)*nbrLightLvlOut = 3;
  else if(analogValue >= 800)*nbrLightLvlOut = 4;
  else(Serial.print("Sensor error"));
}
}

Everything except the error described above works in the code except the big if() in the void loop() function.

I’ll most likely be able to fix it on my own, but if you see why is doesn’t work the way I’d like, pls let me know.

If you need anything else, please tell me.

ru.

    if (recData == 1 || recData == 2 || recData == 3) {

You are checking for the numeric values of 1, 2, 3, not the ASCII codes for the numbers 1, 2, 3. Place the numbers in single quotes to check for the ASCII characters:

    if (recData == '1' || recData == '2' || recData == '3') {

Also note that Serial.flush() waits for the send buffer to become empty, it does not empty the receive buffer.

This is indeed a beginner mistake... I've heard of that but never did I realize I was in that case. :frowning:

I understood that the .flush() wasn't cleaning the buffer after posting, I used Serial.end(); Serial.begin(9600); instead.

Now when I start the code, it goes well into that loop... But a bit later I have to make a logic test as follow:

if(recData == menu)return 1;
      else {menu = recData; return 0};

menu being an integer and recData a char, I shouldn't have expect it to work.

So I thought about converting recData to an int, and found on this forum the function .toInt(),

char recData;
[...]
if((recData == '1') || (recData == '2') || (recData == '3')){
      int recInt = recData.toInt();
      if(recInt == menu)return 1;
      else {menu = recInt; return 0;Serial.print("return");};
    }

but it gives me this error:
error: request for member 'toInt' in 'recData', which is of non-class type 'char'

  • int recInt = recData.toInt();*
  • ^~~~~*
    exit status 1
    request for member 'toInt' in 'recData', which is of non-class type 'char'

Do you understand why?

Thank you very much,

ru...

.toInt() expects a String, not a char.

Easy way to convert a single ASCII numeric character to an integer is to subtract the ASCII value for zero:

      int recInt = recData - '0';

I understood that the .flush() wasn't cleaning the buffer after posting, I used Serial.end(); Serial.begin(9600); instead.

Easier to just read in characters until the buffer is empty, although with either method you have to realize that the Arduino board is running much faster than serial communications, so the Serial.end() and Serial.begin() will be executed in much less time than it takes to send a single character. For simple code like yours, the easiest thing to do is set the serial monitor for "No line ending" then you will not need to be concerned with the carriage return and newline characters. For more complex uses, see the very well written Serial Input Basics.

    while (Serial.available() > 0) {
      Serial.read();  //read input and do nothing with it, until the buffer is empty
    }

rushi_:
I understood that the .flush() wasn't cleaning the buffer after posting, I used Serial.end(); Serial.begin(9600); instead.

A simple way to clear the Serial Input Buffer is like this

while (Serial.available > 0) {
   Serial.read();
}

...R

Thank you so much Robin and david! <3

Everything is working properly now!

Here is the final code (only the relevant function):

int menu_check(){

  if(digitalRead(menu_button) > 0){
    menu += 1;
    if(menu > 3)menu=1;
    return 0;
  }
  else if (Serial.available() > 0){
    recData = Serial.read();
    newData = true;
    while(Serial.available() > 0){Serial.read();}
  }
  if(newData == true){
    newData = false;
    if((recData == '1') || (recData == '2') || (recData == '3')){
      int recInt = recData - '0';
      if(recInt == menu) return 1;
      else {menu = recInt; return 0;};
    }
    else {
      menu += 1;
      if(menu > 3)menu=1; return 0;
    }
  }
  else return 1;
}

Thanks to your advices, it not only works, but it also works much faster than with the .end()/.begin() solution… c: