Control de salidas digitales en función del tiempo

Muy buenas,

Antes de nada saludaros a todos ya que soy nuevo por aquí.

Os comento el proyecto que tengo entre manos. En el campo tengo un sistema de filtrado que para su auto limpieza (que se ha roto y quiero reemplazar con arduino y relés) tiene algo así:

Es decir, tengo tres bloques de electroválvuas que se repetirán en función del tiempo (A, B y C) y cada bloque tiene cuatro controles, me explico

Durante el primer minuto, A1 estará activo, pero durante los primeros 5 segundo estará activo A2, luego durante 45 segundos estará activo A3 y luego durante 10 segundos estará activo A4. Después, repito los mismo con B1, B2, B3 y B4 y lo mismo con C...

El tema es que no quiero programarlo con if if if, me gustaría saber si existe alguna librería o alguna ayuda para programar según función de tiempo o algo parecido, no sé si me explico...

Por ejemplo, definir rangos de activación para cada variable, por ejemplo

A1 {0,60}
A2 {0,5}
A3 {5,50}
A4 {50,60}

B1 {60,120}
B2 {60,65}
B3 {65,110}
B4 {110,120}

C1 ...
...
C4 ...

Y en el momento de lanzar la limpieza pongo el tiempo a cero y veo en que rango estoy activando esa salida o en que rango no estoy desactivando la salida...

Cómo lo veis?

Muchas gracias por la ayuda.

Para ver imágenes lee Las normas del foro y al final hay un post complementario que te dice como luego de adjuntar una imagen puedes editar el post para que se pueda visualizar.

Por ahora el mejor consejo es usar millis()
Asi que eso lo encuentras en Documentación => Indice de temas tutoriales => Millis()

Si no te complace porque te llevará tiempo entenderla, puedes usar TimeAlarms pero solo mira los ejemplos de timers

Creating Timers
Timers call a function at regular intervals.

Alarm.timerRepeat(seconds, function);
Create a timer that will call a function every at an interval of "seconds".

Alarm.timerOnce(seconds, function);
Create a timer that will call a function once in "seconds".

#include <Time.h>
#include <TimeAlarms.h>

void setup()
{
  Serial.begin(9600);
  setTime(20, 0, 0, 9, 7, 18); // Fija la hora a las 20:00:00 09/07/18
  // create the alarms 
 
  Alarm.timerRepeat(15, Repeats);            // timer for every 15 seconds    
  Alarm.timerOnce(10, OnceOnly);             // called once after 10 seconds 
}

void  loop(){  
  digitalClockDisplay();
  Alarm.delay(1000); // wait one second between clock display
}

// functions to be called when an alarm triggers:
   
void Repeats(){
  Serial.println("15 second timer");         
}

void OnceOnly(){
  Serial.println("This timer only triggers once");  
}

void digitalClockDisplay()
{
  // digital clock display of the time
  Serial.print(hour());
  printDigits(minute());
  printDigits(second());
  Serial.println(); 
}

void printDigits(int digits)
{
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

Y esto permitirá que obtengas uan salida de este tipo mas o menos, no se veran las alarmas
Alarm: - turn lights off

Gracias surbyte por la respuesta.

Bueno, lo primero ya arreglé la foto, reconozco que no leí hasta el final el post de las normas del foro, lo siento... me quedé en la parte superior.

Por otro lado, ya he avanzado y creo que he conseguido lo que quería, que por ahora era lo que me preocupaba, encender y apagar salidas según un esquema de tiempos, que por ahora son "absolutos". Mas adelante, pondré un pulsador que hará ese esquema de tiempo relativo al momento de pulsar, pero eso no me preocupa...

Os muestro lo que he programado, se admiten todo tipo de críticas...

// formato Esquema {salida, inicio activacion, fin activacion} vector por cada salida,

int Esquema[6][3] = {
  { 2,  0,    60}, //Salida 2, se activa desde el momento 0 hasta el 60
  { 3,  5,    50}, //Salida 3, se activa desde el momento 5 hasta el 50
  { 4,  60,  120}, //...
  { 5,  65,  110},
  { 6,  120, 180},
  { 7,  125, 170}
};

boolean On = LOW; //mis relés se activan con señal baja
boolean Off = HIGH;

unsigned long TActual;


void setup() {
  Serial.begin(115200);
  Serial.println("Configuración de salidas:");
  for (int i = 0; i < 6; i++) {
    pinMode(Esquema[i][0], OUTPUT);
    digitalWrite(Esquema[i][0], Off);
    Serial.print(Esquema[i][0]);
    Serial.println(" como salida");
  }
  Serial.println("******");
}

void loop() {
  //ToDo: Lanzar la sec de lim cuando se pulse el pulsador, aún no implementado
  TActual = millis() / 1000;
  SecuenciaLimpieza();

}

void SecuenciaLimpieza() {
  for (int i = 0; i < 6; i++) {
    if ((TActual >= Esquema[i][1]) && (TActual <= Esquema[i][2])) {
      Enciende(Esquema[i][0]);
    }
    else {
      Apaga(Esquema[i][0]);
    }
  }
}

void Enciende(byte Puerto) {
  if (digitalRead(Puerto) == Off) {
    Serial.print("A las ");;
    Serial.print(TActual);
    digitalWrite(Puerto, On);
    Serial.print(", enciendo ");
    Serial.println(Puerto);
  }
}


void Apaga(byte Puerto) {
  if (digitalRead(Puerto) == On) {
    Serial.print("A las ");;
    Serial.print(TActual);
    digitalWrite(Puerto, Off);
    Serial.print(", apago ");
    Serial.println(Puerto);

  }
}

Bienvenido jmcabgam, no entiendo muy bien en tu primera explicación hablas de 3 bloques iguales de 4 válvulas c/u, porque en tu código defines solo 6 salidas ?

Yo esperaría que usaras 12 (3x4) salidas o si los bloques son idénticos 7 (3+4) salidas, es decir cada válvula la controlas con 2 salidas una del bus y la otra de control como se manejan los display 7 segmentos.

Comentarte varios temas generales.

  1. Arduino UNO va un poco justo de memoria RAM (2K), por lo que crear una matriz de 36 valores int (2 bytes c/u) para almacenar números enteros hasta 170 es malgastar la memoria. Te recomiendo cambiar al tipo byte (0 a 255) y hacerla constante.
const byte Esquema[6][3]={
  { 2,  0,    60},  //Salida 2, se activa desde el momento 0 hasta el 60
  { 3,  5,    50},  //Salida 3, se activa desde el momento 5 hasta el 50
  { 4,  60,  120}, //...
  { 5,  65,  110},
  { 6,  120, 180},
  { 7,  125, 170}
};

Ademas recuerda que los indices en las matrices empiezan en 0.

  1. Mismo comentario para i dentro de for, podria ser tipo byte.

  2. digitalRead(Puerto) de por si sera verdadero o falso por lo que no se requiere igualar y las funciones Enciende y Apaga serian una sola.

Hola Kike_GL, muchas gracias por tus comentarios!

Te cuento, aún no estoy seguro que cuanto tiempo voy a necesitar, y si supero los 4 minutos ya no podría usar byte, por eso lo tengo en int.

Lo de los índices que empiezan en cero lo tengo claro, pero no sé por qué me lo comentas... hay algo raro en el código? Te agradezco tus comentarios

Lo del i del for totalmente de acuerdo!!!

El punto 3 no entiendo bien tu comentario. He puesto dos funciones para decidir qué hacer en cada una, y lo leo primero para no estar haciendo algo que ya ha hecho y no hay que volver a hacerlo... no sé si me explico.

Gracias por los comentarios!

Hola ArduMyth, muchas gracias por tus comentarios!!!

En principio el uso de librerías de timer la descarto porque creo haber encontrado un camino que me facilita lo que necesito, igual estoy equivocado, pero creo que activar/desactivar timers según el esquema que necesito me parece más complicado que lo que he montado, a mi humilde parecer.

Lo del array te refieres a ponerlo así:

  for (byte i = 0; i < sizeof(Esquema)/sizeof(Esquema[0]); i++) {
    pinMode(Esquema[i][0], OUTPUT);
    digitalWrite(Esquema[i][0], Off);
    Serial.print(Esquema[i][0]);
    Serial.println(" como salida");
  }

y

  for (byte i = 0; i < sizeof(Esquema)/sizeof(Esquema[0]); i++) {
    if ((TActual >= Esquema[i][1]) && (TActual <= Esquema[i][2])) {
      Enciende(Esquema[i][0]);
    }
    else {
      Apaga(Esquema[i][0]);
    }
  }

Lo he simulado y creo que funciona bien

Lo que no entiendo es lo de ponerlo en una función o en #define... un ejemplillo?

Respecto a esto:

boolean On = LOW; //mis relés se activan con señal baja
boolean Off = HIGH;

Es por que mis relés se activan con un 0 (LOW) a la salida, y se desactivan con un 1 (HIGH), por eso lo he programado así, para evitar que un

digitalWrite(Esquema[i][0], 0);

Se lea rápidamente como un apagado cuando realmente activa el relé. No pretende ser el estado del relé... No sé si me explico.

De nuevo, gracias por el soporte!