Nan keeps displaying on LCD

Got almost everything working except for the DISPLAY SETTING MODE. Can anyone point out what's wrong? Also, the motor doesn't turn off when the moisture level reaches a high percentage. Is it possible that it's because I haven't fixed the setting mode?

For context: I'm making an irrigation system, there are 3 buttons that are used for the setting mode.

#include <EEPROM.h>
#include <LiquidCrystal_I2C.h>


// Initialize the LCD with the pins connected to the Arduino
LiquidCrystal_I2C lcd(0x27,  16, 2);

#define MoistureSensorPin A0 // Analog pin for the soil moisture sensor


// Define button pins
#define bt_set  A1
#define bt_up   A2
#define bt_down A3


#define motorRelay 9 // Pin for the motor relay


int moistureValue;
float setL_moisture = 30.0; // Default low moisture level
float setH_moisture = 70.0; // Default high moisture level
float moisture = 0;


int Set = 0, flag = 0, flash = 0;


void setup() {
  pinMode(MoistureSensorPin, INPUT);
  
  pinMode(bt_set,  INPUT_PULLUP);
  pinMode(bt_up,   INPUT_PULLUP);
  pinMode(bt_down, INPUT_PULLUP);


  pinMode(motorRelay, OUTPUT);

  Serial.begin(9600); // Start serial communication

  lcd.begin(16, 2); // Initialize the LCD with 16 columns and 2 rows
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("   Welcome To   ");
  lcd.setCursor(0, 1);
  lcd.print("Plant Watering ");


  // Initialize EEPROM values
  if (EEPROM.read(0) == 0) {
    // First-time run, save default values to EEPROM
    EEPROM.put(10, setL_moisture);
    EEPROM.put(15, setH_moisture);
    EEPROM.write(0, 0);
  }
  
  // Retrieve stored values from EEPROM
  EEPROM.get(10, setL_moisture);
  EEPROM.get(15, setH_moisture);


  delay(2000); // Wait for 2 seconds
  lcd.clear();
}


void loop() {
  // Read moisture sensor value and map it to percentage
  moistureValue = analogRead(MoistureSensorPin);
  moisture = map(moistureValue, 1023, 300, 0, 100); 

  // Serial monitor
  Serial.print("Moisture: ");
  Serial.print(moisture);
  Serial.println("%");

  // Control motor relay based on moisture levels
if (moisture < setL_moisture) {
  digitalWrite(motorRelay, LOW); // Turn off the motor
} else {
  digitalWrite(motorRelay, HIGH); // Turn on the motor
}


  // Button handling for setting modes
  if (digitalRead(bt_set) == 0) {
    if (flag == 0) {
      flag = 1;
      Set = Set + 1;
      if (Set > 2) {
        Set = 0; 
        flash = 0;
      } 
      delay(200); // Debounce delay
    }
  } else {
    flag = 0;
  }


  // Button handling for increasing set values
  if (digitalRead(bt_up) == 0) {
    if (Set == 1) {
      setL_moisture = setL_moisture + 1;
      if (setL_moisture > 100) setL_moisture = 100; // Limit to 100%
      EEPROM.put(10, setL_moisture);
    }
    if (Set == 2) {
      setH_moisture = setH_moisture + 1;
      if (setH_moisture > 100) setH_moisture = 100; // Limit to 100%
      EEPROM.put(15, setH_moisture);
    }  
    delay(10); // Debounce delay
  }


  // Button handling for decreasing set values
  if (digitalRead(bt_down) == 0) {
    if (Set == 1) {
      setL_moisture = setL_moisture - 1;
      if (setL_moisture < 0) setL_moisture = 0; // Limit to 0%
      EEPROM.put(10, setL_moisture);
    }
    if (Set == 2) {
      setH_moisture = setH_moisture - 1;
      if (setH_moisture < 0) setH_moisture = 0; // Limit to 0%
      EEPROM.put(15, setH_moisture);
    }  
    delay(10); // Debounce delay
  }


  // Display current moisture level and motor status
  if (Set == 0) {
    lcd.setCursor(0, 0);
    lcd.print(" Moisture: ");
    lcd.print(moisture, 1);
    lcd.print("%  ");


    lcd.setCursor(0, 1);
    lcd.print(" Motor: ");
    if (digitalRead(motorRelay) == HIGH) {
      lcd.print("ON ");
    } else {
      lcd.print("OFF");
    }
    lcd.print("   ");
  } else {
    // Display setting mode
    lcd.setCursor(0, 0);
    lcd.print("  Setting Mode  ");


    lcd.setCursor(0, 1);
    lcd.print("L:");
    if (Set == 1 && flash == 1) {
      lcd.print("    ");
    } else {
      lcd.print(setL_moisture, 1);
    }
    lcd.print("%  ");


    lcd.setCursor(9, 1);
    lcd.print("H:");
    if (Set == 2 && flash == 1) {
      lcd.print("    ");
    } else {
      lcd.print(setH_moisture, 1);
    }
    lcd.print("%  ");
  }


  // Flash the display in setting mode
  if (Set > 0) {
    flash = !flash;
  }
  delay(1); // Small delay for loop
}

The value of erased EEPROM is 255 or 0xFF, not 0, so its likely you never set the initial values in EEPROM.

nan is what will be displayed if a float variable contains invalid data, and means "not a number".

2 Likes

Maybe consider putting a "magic code", say "AB12" in the first 2 (or so) bytes of the EEPROM and test that to determine if the EEPROM contains valid data. The problem with testing only one byte (for 0xFF) to see if the EEPROM is in the "factory state" is that that value may exist there as part of some data that you have written. Also, if the format of the data in the EEPROM is changed, then you can also update the magic code to ensure that an new program does not attempt to process old data.
If you have multiple variables in the EEPROM it can be better to define a struct to avoid having to manually calculate the offset of the individual data items in the EEPROM.

Thanks! This solved the problem with the LCD. Do you notice anything else incorrect with the code that's making my motor not turn off?

I guess the problem is here. I'd have thought that this test should be inverted.
If the current moisture content of the soil is less than the expected moisture then surely you want to turn on the water.

  // Control motor relay based on moisture levels
if (moisture < setL_moisture) {
  digitalWrite(motorRelay, LOW); // Turn off the motor
} else {
  digitalWrite(motorRelay, HIGH); // Turn on the motor
}
1 Like

Thank you!! Everything's working perfectly now.

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