Garden project - problem with button

Hello.

I am making an automatic gardening project. My idea is to have my sensors display the information on an LCD, and have a button that initiates a water pump using a relay.

I have designed the code to have to IFs, one where the button is pressed and the water pump is working, and another one when the button is not pressed that shows the sensor information on the LCD. However, when I press the button, I have to wait until all the delays are done until the pump starts working. Here is my code (variables are in Spanish):

#include <LiquidCrystal_I2C.h>
#include "DHT.h"

LiquidCrystal_I2C lcd(0x27, 16, 2);
#define dhtPin 2
#define dhtTipo DHT11
DHT dht(dhtPin, dhtTipo);
#define sensorDeAguaPin A3
int valorSensorDeAgua = 0;
#define sensorDeHumedadDeTierraPin A0
int valorSensorDeHumedadDeTierra = 0;
int piezoPin = 4;
int botonPin = 5;

void setup() {
  Serial.begin(9600);
  dht.begin();
  lcd.init();
  lcd.backlight();
  pinMode(piezoPin, OUTPUT);
  pinMode(botonPin, INPUT_PULLUP);
}

void loop() {
  if (digitalRead(botonPin) == LOW) {
    tone(piezoPin, 2000);
    delay(100);
    tone(piezoPin, 2500);
    delay(200);
    noTone(piezoPin);
    delay(100);
    //WATER PUMP
    digitalWrite(botonPin, HIGH);
  }
  if (digitalRead(botonPin) == HIGH) {
    float humedad = dht.readHumidity();
    float temperatura = dht.readTemperature();
    valorSensorDeAgua = analogRead(sensorDeAguaPin);
    valorSensorDeHumedadDeTierra = analogRead(sensorDeHumedadDeTierraPin);
    lcd.setCursor(0, 0);
    lcd.print("Temp.: ");
    lcd.print(temperatura);
    lcd.print("C");
    delay(10000);
    lcd.setCursor(0, 0);
    lcd.print("                    .");
    delay(1000);
    lcd.setCursor(0, 0);
    lcd.print("Humedad: ");
    lcd.print(humedad);
    lcd.print("%");
    delay(10000);
    lcd.setCursor(0, 0);
    lcd.print("                    .");
    delay(1000);
    lcd.setCursor(0, 0);
    lcd.print("Cant. de agua: ");
    lcd.setCursor(0, 1);
    lcd.print(valorSensorDeAgua);
    delay(10000);
    lcd.setCursor(0, 0);
    lcd.print("                     .");
    lcd.setCursor(0, 1);
    lcd.print("                     .");
    delay(1000);
    lcd.setCursor(0, 0);
    lcd.print("Hum. del suelo: ");
    lcd.setCursor(0, 1);
    lcd.print(valorSensorDeHumedadDeTierra);
    delay(10000);
    lcd.setCursor(0, 0);
    lcd.print("                     .");
    lcd.setCursor(0, 1);
    lcd.print("                     .");
    delay(1000);
  }
}

Why is that happening and how can I fix it? Thank you.

The answer, of course, is not to use delay() for timing

See Using millis() for timing. A beginners guide, Several things at the same time and the BlinkWithoutDelay example in the IDE

1 Like

Perhaps also look up functions and state machines. You will need them as you develop your project further. Basically, instead of coding everything in loop (which is a function) you can make your own and then call the function in loop when you want to use it. Eg

void TogglePump(){
Your code here eg 
pumpPin = !pumpPin;
}

You can also pass arguments to the function so for an LCD display function you could pass the string to display

It makes your code in loop more readable so you only need to write: togglePump(); to turn the pump off/on etc

Hi, thank you very much for the link, it has helped me a lot. However, I'm still having problems understanding how a sequence of events would work, not just one repetitive task. Here is my code for now (variables still in Spanish):

#include <LiquidCrystal_I2C.h>
#include "DHT.h"

LiquidCrystal_I2C lcd(0x27, 16, 2);
#define dhtPin 2
#define dhtTipo DHT11
DHT dht(dhtPin, dhtTipo);
#define sensorDeAguaPin A3
int valorCantidadDeAgua = 0;
#define sensorDeHumedadDeTierraPin A0
int valorHumedadDelSuelo = 0;
int piezoPin = 4;
int botonPin = 5;



unsigned long tiempoActual;
unsigned long empezarTemperatura;
unsigned long empezarHumedad;
unsigned long empezarCantidadDeAgua;
unsigned long empezarHumedadDelSuelo;
unsigned long empezarPausaDatos;
const unsigned long tiempoTemperatura = 0;
const unsigned long tiempoHumedad = 10000;
const unsigned long tiempoCantidadDeAgua = 20000;
const unsigned long tiempoHumedadDelSuelo = 30000;
const unsigned long tiempoPausaDatos = 1000;







void setup() {
  Serial.begin(9600);
  dht.begin();
  lcd.init();
  lcd.backlight();
  pinMode(piezoPin, OUTPUT);
  pinMode(botonPin, INPUT_PULLUP);
  empezarTemperatura = millis();
  empezarHumedad = millis();
  empezarCantidadDeAgua = millis();
  empezarHumedadDelSuelo = millis();
  empezarPausaDatos = millis();
}






//----------------------------------------------------- FUNCTIONS

void medirTemperatura() {
  float temperatura = dht.readTemperature();
  lcd.setCursor(0, 0);
  lcd.print("Temp.: ");
  lcd.print(temperatura);
  lcd.print("C");
}

void medirHumedad() {
  float humedad = dht.readHumidity();
  lcd.setCursor(0, 0);
  lcd.print("Humedad: ");
  lcd.print(humedad);
  lcd.print("%");
}

void medirCantidadDeAgua() {
  valorCantidadDeAgua = analogRead(sensorDeAguaPin);
  lcd.setCursor(0, 0);
  lcd.print("Cant. de agua: ");
  lcd.setCursor(0, 1);
  lcd.print(valorCantidadDeAgua);
}

void medirHumedadDelSuelo() {
  valorHumedadDelSuelo = analogRead(sensorDeHumedadDeTierraPin);
  lcd.setCursor(0, 0);
  lcd.print("Hum. del suelo: ");
  lcd.setCursor(0, 1);
  lcd.print(valorHumedadDelSuelo);
}

void pausaDatos() {
  lcd.setCursor(0, 0);
  lcd.print("                      .");
  lcd.setCursor(0, 1);
  lcd.print("                      .");
}

void bombaDeAgua() {
  tone(piezoPin, 2000);
  delay(100);
  tone(piezoPin, 2500);
  delay(200);
  noTone(piezoPin);
  delay(100);
  //BOMBA DE AGUA
  digitalWrite(botonPin, HIGH);
}








//---------------------------------------------------------------MILLIS FUNCTIONS

void temperatura() {
  if (tiempoActual - empezarTemperatura >= tiempoTemperatura) {
    medirTemperatura();
    empezarTemperatura = tiempoActual;
  }
}

void humedad() {
  if (tiempoActual - empezarHumedad >= tiempoHumedad) {
    medirHumedad();
    empezarHumedad = tiempoActual;
  }
}

void cantidadDeAgua() {
  if (tiempoActual - empezarCantidadDeAgua >= tiempoCantidadDeAgua) {
    medirCantidadDeAgua();
    empezarCantidadDeAgua = tiempoActual;
  }
}

void humedadDelSuelo() {
  if (tiempoActual - empezarHumedadDelSuelo >= tiempoHumedadDelSuelo) {
    medirHumedadDelSuelo();
    empezarHumedadDelSuelo = tiempoActual;
  }
}

void pausaDatosTiempo() {
  if (tiempoActual - empezarPausaDatos >= tiempoPausaDatos) {
    pausaDatos();
    empezarPausaDatos = tiempoActual;
  }
}






void loop() {  
  tiempoActual = millis();
  temperatura();
  pausaDatosTiempo();
  humedad();
  pausaDatosTiempo();
  cantidadDeAgua();
  pausaDatosTiempo();
  humedadDelSuelo();
  pausaDatosTiempo();
  if (digitalRead(botonPin) == LOW) {
    bombaDeAgua();
  }
}

Before going any further I have a question

Assuming that botonPin is the button pin then why do you do this

  //BOMBA DE AGUA
  digitalWrite(botonPin, HIGH);

Oh I have changed that now, here's the new code:

#include <LiquidCrystal_I2C.h>
#include "DHT.h"

LiquidCrystal_I2C lcd(0x27, 16, 2);
#define dhtPin 2
#define dhtTipo DHT11
DHT dht(dhtPin, dhtTipo);
#define sensorDeAguaPin A3
int valorCantidadDeAgua = 0;
#define sensorDeHumedadDeTierraPin A0
int valorHumedadDelSuelo = 0;
int piezoPin = 4;
int botonPin = 5;
int releMotor = 3;



unsigned long tiempoActual;
unsigned long empezarTemperatura;
unsigned long empezarHumedad;
unsigned long empezarCantidadDeAgua;
unsigned long empezarHumedadDelSuelo;
unsigned long empezarPausaDatos;
const unsigned long tiempoTemperatura = 0;
const unsigned long tiempoHumedad = 10000;
const unsigned long tiempoCantidadDeAgua = 20000;
const unsigned long tiempoHumedadDelSuelo = 30000;
const unsigned long tiempoPausaDatos = 1000;







void setup() {
  Serial.begin(9600);
  dht.begin();
  lcd.init();
  lcd.backlight();
  pinMode(piezoPin, OUTPUT);
  pinMode(botonPin, INPUT_PULLUP);
  pinMode(releMotor, OUTPUT);
  digitalWrite(releMotor, LOW);
  empezarTemperatura = millis();
  empezarHumedad = millis();
  empezarCantidadDeAgua = millis();
  empezarHumedadDelSuelo = millis();
  empezarPausaDatos = millis();
}






//----------------------------------------------------- FUNCTIONS

void medirTemperatura() {
  float temperatura = dht.readTemperature();
  lcd.setCursor(0, 0);
  lcd.print("Temp.: ");
  lcd.print(temperatura);
  lcd.print("C");
}

void medirHumedad() {
  float humedad = dht.readHumidity();
  lcd.setCursor(0, 0);
  lcd.print("Humedad: ");
  lcd.print(humedad);
  lcd.print("%");
}

void medirCantidadDeAgua() {
  valorCantidadDeAgua = analogRead(sensorDeAguaPin);
  lcd.setCursor(0, 0);
  lcd.print("Cant. de agua: ");
  lcd.setCursor(0, 1);
  lcd.print(valorCantidadDeAgua);
}

void medirHumedadDelSuelo() {
  valorHumedadDelSuelo = analogRead(sensorDeHumedadDeTierraPin);
  lcd.setCursor(0, 0);
  lcd.print("Hum. del suelo: ");
  lcd.setCursor(0, 1);
  lcd.print(valorHumedadDelSuelo);
}

void pausaDatos() {
  lcd.setCursor(0, 0);
  lcd.print("                      .");
  lcd.setCursor(0, 1);
  lcd.print("                      .");
}

void bombaDeAgua() {
  tone(piezoPin, 2000);
  delay(100);
  tone(piezoPin, 2500);
  delay(200);
  noTone(piezoPin);
  delay(1000);
  //BOMBA DE AGUA
  if (digitalRead(botonPin) == LOW) {
    digitalWrite(releMotor, HIGH);
    }
   else {
    digitalWrite(releMotor, LOW);
  }
}








//---------------------------------------------------------------MILLIS FUNCTIONS

void temperatura() {
  if (tiempoActual - empezarTemperatura >= tiempoTemperatura) {
    medirTemperatura();
    empezarTemperatura = tiempoActual;
  }
}

void humedad() {
  if (tiempoActual - empezarHumedad >= tiempoHumedad) {
    medirHumedad();
    empezarHumedad = tiempoActual;
  }
}

void cantidadDeAgua() {
  if (tiempoActual - empezarCantidadDeAgua >= tiempoCantidadDeAgua) {
    medirCantidadDeAgua();
    empezarCantidadDeAgua = tiempoActual;
  }
}

void humedadDelSuelo() {
  if (tiempoActual - empezarHumedadDelSuelo >= tiempoHumedadDelSuelo) {
    medirHumedadDelSuelo();
    empezarHumedadDelSuelo = tiempoActual;
  }
}

void pausaDatosTiempo() {
  if (tiempoActual - empezarPausaDatos >= tiempoPausaDatos) {
    pausaDatos();
    empezarPausaDatos = tiempoActual;
  }
}






void loop() {  
  tiempoActual = millis();
  temperatura();
  pausaDatosTiempo();
  humedad();
  pausaDatosTiempo();
  cantidadDeAgua();
  pausaDatosTiempo();
  humedadDelSuelo();
  pausaDatosTiempo();
  if (digitalRead(botonPin) == LOW) {
    bombaDeAgua();
  }
}

I am a little lost as to what you are trying to do. For clarity please list what should happen while the button is pressed (I guess the pump runs) and when the button is not pressed (I guess that a series of values is displayed each for a period of time)

If I am right this should give us a list of states that the system can be in and we can move on from there, probably with a couple of state machines implemented using switch/case, but we will see

OK

The data collected by the sensors is shown on the LCD, and whenever I decide to push the button, the water pump is activated (only while the button is pressed).

The data showed on the LCD is independent from the button-pump process, so the data is shown even if the pump is activated.

Here is an example showing how to display a series of values read from sensors without stopping the loop() function running freely allowing the button to be read and acted upon at any time

enum displayStates
{
  VALUE_A,
  VALUE_B
};

byte currentDisplayValue = VALUE_A;
unsigned long currentTime = millis();
unsigned long valueStartTime = currentTime;
unsigned long valueDisplayPeriod = 1000;

const byte buttonPin = A3;

void setup()
{
  Serial.begin(115200);
  pinMode(buttonPin, INPUT_PULLUP);
}

void loop()
{
  currentTime = millis();
  switch (currentDisplayValue)
  {
    case VALUE_A:
      if (currentTime - valueStartTime >= valueDisplayPeriod)
      {
        valueStartTime = currentTime;
        currentDisplayValue = VALUE_B;
      }
      Serial.print("VALUE_A : ");
      Serial.println(analogRead(A7));
      break;
    case VALUE_B:
      if (currentTime - valueStartTime >= valueDisplayPeriod)
      {
        valueStartTime = currentTime;
        currentDisplayValue = VALUE_A;
      }
      Serial.print("VALUE_B : ");
      Serial.println(analogRead(A5));
      break;
  };
  if (digitalRead(buttonPin) == LOW)
  {
    Serial.println("The button is pressed");
  }
}

The code can be improved upon in several ways but should give you some ideas

1 Like

Thank you, I'll try to implement that to my project, hopefully it works.

make sure that you understand the principles of the example first

  • use of switch/case to read sensors in turn
  • use of millis() for timing how long each value is displayed
  • no code in loop() (or called from it) that causes it to be blocked from running freely

Possible improvements include, but are not limited to, reading the sensors less frequently to avoid loading the system and only printing the sensor value if it has changed

1 Like

Hello.

I am making an automatic garden, and I'm showing the information taken from four sensors on an LCD screen.

I would like to repeat four tasks infinitely: show temperature for 10s, humidity for 10s, water 10s and soil moisture 10s. Because I need a delay for another task, I have used the millis() function, but the problem is that it only repeats the four tasks once, and it gets stuck showing the soil moisture data on the LCD.

Here is the void loop() section of my code (variables in Spanish):

void loop() {  
  bombaDeAgua();
  tiempoActual = millis();
  if (tiempoActual >= tiempoTemperatura) {
    medirTemperatura();
    tiempoTemperatura += 40000;
  }
  if (tiempoActual >= tiempoHumedad) {
    medirHumedad();
    tiempoHumedad += 40000;
  }
  if (tiempoActual >= tiempoCantidadDeAgua) {
    medirCantidadDeAgua();
    tiempoCantidadDeAgua += 40000;
  }
  if (tiempoActual >= tiempoHumedadDelSuelo) {
    medirHumedadDelSuelo();
    tiempoHumedadDelSuelo += 40000;
  }
}

Post all your code. Always!
If you think the code is too much then make a minimum representative example that demonstrates the error but it should compile. Snippets are useless

Basically what you posted is like a paragraph where you made up some words and didn’t bother with the page of definitions. How are we supposed to know what the functions do or what the variables relate to

#include <LiquidCrystal_I2C.h>
#include "DHT.h"

LiquidCrystal_I2C lcd(0x27, 16, 2);
#define dhtPin 2
#define dhtTipo DHT11
DHT dht(dhtPin, dhtTipo);
#define sensorDeAguaPin A3
int valorCantidadDeAgua = 0;
#define sensorDeHumedadDeTierraPin A0
int valorHumedadDelSuelo = 0;
int piezoPin = 4;
int botonPin = 5;
int releMotor = 3;



unsigned long tiempoActual;
int tiempoTemperatura = 0;
int tiempoHumedad = 10000;
int tiempoCantidadDeAgua = 20000;
int tiempoHumedadDelSuelo = 30000;






void setup() {
  Serial.begin(9600);
  dht.begin();
  lcd.init();
  lcd.backlight();
  pinMode(piezoPin, OUTPUT);
  pinMode(botonPin, INPUT_PULLUP);
  pinMode(releMotor, OUTPUT);
  digitalWrite(releMotor, LOW);
}











void medirTemperatura() {
  float temperatura = dht.readTemperature();
  lcd.setCursor(0, 0);
  lcd.print("Temp.: ");
  lcd.print(temperatura);
  lcd.print("C");
}

void medirHumedad() {
  float humedad = dht.readHumidity();
  lcd.setCursor(0, 0);
  lcd.print("Humedad: ");
  lcd.print(humedad);
  lcd.print("%");
}

void medirCantidadDeAgua() {
  valorCantidadDeAgua = analogRead(sensorDeAguaPin);
  lcd.setCursor(0, 0);
  lcd.print("Cant. de agua: ");
  lcd.setCursor(0, 1);
  lcd.print(valorCantidadDeAgua);
}

void medirHumedadDelSuelo() {
  valorHumedadDelSuelo = analogRead(sensorDeHumedadDeTierraPin);
  lcd.setCursor(0, 0);
  lcd.print("Hum. del suelo: ");
  lcd.setCursor(0, 1);
  lcd.print(valorHumedadDelSuelo);
}

void bombaDeAgua() {
  if (digitalRead(botonPin) == LOW) {
    tone(piezoPin, 2000);
    delay(100);
    tone(piezoPin, 2500);
    delay(200);
    noTone(piezoPin);
    delay(1000);
    digitalWrite(releMotor, HIGH);
    }
   else {
    digitalWrite(releMotor, LOW);
    noTone(piezoPin);
  }
}








void loop() {  
  bombaDeAgua();
  tiempoActual = millis();
  if (tiempoActual >= tiempoTemperatura) {
    medirTemperatura();
    tiempoTemperatura += 40000;
  }
  if (tiempoActual >= tiempoHumedad) {
    medirHumedad();
    tiempoHumedad += 40000;
  }
  if (tiempoActual >= tiempoCantidadDeAgua) {
    medirCantidadDeAgua();
    tiempoCantidadDeAgua += 40000;
  }
  if (tiempoActual >= tiempoHumedadDelSuelo) {
    medirHumedadDelSuelo();
    tiempoHumedadDelSuelo += 40000;
  }
}

In case you need to know more about the variables

Your two topics on the same or similar subject have been merged.

Why did you start a second topic when there were answers, including a solution, on your original topic ?

Please do not duplicate your questions as doing so wastes the time and effort of the volunteers trying to help you as they are then answering the same thing in different places.

Please create one topic only for your question and choose the forum category carefully. If you have multiple questions about the same project then please ask your questions in the one topic as the answers to one question provide useful context for the others, and also you won’t have to keep explaining your project repeatedly.

Repeated duplicate posting could result in a temporary or permanent ban from the forum.

Could you take a few moments to Learn How To Use The Forum

It will help you get the best out of the forum in the future.

Thank you.

My post makes no sense now your double posting is apparent as you have already got the solution using switch case state machine

I do apologise for not having read the Learn How To Use The Forum post.

Do excuse my ignorance on this topic as I couldn't completely wrap my head around how to use the millis() function.

I have come up with this code that seems to do the job, even though it is not a very correct use of the millis() function, but I just knew that I was close:

#include <LiquidCrystal_I2C.h>
#include "DHT.h"

LiquidCrystal_I2C lcd(0x27, 16, 2);
#define dhtPin 2
#define dhtTipo DHT11
DHT dht(dhtPin, dhtTipo);
#define sensorDeAguaPin A3
int valorCantidadDeAgua = 0;
#define sensorDeHumedadDeTierraPin A0
int valorHumedadDelSuelo = 0;
int piezoPin = 4;
int botonPin = 5;
int releMotor = 3;



unsigned long tiempoActual;
unsigned long tiempoTemperatura = 0;
unsigned long tiempoHumedad = 10000;
unsigned long tiempoCantidadDeAgua = 20000;
unsigned long tiempoHumedadDelSuelo = 30000;
unsigned long tiempoLimpiarPantalla = 40000;







void setup() {
  Serial.begin(9600);
  dht.begin();
  lcd.init();
  lcd.backlight();
  pinMode(piezoPin, OUTPUT);
  pinMode(botonPin, INPUT_PULLUP);
  pinMode(releMotor, OUTPUT);
  digitalWrite(releMotor, LOW);
}











void medirTemperatura() {
  float temperatura = dht.readTemperature();
  lcd.setCursor(0, 0);
  lcd.print("Temp.: ");
  lcd.print(temperatura);
  lcd.print("C");
}

void medirHumedad() {
  float humedad = dht.readHumidity();
  lcd.setCursor(0, 0);
  lcd.print("Humedad: ");
  lcd.print(humedad);
  lcd.print("%");
}

void medirCantidadDeAgua() {
  valorCantidadDeAgua = analogRead(sensorDeAguaPin);
  lcd.setCursor(0, 0);
  lcd.print("Cant. de agua: ");
  lcd.setCursor(0, 1);
  lcd.print(valorCantidadDeAgua);
}

void medirHumedadDelSuelo() {
  valorHumedadDelSuelo = analogRead(sensorDeHumedadDeTierraPin);
  lcd.setCursor(0, 0);
  lcd.print("Hum. del suelo: ");
  lcd.setCursor(0, 1);
  lcd.print(valorHumedadDelSuelo);
}

void limpiarPantalla() {
  lcd.setCursor(0, 0);
  lcd.print("                        .");
  lcd.setCursor(0, 1);
  lcd.print("                        .");
}

void bombaDeAgua() {
  if (digitalRead(botonPin) == LOW) {
    tone(piezoPin, 2000);
    delay(100);
    tone(piezoPin, 2500);
    delay(200);
    noTone(piezoPin);
    delay(1000);
    digitalWrite(releMotor, HIGH);
    }
   else {
    digitalWrite(releMotor, LOW);
    noTone(piezoPin);
  }
}








void loop() {  
  bombaDeAgua();
  tiempoActual = millis();
  if (tiempoActual >= tiempoTemperatura) {
    medirTemperatura();
    tiempoTemperatura += 42000;
  }
  if (tiempoActual >= tiempoHumedad) {
    medirHumedad();
    tiempoHumedad += 42000;
    
  }
  if (tiempoActual >= tiempoCantidadDeAgua) {
    medirCantidadDeAgua();
    tiempoCantidadDeAgua += 42000;
  }
  if (tiempoActual >= tiempoHumedadDelSuelo) {
    medirHumedadDelSuelo();
    tiempoHumedadDelSuelo += 42000;
  }
  if ((tiempoActual >= tiempoLimpiarPantalla) and (tiempoActual < 41000)) {
    limpiarPantalla();
    tiempoLimpiarPantalla += 42000;
  }
}

See post 9
You have been given the solution you just need to change the number of cases to match

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