,

3 . Añadir LCD

Continuamos con nuestro proyecto y ahora vamos a añadirle un LCD del tipo LCD KEY PAD SHIELD de 16×2 líneas Este tipo de LCD ya viene preparada para conectar directamente encima del arduino Uno o del Mega, pero en nuestro caso al utilizar el nano tenemos que hacer las conexiones siguientes:

Se ha cambiado la lectura del sensor DHT al A1 para dejar el A0 para los botones del LCD

El esquema de conexión sería:

LCD Arduino Nano
A0 A0
D4 D4
D5 D5
D6 D6
D7 D7
D8 D8
D9 D9

El código:

//// wiki.intrusos.info
// modificación del código de http://webdelcire.com/wordpress/archives/2471



//---------------------------Sensor DHT ------------------------------------------------
#include "DHT.h" // Libreria para Sensores DHT
#define DHTPIN 2     // Pin del Arduino al cual esta conectado el pin 2 del sensor
// Descomentar segun el tipo de sensor DHT usado
#define DHTTYPE DHT11   // DHT 11 
DHT dht(DHTPIN, DHTTYPE);// Inicializa el sensor

//---------------LCD ---------------------------------------------------------------------
#include <LiquidCrystal.h>  //Libreria LCD
// Inicializa el objeto LCD con los pines de la interfaz
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// Pines digitales
byte pinLedVerde = 10;
byte pinLedRojo = 11;
byte pinMotor = 12;

// Pines analógicos
byte pinSensorHumedad = 1;

// definición teclado
int lcd_key     = 0;
int adc_key_in  = 0;
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

// Constantes para los posibles modos de funcionamiento
byte MODO_TIEMPO_HUMEDAD = 0;
byte MODO_SOLO_TIEMPO = 1;
byte MODO_SOLO_HUMEDAD = 2;


int modoElegido = 0;		// Modo de funcionamiento

int umbralHumedad = 0;		// Umbral de humedad seleccionado para empezar a regar

int diasTemporizacion = 0;
int horasTemporizacion = 0;
int minutosTemporizacion = 0;

int duracionRiego = 0;		// Duración del riego en segundos una vez alcanzado el evento de activación

String linea1;			// Contenido para la línea superior del display
String linea2;			// Contenido para la línea inferior del display

int humedadMinima = 0;		// Lectura mínima por defecto para el sensor de humedad (se ajusta dinámicamente)
int humedadMaxima = 100;	// Lectura máxima por defecto para el sensor de humedad (se ajusta dinámicamente)

int lecturasHumedad[10];	// Ultimas 10 lecturas del sensor para hacer la media
int indiceLecturasHumedad = 0;	// Indice para saber que valor toca rellenar del array previo
boolean mediaLista = false;	// Indicador de que ya están rellenos los 10 valores del array
int mediaHumedad = 0;		// Media de las últimas 10 lecturas de humedad
int riegos = 0;                 // Numero de riegos realizados
int limiteRiegos = 10;          // Limite de seguridad del número de riegos

int read_LCD_buttons();  // para leer los botones

int read_LCD_buttons()
{ adc_key_in = analogRead(0);      // Leemos A0
  if (adc_key_in > 900)  return btnNONE;     // Ningun boton pulsado
  if (adc_key_in < 50)   return btnRIGHT;
  if (adc_key_in < 200)  return btnUP;
  if (adc_key_in < 400)  return btnDOWN;
  if (adc_key_in < 600)  return btnLEFT;
  if (adc_key_in < 800)  return btnSELECT;
  return btnNONE;  // Por si todo falla
}


//----------------------------------inicio setup ----------------------------------
void setup()
{
  
  // Inicializa el número de columnas y filas del LCD
  lcd.begin(16, 2);

  // Establece a modo salida los pines para controlar la bomba y los led de señalización
  pinMode(pinMotor,OUTPUT);
  pinMode(pinLedRojo,OUTPUT);
  pinMode(pinLedVerde,OUTPUT);

  // Activa el led rojo y muestra la pregunta sobre el modo en el que va a funcionar
  digitalWrite(pinLedRojo, HIGH);
  mostrarPregunta(modoElegido);

  // Pregunta por el modo de funcionamiento: tiempo + humedad, sólo tiempo o sólo humedad
  boolean respuesta = false;
  while (!respuesta)
  {
    lcd_key = read_LCD_buttons();
    delay(200);  //para evitar lecturas seguidas
    if ( lcd_key == btnDOWN)
    {
      modoElegido--;
      if (modoElegido == -1) modoElegido = 2;
      mostrarPregunta(modoElegido);
    }
    else if ( lcd_key == btnUP)
    {
      modoElegido++;
      if (modoElegido == 3) modoElegido = 0;
      mostrarPregunta(modoElegido);
    }
    else if ( lcd_key == btnSELECT)
    {
      respuesta = true;
    }
  }


  // Si el modo elegido incluye riego por tiempo, pregunta cada cuantos días, horas y minutos
  if (modoElegido == MODO_TIEMPO_HUMEDAD || modoElegido == MODO_SOLO_TIEMPO)
  {
    // No permite elegir un tiempo cero
    while (diasTemporizacion + horasTemporizacion + minutosTemporizacion == 0)
    {
      diasTemporizacion = preguntarValor("Numero de dias:", 0, 30);
      horasTemporizacion = preguntarValor("Numero de horas:", 0, 23);
      minutosTemporizacion = preguntarValor("Numero minutos:", 0, 59);
    }

    // Muestra un resumen del tiempo elegido
    linea1 = "  DD : HH : MM";
    linea2 = "  " + str(diasTemporizacion) + " : " + str(horasTemporizacion) + " : " + str(minutosTemporizacion);
    mostrarTexto();
    delay(1000);
  }

  // Si el modo elegido incluye riego por sensor de humedad, pregunta cual es el umbral de humedad para regar
  if (modoElegido == MODO_TIEMPO_HUMEDAD || modoElegido == MODO_SOLO_HUMEDAD)
  {
    umbralHumedad = preguntarValor("Umbral humedad:", 40, 99);
  }

  // Pregunta cuantos segundos deberá durar el riego cuando se active
  duracionRiego = preguntarValor("Duracion riego:", 15, 300);

  // Finalizada la programación desactiva el led rojo y activa el verde
  digitalWrite(pinLedRojo, LOW);
  digitalWrite(pinLedVerde, HIGH);
}


void loop()
{
  // inicializa las variables de tiempo para el riego por temporización
  int diasPendientes = diasTemporizacion;
  int horasPendientes = horasTemporizacion;
  int minutosPendientes = minutosTemporizacion;
  int segundosPendientes = 0;

  if (modoElegido == MODO_TIEMPO_HUMEDAD)
  {
    // Continua el bucle hasta que el tiempo llegue a cero
    while ((diasPendientes + horasPendientes + minutosPendientes + segundosPendientes) > 0)
    {
      // Espera un segundo y decrementa las variables el equivalente a un segundo
      delay(987);
      segundosPendientes--;
      if (segundosPendientes == -1)
      {
        segundosPendientes = 59;
        minutosPendientes--;
      }
      if (minutosPendientes == -1)
      {
        minutosPendientes = 59;
        horasPendientes--;
      }
      if (horasPendientes == -1)
      {
        horasPendientes = 23;
        diasPendientes--;
      }

      // Actualiza la variable con la humedad actual
      leerHumedad();

      // Actualiza el display con el tiempo hasta el siguiente riego y la humedad actual
      linea1 = str(diasPendientes) + ":" + str(horasPendientes) + ":" + str(minutosPendientes) + ":" + str(segundosPendientes);
      linea2 = "Humedad:" + str(mediaHumedad) + "\x25" + " [" + str(umbralHumedad) + "]";
      mostrarTexto();

      // Si la media de humedad de las últimas 10 lecturas está lista y es inferior al umbral configurado, activa el riego
      if ((mediaHumedad < umbralHumedad) && mediaLista)
      {
        regar();
        // Reinicia la media de humedad para que le tiempo a la tierra a empaparse
        indiceLecturasHumedad = 0;
        mediaLista = false;
      }
    }

    // Activa lo bomba de riego durante el tiempo configurado
    regar();
  }
  else if (modoElegido == MODO_SOLO_TIEMPO)
  {
    // Continua el bucle hasta que el tiempo llegue a cero
    while ((diasPendientes + horasPendientes + minutosPendientes + segundosPendientes) > 0)
    {
      delay(990);
      segundosPendientes--;
      if (segundosPendientes == -1)
      {
        segundosPendientes = 59;
        minutosPendientes--;
      }
      if (minutosPendientes == -1)
      {
        minutosPendientes = 59;
        horasPendientes--;
      }
      if (horasPendientes == -1)
      {
        horasPendientes = 23;
        diasPendientes--;
      }

      // Actualiza el display con el tiempo hasta el siguiente riego
      linea1 = "Proximo riego:";
      linea2 = str(diasPendientes) + ":" + str(horasPendientes) + ":" + str(minutosPendientes) + ":" + str(segundosPendientes);
      mostrarTexto();
    }

    // Activa lo bomba de riego durante el tiempo configurado
    regar();
  }
  else if (modoElegido == MODO_SOLO_HUMEDAD)
  {
    while (true)
    {
      delay(1000);

      // Actualiza la variable con la humedad actual
      leerHumedad();

      // Actualiza el display con la humedad actual y el número de riegos efectuados hasta el momento
      linea1 = "Humedad: " + str(mediaHumedad) + "\x25" + " [" + str(umbralHumedad) + "]";  // \x25 es el símbolo ascii de %
      linea2 = "Riegos: " + str(riegos);
      mostrarTexto();

      // Si la media de humedad de las últimas 10 lecturas está lista y es inferior al umbral configurado, activa el riego
      if ((mediaHumedad < umbralHumedad) && mediaLista)
      {
        regar();
        // Reinicia la media de humedad para que le tiempo a la tierra a empaparse
        indiceLecturasHumedad = 0;
        mediaLista = false;
      }
    }
  }
}


// Pregunta el modo de funcionamiento con la última opción elegida
void mostrarPregunta(byte modo)
{
  lcd.clear();
  lcd.print("Modo de riego?");
  lcd.setCursor(0, 1);
  if (modo == MODO_TIEMPO_HUMEDAD) lcd.print("Tiempo + Humedad");
  else if (modo == MODO_SOLO_TIEMPO) lcd.print("Solo Tiempo");
  else if (modo == MODO_SOLO_HUMEDAD) lcd.print("Solo Humedad");
}

// Muestra el texto configurado en el display
void mostrarTexto()
{
  lcd.clear();
  lcd.print(linea1);
  lcd.setCursor(0, 1);
  lcd.print(linea2);
}


// Muestra una pregunta y recoge un valor numérico
int preguntarValor(String texto, int inicial, int maximo)
{
  linea1 = texto;
  linea2 = str(inicial);
  mostrarTexto();
  boolean respuesta = false;
  int valor = inicial;
  while (!respuesta)
  {
    lcd_key = read_LCD_buttons();
    delay(200); //para evitar lecturas seguidas
    if ( lcd_key == btnDOWN)
    { valor--;
      if (valor == -1) valor = maximo;
      linea2 = str(valor);
      mostrarTexto();
    }

    else if ( lcd_key == btnUP)
    {
      valor++;
      if (valor > maximo) valor = 0;
      linea2 = str(valor);
      mostrarTexto();
    }

    else if ( lcd_key == btnSELECT)
    {
      respuesta = true;
    }
  }
  return valor;
}

// Devuelve una cadena numérica de al menos 2 caractes, rellenando con un cero por la izquierda si hace falta
String str(int valor)
{
  if (valor < 10) return "0" + String(valor);
  else return (String(valor));
}


// Actualiza la variable con la media de humedad de las últimas 10 lecturas
void leerHumedad()
{
  lecturasHumedad[indiceLecturasHumedad] = analogRead(pinSensorHumedad);
  lecturasHumedad[indiceLecturasHumedad] = map (lecturasHumedad[indiceLecturasHumedad], 0, 1023, 100, 0); // Mapeamos el valor del sensor de 0 a 100
  indiceLecturasHumedad++;
  if (indiceLecturasHumedad > 9)
  {
    indiceLecturasHumedad = 0;
    mediaLista = true;
  }

  mediaHumedad = 0;
  for (int i = 0; i < 10; i++) mediaHumedad += lecturasHumedad[i];
  mediaHumedad /= 10;
  if (mediaHumedad > humedadMaxima) humedadMaxima = mediaHumedad;
  if (mediaHumedad < humedadMinima) humedadMinima = mediaHumedad;
  mediaHumedad -= humedadMinima;

  mediaHumedad = (double)((double)mediaHumedad / (double)(humedadMaxima - humedadMinima)) * 100;
  if (mediaHumedad == 100) mediaHumedad = 99;
}


// Activa lo bomba de riego durante el tiempo configurado
void regar()
{
  if (riegos == limiteRiegos)
  {
    linea1 = " - BLOQUEADO - ";
    linea2 = "Limite de riegos";
    mostrarTexto();
    while (true) {
      delay(999999);
    }
  }
  int riegoPendiente = duracionRiego;
  digitalWrite(pinMotor, HIGH);
  while (riegoPendiente > 0)
  {
    linea1 = " -- REGANDO -- ";
    linea2 = "Restante: " + str(riegoPendiente);
    mostrarTexto();
    delay(990);
    riegoPendiente--;
  }
  digitalWrite(pinMotor, LOW);
  riegos++;
}

Referencias