//Incluir Librerias
#include <OneWire.h>
#include <DallasTemperature.h>
#define LED_BUILTIN 2
#define MAX_NUM_TASKS 10
#define TASK1_POLLRATE_MS 15UL //Solicitudes de trclas de usuario (CONSOLA)
#define TASK2_POLLRATE_MS 150UL //EJECUCION DE SECUENCIA AUTOMATICO
#define TASK3_POLLRATE_MS 300000UL //EJECUCION DE SECUENCIA DE RIEGO A INTERVALOS DE MODO AUTOMATICO.....5 min
#define TASK4_POLLRATE_MS 1000UL //MOSTRAR VALORES DE LOS SENSORE (EVALUAR)
/*
Constantes Globales ROM
*/
//Pines de salidas /ACTUADORES
const uint8_t ENA_Motor_Bomba_PIN=32; //Pin tipo GPIO que modula la potencia del motor Bomba por PWM(OUT1)
const uint8_t ENB_Motor_Ventilador_PIN=33; //Pin tipo GPIO que modula la potencia del Ventilador DC (OUT2)
const uint8_t IN1_Sentido=25; // Pin de control de sentido/Habilitacion del motor que modula ENA (OUT1) (solo puede ser L si se quiere habilitar)
// ........IN1 ya esta en H
const uint8_t RELAY_OUTPUT_PIN=26; //Pin tipo GPIO que va hacia el RELAY /modulo relay. Puede encender una carga AC(FOCO)
//Pines de entrada/SENSORES
const uint8_t ONE_WIRE_BUS=4; //Pin tipo GPIO (Bidireccional) que va hacia el sensor de temperatura DS18B20
const uint8_t LDR_PIN=35; //Pin tipo GPIO (Entrada) que viene desde el Modulo LDR (Se debe calibrar la perilla para saber : LUZ/OSCURIDAD)
//Constantes de trabajo
const int minDutyMotorBomb =0 ; //Limite Minimo Inferior del ciclaje PWM del motor Bomba
const int maxDutyMotorBomb= 230; //Limit MAXIMO Superior del ciclaje PWM del motor Bomba
const int minDutyMotorVentilador=0; //Limite Minimo Inferior del ciclaje PWM del VENTILADOR
const int maxDutyMotorVentilador=220; //Limit MAXIMO Superior del ciclaje PWM del VENTILADOR
const float temperaturaLimiteSuperior=28.0f; //Limite maximo supeior de la temperatura
const float temperaturaLimiteInferior=24.0f; //Limite minimo inferior de la temperatura
/*
Variables Globales RAM
*/
static uint32_t timePrev[MAX_NUM_TASKS]={0}; //Arreglo de Temporiacion de tiempos para tareas
static uint32_t initialRelativeTimeT0=0; //Variable de impresion de tiempo relativo
static uint8_t relayState = LOW ; //Variable que almacena el estado del RELAY
static uint8_t ledState = LOW ; //Variable que almacena el estado del RELAY
static bool estadoRiego=false; //Variavle que almacena el estado del riego
static bool autoMode=false; //Modo manual(false) /automatico(true) ??
static char byteIn = 0x00; //Variable para recepcionar data o bytes del puerto serie (Tecla presionada)
static bool showConsole=false; //Mostrar valores (de interes) en la consola de puerto serie ?
static int dutyMotorBomb= 0; //Ciclo de trabajo PWM del motor Bomba
static bool motorBombEnableStatus=false; //Estado del Motor Bomba (Habilitado/Deshabilitado)
static int dutyMotorVentilador=0; //Ciclo de trabajo PWM del ventilador
static int motorBombDutyDefault=180; //Valor por defecto (MODO AUTOMATICO) de la potencia del motor de BOMBEO.............puede cambiarse por consola
static int motorVentiladorDutyDefault=190; //Valor por defecto de la potencia del motor del VENTILADOR (MODO AUTOMATICO)
static float tempC; //Variable donde se va a guardar la temperatura
/*
Inicializacion de objetos de Librerias
*/
// Setup a oneWire instance to communicate with any OneWire devices (not just Maxim/Dallas temperature ICs)
OneWire oneWire(ONE_WIRE_BUS);
// Pass our oneWire reference to Dallas Temperature.
DallasTemperature sensors(&oneWire);
void setup() {
//Led por default como salida e inicialmente LOW
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, LOW);
//Establecer la frecuencia de Trabajo PWM...........similar al Arduono UNO
analogWriteFrequency(ENA_Motor_Bomba_PIN, 490);
analogWriteFrequency(ENB_Motor_Ventilador_PIN, 490);
//Pines del motor BOMBA ENx e INx como salidas digitales
pinMode(ENA_Motor_Bomba_PIN , OUTPUT);
pinMode(IN1_Sentido, OUTPUT);
digitalWrite(IN1_Sentido ,HIGH); //Deshabilitar Motor Bomba [OUT1]
analogWrite(ENA_Motor_Bomba_PIN, 0); //Iniciar el motor en apagado OFF (no gira)
//Pines del ventilador ENx como salida digital
pinMode(ENB_Motor_Ventilador_PIN, OUTPUT);
analogWrite(ENB_Motor_Ventilador_PIN, 0); //Iniciar el ventilador en apagado OFF (no gira)
//Pin del Modulo RELAY como salida e inicialmente LOW (no se debe accionar el frelay)
pinMode(RELAY_OUTPUT_PIN, OUTPUT);
digitalWrite(RELAY_OUTPUT_PIN, LOW);
//Pin del Modulo LDR como entrada
pinMode(LDR_PIN, INPUT);
//Iniciar sensor de Temmperatura: DS18B20
sensors.begin();
//Iniciar el puerto serie de consola a 9600 baudios
Serial.begin(9600);
//Mensaje de bienvenida
Serial.println("Hola Proyecto HIDROPONIA, desde ESP32-WROOM !!\r\n");
//Inicio de temproiacion relativa de tareas
TaskSchedulerTimeInit();
}
void loop() {
if(millis()>=(timePrev[1] + TASK1_POLLRATE_MS))
{
timePrev[1]=millis();
/*
Este segmento se ejecuta cada 'TASK1_POLLRATE_MS' Serial_Console_Get_Status(void)
*/
Serial_Console_Poll_In();
}
if(millis()>=(timePrev[2] + TASK2_POLLRATE_MS))
{
timePrev[2]=millis();
/*
Este segmento se ejecuta cada 'TASK2_POLLRATE_MS'
*/
SECUENCIA_Automatico();
}
if(millis()>=(timePrev[3] + TASK3_POLLRATE_MS))
{
timePrev[3]=millis();
/*
Este segmento se ejecuta cada 'TASK3_POLLRATE_MS'
*/
//Secuencia de riego periodica
SECUENCIA_Riego_Automatico();
}
if(millis()>=(timePrev[4] + TASK4_POLLRATE_MS))
{
timePrev[4]=millis();
/*
Este segmento se ejecuta cada 'TASK4_POLLRATE_MS'
*/
Mostrar_Valores_Sensores();
ALARMA_Temperatura_Muy_Baja();
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
/*
Subrutinas /funciones
*/
//Subrutina relativa al inicio del reloj de tiempo de arduino (millis)*/
void TaskSchedulerTimeInit(void){
//Iniciar millis.......Punto de partida de reloj de tiempo
for(uint8_t i=0; i<MAX_NUM_TASKS;i++){
timePrev[i] = millis();
}
}
uint32_t TaskGetRelativeTime_T0(void){
return initialRelativeTimeT0;
}
/*Sub Funciones relativa al modo: MANUAL/AUTOMATICO*/
void Mode_Auto_Manual_Toogle(void){
autoMode=!autoMode;
}
void Mode_Set_Manual(void){
autoMode=false;
}
void Mode_Set_Auto(void){
autoMode=true;
}
bool Mode_Auto_Manual_Get_Status(void){
return autoMode; // 0 : Manual, 1 Automatico
}
/*Sub-rutina que habilita/deshabilita que se muestren valores por consola
*/
void Serial_Console_Toogle(void){
showConsole=!showConsole; //Hace un toogle al valor de la consola
}
void Serial_Console_Show(void){
showConsole=true; //Fuerza que se muestre la consola
}
void Serial_Console_Hide(void){
showConsole=false; //Oculta la consola
}
bool Serial_Console_Get_Status(void){
return showConsole; //Retorna True si la consola se muestra o False si se oculta
}
/*Subrutina en relacion a las ALARMAS*/
void ALARMA_Temperatura_Muy_Baja(void){
if(Mode_Auto_Manual_Get_Status()==true){ //Solo si estamos en modo automatico
//Si la Temperatura es muy baja, poner a parpadear el LED incorporado
if(tempC<=(temperaturaLimiteInferior - 3.0f)){
Toogle_LED_BUILTIN(); //Hacer toogle al LED
}else{
Clear_LED_BUILTIN(); //ApGAR EL led
}
}
}
/*Subrutinas relativas a la muestra de la informacion de los sensores*/
void Mostrar_Valores_Sensores(void){
if(Serial_Console_Get_Status()){
sensors.requestTemperatures(); // Enviar comando para leer temperatura
tempC = sensors.getTempCByIndex(0);
Serial.print("Temperatura_[°C]:");
// Verificar si todo OK con el sensor
if(tempC != DEVICE_DISCONNECTED_C)
{
Serial.print(tempC);
}
else
{
Serial.print("ERROR");
}
Serial.print(",");
Serial.print("LDR_Valor:");
Serial.print(digitalRead(LDR_PIN)? "OSCURO":"LUZ");
Serial.print(",");
Serial.print("ESTADO_RIEGO:");
Serial.print(Get_Riego_Status()? "IRRIGANDOSE":"SIN_REGAR");
Serial.print(",");
Serial.print("VENTILADOR:");
Serial.print(Motor_Ventilador_Get_Duty_PWM()? "ENCENDIDO":"APAGADO");
Serial.print(",");
Serial.print("T_ms:");
Serial.println(millis() - TaskGetRelativeTime_T0()); //El Serial Plotter solo reconoce: "CRLF(\r\n)" (equivalente letra enter PC)
}
}
/*Subrutinas relativas a la ejecucion de la secuencia AUTOMATICO*/
void SECUENCIA_Riego_Automatico(void){
if(Mode_Auto_Manual_Get_Status()==true){ //Solo se se ha activado el modo AUTOMATICO
//if(tempC>=temperaturaLimiteSuperior){
//Re-establecer la marcha del motor bomba
//Motor_Bomba_Set_Duty_PWM(motorBombDutyDefault, true);
//}else{
//Colocar el motor BOMBA en estado OFF (apagar)
// Motor_Bomba_Set_Duty_PWM(0, false);
//}
//Conmutar el estado del riego
Toogle_EstadoRiego();
if(Get_Riego_Status()==true){
//Re-establecer la marcha del motor bomba
Motor_Bomba_Set_Duty_PWM(motorBombDutyDefault, true);
}else{
//Colocar el motor BOMBA en estado OFF (apagar)
Motor_Bomba_Set_Duty_PWM(0, false);
}
}////////////////////////////////////////////////////////////////
}
void SECUENCIA_Automatico(void){
if(Mode_Auto_Manual_Get_Status()==true){ //Solo se se ha activado el modo AUTOMATICO
//SENSOR DE TEMPERATURA DS18B20
if(tempC>=temperaturaLimiteSuperior){
/*
Si la Temperatura es mayor o igual que el limitesupeior???
*/
//Poner el ventilador a valor por defecto
Motor_Ventilador_Set_Duty_PWM(motorVentiladorDutyDefault);
}
if(tempC<=temperaturaLimiteInferior){
/*
Si la Temperatura baja el limite inferior??????
*/
//Poner en OFF el ventilador
Motor_Ventilador_Set_Duty_PWM(0);
}
//SENSOR DE LUZ LDR.................................Se debe calibrar su perilla
if(digitalRead(LDR_PIN)==LOW){
//Hay Luz, el foco se debe apagar
Clear_RELAY();
}else{
//No hay Luz, el foco se debe encender
Set_RELAY();
}
}///////////////////////////////////////////////////////////////
}
/*Sub-rutinas de poleo o lecutra constante de caracteres ASCII o teclas del puerto serial
*/
void Serial_Console_Poll_In(void){
if (Serial.available()){ //Evaluar si han llegado bytes al puerto.........COM
// capturamos la tecla presionada
byteIn = Serial.read(); //Leer el byte
/*
Evaluar la respuesta acorde tecla presionada,
Algunas teclas no haran efecto si se encuentra en modo automatico habilitado, osea si 'Mode_Auto_Manual_Get_Status()' ==true
*/
if(byteIn=='R' && !Mode_Auto_Manual_Get_Status()){
//Hacemos que el Relay conmute su valor
Toogle_RELAY();
//Notificar al usuario del cambio
Serial.print("ESTADO DEL FOCO: ");
Serial.println(Get_RELAY_Status()? "ENCENDIDO":"APAGADO");
}else if(byteIn=='W' && !Mode_Auto_Manual_Get_Status()){
//Hacemos que el duty de la bomba se incremente su valor en 10 (para poder ajustar flujo de agua)
dutyMotorBomb=dutyMotorBomb+20;
//Re-establecer la marcha del motor bomba
Motor_Bomba_Set_Duty_PWM(dutyMotorBomb, true);
//Mostrar por consola el valor actual del duty PWM...........Notificar al usuario
Serial.print("Motor Flow Bomb Duty PWM= ");
Serial.println(Motor_Bomba_Get_Duty_PWM(), DEC);
}else if(byteIn=='S' && !Mode_Auto_Manual_Get_Status()){
//Hacemos que el duty de la bomba se disminuya su valor en 10 (para poder ajustar flujo de agua)
dutyMotorBomb=dutyMotorBomb-20;
//Re-establecer la marcha del motor bomba
Motor_Bomba_Set_Duty_PWM(dutyMotorBomb, true);
//Mostrar por consola el valor actual del duty PWM...........Notificar al usuario
Serial.print("Motor Flow Bomb Duty PWM= ");
Serial.println(Motor_Bomba_Get_Duty_PWM(), DEC);
}else if(byteIn=='D'){ //FRENO DE EMERGENCIA contra rebalse de agua: MODO MANUAL O AUTOMATICO
//FRENO DE EMERGENCIA en caso rebalse el agua
//Colocar el motor BOMBA en estado OFF (apagar)
Motor_Bomba_Set_Duty_PWM(0, false);
//Poner en OFF el ventilador
Motor_Ventilador_Set_Duty_PWM(0);
//RE-establecer a modo manual
Mode_Set_Manual();
//Notificar al usuario
Serial.print("Motor BOMBA OFF(PWM= ");
Serial.print(Motor_Bomba_Get_Duty_PWM(), DEC);
Serial.print("Motor VENTILADOR OFF(PWM= ");
Serial.print(Motor_Ventilador_Get_Duty_PWM(), DEC);
Serial.print("), MODE: ");
Serial.println(Mode_Auto_Manual_Get_Status()? "AUTO":"MANUAL");
}else if(byteIn=='Q' && !Mode_Auto_Manual_Get_Status()){
//Hacemos que el duty PWM del ventilador aumente
dutyMotorVentilador=dutyMotorVentilador+50;
Motor_Ventilador_Set_Duty_PWM(dutyMotorVentilador);
//Notificar al usuario
Serial.print("Motor VENTILADOR PWM= ");
Serial.println(Motor_Ventilador_Get_Duty_PWM(), DEC);
}else if(byteIn=='A' && !Mode_Auto_Manual_Get_Status()){
//Hacemos que el duty PWM del ventilador disminuy
dutyMotorVentilador=dutyMotorVentilador-20;
Motor_Ventilador_Set_Duty_PWM(dutyMotorVentilador);
//Notificar al usuario
Serial.print("Motor VENTILADOR PWM= ");
Serial.println(Motor_Ventilador_Get_Duty_PWM(), DEC);
}else if(byteIn=='c' && !Mode_Auto_Manual_Get_Status()){
//Habilita/Deshabilita se muestren valores por consola, solo en modo manual
Serial_Console_Toogle();
initialRelativeTimeT0 = millis(); //Cuenta iniical del dT de adquisuion
//Notifica al usuario del cambio
Serial.println(Serial_Console_Get_Status()? "\r\rOK Console ON":"\r\nOK Console OFF");
}else if(byteIn=='C' && !Mode_Auto_Manual_Get_Status()){
/*
Copiar los valores en variables locales
*/
motorBombDutyDefault=dutyMotorBomb;
motorVentiladorDutyDefault=dutyMotorVentilador;
//Notificar al usuario
Serial.println("Valores de Trabajo copiados(para modo AUTO) !!");
Serial.print("Motor BOMB PWM Default: ");
Serial.println(motorBombDutyDefault, DEC);
Serial.print("Motor VENTILADOR PWM Default: ");
Serial.println(motorVentiladorDutyDefault, DEC);
}else if(byteIn=='M'){
/*
ACTIVAR/DESACTIVAR LA SECUENCIA DE MODO AUTOMATICO
*/
Mode_Auto_Manual_Toogle();
//Notificar al usuario
if(Mode_Auto_Manual_Get_Status()==true) // modo automatico (1) habilitado
{
Serial_Console_Show(); //Habilita la consola de datos
initialRelativeTimeT0 = millis(); //Cuenta iniical del dT de adquisuion
Serial.println("OK AUTO MODE Enabled");
}else{
Serial_Console_Hide(); //Habilita la consola de datos
Serial.println("OK MANUAL MODE Enabled"); //si la variable es false
}
}else if(byteIn=='p'){
/*Preguntar por los parametros operativos: */
//Retorna el valor de duty................BOMBA
Serial.print("Actual Motor BOMB Duty PWM?= ");
Serial.print(Motor_Bomba_Get_Duty_PWM(),DEC);
//Retorna el valor Def del duty (el que va a usar en modo automatico)
Serial.print(" ,Motor DUTY PWM DEF?= ");
Serial.print(motorBombDutyDefault, DEC);
//Retorna el valor de duty................VENTILADOR
Serial.print(" ,Actual Motor VENTILADOR Duty PWM?= ");
Serial.print(Motor_Ventilador_Get_Duty_PWM(),DEC);
//Retorna el valor Def del duty (el que va a usar en modo automatico)
Serial.print(" ,Motor DUTY VENTILADOR PWM DEF?= ");
Serial.print(motorVentiladorDutyDefault, DEC);
//Mostrar el estado actual del foco RELAY
Serial.print(" ,ESTADO DEL FOCO-RELAY?= ");
Serial.println(Get_RELAY_Status()? "ENCENDIDO":"APAGADO");
//Retorna el valor de los limites de temperatura
Serial.print(" ,Temperatura Valor INFERIOR?= ");
Serial.print(temperaturaLimiteInferior, 2);
Serial.print(" ,Temperatura Valor SUPERIOR?= ");
Serial.print(temperaturaLimiteSuperior, 2);
//Retorna el modo AUTO/MANUAL
Serial.print(" ,MODE?= ");
//Imprime que MODO se encuentra
if(Mode_Auto_Manual_Get_Status()==true) Serial.println("AUTO");
else Serial.println("MANUAL");
}
}
}
/*Sub-funciones relativas al giro de los motores DC*/
void Motor_Bomba_Set_Duty_PWM(const int dutyMotorPWM, const bool enableMotor){
int _localDutyMotor=dutyMotorPWM;
if(_localDutyMotor>=maxDutyMotorBomb) _localDutyMotor=maxDutyMotorBomb; //Truncar el valor del duty PWM (Maximo)
if(_localDutyMotor<=minDutyMotorBomb) _localDutyMotor=minDutyMotorBomb; //Truncar el valor del duty PWM (Minimo)
//Re-(Des) Habilitar el Motor
if(enableMotor==true) digitalWrite(IN1_Sentido ,LOW); //Habilitar Motor Bomba [OUT1] (IN1 ya es HIGH por cable)
else digitalWrite(IN1_Sentido ,HIGH);//Deshabilitar Motor Bomba [OUT1] (IN1 ya es HIGH por cable)
//Actualizar valor de PWM
analogWrite(ENA_Motor_Bomba_PIN , _localDutyMotor);
dutyMotorBomb=_localDutyMotor; //Guardar el PWM seteado en variable GlobalW
motorBombEnableStatus=enableMotor; //Guardar el estado ENABLE en variable Global
}
int Motor_Bomba_Get_Duty_PWM(void){
return dutyMotorBomb;
}
/*Sub-funciones relativas al giro del ventilador DC*/
void Motor_Ventilador_Set_Duty_PWM(const int dutyMotorPWM){
int _localDutyMotor=dutyMotorPWM;
if(_localDutyMotor<=minDutyMotorVentilador) _localDutyMotor=minDutyMotorVentilador;
if(_localDutyMotor>=maxDutyMotorVentilador) _localDutyMotor=maxDutyMotorVentilador;
//Actualizar valor de PWM
analogWrite(ENB_Motor_Ventilador_PIN, _localDutyMotor);
dutyMotorVentilador=_localDutyMotor; //Guardar el PWM seteado en variable Global
}
int Motor_Ventilador_Get_Duty_PWM(void){
return dutyMotorVentilador;
}
/*Sub-funciones relativas al estado y/o habilitacion del relay*/
bool Get_RELAY_Status(void){
return relayState;
}
void Toogle_RELAY(void){
//Conmutar el estado del RELAY (puede accionar cargas)
relayState=!relayState;
digitalWrite(RELAY_OUTPUT_PIN, relayState);
}
void Set_RELAY(void){
relayState=HIGH;
digitalWrite(RELAY_OUTPUT_PIN, relayState);
}
void Clear_RELAY(void){
relayState=LOW;
digitalWrite(RELAY_OUTPUT_PIN, relayState);
}
/*Sub-funciones relativas al estado y/o habilitacion del LED incorporado en placa*/
bool Get_LED_BUILTIN_Status(void){
return ledState;
}
void Toogle_LED_BUILTIN(void){
//Conmutar el estado del RELAY (puede accionar cargas)
ledState=!ledState;
digitalWrite(LED_BUILTIN, ledState);
}
void Clear_LED_BUILTIN(void){
//APAGAR LED
ledState=LOW;
digitalWrite(LED_BUILTIN, ledState);
}
/*Subfunciones reñativas a la activacion/desactivacion del estado de riego*/
bool Get_Riego_Status(void){
return estadoRiego;
}
void Toogle_EstadoRiego(void){
estadoRiego=!estadoRiego;
}