//Pagina de informacion y programcion de pantalla OLED SSD1306
//https://programarfacil.com/blog/arduino-blog/ssd1306-pantalla-oled-con-arduino/
//Pagina de informacion y programcion de reduccion consumos
//https://www.electrosoftcloud.com/arduino-reducir-el-consumo-de-energia/
//Pagina de informacion y programcion de multitaskisk y tareas temporizadas
//https://www.electrosoftcloud.com/arduino-taskscheduler-no-mas-millis-ni-delay/
//Pagina de informacion y programcion de interrruciones arduino
//https://www.electrosoftcloud.com/arduino-interrupciones-hardware-software/
//*******************************************************************************************
//*OJO QUE ES EN CM SE PUEDE PASAR A MM PROBAR *
//https://programarfacil.com/tutoriales/fragmentos/sensor-de-ultrasonidos-con-arduino/ *
//* *
//* Paágina ejemplo programcacion pnatalla ILI9341 *
//* https://electronoobs.com/eng_arduino_tut58.php *
//* *
//* Paágina ejemplo programcacion SLEEP *
//* https://www.prometec.net/el-modo-sleep-en-arduino/ *
//* *
//* Paágina ejemplo programcacion SLEEP LOWPOWDER
//* https://www.electrosoftcloud.com/arduino-reducir-el-consumo-de-energia/
//* * *
//* Interrupciones
//* https://lab.bricogeek.com/tutorial/como-funcionan-y-como-usar-interrupciones-en-arduino-con-ejemplos
//* *
//* Paágina ejemplo programcacion Multiplexor *
//* https://www.luisllamas.es/mas-salidas-y-entradas-en-arduino-con-multiplexor-cd74hc4067/ *
//*******************************************************************************************
#include <Wire.h>
#include "Adafruit_GFX.h"
#include "Adafruit_ILI9341.h"
#include <TimerOne.h>
#include <LowPower.h>
// Entradas Y Salidas Ultrasonico
const int Trigger = 6; // Pin digital 6 para el Trigger del sensor
int Echo_Sensor[6] = {A0, A1, A2, A3, A4, A5};
int Lectura_Sensor[6] = {0, 0, 0, 0, 0, 0};
int nivel_min[6] = {25, 25, 25, 25, 25, 25};
int nivel_max[6] = {5, 5, 5, 5, 5, 5};
int porcentaje_nivel[6] = {0, 0, 0, 0, 0, 0};
bool alarma[6] = {false, false, false, false, false, false};
const int ancho_casilla=106;
const int largo_casilla=120;
// Constante velocidad sonido
const float VelSon = 34314.00; // Velocidad sonido en cm/s
//const float VelSon = 343140.00; // Velocidad sonido en mm/s
// Entradas y Salidas Pantalla
#define TFT_CLK 13
#define TFT_MISO 12
#define TFT_MOSI 11
#define TFT_DC 9
#define TFT_CS 10
#define TFT_RST 8
// Entradas menu
#define BOTON_MENU 3
#define BOTON_NEXT 4
bool Pulsacion_LargaA = false;
bool Pulsacion_CortaA = false;
bool PulsadoA = false;
bool Pulsacion_LargaB = false;
bool Pulsacion_CortaB = false;
bool PulsadoB = false;
volatile bool ModoCalib = false;
int segundos_salir = 0;
bool salir_calib = false;
unsigned long Inicio_pulsacionA = 0;
unsigned long duracionA = 0;
unsigned long Inicio_pulsacionB = 0;
unsigned long duracionB = 0;
bool a = false;
bool b = false;
//https://github.com/Bodmer/TFT_eSPI/blob/master/TFT_eSPI.h
#define ILI9341_BLACK 0x0000 ///< 0, 0, 0
//#define ILI9341_NAVY 0x000F ///< 0, 0, 123
//#define ILI9341_DARKGREEN 0x03E0 ///< 0, 125, 0
//#define ILI9341_DARKCYAN 0x03EF ///< 0, 125, 123
//#define ILI9341_MAROON 0x7800 ///< 123, 0, 0
//#define ILI9341_PURPLE 0x780F ///< 123, 0, 123
#define ILI9341_OLIVE 0x7BE0 ///< 123, 125, 0
//#define ILI9341_LIGHTGREY 0xC618 ///< 198, 195, 198
#define ILI9341_DARKGREY 0x7BEF ///< 123, 125, 123
#define ILI9341_BLUE 0x001F ///< 0, 0, 255
#define ILI9341_GREEN 0x07E0 ///< 0, 255, 0
#define ILI9341_CYAN 0x07FF ///< 0, 255, 255
#define ILI9341_RED 0xF800 ///< 255, 0, 0
#define ILI9341_MAGENTA 0xF81F ///< 255, 0, 255
#define ILI9341_YELLOW 0xFFE0 ///< 255, 255, 0
#define ILI9341_WHITE 0xFFFF ///< 255, 255, 255
#define ILI9341_ORANGE 0xFD20 ///< 255, 165, 0
//#define ILI9341_GREENYELLOW 0xAFE5 ///< 173, 255, 41
//#define ILI9341_PINK 0xFC18 ///< 255, 130, 198
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);
#define buzzerPin 2 //buzzer name and pin
//int Do = 262; // do
//int Re = 294; // re
//int Mi = 330; // mi
//int Fa = 349; // fa
//int Sol = 392; // sol
//int Lya = 440; // la
//int Si = 494; // si
int pitido = 1000; //
int cnt_pitido = 0;
volatile bool alarmaON = false;
bool parpadeo1 = false;
unsigned long tiempo1 = 0;
int Antirrebote = 250;
void setup() {
attachInterrupt(digitalPinToInterrupt(BOTON_MENU), Despertar, FALLING);
Serial.begin(9600);
pinMode(BOTON_MENU, INPUT_PULLUP);
pinMode(BOTON_NEXT, INPUT_PULLUP);
pinMode(Trigger, OUTPUT); //pin como salida
for (int k = 0; k <= 5; k++) {
pinMode(Echo_Sensor[k], INPUT);
delay(10);
}
digitalWrite(Trigger, LOW);//Inicializamos el pin con 0
// Init screen
tft.begin();
tft.setRotation(3);
tft.fillScreen(ILI9341_BLACK);
Pantalla_vacia();
Lectura_niveles();
Pintar_niveles();
delay(100);
//Conficguracion interrupcion cada segundo Si USO TIMER 0
Timer1.initialize(1000000); //Configura el TIMER en 1 Segundo
Timer1.attachInterrupt(Interrupcion) ; //Configura la interrupción del Timer 1
}
void loop() {
Lectura_niveles();
Pantalla_vacia();
Pintar_niveles();
alerta_nivel_bajo();
sonido_alarma();
if (ModoCalib == true) {
salir_calib = false;
detachInterrupt(0);
// Serial.println("entramos a calib");
bool salir = false;
unsigned long ta = 0;
ta = millis();
while (salir == false) {
leerbotones() ;
if (Pulsacion_LargaA) {
Menu();
}
if (millis() > ta + 10000) {
salir = true;
//Serial.println("salimos sin hacer el huevo");
}
}
ModoCalib = false;
salir_calib = false;
///BORRAR EN APLICACION REAL ESTAS LINEAS*******
for (int i = 0; i < 6; i++) { //***
nivel_min[i] = 25; //***
nivel_max[i] = 5; //***
} //***
//**********************************************
attachInterrupt(digitalPinToInterrupt(BOTON_MENU), Despertar, FALLING);
}
else if (ModoCalib == false) {
LowPower.powerDown(SLEEP_8S, ADC_OFF, BOD_ON);
// Serial.println("A MIMIR");
}
}
void Interrupcion(void) { // funcion ISR
//Sumar segundos para salir de CalibraCION O aPAGAR PANTALLA
if (ModoCalib == true) {
segundos_salir ++;
// Serial.println(segundos_salir);
}
if (segundos_salir >= 100) {
segundos_salir = 0;
salir_calib = true;
}
}
void Despertar() {
ModoCalib = true;
}
void Menu() {
Pantalla_vacia();
Pintar_niveles();
ModoCalib = true;
salir_calib = false;
int cnt_indice = 0;
int indice_x[3] = {0, ancho_casilla, 2*ancho_casilla};
int indice_y[2] = {0, largo_casilla};
String titulo[6] = {"SOL A1", "SOL B1", "BAJ PH", "SOL A2", "SOL B2", "BAJ PH"};
// Disable external pin interrupt on wake up pin.
//Serial.println("ENTARAMOS A MENU");
while ((Pulsacion_LargaB == false) && (salir_calib == false)) {
leerbotones() ;
if (millis() > tiempo1 + 700) {
tiempo1 = millis();
parpadeo1 = !parpadeo1;
if (parpadeo1 == true) {
tft.fillScreen(ILI9341_BLACK);
//marcos();
}
else if ((parpadeo1 == false)) {
Pantalla_vacia();
Pintar_niveles();
}
}
}
Pantalla_vacia();
Pintar_niveles();
for (int y = 0; y < 2; y++) {
for (int x = 0; x < 3; x++) {
nivel_max[cnt_indice] = calibracion_nivel(cnt_indice, indice_x[x], indice_y[y], titulo[cnt_indice], 0);
//Serial.print(cnt_indice);
// Serial.print(" Nivel 0 = ");
//Serial.println(nivel_max[cnt_indice]);
Pulsacion_CortaB = false;
delay(1);
cnt_indice ++;
}
} //end for principal
cnt_indice = 0;
for (int y = 0; y < 2; y++) {
for (int x = 0; x < 3; x++) {
nivel_min[cnt_indice] = calibracion_nivel(cnt_indice, indice_x[x], indice_y[y], titulo[cnt_indice], 100);
// Serial.print(cnt_indice);
// Serial.print(" Nivel 100 = ");
// Serial.println(nivel_min[cnt_indice]);
Pulsacion_CortaB = false;
delay(1);
cnt_indice ++;
}
} //end for principal
//cnt_indice = 0;
tft.fillScreen(ILI9341_BLACK);
Pantalla_vacia();
Lectura_niveles();
Pintar_niveles();
}
int calibracion_nivel(int indice, int x, int y, String titulo, int nivel_calib) {
int lectura = 0;
//tft.fillScreen(ILI9341_BLACK);
//Pantalla_vacia();
//Pintar_niveles();
while ((Pulsacion_CortaB == false) && (salir_calib == false)) {
leerbotones() ;
if (millis() > tiempo1 + 700) {
tiempo1 = millis();
parpadeo1 = !parpadeo1;
if (parpadeo1 == true) {
tft.fillRect(x + 1, y + 1, 105, 119, ILI9341_BLACK);
}
else if ((parpadeo1 == false)) {
dibujar_tanque_vacio(x, y, ancho_casilla, largo_casilla, titulo);
Pintar_nivel_tanque(x, y, ancho_casilla, largo_casilla, nivel_calib);
}
}
lectura = Leer_Sensor(indice);
}
dibujar_tanque_vacio(x, y, ancho_casilla, largo_casilla, titulo);
Pintar_nivel_tanque(x, y, ancho_casilla, largo_casilla, nivel_calib);
delay(250);
return lectura;
}
void leerbotones() {
segundos_salir = 0;
duracionA = 0;
duracionB = 0;
Pulsacion_LargaA = false;
Pulsacion_CortaA = false;
Pulsacion_LargaB = false;
Pulsacion_CortaB = false;
delay(5);
a = digitalRead(BOTON_MENU); // pin donde miras la señal digital
if ((a == LOW) && (PulsadoA == false)) { // si hay flanco 0 a 1 entonces
Inicio_pulsacionA = millis();
PulsadoA = true;
// Serial.print("Inicio_pulsacionA = ");
// Serial.println(Inicio_pulsacionA);
}
if ((a == HIGH) && (PulsadoA == true)) { // si el flanco es 1 a 0, entonces detengo la cuenta
duracionA = millis() - Inicio_pulsacionA; // en milisegundos
// Serial.print("duracionA = ");
// Serial.println(duracionA);
}
if ((duracionA >= 150) && (duracionA < 3000)) {
// Serial.println("Pulsacion Corta A");
Pulsacion_CortaA = true;
PulsadoA = false;
}
if (duracionA >= 3000) {
// Serial.println("Pulsacion Larga A");
Pulsacion_LargaA = true;
PulsadoA = false;
}
b = digitalRead(BOTON_NEXT); // pin donde miras la señal digital
if ((b == LOW) && (PulsadoB == false)) { // si hay flanco 0 a 1 entonces
Inicio_pulsacionB = millis();
PulsadoB = true;
// Serial.print("Inicio_pulsacionB = ");
// Serial.println(Inicio_pulsacionB);
}
if ((b == HIGH) && (PulsadoB == true)) { // si el flanco es 1 a 0, entonces detengo la cuenta
duracionB = millis() - Inicio_pulsacionB; // en milisegundos
// Serial.print("duracionB = ");
// Serial.println(duracionB);
}
if ((duracionB >= 1000) && (duracionB < 2000)) {
// Serial.println("Pulsacion Corta B");
Pulsacion_CortaB = true;
PulsadoB = false;
}
if (duracionB >= 2000) {
// Serial.println("Pulsacion Larga B");
Pulsacion_LargaB = true;
PulsadoB = false;
}
delay(5);
}
void Pantalla_vacia() {
//marcos();
dibujar_tanque_vacio(0, 0, ancho_casilla, largo_casilla, "SOL A1");
dibujar_tanque_vacio(ancho_casilla, 0, ancho_casilla, largo_casilla, "SOL B1");
dibujar_tanque_vacio(2*ancho_casilla, 0, ancho_casilla, largo_casilla, "BAJ PH");
dibujar_tanque_vacio(0, largo_casilla, ancho_casilla, largo_casilla, "SOL A2");
dibujar_tanque_vacio(ancho_casilla, largo_casilla, ancho_casilla, largo_casilla, "SOL B2");
dibujar_tanque_vacio(2*ancho_casilla, largo_casilla, ancho_casilla, largo_casilla, "BAJ PH");
}
void dibujar_tanque_vacio(int x, int y, int tam_x, int tam_y, String texto) {
// x coordenada hotizontal,
// y coordenada vertical
// tam_x dimension en horizontal
// tam_x dimension en vertical
// dibujar titulo de tanque
tft.setCursor((x + (tam_x / 5.5)), y + 5);
tft.setTextSize(2);
tft.setTextColor(ILI9341_WHITE);
tft.println(texto);
//dibujar origen de recuadro
//tft.drawLine(x, y, x, y, ILI9341_RED);
int margen_x = 20;
int margen_y = 10;
int margen_y_sup = 25;
// dibujar lineas de tanque
int x1 = (x + margen_x);
int y1 = (y + margen_y_sup);
int x2 = x1;
int y2 = y + (tam_y - margen_y);
int x3 = x + (tam_x - margen_x);
int y3 = y2;
int x4 = x + (tam_x - margen_x);
int y4 = y1;
tft.drawLine(x1, y1, x2, y2, ILI9341_WHITE);
tft.drawLine(x2, y2, x3, y3, ILI9341_WHITE);
tft.drawLine(x3, y3, x4, y4, ILI9341_WHITE);
}
void Lectura_niveles() {
for (int i = 0; i <= 5; i++) {
Lectura_Sensor[i] = Leer_Sensor(i);
// Serial.println(Lectura_Sensor[i] );
delay(5);
// Calculo de porcenaje
porcentaje_nivel[i] = map(Lectura_Sensor[i], nivel_min[i], nivel_max[i], 0, 100);
delay(350);
}
// Serial.println("******** ");
for (int ii = 0; ii <= 5; ii++) {
//Serial.print(ii + 1);
// Serial.print(" - ");
// Serial.print(Lectura_Sensor[ii] );
// Serial.print(" Porcentaje = ");
// Serial.print(porcentaje_nivel[ii] );
if (porcentaje_nivel[ii] >= 100) {
porcentaje_nivel[ii] = 100;
}
if (porcentaje_nivel[ii] <= 0) {
porcentaje_nivel[ii] = 0;
}
// Serial.println(" ");
}
// Serial.println(" ");
// Serial.println("------- ");
// Serial.println(" ");
}
int Leer_Sensor(int indice) {
int muestras = 5; // numero de muestras
float suma = 0;
float media = 0;
unsigned long t = 0; //timepo que demora en llegar el eco
float d = 0; //distancia en centimetros
suma = 0;
delay(5);
for (int j = 0; j < muestras; j++) {
digitalWrite(Trigger, LOW);
delayMicroseconds (5);
digitalWrite(Trigger, HIGH);
delayMicroseconds(10); //Enviamos un pulso de 10us
digitalWrite(Trigger, LOW);
t = pulseIn(Echo_Sensor[indice], HIGH); //obtenemos el ancho del pulso
// d = t / 59;
// Obtenemos la distancia en cm, hay que convertir el tiempo en segudos ya que está en microsegundos
// por eso se multiplica por 0.000001
// Si queremos precision mm/s tenemos que desmarcar la opcion VelSon en mm/s y comentar la cm/s
d = t * 0.000001 * VelSon / 2.0;
suma = suma + d;
delay(70);
}
media = suma / muestras;
return media;
}
void Pintar_niveles() {
Pintar_nivel_tanque(0, 0, ancho_casilla, largo_casilla, porcentaje_nivel[0]);
Pintar_nivel_tanque(ancho_casilla, 0, ancho_casilla, largo_casilla, porcentaje_nivel[1]);
Pintar_nivel_tanque(2*ancho_casilla, 0, ancho_casilla, largo_casilla, porcentaje_nivel[2]);
Pintar_nivel_tanque(0, largo_casilla, ancho_casilla, largo_casilla, porcentaje_nivel[3]);
Pintar_nivel_tanque(ancho_casilla, largo_casilla, ancho_casilla, largo_casilla, porcentaje_nivel[4]);
Pintar_nivel_tanque(2*ancho_casilla, largo_casilla, ancho_casilla, largo_casilla, porcentaje_nivel[5]);
}
void Pintar_nivel_tanque(int x, int y, int tam_x, int tam_y, int num) {
//dibujar origen de recuadro
int margen_x = 20;
int margen_y = 10;
int margen_y_sup = 25;
int l0 = 2;
int l100 = tam_y - (margen_y + margen_y_sup + 5);
int level = map(num, 0, 100, l0, l100);
// dibujar lineas de tanque
int x1 = (x + margen_x) + 1;
int y1 = y + (tam_y - margen_y) - 1;
int x2 = (tam_x - 2 * margen_x) - 1;
int y2 = - level;
tft.fillRect(x1, (y + margen_y_sup + 5), x2, (l100 - level - 0), ILI9341_DARKGREY);
if (num <= 10) {
tft.fillRect(x1, y1, x2, y2, ILI9341_RED);
}
else if ((num > 10) && (num <= 20) ) {
tft.fillRect(x1, y1, x2, y2, ILI9341_MAGENTA);
}
else if ((num > 20) && (num <= 30) ) {
tft.fillRect(x1, y1, x2, y2, ILI9341_ORANGE);
}
else if ((num > 30) && (num <= 40) ) {
tft.fillRect(x1, y1, x2, y2, ILI9341_YELLOW);
}
else if ((num > 40) && (num <= 60) ) {
tft.fillRect(x1, y1, x2, y2, ILI9341_OLIVE);
}
else if (num > 60) {
tft.fillRect(x1, y1, x2, y2, ILI9341_GREEN);
}
// escribir nivel tanque
tft.drawRect((x + (tam_x / 3.8)), y + (tam_y / 2), 50 + 3, 20 + 2, ILI9341_BLACK);
tft.setTextSize(2);
if (num < 10) {
tft.setCursor((x + (tam_x / 3.8) + 2 + 14), y + (tam_y / 2) + 4);
}
if ((num >= 10) && (num < 100)) {
tft.setCursor((x + (tam_x / 3.8) + 2 + 8), y + (tam_y / 2) + 4);
}
if (num == 100) {
tft.setCursor((x + (tam_x / 3.8) + 2), y + (tam_y / 2) + 4);
}
tft.setTextColor(ILI9341_BLACK);
tft.print(num);
tft.print("%");
}
void alerta_nivel_bajo() {
// Serial.println("mirandoooo");
for (int i = 0; i < 6; i++) {
// Serial.print(porcentaje_nivel[i]);
// Serial.print(",");
if (porcentaje_nivel[i] <= 10) {
alarma[i] = true;
}
else {
alarma[i] = false;
}
delay(1);
}
// Serial.println(" ");
//recuento alarmas
int n_alarma = 0;
for (int i = 0; i < 6; i++) {
// Serial.print(alarma[i]);
// Serial.print(",");
if (alarma[i] == true) {
n_alarma ++;
}
delay(1);
}
// Serial.println(" ");
// comprobamos si hay alarmas
if (n_alarma >= 1) {
alarmaON = true;
}
else if (n_alarma == 0) {
alarmaON = false;
}
//Serial.println(n_alarma);
// Serial.println(alarmaON);
//llamamos a la rutina de alarma
//sonido_alarma();
}
void sonido_alarma() {
// Serial.println("ENTRAMOSSSSA SONIDO ");
// Activate the buzzer (produce sound)
if ((alarmaON == true) && (ModoCalib == false)) {
// Serial.println("alarma");
for (int h = 0; h <3; h++) {
for (int hh = 0; hh < 3; hh++) {
// Serial.println("PITIDO");
tone(buzzerPin, pitido); // You can adjust the f
delay(333);
noTone(buzzerPin); // You can adjust the f
delay(333);
}
delay(500);
}
alarmaON = false;
}
}
//void marcos() {
// tft.drawRect(0, 0, 320, 240, ILI9341_BLUE);
// tft.drawLine(0, 120, 320, 120, ILI9341_BLUE);
// tft.drawLine(106, 0, 106, 240, ILI9341_BLUE);
// tft.drawLine(212, 0, 212, 240, ILI9341_BLUE);
//}SOL. A1
SOL. B1
PH- 1
PH- 2
SOL. A2
SOL. B2
BTN MENU
BTN NEXT