Bien, hace varios años, había armado un proyecto similar para controlar 4 relay por tiempo y las variantes de funciones de salida. En aquel momento lo había realizado en PBP y el pobre 16F877 estaba azul de lo que lo exprimí para poder meter toda la programación
Hace un tiempo, arranque a redactar un libro para autodidactas de programación de Arduino desde cero, y llegue a un punto en el que se me habían acabado las ideas de que proyectos subir a modo de ejemplo, así que tome una carpeta vieja de proyectos en PBP y me tome el trabajo de sacarme HUMO de la cabeza para poder pasar de un lenguaje a otro todo.... Sin los Gosub-Return y el modo en que trabaja el C a diferencia del Basic, la verdad que me llevo un tiempo acostumbrarme a tomar determinados hábitos para poder tener las mismas funciones... En este ejemplo simplificado, muestro como podemos hacer un relay controlado por tiempo implementando la librería "TimerONE.h", y la navegación de menú o funciones por medio del empleo de flags para indicar a donde ir, donde quedarse o a donde volver cuando tuve que saltar....
Si bien, se puede hacer un simple contador y comparar los valores de dos variables, hay que tener en cuenta que esta es la base / un extracto de otro proyecto de mas envergadura. Como verán, puede parecernos un poco extenso y engorroso, pero si prestamos atención a los comentarios del sketch, no es para nada complicado replicarlo y sumarle mas relay al controlador.... Les dejo una vista ampliada de como quedaría:
Ejemplo de un Control Temporizado de 4 canales con función de salida en Cascada, Secuencial y Paso a Paso:
Hace un tiempo, arranque a redactar un libro para autodidactas de programación de Arduino desde cero, y llegue a un punto en el que se me habían acabado las ideas de que proyectos subir a modo de ejemplo, así que tome una carpeta vieja de proyectos en PBP y me tome el trabajo de sacarme HUMO de la cabeza para poder pasar de un lenguaje a otro todo.... Sin los Gosub-Return y el modo en que trabaja el C a diferencia del Basic, la verdad que me llevo un tiempo acostumbrarme a tomar determinados hábitos para poder tener las mismas funciones... En este ejemplo simplificado, muestro como podemos hacer un relay controlado por tiempo implementando la librería "TimerONE.h", y la navegación de menú o funciones por medio del empleo de flags para indicar a donde ir, donde quedarse o a donde volver cuando tuve que saltar....
CSS:
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
#include "TimerOne.h"
#include "H_Config.h"
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4);
#include <EEPROM.h>
#include <Wire.h>
#define START_button 3 // boton inicio
#define STOP_button 4 // boton parada
#define CLEAR_button 5 // boton borrar
#define MAS_button 6 // boton mas
#define MENOS_button 7 // boton menos
#define ENTER_button 8 // entrada disparo auxiliar
//Definimos los puertos afectados a los Relay de control
int RELAY_1 = 10;
//Definimos las variables globales del programa
int banderaPROG;
int bandera_MPROG;
int banderaPROG_R1=0;
int bandera=0; //variable auxiliar
int BANDERA_R1=0;
int BANDERA_R1est=0;
int BANDERA_PARADA_R1 = 0;
int TICKS; //variable auxiliar para los for-next
int i; //variable auxiliar para los for-next
int setHOUR_R1=0; // variable set HORAS programadas
int setMINUTE_R1=0; // variable set minutos programadas
int setSECOND_R1=0;
int AsetHOUR_R1=0; // variable set HORAS programadas
int AsetMINUTE_R1=0; // variable set minutos programadas
int AsetSECOND_R1=0;
iint HOUR = 0; //variable HORAS cronometro
int MINUTE = 0; //variable Minutos cronometro
int SECOND= 0; //variable Segundos cronometro
//Variables afectadas al MENU
int menu = 1;
int modo = 0;
int listaMENU=0;
int listaMENU2=0;
int mode=0;
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void setup()
{
Timer1.initialize(1000000); // 1 segundo
Timer1.attachInterrupt(CONTADOR); // LLama a la funcion cuando se produce la interrupcion por timer
setHOUR_R1 =0; //valor inicial de la variable
setMINUTE_R1 =0; //valor inicial de la variable
setSECOND_R1 =0; //valor inicial de la variable
// Configuramos los puertos de ENTRADA
pinMode(START_button, INPUT_PULLUP); // Pin digital como entrada con conexión PULL-UP interna
pinMode(STOP_button, INPUT_PULLUP); // Pin digital como entrada con conexión PULL-UP interna
pinMode(CLEAR_button, INPUT_PULLUP); // Pin digital como entrada con conexión PULL-UP interna
pinMode(MAS_button, INPUT_PULLUP); // Pin digital como entrada con conexión PULL-UP interna
pinMode(MENOS_button, INPUT_PULLUP); // Pin digital como entrada con conexión PULL-UP interna
pinMode(ENTER_button, INPUT_PULLUP); // Pin digital como entrada con conexión PULL-UP interna
// Configuramos los puertos de SALIDA
pinMode(RELAY_1, OUTPUT);
// Configuramos el estado de los puertos de SALIDA en el momento de arranque
digitalWrite(RELAY_1,LOW); //Poner en bajo el relay (tiene logica negativa)
//Arrancamos con la pantalla de INICIO
lcd.init();
lcd.clear();
lcd.backlight();
lcd.setCursor(0,0);
lcd.print("--------------------");
lcd.setCursor(0,1);
lcd.print("Tempo PROGRAMABLE Vx");
lcd.setCursor(0,2);
lcd.print(" ETI Patagonia");
lcd.setCursor(0,3);
lcd.print("--------------------");
delay(900);
lcd.clear();
leerEEPROM();
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void loop()
{
modo = 0;
digitalWrite(RELAY_1,LOW);
lcd.setCursor(0,0);
lcd.print("-MENU---------------");
lcd.setCursor(0,1);
lcd.print("INICIO ->(ENTER)");
lcd.setCursor(0,2);
lcd.print("CONFIG ->(STOP!)");
lcd.setCursor(0,3);
lcd.print("--------------------");
Timer1.start();
if((digitalRead (ENTER_button) == 0) || (digitalRead(START_button) == 0))
{
while (digitalRead(ENTER_button) == 0) { } // espera a que se suelte el pulsador
leerEEPROM();
lcd.clear();
modo = 3;
lcd.clear();
Timer1.start(); // Habilitamos el timer1
R_TempoON();
}
if(digitalRead(START_button) == 0)
{
while (digitalRead(START_button) == 0) { } // espera a que se suelte el pulsador
leerEEPROM();
lcd.clear();
modo = 3;
SECOND=0;
lcd.clear();
Timer1.start(); // Habilitamos el timer1
R_TempoON();
}
if(digitalRead (STOP_button) == 0)
{
while (digitalRead(STOP_button) == 0) { } // espera a que se suelte el pulsador
leerEEPROM();
modo = 10;
lcd.clear();
progTEMPO_R1();
}
}
////////////////////////////////////////////////////////////////////////////////
//************* INICIO SUBPROGRAMA PARA CONFIGURAR TIEMPO R1****************
////////////////////////////////////////////////////////////////////////////////
void progTEMPO_R1()
{
lcd.clear();
CONFIG_R1_SEG();
}
////////////////////////////////////////////////////////////////////////////////
//**************** sub programa para configurar el tiempo ******************
////////////////////////////////////////////////////////////////////////////////
void CONFIG_R1_SEG()
{
modo=10;
lcd.setCursor(0,0);
lcd.print("-Config-R1----------");
lcd.setCursor(0,1);
lcd.print(" >>SEG<< ");
lcd.setCursor(0,2);
lcd.print("TIEMPO: ");
if(setHOUR_R1<=9){lcd.print("0");}
lcd.print(setHOUR_R1);
lcd.print(":");
if(setMINUTE_R1<=9){lcd.print("0");}
lcd.print(setMINUTE_R1);
lcd.print(":");
if(setSECOND_R1<=9){lcd.print("0");}
lcd.print(setSECOND_R1);
lcd.print(" ");
if(digitalRead (MAS_button) == 0)
{
setSECOND_R1++;
if(setSECOND_R1>59){setSECOND_R1=0;}
delay(200);
}
if(digitalRead (MENOS_button) == 0)
{
setSECOND_R1--;
if(setSECOND_R1<0){setSECOND_R1=59;}
delay(200);
}
if(digitalRead (ENTER_button) == 0)
{
while (digitalRead(ENTER_button) == 0) { } // espera a que se suelte el pulsador
EEPROM.write(2, setSECOND_R1);
BANDERA_R1 = 1;
modo=11;
setOK();
CONFIG_R1_MIN();
}
if(digitalRead (STOP_button) == 0)
{
while (digitalRead(STOP_button) == 0) { } // espera a que se suelte el pulsador
EEPROM.write(2, setSECOND_R1);
modo=0;
lcd.clear();
loop();
}
if(digitalRead (CLEAR_button) == 0)
{
while (digitalRead(CLEAR_button) == 0) { } // espera a que se suelte el pulsador
setSECOND_R1 = 0;
}
if(modo==10)
{
CONFIG_R1_SEG();
}
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void CONFIG_R1_MIN()
{
modo=11;
lcd.setCursor(0,0);
lcd.print("-Config-R1----------");
lcd.setCursor(0,1);
lcd.print(" >>MIN<< ");
lcd.setCursor(0,2);
lcd.print("TIEMPO: ");
if(setHOUR_R1<=9){lcd.print("0");}
lcd.print(setHOUR_R1);
lcd.print(":");
if(setMINUTE_R1<=9){lcd.print("0");}
lcd.print(setMINUTE_R1);
lcd.print(":");
if(setSECOND_R1<=9){lcd.print("0");}
lcd.print(setSECOND_R1);
lcd.print(" ");
if(digitalRead (MAS_button) == 0)
{
setMINUTE_R1++;
if(setMINUTE_R1>59){setMINUTE_R1=0;}
delay(200);
}
if(digitalRead (MENOS_button) == 0)
{
setMINUTE_R1--;
if(setMINUTE_R1<0){setMINUTE_R1=59;}
delay(200);
}
if(digitalRead (ENTER_button) == 0)
{
while (digitalRead(ENTER_button) == 0) { } // espera a que se suelte el pulsador
EEPROM.write(3, setMINUTE_R1);
BANDERA_R1 = 1;
modo=12;
setOK();
CONFIG_R1_HOR();
}
if(digitalRead (STOP_button) == 0)
{
while (digitalRead(STOP_button) == 0) { } // espera a que se suelte el pulsador
EEPROM.write(3, setMINUTE_R1);
modo=0;
lcd.clear();
loop();
}
if(digitalRead (CLEAR_button) == 0)
{
while (digitalRead(CLEAR_button) == 0) { } // espera a que se suelte el pulsador
setMINUTE_R1 = 0;
}
if(modo==11)
{
CONFIG_R1_MIN();
}
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void CONFIG_R1_HOR()
{
modo=12;
lcd.setCursor(0,0);
lcd.print("-Config-R1----------");
lcd.setCursor(0,1);
lcd.print(" >>HOR<< ");
lcd.setCursor(0,2);
lcd.print("TIEMPO: ");
if(setHOUR_R1<=9){lcd.print("0");}
lcd.print(setHOUR_R1);
lcd.print(":");
if(setMINUTE_R1<=9){lcd.print("0");}
lcd.print(setMINUTE_R1);
lcd.print(":");
if(setSECOND_R1<=9){lcd.print("0");}
lcd.print(setSECOND_R1);
lcd.print(" ");
if(digitalRead (MAS_button) == 0)
{
setHOUR_R1++;
if(setHOUR_R1>98){setHOUR_R1=0;}
delay(200);
}
if(digitalRead (MENOS_button) == 0)
{
setHOUR_R1--;
if(setHOUR_R1<0){setHOUR_R1=98;}
delay(200);
}
if(digitalRead (ENTER_button) == 0)
{
lcd.clear();
while (digitalRead(ENTER_button) == 0) { } // espera a que se suelte el pulsador
EEPROM.write(4, setHOUR_R1);
BANDERA_R1 = 1;
setOK();
modo=1;
banderaPROG_R1 = 1;
menuPROG();
}
if(digitalRead (STOP_button) == 0)
{
while (digitalRead(STOP_button) == 0) { } // espera a que se suelte el pulsador
EEPROM.write(4, setHOUR_R1);
modo=0;
lcd.clear();
loop();
}
if(digitalRead (CLEAR_button) == 0)
{
while (digitalRead(CLEAR_button) == 0) { } // espera a que se suelte el pulsador
setHOUR_R1 = 0;
}
if(modo==12)
{
CONFIG_R1_HOR();
}
}
//////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////
void R_TempoON()
{
banderaPROG=1;
modo = 3;
lcd.clear();
leerEEPROM();
INI_TEMPO();
SECOND=0;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void INI_TEMPO()
{
lcd.setCursor(0,0);
lcd.print("--------------------");
verDISPLAY();
if (BANDERA_R1 == 1)
{
digitalWrite(RELAY_1,HIGH); //Poner en alto el relay (tiene logica negativa)
BANDERA_R1est=1;
}
if (SECOND == 60) //; consigna: si variable segundos es = a 60, entonces
{
SECOND = 0; //ponemos variable segundos en 0
MINUTE ++;
}
if (MINUTE == 60) //consigna dentro de consigna, si minuto es = 60 entonces
{MINUTE = 0; //ponemos variable minutos en 0
HOUR ++;
}
lcd.setCursor(0,0);
lcd.print("--------------------");
verDISPLAY();
if ((setHOUR_R1 == HOUR) && (setMINUTE_R1 == MINUTE) && (setSECOND_R1 == SECOND)) //RELAY1
{
digitalWrite(RELAY_1,LOW); //Poner en bajo el relay (tiene logica negativa)
BANDERA_R1est=0;
BANDERA_R1=0;
}
if (BANDERA_R1==0)
{
SECOND = 0;
MINUTE = 0;
HOUR = 0;
leerEEPROM();
delay(1500);
lcd.clear();
lcd.setCursor(0,0);
lcd.print("--------------------");
lcd.setCursor(0,1);
lcd.print(" TIEMPO PROGRAMA ");
lcd.setCursor(0,2);
lcd.print(" TERMINADO ");
lcd.setCursor(0,3);
lcd.print("--------------------");
delay(2500);
lcd.clear();
BANDERA_R1=1;
modo=0;
loop();
}
if(digitalRead (STOP_button) == 0)
{
BANDERA_PARADA_R1 = 1; // Flag para saber de donde me fui, y donde retornar
Timer1.stop(); // Paramos el timer para que no siga sumando tiempo
PARADA();
}
if(modo==3)
{
INI_TEMPO();
}
}
////////////////////////////////////////////////////////////////////////////////
//****************** sub programa para el cronometro ***********************
////////////////////////////////////////////////////////////////////////////////
void CONTADOR()
{
SECOND ++; ; //incrementar 1 en variable segundo
}
void CONTADOR_MIN()
{
MINUTE ++; //incrementamos 1 en variable minuto
}
void CONTADOR_HOR()
{
HOUR ++; //incrementamos 1 en variable hora
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void verDISPLAY()
{
lcd.setCursor(0,1);
lcd.print("R1:");lcd.print(BANDERA_R1est);
lcd.setCursor(0,2);
lcd.print("Tiempo: ");
if(HOUR<=9){lcd.print("0");};lcd.print(HOUR);
lcd.print(":");
if(MINUTE<=9){lcd.print("0");};lcd.print(MINUTE);
lcd.print(":");
if(SECOND<=9){lcd.print("0");};lcd.print(SECOND);
lcd.setCursor(0,3);
lcd.print("--------------------");
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void GrabarEEPROM()
{
EEPROM.write(2,setSECOND_R1);
EEPROM.write(3,setMINUTE_R1);
EEPROM.write(4,setHOUR_R1);
EEPROM.write(14,bandera_MPROG);
AsetHOUR_R1=setHOUR_R1;
AsetMINUTE_R1=setMINUTE_R1;
AsetSECOND_R1=setSECOND_R1;
}
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
void leerEEPROM()
{
setSECOND_R1 = EEPROM.read(2);
setMINUTE_R1 = EEPROM.read(3);
setHOUR_R1 = EEPROM.read(4);
bandera_MPROG = EEPROM.read(14);
AsetHOUR_R1=setHOUR_R1;
AsetMINUTE_R1=setMINUTE_R1;
AsetSECOND_R1=setSECOND_R1;
}
////////////////////////////////////////////////////////////////////////////////
//********************** sub programa para la pausa ************************
////////////////////////////////////////////////////////////////////////////////
void PARADA()
{
modo=70;
Timer1.stop();
digitalWrite(RELAY_1,LOW); //Poner en bajo el relay
BANDERA_R1 == 0;
BANDERA_R1est=0;
lcd.clear();
for(TICKS=0;TICKS<4;TICKS++)
{
lcd.setCursor(0,0);
lcd.print("-M.PAUSA------------");
verDISPLAY();
delay(350);
if(digitalRead (START_button) == 0)
{
lcd.clear();
if (BANDERA_PARADA_R1 == 1)
{
BANDERA_PARADA_R1 = 0;
BANDERA_R1 == 1;
Timer1.start();
modo = 80;
R_1();
}
}
if(digitalRead (CLEAR_button) == 0){loop();}
lcd.clear();
for(TICKS=0;TICKS<4;TICKS++)
{
lcd.setCursor(0,0);
lcd.print("-M.PAUSA------------");
lcd.setCursor(0,1);
lcd.print("TIEMPO DETENIDO ");
lcd.setCursor(0,2);
lcd.print("paraSEGUIR-> (ENTER)");
lcd.setCursor(0,3);
lcd.print("--------------------");
delay(350);
if(digitalRead (ENTER_button) == 0)
{
lcd.clear();
if (BANDERA_PARADA_R1 == 1)
{
BANDERA_PARADA_R1 = 0;
Timer1.start();
modo = 80;
R_1();
}
}
if(digitalRead (CLEAR_button) == 0) {loop();} // salimos del programa y vamos al loop principal
}
if(modo==70) implementamos la variable modo para usarla como bandera y volver al principio del subprograma
{
PARADA();
}
}
Si bien, se puede hacer un simple contador y comparar los valores de dos variables, hay que tener en cuenta que esta es la base / un extracto de otro proyecto de mas envergadura. Como verán, puede parecernos un poco extenso y engorroso, pero si prestamos atención a los comentarios del sketch, no es para nada complicado replicarlo y sumarle mas relay al controlador.... Les dejo una vista ampliada de como quedaría:
Ejemplo de un Control Temporizado de 4 canales con función de salida en Cascada, Secuencial y Paso a Paso: