#include <LiquidCrystal_I2C.h>
#include <Key.h>
#include <Keypad.h>
#include <string.h>
#include "Wire.h"
// este script es escrito con asistencia de ia
/*Arduino mega 2560
Conexionado// por defecto los pines se configuran como entradas
pines:
4 sensor infrarrojo
*/
// #define OFF 0
// #define ON 1
//VARIABLES FISICAS DE TRABAJO
long tiempoInicial = 0;
long tiempoCompuertaInicial = 0;
bool seEmpujaJabon = false;
byte jabonIndice = -1;
const int TIEMP_LECTURA_ETIQUETA = 2000;
const int TIEMPO_DE_APERTURA_COMPUERTA = 1000;
const int TIEMPO_DE_RECORRIDO_ACTUADOR = 2000;
const int TIEMPO_CAIDA_JABON = 500;
const int TIEMPO_COMPUERTA_ABIERTA_TOTAL = 2 * TIEMPO_DE_APERTURA_COMPUERTA + TIEMPO_DE_RECORRIDO_ACTUADOR + TIEMPO_CAIDA_JABON;
const int TIEMPO_DURACION_PULSO_BUS = 100;
const int LECTURA_HUMEDAD_MAXIMA = 500;
const int LECTURA_TEMPERATURA_MAXIMA = 500;
int cajaSeleccionada = -1;
byte huecos = 0;
const int LLAVE_ABIERTA = LOW;
const int LLAVE_CERRADA = HIGH;
//ESTADOS DE FUNCIONAMIENTO========================================================================
enum Estado {
//ESTADOS DE ENCENDIDO
ESTADO_INICIO, //0,
ESTADO_ESPERANDO_OPERARIO, //1
//ESTADOS DE TRABAJO
ESTADO_COMPROBANDO_ESTADO_GENERAL, //2
/*Se comprueva el estado de:
las condiciones de mantenimiento
las compuertas todas cerradas
las condiciones ambientales correctas
los retenedores de cajas no se hayan pulsado
*/
ESTADO_LLAMANDO_JABON, //3 // ESTADO: OK-> PASA A LEYENDO_JABON
ESTADO_LEYENDO_JABON, //4 // ESTADO: OK-> PASA A ABRIENDO_COMPUERTA
ESTADO_ABRIENDO_COMPUERTA, //5 // ESTADO: OK-> PASA A EMPUJANDO_JABON
ESTADO_EMPUJANDO_JABON, //6 // ESTADO: OK-> PASA A CERRANDO_COMPUERTAS
ESTADO_CERRANDO_COMPUERTA, //7 // ESTADO: OK-> PASA A COMPROBANDO ESTADO GENERAL
//ESTADOS DE INTERRUPCION DEL TRABAJO
ESTADO_SOLTANDO_CAJAS, //8 //Soltando la caja de jabones, mostrar por pantalla el tipo y la cantidad de jabones soltados
ESTADO_RECOLOCANDO_CAJAS, //9 //Vuelve a iniciar el trabajo, reiniciar el contador de jabones
ESTADO_CONDICIONES_AMBIENTALES_INAPROPIADAS, //10 //se detiene el proceso mientras las condiciones ambientalees son inapropiadas
/*mostrar datos por pantalla, y enviar por puerto serial*/
ESTADO_EMERGENCIA, //11 //SE REQUIERE RECORDAR EL ESTADO EN EL QUE ESTABA ANTES
ESTADO_ALARMA, //12 // CONDICION: OK-> PASA A COMPROBANDO_ESTADO_GENERAL
ESTADO_MANTENIMIENTO, //13 // CONDICION CORRECTA: -> Pasa a inicio
};
Estado estadoActual = ESTADO_INICIO;
Estado estadoAnterior = ESTADO_INICIO;
//PROPIEDADES DE FUNCIONAMIENTO
bool climatizadorEstado = false;
//VARIABLES DE FUNCIONAMIENTO======================================================================
// CATEGORIA DE JABONES----------------------------------------------
struct jabon {
String nombre;
byte cantidad;
};
jabon JABONES[] = {
{ "CREMOSO", 0 }, //0
{ "LIMON", 0 }, //1
{ "GLICERINA", 0 }, //2
{ "ANTIBACTERIAL", 0 }, //3
{ "DEFECTUOSO", 0 }, //4
};
const byte JABONES_TIPOS_CANT = sizeof(JABONES) / sizeof(JABONES[0]);
//Categoria Alarmas--------------------------------------------------------------------------------
enum AlarmaNombre {
ALARMA_EMERGENCIA,
ALARMA_HUECOS_MAXIMOS_ALCANZADOS, // se envia 1 pulso
ALARMA_ERROR_COMPUERTAS, //se envian 1 pulso
ALARMA_MANTENIMIENTO, // se envian 3 pulsos
};
class Alarma {
private:
AlarmaNombre nombre;
bool estado;
int clave;
int pulsosDelTren;
public:
Alarma() {}
Alarma(AlarmaNombre _nombre, bool _estado, int _clave, int _pulsosDelTren) {
nombre = _nombre;
estado = _estado;
clave = _clave;
pulsosDelTren = _pulsosDelTren;
}
AlarmaNombre getNombre() {
return nombre;
}
void begin(){};
bool getEstado() {
return estado;
}
void activar() {
estado = true;
}
void desactivar() {
estado = false;
}
int getClave() {
return clave;
}
int getPulsosDelTren() {
return pulsosDelTren;
}
};
Alarma LISTA_ALARMAS[] = {
Alarma(ALARMA_EMERGENCIA, false, 0000, 101),
Alarma(ALARMA_HUECOS_MAXIMOS_ALCANZADOS, false, 1111, 201),
Alarma(ALARMA_ERROR_COMPUERTAS, false, 2222, 301),
Alarma(ALARMA_MANTENIMIENTO, false, 3333, 401),
};
Alarma alarmaActual;
//SEÑALES ENVIADAS POR EL BUS DE DATOS-------------------------------------------------------------
const byte BUS_MENSAJES[8][3] = {
{ 1, 1, 1 }, //0 ESPERANDO
{ 1, 1, 0 }, //1 cinta transportadora
{ 1, 0, 1 }, //2 empujador
{ 1, 0, 0 }, //4 climatizador
{ 0, 1, 1 }, //3 alarma
{ 0, 1, 0 }, //5 MARCHA
{ 0, 0, 1 }, //6 CONTRAMARCHA
{ 0, 0, 0 }, //7 EMERGENCIA
};
/*como la señal es activa baja se debe usar 0 para activo y 1 para inactivo*/
const byte BUS_MENSAJES_CANTIAD = 8;
const byte BUS_MENSAJE_EMERGENCIA[3] = {
BUS_MENSAJES[6][0],
BUS_MENSAJES[6][1],
BUS_MENSAJES[6][2],
};
enum ActuadorNombre {
MENSAJE_ESPERANDO,
MENSAJE_CINTA_TRANSPORTADORA,
MENSAJE_EMPUJADOR,
MENSAJE_CLIMATIZADOR,
MENSAJE_ALARMA,
MENSAJE_MARCHA,
MENSAJE_CONTRAMARCHA,
MENSAJE_EMERGENCIA,
};
class BusDeDatos {
private:
byte lineas[3];
byte lineaTren;
const byte codigoMensajeBus[8][3] = {
{ 1, 1, 1 },
{ 1, 1, 0 },
{ 1, 0, 1 },
{ 1, 0, 0 },
{ 0, 1, 1 },
{ 0, 1, 0 },
{ 0, 0, 1 },
{ 0, 0, 0 }
};
public:
BusDeDatos(byte i1, byte i2, byte ib, byte ic) {
lineas[0] = i1;
lineas[1] = i2;
lineas[2] = ib;
lineaTren = ic;
}
void begin() {
for (byte i = 0; i < 3; i++) {
pinMode(lineas[i], OUTPUT);
}
pinMode(lineaTren, OUTPUT);
ponerBusEnEspera();
}
void ponerBusEnEspera() {
for (byte i = 0; i < 3; i++) {
digitalWrite(lineas[i], codigoMensajeBus[MENSAJE_ESPERANDO][i]);
digitalWrite(lineaTren, codigoMensajeBus[MENSAJE_ESPERANDO][i]);
};
}
void ponerBusEnEstado(ActuadorNombre mensaje) {
String estadoPines = "";
for (byte i = 0; i < 3; i++) {
byte valorLinea = BUS_MENSAJES[mensaje][i];
digitalWrite(lineas[i], codigoMensajeBus[mensaje][i]);
estadoPines += String(valorLinea) + String(" | ");
};
Serial.println("BUS_PINES_ESTADO: " + String(estadoPines));
Serial.println(estadoPines);
Serial.println(String(mensaje));
}
void enviarPulsoPorBus(ActuadorNombre mensaje) {
static long tiempoInicial = millis();
bool enviandoPulso = millis() - tiempoInicial < TIEMPO_DURACION_PULSO_BUS;
if (!enviandoPulso) {
ponerBusEnEstado(mensaje);
} else {
ponerBusEnEspera();
};
}
void ponerBusEnEmergencia() {
static long tiempoInicial = millis();
}
void enviarTrenDePulsos(int pulsosCantidad) {
// [[COMENTARIO]]: Si por cada pulso del tren de pulsos hay que esperar 100 milisegundos (TIEMPO_DURACION_PULSO_BUS).
// Entonces si hay que mandar 100 pulsos en total, el programa se va demorar 10 segundos en enviar esos
// 100 pulsos
/*[[RESPUESTA]]: el TIEMPO_DURACION_PULSO_BUS es un tiempo necesario para que el rele lea el pulso, se puede reducir, pero para asegurarnos que se lea el pulso y como no mandamos mas de 4 usamos ese tiempo*/
// [[ERROR SOLUCIONADO]] Esto va a dar siempre false porque tiempoInicial es igual a millis() siempre, entonces el resultado es 0
// La solucion es restarle TIEMPO_DURACION_PULSO_BUS a tiempo inicial
/*[[RESPUESTA]]: corregido con el calculo correcto, era una version anterior del codigo*/
static long tiempoInicialDePulso = millis();
bool enviandoPulso = millis() - tiempoInicialDePulso < TIEMPO_DURACION_PULSO_BUS;
static int contadorPulsos = 0;
Serial.print("ENVIANDO_TREN_DE_PULSOS ");
Serial.println(pulsosCantidad);
if (pulsosCantidad > 0) {
if (contadorPulsos <= pulsosCantidad) {
if (!enviandoPulso) {
digitalWrite(lineaTren, HIGH);
tiempoInicialDePulso = millis();
contadorPulsos++;
}
} else {
Serial.println("tren de pulsos enviado");
}
}
}
};
struct Actuador {
ActuadorNombre nombre;
bool activo;
int pulsos;
};
Actuador LISTA_ACTUADORES_BUS[] = {
{ MENSAJE_ESPERANDO, false, 101 }, //0
{ MENSAJE_CINTA_TRANSPORTADORA, false, 202 }, //1
{ MENSAJE_EMPUJADOR, false, 303 }, //2
{ MENSAJE_CLIMATIZADOR, false, 404 }, //3
{ MENSAJE_ALARMA, false, 505 }, //4
{ MENSAJE_MARCHA, false, 606 }, //5
{ MENSAJE_CONTRAMARCHA, false, 707 }, //6
{ MENSAJE_EMERGENCIA, false, 808 }, //7
};
//TECLADO------------------------------------------------------------------------------------------
const byte FILAS = 4; // cantidad de filas del teclado matricial
const byte COLUMNAS = 4; // cantidad de columnas del teclado matricial
char keys[FILAS][COLUMNAS] = { //definicion de los botones del teclado matricial 4x4
{ '1', '2', '3', 'A' },
{ '4', '5', '6', 'B' },
{ '7', '8', '9', 'C' },
{ '*', '0', '#', 'D' }
};
//DECLARACION DE PINES====================================================================================================================
//ENTRADAS=========================================================================================
class PinEntrada {
private:
const byte pin;
int estado;
const bool esAnalogico;
public:
PinEntrada(byte _pin, bool _esAnalogico = false)
: pin(_pin), esAnalogico(_esAnalogico), estado(0) {
}
void begin() {
pinMode(pin, INPUT);
};
byte getPin() {
return pin;
};
int getEstado() {
return estado;
};
int leerPin() {
if (esAnalogico) {
estado = analogRead(pin);
return estado;
} else {
estado = digitalRead(pin);
return estado;
}
}
void actualizarEstado() {
estado = leerPin();
}
};
//EMERGENCIA
PinEntrada STOP(2); //ACTIVO ALTO
//SENSORES
PinEntrada SENSOR_INFRARROJO(4); //ACTIVO BAJO
//SENSORES AMBIENTALES
PinEntrada SENSOR_HUMEDAD(A0, true);
PinEntrada SENSOR_TEMPERATURA(A1, true);
//LLAVES SELECTORA PARA SOLTAR CAJAS
PinEntrada LLAVES_SOLTAR_CAJAS[] = {
{ 30 }, //pulsador soltador 0
{ 32 }, //pulsador soltador 1
{ 34 }, //pulsador soltador 2
{ 36 }, //pulsador soltador 3
{ 38 }, //pulsador soltador 4
};
const byte LLAVES_SOLTAR_CAJAS_CANT = sizeof(LLAVES_SOLTAR_CAJAS) / sizeof(LLAVES_SOLTAR_CAJAS[0]); // cantidad de llaves para soltar las cajas
// SENSORES DE COMPUERTAS
PinEntrada SENSORES_COMPUERTAS[] = {
{ 31 }, //0
{ 33 }, //1
{ 35 }, //2
{ 37 }, //3
{ 39 }, //4
};
byte SENSORES_COMPUERTAS_CANTIDAD = sizeof(SENSORES_COMPUERTAS) / sizeof(SENSORES_COMPUERTAS[0]);
PinEntrada* LISTA_ENTRADAS[] = {
&STOP,
&SENSOR_INFRARROJO,
&SENSOR_HUMEDAD,
&SENSOR_TEMPERATURA,
&LLAVES_SOLTAR_CAJAS[0],
&LLAVES_SOLTAR_CAJAS[1],
&LLAVES_SOLTAR_CAJAS[2],
&LLAVES_SOLTAR_CAJAS[3],
&LLAVES_SOLTAR_CAJAS[4],
};
byte LISTA_ENTRADAS_CANTIDAD = sizeof(LISTA_ENTRADAS) / sizeof(LISTA_ENTRADAS[0]);
//SALIDAS==========================================================================================
class PinSalida {
private:
const byte pin;
byte estado;
public:
PinSalida(byte _pin, byte _estado)
: pin(_pin), estado(_estado){};
void begin() {
pinMode(pin, OUTPUT);
Serial.println(String(pin) + " | " + String(estado));
}
byte getPin() {
return pin;
};
byte getEstado() {
return estado;
}
void activar() {
digitalWrite(pin, HIGH);
estado = HIGH;
Serial.println(String(pin) + " | " + String(estado));
}
void desactivar() {
digitalWrite(pin, LOW);
estado = LOW;
Serial.println(String(pin) + " | " + String(estado));
}
};
// COMPUERTAS
PinSalida COMPUERTAS[] = {
{ 40, LOW }, //actuador compuerta 0
{ 41, LOW }, //actuador compuerta 1
{ 42, LOW }, //actuador compuerta 2
{ 43, LOW }, //actuador compuerta 3
{ 44, LOW }, //actuador compuerta 4
};
byte COMPUERTAS_CANTIDAD = sizeof(COMPUERTAS) / sizeof(COMPUERTAS[0]);
// SEGUROS DE CAJAS
PinSalida RETENEDORES_CAJAS[] = {
{ 45, LOW }, //seguro caja 0
{ 46, LOW }, //seguro caja 1
{ 48, LOW }, //seguro caja 2
{ 50, LOW }, //seguro caja 3
{ 52, LOW }, //seguro caja 4
};
const byte RETENEDORES_CAJAS_CANTIDAD = sizeof(RETENEDORES_CAJAS) / sizeof(RETENEDORES_CAJAS[0]);
PinSalida* LISTA_SALIDAS[] = {
&COMPUERTAS[0],
&COMPUERTAS[1],
&COMPUERTAS[2],
&COMPUERTAS[3],
&COMPUERTAS[4],
&RETENEDORES_CAJAS[0],
&RETENEDORES_CAJAS[1],
&RETENEDORES_CAJAS[2],
&RETENEDORES_CAJAS[3],
&RETENEDORES_CAJAS[4],
};
byte LISTA_SALIDAS_CANTIDAD = sizeof(LISTA_ENTRADAS) / sizeof(LISTA_ENTRADAS[0]);
//=================================================================================================
//BUS DE DATOS=====================================================================================
PinSalida BUS[]{
{ 47, HIGH }, //LINEA 0 -> I1
{ 49, HIGH }, //LINEA 1 -> I2
{ 51, HIGH }, //LINEA 2 -> IB
};
const byte BUS_LINEAS_CANTIDAD = sizeof(BUS) / sizeof(BUS[0]);
//LINEA DEL BUS DE COMUNICACION POR TREN DE DATOS
PinSalida BUS_TREN{ 53, HIGH }; //LINEA 3 -> IC
//===================================================================================================
//PINES auxiliares-------------------------------------
byte PINES_FILAS[FILAS] = { 22, 24, 26, 28 };
byte PINES_COLUMNAS[COLUMNAS] = { 23, 25, 27, 29 };
//teclado 4x4 matricial - instanciado con la clase NewKeypad
Keypad teclado = Keypad(makeKeymap(keys), PINES_FILAS, PINES_COLUMNAS, FILAS, COLUMNAS);
//pantalla lcd - Conectar mediante I2C, dirección predeterminada: 0 (A0-A2 sin puentear, o SDA CCL)
LiquidCrystal_I2C pantalla(0x27, 16, 2);
//INSTANCIAS DE CLASE==============================================================================
BusDeDatos bus(47, 49, 51, 53);
Alarma alarma;
//UTILIDADES=======================================================================================
String stringParaEstado(Estado estado) {
switch (estado) {
case ESTADO_INICIO:
return "ESTADO_INICIO";
case ESTADO_ESPERANDO_OPERARIO:
return "ESTADO_ESPERANDO_OPERARIO";
case ESTADO_COMPROBANDO_ESTADO_GENERAL:
return "ESTADO_COMPROBANDO_ESTADO_GENERAL";
case ESTADO_LLAMANDO_JABON:
return "ESTADO_LLAMANDO_JABON";
case ESTADO_LEYENDO_JABON:
return "ESTADO_LEYENDO_JABON";
case ESTADO_ABRIENDO_COMPUERTA:
return "ESTADO_ABRIENDO_COMPUERTA";
case ESTADO_EMPUJANDO_JABON:
return "ESTADO_EMPUJANDO_JABON";
case ESTADO_CERRANDO_COMPUERTA:
return "ESTADO_CERRANDO_COMPUERTA";
case ESTADO_SOLTANDO_CAJAS:
return "ESTADO_SOLTANDO_CAJAS";
case ESTADO_RECOLOCANDO_CAJAS:
return "ESTADO_RECOLOCANDO_CAJAS";
case ESTADO_CONDICIONES_AMBIENTALES_INAPROPIADAS:
return "ESTADO_CONDICIONES_AMBIENTALES_INAPROPIADAS";
case ESTADO_EMERGENCIA:
return "ESTADO_EMERGENCIA";
case ESTADO_ALARMA:
return "ESTADO_ALARMA";
case ESTADO_MANTENIMIENTO:
return "ESTADO_MANTENIMIENTO";
default:
return "estado desconocido...";
}
}
//PROCEDIMIENTOS===================================================================================
/**/
void iniciarProcesos() {
//instanciado del tiempo inicial de procesamiento
tiempoInicial = millis();
cambiarEstado(ESTADO_ESPERANDO_OPERARIO);
};
/*Se reinicia la caja seleccionada, con el contador de jabones a cero,
se reinicia el bucle de trabajao reiniciando el estado a COMPROBANDO_ESTADO_GENERAL*/
void reiniciarJabon(int jabonIndice = -1) {
if (jabonIndice == -1) {
for (byte i = 0; i < JABONES_TIPOS_CANT; i++) { JABONES[i].cantidad = 0; }
} else {
JABONES[jabonIndice].cantidad = 0;
}
};
/**/
void mostrarPorPantalla(String linea1, String linea2) {
pantalla.clear();
pantalla.setCursor(0, 0);
pantalla.print(linea1);
pantalla.setCursor(0, 1);
pantalla.print(linea2);
Serial.println("PANTALLA: | " + linea1 + " | " + linea2);
};
/**/
void cambiarEstado(Estado nuevo) {
estadoAnterior = estadoActual;
estadoActual = nuevo;
Serial.print("pasando de estado: | ");
Serial.print(stringParaEstado(estadoAnterior));
Serial.print(" | a estado: |");
Serial.println(stringParaEstado(estadoActual));
};
bool esperarConfirmacionOperario(char teclaContinuar) {
char tecla = teclado.getKey();
if (tecla == teclaContinuar) {
Serial.println("CONTINUANDO");
pantalla.clear();
return true;
} else {
return false;
};
};
/*Se espera a que el operario oprima la tecla C del teclado matricial*/
void leerJabon() {
static long tiempoInicialDeLectura = millis();
bool isReadingLabel = millis() - tiempoInicialDeLectura < TIEMP_LECTURA_ETIQUETA;
if (SENSOR_INFRARROJO.leerPin() == HIGH) { //NO HAY JABOON El sensor es actibo bajo, cuando detecta jabon pone el pin en LOW
huecos++;
Serial.println("HUECO: " + String(huecos));
cambiarEstado(ESTADO_COMPROBANDO_ESTADO_GENERAL);
return;
} else if (!isReadingLabel) {
jabonIndice = random(0, JABONES_TIPOS_CANT);
tiempoInicialDeLectura = 0;
JABONES[jabonIndice].cantidad++;
Serial.println("JABON_TIPO: " + String(JABONES[jabonIndice].nombre));
abrirCompuerta(COMPUERTAS[jabonIndice]);
mostrarPorPantalla("Jabon:", String(JABONES[jabonIndice].nombre));
cambiarEstado(ESTADO_ABRIENDO_COMPUERTA);
return;
}
}; //devuelve un indice de la lista de jabones al azar
/**/
bool validarClave(int clave) {
static String entrada = "";
char tecla = teclado.getKey();
if (isDigit(tecla)) {
//la entrada es un numero
entrada += tecla;
mostrarPorPantalla("ALARMA: " + String(alarmaActual.getNombre()) + " | CLAVE:", entrada);
return false;
} else if ((tecla == 'A') && (clave == entrada.toInt())) {
//clave correcta ingresada
mostrarPorPantalla("contraceña", "CORRECTA");
tecla = NO_KEY;
entrada = "";
pantalla.clear();
return true;
} else if (tecla == 'D' && (entrada.length() > 0)) { // no es un numero y si es D y la entrada es mayor a 0 byts para evitar que se borre sobre nulo
//borrar ultima entrada
entrada.remove(entrada.length() - 1); // se elimina el ultimo elemento de la entrada
mostrarPorPantalla("ALARMA: " + String(alarmaActual.getNombre()) + " | CLAVE:", entrada);
return false;
};
};
//COMPROBACIONES-----------------------------------------------------------------------------------
/*
false -> condiciones MALAS
true -> condicion BUENAS
*/
bool comprobarCondicionesAmbientales() {
static long tiempoInicial = 0;
bool condicionesInapropiadas = true;
//lectura entre 0 y 100 % de humedad
int humedad = map(SENSOR_HUMEDAD.leerPin(), 0, 1023, 0, 100);
//lectura entre 0 a 100 °C
int temperatura = map(SENSOR_TEMPERATURA.leerPin(), 0, 1023, 0, 70);
//leerPinAnalogico(SENSOR_TEMPERATURA);
if ((humedad >= LECTURA_HUMEDAD_MAXIMA) || (temperatura >= LECTURA_TEMPERATURA_MAXIMA)) {
//condiciones inapropiadas
Serial.println("CONDICIONES_AMBIENTALES: T(°C)|H(%)");
Serial.println(" " + String(temperatura) + " | " + String(humedad));
return condicionesInapropiadas;
} else {
//condiciones apropiadas
Serial.println("CONDICIONES_AMBIENTALES_APROPIADAS");
return !condicionesInapropiadas;
}
};
/*
false -> condiciones MALAS
true -> condicion BUENAS
*/
bool comprobarCondicionesMantenimiento() {
byte totalJabones = 0;
for (byte i = 0; i < JABONES_TIPOS_CANT; i++) { totalJabones += JABONES[i].cantidad; };
if ((totalJabones >= 10) || (millis() - tiempoInicial > 600000)) {
//condiciones inapropiadas
return true;
} else {
//condiciones apropiadas
return false;
};
};
/*
false -> condiciones MALAS | llave abierta: HIGH -> compuerta avierta
true -> condicion BUENAS | llave cerrada: LOW -> compuerta cerrada
*/
bool comprobarCompuertas() {
byte compuertasAbiertas = 0;
Serial.println("COMPROBANDO_COMPUERTAS");
for (byte i = 0; i < 5; i++) {
//HIGH cerrado | LOW abierto
if (SENSORES_COMPUERTAS[i].leerPin() == HIGH) {
compuertasAbiertas++;
Serial.println("COMPUERTA_ABIERTA: " + JABONES[i].nombre + " llaveCompuertaLectura: " + String(SENSORES_COMPUERTAS[i].leerPin()));
};
}
return !(compuertasAbiertas == 0);
};
/*
false -> condiciones MALAS | boton en HIGH
true -> condicion BUENAS | boton en LOW
*/
bool comprobarBotonEmergencia() {
if (STOP.leerPin() == HIGH) {
//Serial.println("STOP.leerPin()= " + String(STOP.leerPin()));
return false; //condiciones malas
} else {
//Serial.println("STOP.leerPin()= " + String(STOP.leerPin()));
return true; //condiciones buenas
}
};
//cuenta la cantidad de llaves seleccionadas, y si solo fue una, asigna el valor del indice a la variable global "cajaSeleccionada"
int cantidadLLavesRetenedorasActivadas() {
byte contador = 0;
byte llaveSeleccionada = -1;
Serial.println("COMPROBANDO_LLAVES_RETENEDORAS");
for (byte i = 0; i < LLAVES_SOLTAR_CAJAS_CANT; i++) {
if (LLAVES_SOLTAR_CAJAS[i].leerPin() == LLAVE_CERRADA) { //la llave esta activa (CONDICION ACTIVA ALTA)
contador++;
llaveSeleccionada = i;
}
}
if (contador > 1) {
Serial.println("CANTIDAD_CAJAS_SELECCIONADAS: " + String(contador));
} else {
Serial.println("CAJA_SELECCIONADA: " + String(JABONES[llaveSeleccionada].nombre));
cajaSeleccionada = llaveSeleccionada;
};
return contador;
};
//se comprueba que las llaves de los retenedores de las cajas esten desactivados
int cantidadDeCompuertasAbiertas() {
bool contador = 0;
for (byte i = 0; i < COMPUERTAS_CANTIDAD; i++) {
if (COMPUERTAS[i].getEstado() == HIGH) {
contador++;
Serial.println("COMPUERTA_AVIERTA: " + String(JABONES[i].nombre));
}
}
return contador;
}
//ESTADOS------------------------------------------------------------------------------------------
/*Cuando se llama esta funcion se comprueva si la alarma esta activada y si no se cambi su estado a activa.
Si esta activa se valida la clave, y si es correcta, se desactiva la alarmama y se cambia de estado segun corresponda */
void estadoDeAlarma() {
/*activar alarma actual*/
if (!alarmaActual.getEstado()) {
Serial.println("ACTIVANDO_ALARMA: " + String(alarmaActual.getNombre()));
bus.ponerBusEnEstado(MENSAJE_ALARMA);
bus.enviarTrenDePulsos(alarmaActual.getPulsosDelTren());
alarmaActual.activar();
} else if (validarClave(alarmaActual.getClave())) {
alarmaActual.desactivar();
bus.enviarPulsoPorBus(MENSAJE_ALARMA);
Serial.println("DESACTIVANDO_ALARMA: " + String(alarmaActual.getNombre()));
cambiarEstado(ESTADO_INICIO);
}
};
/**/
void estadoDeEmergencia() {
//se comprueva la contracña
if (!validarClave(MENSAJE_EMERGENCIA)) {
//si la contraceña es incorrecta y no se mando un mensaje por el actuador, se activa la emergencia
if (!LISTA_ACTUADORES_BUS[MENSAJE_EMERGENCIA].activo) {
//bloquear rele
bus.enviarPulsoPorBus(MENSAJE_EMERGENCIA);
LISTA_ACTUADORES_BUS[MENSAJE_EMERGENCIA].activo = true;
//desactivar los pines
for (byte i = 0; i < LISTA_SALIDAS_CANTIDAD; i++) { LISTA_SALIDAS[i]->desactivar(); };
//enviar señal al rele
bus.enviarPulsoPorBus(MENSAJE_ALARMA);
alarmaActual = LISTA_ALARMAS[ALARMA_EMERGENCIA];
//mostrar por pantalla
mostrarPorPantalla("EMERGENCIA", "");
}
} else {
//apagar estado de emergencia
bus.enviarPulsoPorBus(MENSAJE_EMERGENCIA);
LISTA_ACTUADORES_BUS[MENSAJE_EMERGENCIA].activo = false;
//desactivar la alarma
bus.enviarPulsoPorBus(MENSAJE_ALARMA);
cambiarEstado(ESTADO_INICIO);
// //continuar con el estado de inicio;
// estadoActual = estadoAnterior;
// estadoAnterior = ESTADO_EMERGENCIA;
}
};
/**/
void estadoLLamandoJabon() {
static long tiempoCintaTransportadora = millis();
// [[ERROR SOLUCIONADO]] Antes tiempoCintaTransportadora era siempre 0
// porque no se le estaba asignando millis() antes de chequear el if
bool cintaTransportadoraFuncionando = millis() - tiempoCintaTransportadora < 2000;
if (!cintaTransportadoraFuncionando) {
bus.enviarPulsoPorBus(MENSAJE_CINTA_TRANSPORTADORA);
tiempoCintaTransportadora = millis();
cambiarEstado(ESTADO_LEYENDO_JABON);
cintaTransportadoraFuncionando = millis();
}
}
//ACTIVACIONES-------------------------------------------------------------------------------------
void abrirCompuerta(PinSalida& compuerta) {
if (compuerta.getEstado() == LOW) {
compuerta.activar();
tiempoCompuertaInicial = millis();
Serial.println("ABRIENDO_COMPUERTA" + String(compuerta.getPin()) + " jabon: " + String(jabonIndice));
}
};
void cerrarCompuerta(PinSalida& compuerta) {
if (compuerta.getEstado() == HIGH && !seEmpujaJabon) {
compuerta.desactivar();
tiempoCompuertaInicial = 0;
Serial.println("CERRANDO_COMPUERTA: " + String(jabonIndice));
}
};
void soltarCajas(int cajaIndice) {
RETENEDORES_CAJAS[cajaIndice].activar();
jabon tipoSeleccionado = JABONES[cajaIndice];
mostrarPorPantalla(
String(tipoSeleccionado.nombre),
String(tipoSeleccionado.cantidad));
Serial.println("SOLTANDO_CAJA :" + String(tipoSeleccionado.nombre));
};
void activarActuadorPorBus(Actuador ACTUADOR) {
static long tiempoInicial = millis();
bool enviandoPulso = millis() - tiempoInicial < TIEMPO_DURACION_PULSO_BUS;
byte indice = ACTUADOR.nombre;
if (!enviandoPulso) {
if (!ACTUADOR.activo) {
// activo actuador
bus.enviarPulsoPorBus(ACTUADOR.nombre);
// pongo el estado en activo
ACTUADOR.activo = true;
// reinicio el tiempoInicial
tiempoInicial = 0;
} else {
//activar actuador
bus.enviarPulsoPorBus(ACTUADOR.nombre);
//pongo el estado en desactivado
ACTUADOR.activo = false;
//reiniciar el tiempoInicial
tiempoInicial = 0;
}
} else {
bus.ponerBusEnEspera();
}
};
//INICIO DEL PROGRAMA==============================================================================
void setup() {
//Instanciado de librerias-----------------------------------------
//funcion random(para la simulacion de la lectura del jabon)
randomSeed(millis());
//pantalla
pantalla.init();
pantalla.backlight();
//PUERTO SERIAL
Serial.begin(9600);
bus.begin();
alarma.begin();
//SALIDAS----------------------------------------------------------------------------------------
for (byte i = 0; i < LISTA_SALIDAS_CANTIDAD; i++) { LISTA_SALIDAS[i]->begin(); }
//ENTRADAS---------------------------------------------------------------------------------------
for (byte i = 0; i < LISTA_ENTRADAS_CANTIDAD; i++) { LISTA_ENTRADAS[i]->begin(); }
Serial.println("INICIO...");
}
//BUCLE DE TRABAJO=================================================================================
void loop() {
//se comprueba el estado del boton de emergencia; si es false se pasa a emergencia, ya que las condicion es mala.
if (!comprobarBotonEmergencia()) {
estadoActual = ESTADO_EMERGENCIA;
}
//SELECTOR DE ESTADO
switch (estadoActual) {
case ESTADO_INICIO:
{
iniciarProcesos();
mostrarPorPantalla("esperando", "CONT-> C");
};
break;
/**/
case ESTADO_ESPERANDO_OPERARIO:
{
if (esperarConfirmacionOperario('C')) {
Serial.println("E");
cambiarEstado(Estado::ESTADO_COMPROBANDO_ESTADO_GENERAL);
};
};
break;
/**/
//ESTADOS DE TRABAJO
case ESTADO_COMPROBANDO_ESTADO_GENERAL:
{
/*
false -> condiciones MALAS
true -> condicion BUENAS
*/
if (comprobarCondicionesMantenimiento()) {
cambiarEstado(ESTADO_ALARMA);
alarmaActual = LISTA_ALARMAS[ALARMA_MANTENIMIENTO];
return;
} else {
Serial.println("CONDICIONES_DE_MANTENIMIENTO_CORRECTAS");
};
if (comprobarCondicionesAmbientales()) {
//condiciones ambientales malas
cambiarEstado(ESTADO_CONDICIONES_AMBIENTALES_INAPROPIADAS);
return;
}
if (comprobarCompuertas()) {
//alguna compuerta avierta
mostrarPorPantalla("COMPUERTA_TRABADA: ", "cont C");
cambiarEstado(ESTADO_ESPERANDO_OPERARIO);
return;
} else {
Serial.println("COMPUERTA_CERRADAS");
};
switch (cantidadLLavesRetenedorasActivadas()) {
case 0:
{
cambiarEstado(ESTADO_LLAMANDO_JABON);
};
break;
case 1:
{
cambiarEstado(ESTADO_SOLTANDO_CAJAS);
};
break;
default:
{
Serial.println("ERROR: MAS_DE_UNA_COMPUERTA_SELECCIONADA");
mostrarPorPantalla("ERROR", ">2 elecciones");
cambiarEstado(ESTADO_ESPERANDO_OPERARIO);
return;
//error mas de uno o menos de cero compuertas seleccionadas
};
break;
};
//comprobando cantidad de huecos
if (huecos >= 3) {
alarmaActual = LISTA_ALARMAS[ALARMA_HUECOS_MAXIMOS_ALCANZADOS];
cambiarEstado(ESTADO_ALARMA);
Serial.println("HUECOS_MAXIMOS_ALCANZADOS: " + String(huecos));
mostrarPorPantalla("HUECOS", "ALARMA 1");
huecos = 0;
return;
}
};
break;
case ESTADO_LLAMANDO_JABON:
{
estadoLLamandoJabon();
};
break;
/*
comprueva el boton de parada de emergencia
se envia la señal por el bus de datos para mover la cinta transportadora
*/
case ESTADO_LEYENDO_JABON:
/*el jabon tiene que estar un segundo frente al lector e etiquetas*/
{
leerJabon();
tiempoCompuertaInicial = millis(); //tiempo inicial de apertura de la compuerta que corresponde al jabon seleccionado
};
break;
/* lee el jabon */
case ESTADO_ABRIENDO_COMPUERTA:
{
abrirCompuerta(COMPUERTAS[jabonIndice]);
cambiarEstado(ESTADO_EMPUJANDO_JABON);
// byte compuertasAbiertas = comprobarCompuertas();
// switch (compuertasAbiertas) {
// case 0:
// {
// //NO HAY COMPUERTAS ABIERTAS
// cambiarEstado(ESTADO_ALARMA);
// alarmaActual = LISTA_ALARMAS[ALARMA_ERROR_COMPUERTAS];
// Serial.println("NO_SE_ABRIO_COMPUERTA CANTIDAD_COMP_ABIERTAS: " + String(compuertasAbiertas));
// return;
// };
// break;
// case 1:
// { //CORRECTAMENTE
// abrirCompuerta(COMPUERTAS[jabonIndice]);
// };
// break;
// default:
// {
// Serial.println("ERROR_COMPUERTAS_AVIERTAS" + String(compuertasAbiertas));
// cambiarEstado(ESTADO_ALARMA);
// alarmaActual = LISTA_ALARMAS[ALARMA_ERROR_COMPUERTAS];
// return;
// };
// break;
//}
};
break;
/*ponerle un segundo de tiempo en que se abre la compuerta*/
/*ANTES DE EMPUJAR EL JABON COMPROBAR QUE NO HAY UNA COMPUERTA ABIERTA ERRONEA*/
case ESTADO_EMPUJANDO_JABON:
{
/**/
seEmpujaJabon = millis() - tiempoCompuertaInicial < TIEMPO_COMPUERTA_ABIERTA_TOTAL;
if (!seEmpujaJabon) {
if (LISTA_ACTUADORES_BUS[MENSAJE_EMPUJADOR].activo == false) {
if (cantidadDeCompuertasAbiertas() != 1) {
//alarma mas de una compuerta avierta
} else {
bus.enviarPulsoPorBus(MENSAJE_EMPUJADOR);
LISTA_ACTUADORES_BUS[MENSAJE_EMPUJADOR].activo = true;
Serial.println("ACTIVANDO_EMPUJADOR");
}
}
} else {
LISTA_ACTUADORES_BUS[MENSAJE_EMPUJADOR].activo = false;
cambiarEstado(ESTADO_CERRANDO_COMPUERTA);
}
};
break;
/**/
case ESTADO_CERRANDO_COMPUERTA:
{
cerrarCompuerta(COMPUERTAS[jabonIndice]);
};
break;
/*tarda un segundo en cerrar la compuerta*/
//REINICIAR EL CICLO DE TRABAJO-> LLAMANDO_JABON
//ESTADOS DE INTERRUPCION DEL TRABAJO
case ESTADO_SOLTANDO_CAJAS:
{
if (RETENEDORES_CAJAS[cajaSeleccionada].getEstado() == HIGH) {
//soltar cajas
soltarCajas(cajaSeleccionada);
Serial.println("SOLTANDO_CAJA: " + String(cajaSeleccionada));
mostrarPorPantalla(JABONES[cajaSeleccionada].nombre, "cant: " + String(JABONES[cajaSeleccionada].cantidad));
//reiniciarJabon(cajaSeleccionada);
reiniciarJabon(cajaSeleccionada);
}
};
break;
/**/
case ESTADO_RECOLOCANDO_CAJAS:
{
esperarConfirmacionOperario('C');
};
break;
/**/
//ALARMAS
case ESTADO_EMERGENCIA:
{ //enviar codigo por bus
//desactivar los actuadores
//activar alarma
estadoDeEmergencia();
};
break;
/**/
case ESTADO_ALARMA:
{
if (!alarmaActual.getEstado()) {
mostrarPorPantalla("ALARMA: " + String(alarmaActual.getNombre()) + " | CLAVE:", "");
}
estadoDeAlarma();
};
break;
case ESTADO_CONDICIONES_AMBIENTALES_INAPROPIADAS:
{
if (LISTA_ACTUADORES_BUS[MENSAJE_CLIMATIZADOR].activo == false) { //climeatizador apagado y malas condiciones ambientales
if (!comprobarCondicionesAmbientales()) {
//encender climatizador
bus.enviarPulsoPorBus(MENSAJE_CLIMATIZADOR);
LISTA_ACTUADORES_BUS[MENSAJE_CLIMATIZADOR].activo = true;
Serial.println("ENCENDIENDO_CLIMATIZADOR");
mostrarPorPantalla("COND. AMB. MALAS", "ENCEND CLIMAT");
}
} else if (comprobarCondicionesAmbientales()) { //climatizador encendido y buenas condiciones ambientales
//apagar climatizador
bus.enviarPulsoPorBus(MENSAJE_CLIMATIZADOR);
LISTA_ACTUADORES_BUS[MENSAJE_CLIMATIZADOR].activo = false;
Serial.println("APAGANDO_CLIMATIZADOR");
mostrarPorPantalla("APAGANDO", "CLIMATIZADOR");
cambiarEstado(ESTADO_LLAMANDO_JABON);
}
};
break;
};
}
linea 0 del bus de datos
linea 1 del bus de datos
linea 2 del bus de datos
linea 3 del bus de datos
(22,24,26,28): filas
(25,27,29,31): columnas
(47,49,51,53): bus de datos BLANCO
CONEXIONES DEL LED
de izq->der:
ROJO
CATODO
VERDE
AZUL
Entradas por sda y scl, (20,21)
CIRCUITO SEPARADORA DE JABONES
CARCASA DE LA MAQUINA (en la zona de trabajo)
TABLERO DE CONTROL PRINCIPAL
POSTE DE ALARMA
SONA DE LECTURA
SENSORES COMPUERTA
SENSOR DE HUMEDAD
A0
SENSOR de
precensia de
jabones
mostrar en pantalla los valores
SOLTAR CAJAS DE JABONES
CAJAS
0
1
2
3
4
switch 0 pin 30
switch 1 pin 32
switch 2 pin 34
switch 3 pin 36
switch 4 pin 38
compuertas
seguros
cajas
climatizador
PIN 2
SENSOR DE TEMPERATURA
A1
hayJabon