Secuencia para una lavaropa con Millis

Hola, estoy intentando hacer una secuencia para 4 LEDs con "millis" pero no me funciona correctamente, por ejemplo se quedan prendido algunos LED.
Adicionalmente no se como hacer que al llegar a la última parte de la secuencia del void loop, el programa se detenga.

Agradecía si me podrían indiciar donde estoy cometiendo el error. Gracias.

int pulsador = 2;
int rele1 = 3;
int rele2 = 4;
int rele3 = 5;
int rele4 = 6;
bool estadoON = HIGH;
bool pushed = LOW;
unsigned long int tActual = 0;
unsigned long int tDeInicio = 0;

bool checkTiempo(unsigned long int tDeEspera)
{
  tActual = millis();
  if (tDeInicio == 0) {
    tDeInicio = millis();
  }
  if ((tActual - tDeInicio) >= tDeEspera)
  {
    return true;
    tDeInicio = 0;
  }
  else
  {
    return false;
  }
}

void setup ()
{
  pinMode(pulsador, INPUT_PULLUP);
  pinMode(rele1, OUTPUT);
  pinMode(rele2, OUTPUT);
  pinMode(rele3, OUTPUT);
  pinMode(rele4, OUTPUT);
}

void loop ()
{
  if (estadoON == HIGH)
  {
    estadoON = digitalRead(2);
    pushed = HIGH;
    delay(200);
  }

  if ((estadoON == LOW) & (pushed = HIGH))
  {
    pushed = LOW;
    digitalWrite(rele1, HIGH);
  }
  if ((pushed == LOW) & checkTiempo(10000))
  {
    digitalWrite(rele1, LOW);
    digitalWrite(rele2, HIGH);
  }
  if ((pushed == LOW) & checkTiempo(15000))
  {
    digitalWrite(rele2, LOW);
    digitalWrite(rele3, HIGH);
  }
  if ((pushed == LOW) & checkTiempo(20000))
  {
    digitalWrite(rele3, LOW);
    digitalWrite(rele4, HIGH);
    estadoON = HIGH;
  }
}

Como todas las comparaciones dependen de que estadoOn sea LOW es mejor que las hagas dentro de un if(), pero modifica la secuencia de tiempos, primero has la comparación por 20 seg, luego 15 y finalmente 10, además usa else if()
Si no pasaron 20 seg, entonces chequeas si son 15 y sino entonces te fijas si fueron 10. Así

if ((estadoON == LOW) {
  if (checkTiempo(20000)) {
// lo que sigue
  }
  else if (checkTiempo(15000)) {
// y lo demas
  }
  else if (checkTiempo(10000)) {
  }
}

Además te haría falta una variable que indique que ese paso ya se ejecutó para que no se repita.

Saludos

1 Like

Gracias por la respuesta, pero no entendi bien donde en que lineas hacer modificacion.
Seria reemplazando " if ((pushed == LOW) & checkTiempo(5000))"?

Esto fue lo que te sugirió @gatul

void loop () {
    if (estadoON == HIGH)    {
        estadoON = digitalRead(pulsador);
        pushed = HIGH;
        delay(200);
    }

    if ((estadoON == LOW) {
        if (checkTiempo(20000)) {
            digitalWrite(rele3, LOW);
            digitalWrite(rele4, HIGH);
            estadoON = HIGH;
        }
        else if (checkTiempo(15000)) {
                digitalWrite(rele2, LOW);
                digitalWrite(rele3, HIGH);
        }
        else if (checkTiempo(10000)) {
                digitalWrite(rele1, LOW);
                digitalWrite(rele2, HIGH);
        }
    }
}

Ya que tu código usa muy bien millis() reconsidera los delay() que tienes en especial el que usas cuando estadoON == HIGH
Una forma seria esta y tmb hago algunos cambios.
Algo que personalmente no comparto es que leas el estado del pulsador dentro de la condición ON. Por esa reazón quite la consulta. También cuando defines un pin debe ser del tipo const y no consumir RAM usando solo int. Lo correcto es const int.
Acá dejo la versión completa

const int pulsador  = 2;
const int rele1     = 3;
const int rele2     = 4;
const int rele3     = 5;
const int rele4     = 6;
bool estadoON       = HIGH;
bool pushed         = LOW;
unsigned long tActual;
unsigned long tDeInicio;
unsigned long tiempoPulOn;
byte estadoPulOn = 0;


bool checkTiempo(unsigned long int tDeEspera) {
    tActual = millis();
    if (tDeInicio == 0) { 
        tDeInicio = millis();
    }
    if ((tActual - tDeInicio) >= tDeEspera)   {
        return true;
        tDeInicio = 0;
    }
    else    {
        return false;
    }
}

void setup ()
{
  pinMode(pulsador, INPUT_PULLUP);
  pinMode(rele1, OUTPUT);
  pinMode(rele2, OUTPUT);
  pinMode(rele3, OUTPUT);
  pinMode(rele4, OUTPUT);
}

void loop () {
    estadoON = digitalRead(pulsador);
    
    if (estadoON == HIGH)    {
        switch(estadoPulOn) {
            case 0: pushed = HIGH;
                    estadoPulOn = 1;
                    tiempoPulOn = millis();
                    break;
            case 1: if (millis() - tiempoPulOn > 200UL){
                        estado = 0;
                    }
                    break;
        }
    }

    if ((estadoON == LOW) {
        if (checkTiempo(20000)) {
            digitalWrite(rele3, LOW);
            digitalWrite(rele4, HIGH);
            estadoON = HIGH;
        }
        else if (checkTiempo(15000)) {
                digitalWrite(rele2, LOW);
                digitalWrite(rele3, HIGH);
        }
        else if (checkTiempo(10000)) {
                digitalWrite(rele1, LOW);
                digitalWrite(rele2, HIGH);
        }
    }
}

Olvidé explicarte esto

switch(estadoPulOn) {
            case 0: pushed = HIGH;
                    estadoPulOn = 1;
                    tiempoPulOn = millis();
                    break;
            case 1: if (millis() - tiempoPulOn > 200UL){
                        estado = 0;
                    }
                    break;
        }

Es una máquina de estados. Comienza con un estado 0 o en el case 0
En ella haces lo mismo que haces en tu código. Entonces inicializas millis() para que a los 200 mseg cambie. Como ya se cumplió el estado 0 pasamos al 1. Que esperará hasta cumplir los 200 mseg pero ahora a diferencia de delay() no bloquea el código y sigue consultando todas las situaciones por lo que si en el siguiente ciclo el pulsador es presionado, no debe esperar tiempo a ser reconocido sino que ya irá a las condiciones de LOW del pulsador.

1 Like

Surbyte, muchas gracias por la respuesta, el código y las explicaciones. Lo estoy leyendo para intentando comprenderlo, pero me es bastante difícil, soy muy principiante en esto.

Creo que yo me explique incorrectamente, el propósito de mi programa era que:

El Arduino no hace nada hasta que yo presiono el pulsador; en ese momento ejecuta las secuencias y al finalizar las secuencias se detiene.

Hice algunos cambios menores pero sería así

const byte pulsador = 2;
const byte rele1 = 3;
const byte rele2 = 4;
const byte rele3 = 5;
const byte rele4 = 6;
bool estadoON = HIGH;
bool pushed = LOW;
unsigned long tActual = 0;
unsigned long tDeInicio = 0;
byte paso = 0;

bool checkTiempo(unsigned long int tDeEspera){
  tActual = millis();
  if(tDeInicio == 0){
    tDeInicio = millis();
  }
  if((tActual - tDeInicio) >= tDeEspera){
    tDeInicio = 0;
    return true;
  }
  return false;
}

void setup(){
  pinMode(pulsador, INPUT_PULLUP);
  pinMode(rele1, OUTPUT);
  pinMode(rele2, OUTPUT);
  pinMode(rele3, OUTPUT);
  pinMode(rele4, OUTPUT);
}

void loop(){
  if(estadoON == HIGH){
    estadoON = digitalRead(2);
    pushed = HIGH;
    delay(200);
  }
  else if(pushed = HIGH){
    pushed = LOW;
    digitalWrite(rele1, HIGH);
  }
  if(pushed == LOW){
    if((paso == 0) && (checkTiempo(10000))){
      digitalWrite(rele1, LOW);
      digitalWrite(rele2, HIGH);
      paso = 1;
    }
    else if((paso == 1) && (checkTiempo(15000))){
      digitalWrite(rele2, LOW);
      digitalWrite(rele3, HIGH);
      paso = 2;
    }
    else if((paso == 2) && (checkTiempo(20000))){
      digitalWrite(rele3, LOW);
      digitalWrite(rele4, HIGH);
      paso = 0;
      estadoON = HIGH;
    }
  }
}

o más prolijo

const byte pulsador = 2;
const byte rele1 = 3;
const byte rele2 = 4;
const byte rele3 = 5;
const byte rele4 = 6;
bool estadoON = HIGH;
bool pushed = LOW;
unsigned long tActual = 0;
unsigned long tDeInicio = 0;
byte paso = 0;

bool checkTiempo(unsigned long int tDeEspera){
  tActual = millis();
  if(tDeInicio == 0){
    tDeInicio = millis();
  }
  if((tActual - tDeInicio) >= tDeEspera){
    tDeInicio = 0;
    return true;
  }
  return false;
}

void setup(){
  pinMode(pulsador, INPUT_PULLUP);
  pinMode(rele1, OUTPUT);
  pinMode(rele2, OUTPUT);
  pinMode(rele3, OUTPUT);
  pinMode(rele4, OUTPUT);
}

void loop(){
  if(estadoON == HIGH){
    estadoON = digitalRead(2);
    pushed = HIGH;
    delay(200);
  }
  else if(pushed = HIGH){
    pushed = LOW;
    digitalWrite(rele1, HIGH);
  }
  if(pushed == LOW){
    switch(paso){
      case 0: if(checkTiempo(10000)){
          digitalWrite(rele1, LOW);
          digitalWrite(rele2, HIGH);
          paso = 1;
        }
        break;
      case 1: if(checkTiempo(15000)){
          digitalWrite(rele2, LOW);
          digitalWrite(rele3, HIGH);
          paso = 2;
        }
        break;
      case 2: if(checkTiempo(20000)){
          digitalWrite(rele3, LOW);
          digitalWrite(rele4, HIGH);
          paso = 0;
          estadoON = HIGH;
        }
        break;
    }
  }
}

Saludos

1 Like

gatul, muchas gracias por los detallados códigos. Los estuve probando y estos son los resultados;

Al iniciar con el pulsador se enciende el relé1, después el relé2, pero se queda prendido el relé1
(siempre, durante toda la secuencia del programa, lo mismo que me pasaba con mi código y sigo sin entender el porqué)
La secuencia continua normalmente y al finalizar queda encendido el relé1 y el relé4.
Intente hacer unas modificaciones para que se apaguen los relé1 y el relé4 sin éxito.

Ahora lo reviso, la verdad que antes solo me limité a mostrarte como "acomodar" el código.

Imagino que te diste cuenta que en ambos códigos me olvidé el punto y coma en

paso = 2;

ya los edité.

A primera vista, efectivamente no hay un 4to. paso que apague el relé4.

Lo del relé1 me sorprendió y lo acabo de simular (en el celular, no es gran cosa) y efectivamente nunca se apaga, pero además sigue haciendo el ciclo sin importar como está pulsador (aunque puede ser un error del emulador).

Lo reviso.

Ya está, encontré el error.

No lo vi antes y lo "arrastré" de tu código original

if ((estadoON == LOW) & (pushed = HIGH)) {

yo luego lo dejé

else if(pushed = HIGH){

cuando debía ser

(pushed == HIGH)

eso hacía que siempre se encendiese relé1 porque entraba siempre en el if(). :man_facepalming:t2:

Ahora corregido y agregado el estado para que se apague el relé4

const byte pulsador = 2;
const byte rele1 = 3;
const byte rele2 = 4;
const byte rele3 = 5;
const byte rele4 = 6;
bool estadoON = HIGH;
bool pushed = LOW;
unsigned long tActual = 0;
unsigned long tDeInicio = 0;
byte paso = 0;

bool checkTiempo(unsigned long int tDeEspera){
  tActual = millis();
  if(tDeInicio == 0){
    tDeInicio = millis();
  }
  if((tActual - tDeInicio) >= tDeEspera){
    tDeInicio = 0;
    return true;
  }
  return false;
}

void setup(){
  pinMode(pulsador, INPUT_PULLUP);
  pinMode(rele1, OUTPUT);
  pinMode(rele2, OUTPUT);
  pinMode(rele3, OUTPUT);
  pinMode(rele4, OUTPUT);
}

void loop(){
  if(estadoON == HIGH){
    estadoON = digitalRead(pulsador);
    pushed = HIGH;
    delay(200);
  }
  else if(pushed == HIGH){
    pushed = LOW;
    digitalWrite(rele1, HIGH);
  }
  if(pushed == LOW){
    switch(paso){
      case 0: if(checkTiempo(10000)){
          digitalWrite(rele1, LOW);
          digitalWrite(rele2, HIGH);
          paso = 1;
        }
        break;
      case 1: if(checkTiempo(15000)){
          digitalWrite(rele2, LOW);
          digitalWrite(rele3, HIGH);
          paso = 2;
        }
        break;
      case 2: if(checkTiempo(20000)){
          digitalWrite(rele3, LOW);
          digitalWrite(rele4, HIGH);
          paso = 3;
        }
        break;
      case 3: if(checkTiempo(10000)){
          digitalWrite(rele4, LOW);
          paso = 0;
          estadoON = HIGH;
        }
        break;
    }
  }
}

Saludos

PD:
Tené en cuenta que los tiempos, de la forma en que programaste checkTiempo() son tiempos "ventana", el primer paso dura 10 segundos, el segundo 15, el 3ro. 20 y el 4to. (que lo puse yo arbitrariamente) dura 10 segundos.
Te lo aclaro porque si la idea era que los pasos se disparasen a los 10, 15 y 20 segundos, no trabaja así.
Yo al principio pensaba que lo hacía de esta forma, por eso te había dicho que primero chequearas el tiempo más largo, pero luego me di cuenta que no era de ese modo. Tal vez debas corregirlos.
Como te dije, al 4to. paso le puse un tiempo arbitrario, corregilo al que sea necesario. Slds

1 Like

gatul, mil gracias por la explicación del error y el nuevo código, ahora si me funciono como deseado . Ya con este nuevo codigo puedo hacer mas secuencias y me queda agregar un presostato.

De nada.
Cuéntanos tus avances.

Saludos

Actualmente me es necesario empezar a hacer pruebas con los cambios presión (20%, 60% y 100).
El presostato original es un MPX10DP, investigando sobre el tema, leí que lo óptimo seria usar un MPX5010DP en este proyecto, ya que ese modelo viene hecho para ser conectado a un microcontrolador como el Arduino (entiendo que el resto de los modelos también puede ser conectado, aunque requieren un amplificador).

El problema es que por el Covid, todos los presostatos MPX (especialmente el 5010DP) están con muy alta demanda, son difíciles de conseguir en stock y tiene un precio muy alto.

¿Hay una alternativa temporal que pueda implementar para hacer un demo que me permita simular los cambios de presión?