// Incluímos la libreria externa para poder utilizarla
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
// Lo primero is inicializar la librería indicando los pins de la interfaz
LiquidCrystal_I2C lcd(0x27,16,2);  //
int porcentaje = 0;
// Definimos las constantes
#define COLS 16 // Columnas del LCD
#define ROWS 2 // Filas del LCD
 
// Configuramos los pines del sensor Trigger y Echo
const int PinTrig = 5;
const int PinEcho = 4;
 
// Constante velocidad sonido en cm/s
const float VelSon = 34000.0;
 
// Número de muestras
const int numLecturas = 61;
 
// Distancia a los 100 ml y vacío
const float distancia100 = 1.13;
const float distanciaVacio = 10.42;
 
float lecturas[numLecturas]; // Array para almacenar lecturas
int lecturaActual = 0; // Lectura por la que vamos
float total = 0; // Total de las que llevamos
float media = 0; // Media de las medidas
bool primeraMedia = false; // Para saber que ya hemos calculado por lo menos una
 
void setup()
{
  // Inicializar el LCD
  lcd.init();
  
  //Encender la luz de fondo.
  lcd.backlight();
  
  // Escribimos el Mensaje en el LCD.
   lcd.setCursor(0, 0);
  lcd.print("Nivel LiQuido");
  lcd.setCursor(0, 1);
  lcd.print("Ultrasonico");
  
  

  // Iniciamos el monitor serie para mostrar el resultado
  Serial.begin(9600);
  // Ponemos el pin Trig en modo salida
  pinMode(PinTrig, OUTPUT);
  // Ponemos el pin Echo en modo entrada
  pinMode(PinEcho, INPUT);
 
  // Inicializamos el array
  for (int i = 0; i < numLecturas; i++)
  {
    lecturas[i] = 0;
  }
 
  // Configuramos las filas y las columnas del LCD en este caso 16 columnas y 2 filas
  lcd.begin(COLS, ROWS);
}
void loop()
{
  // Eliminamos la última medida
  total = total - lecturas[lecturaActual];
 
  iniciarTrigger();
 
  // La función pulseIn obtiene el tiempo que tarda en cambiar entre estados, en este caso a HIGH
  unsigned long tiempo = pulseIn(PinEcho, HIGH);
 
  // Obtenemos la distancia en cm, hay que convertir el tiempo en segudos ya que está en microsegundos
  // por eso se multiplica por 0.000001
  float distancia = tiempo * 0.000001 * VelSon / 2.0;
 
  // Almacenamos la distancia en el array
  lecturas[lecturaActual] = distancia;
 
  // Añadimos la lectura al total
  total = total + lecturas[lecturaActual];
 
  // Avanzamos a la siguiente posición del array
  lecturaActual = lecturaActual + 1;
 
  // Comprobamos si hemos llegado al final del array
  if (lecturaActual >= numLecturas)
  {
    primeraMedia = true;
    lecturaActual = 0;
  }
 
  // Calculamos la media
  media = total / numLecturas;
 
  // Solo mostramos si hemos calculado por lo menos una media
  if (primeraMedia)
  {
    float distanciaLleno = distanciaVacio - media;
    float cantidadLiquido = distanciaLleno * 61 / distancia100;
   
    int porcentaje = cantidadLiquido;   
    porcentaje = constrain (porcentaje, 0, 400);             /* Rango de medición */
     porcentaje = map (porcentaje, 0, 400, 0,100); 
    
    // Mostramos en la pantalla LCD
    lcd.clear();
    // Cantidada de líquido
    lcd.setCursor(0, 0);
    lcd.print(String(cantidadLiquido) + " ml");
 
    // Porcentaje
    lcd.setCursor(0, 1);
    lcd.print(String(porcentaje) + " %");
 
    Serial.print(media);
    Serial.println(" cm");
 
    Serial.print(cantidadLiquido);
    Serial.println(" ml");
  }
  else
  {
    lcd.setCursor(0, 0);
    lcd.print("Calculando: " + String(lecturaActual));
  }
 
  delay(500);
}
 
// Método que inicia la secuencia del Trigger para comenzar a medir
void iniciarTrigger()
{
  // Ponemos el Triiger en estado bajo y esperamos 2 ms
  digitalWrite(PinTrig, LOW);
  delayMicroseconds(2);
 
  // Ponemos el pin Trigger a estado alto y esperamos 10 ms
  digitalWrite(PinTrig, HIGH);
  delayMicroseconds(10);
 
  // Comenzamos poniendo el pin Trigger en estado bajo
  digitalWrite(PinTrig, LOW);
}