[SOLUCIONADO] Parpadeo sin delay en un ciclo while

Buenas tardes,

Soy nuevo en arduino y de programación sé muy poco. Por eso, después de buscar por todas partes información sobre mi problema, he decidido postearlo para ver si alguien tiene alguna idea sobre como solucionarlo.

Estoy haciendo una compuerta que se abre verticalmente. He puesto un botón para subir y otro para bajar y dos finales de carrera, uno arriba y otro abajo, para indicar al motor cuando tiene que parar.

Quiero que mientras sube la compuerta esté parpadeando un led, y que deje de parpadear cuando llegue al final de carrera. El problema es que si programo el parpadeo dentro de un ciclo while usando un delay, el motor no para cuando llega al final de carrera, sinó cuando llega al final de carrera pero pasado el delay. Por eso he intentado hacer el parpadeo sin delay, con millis. Pero la verdad es que no consigo que me funcione.

Pogo aquí el código:

#define BotonSubir 4
#define BotonBajar 9
#define FinalCarreraSubir 7 
#define FinalCarreraBajar 8 
#define SUBIR 3 
#define BAJAR 2

const int LED = 11;

int estadoBotonSubir = 0;
int estadoBotonBajar = 0;
int estadoFinalSubir = 0;
int estadoFinalBajar = 0;
int estadoLED = LOW;

unsigned long previousMillis = 0;
const long interval = 1000;
 
//**********************************************************************************


void setup() {
  Serial.begin(9600);
  pinMode(BotonSubir, INPUT);
  pinMode(BotonBajar, INPUT);
  pinMode(FinalCarreraSubir, INPUT_PULLUP);
  pinMode(FinalCarreraBajar, INPUT_PULLUP);
  pinMode(SUBIR, OUTPUT);
  digitalWrite(SUBIR, HIGH);
  pinMode(BAJAR, OUTPUT);
  digitalWrite(BAJAR, HIGH);
  pinMode(LED, OUTPUT);
}

void parpadeo(){
  
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis >= interval){ 

    if(estadoLED == LOW){
      estadoLED = HIGH;
    }
    else{
      estadoLED = LOW;
    }
  }
  digitalWrite(LED, estadoLED);
  previousMillis = currentMillis;
}


void loop() {

estadoBotonSubir = digitalRead(BotonSubir);
estadoBotonBajar = digitalRead(BotonBajar);
estadoFinalSubir = digitalRead(FinalCarreraSubir);
estadoFinalBajar = digitalRead(FinalCarreraBajar);

if(estadoFinalSubir == LOW){
  digitalWrite(SUBIR, HIGH);
  digitalWrite(LED, LOW);
}
else if(estadoBotonSubir == HIGH){
  digitalWrite(SUBIR, LOW);
  digitalWrite(BAJAR, HIGH);
  while(estadoFinalSubir != LOW){
    parpadeo();
  }

if(estadoFinalBajar == LOW){
  digitalWrite(BAJAR, HIGH);

  }
else if(estadoBotonBajar == HIGH){
  digitalWrite(BAJAR, LOW);
  digitalWrite(SUBIR, HIGH);
  digitalWrite(LED, LOW);
  }
}
}

Alguna idea de cómo solucionarlo? Gracias de antemano.

Hola,

Quiero que mientras sube la compuerta esté parpadeando un led, y que deje de parpadear cuando llegue al final de carrera. El problema es que si programo el parpadeo dentro de un ciclo while usando un delay, el motor no para cuando llega al final de carrera, sinó cuando llega al final de carrera pero pasado el delay.

Tal vez esto te sirva. Cambia los delay por este delay “tuneado”:

bool wait(unsigned long ms) {
 //espera ms msec y si pasa algo, sale con true
 unsigned long end = millis() + ms;
 do {
 if(Aqui colocar la condición de fin de carrera 1) return true;
                if(Aqui colocar la condición de fin de carrera 2) return true;
                //o más condiciones si se usa para apagar o encender el led
 } while (millis() < end);
 return false;
}

y

en el do lo llamas así, sustituyendo los delays: (ejemplo para sustituir un delay(50):wink:

do {
....
//delay(50);
if (wait(50)) return;
....
}while();

Tal vez no es lo más elegante en programación pero creo que puede servir.

Un saludo

Metodo 2:

Primero.
Correcciones, todo lo que involucre millis() siempre usar unsigned long, no solo long y menos que menos int o unsigned int.

const unsigned long interval = 1000;

Segundo:
Con esto supongo que tu rutina debería funcionar

void parpadeo(){
 
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis >= interval){

    if (estadoLED == LOW){
        estadoLED = HIGH;
    }
    else{
        estadoLED = LOW;
    }
    previousMillis = currentMillis;
  }
  digitalWrite(LED, estadoLED);
}

He utilizado el método 2 de surbyte y funciona a la perfección.

Gracias a los dos por vuestras respuestas y correcciones!

Saludos! :slight_smile:

Tu unico error fue que colocaste

previousMillis = currentMillis;

fuera de la consulta cuando se cumple la condición de haber superado el intervalo, solo ahi debes actualizar el valor previo de millis.

O sea, falto un pequeño detalle a tu programa.

Ok, gracias por la aclaración. La verdad que a veces me pierdo entre los corchetes... :slight_smile:

Cuelgo el código final por si le sirve a alguien.

#define BotonSubir 4
#define BotonBajar 9
#define FinalCarreraSubir 7 
#define FinalCarreraBajar 8 
#define SUBIR 3 
#define BAJAR 2

const int LED = 11;

int estadoBotonSubir = 0;
int estadoBotonBajar = 0;
int estadoFinalSubir = 0;
int estadoFinalBajar = 0;
int estadoLED = LOW;

unsigned long previousMillis = 0;
const unsigned long interval = 1000;
 
//**********************************************************************************


void setup() {
  Serial.begin(9600);
  pinMode(BotonSubir, INPUT);
  pinMode(BotonBajar, INPUT);
  pinMode(FinalCarreraSubir, INPUT_PULLUP);
  pinMode(FinalCarreraBajar, INPUT_PULLUP);
  pinMode(SUBIR, OUTPUT);
  digitalWrite(SUBIR, HIGH);
  pinMode(BAJAR, OUTPUT);
  digitalWrite(BAJAR, HIGH);
  pinMode(LED, OUTPUT);
}


void loop() {

estadoBotonSubir = digitalRead(BotonSubir);
estadoBotonBajar = digitalRead(BotonBajar);
estadoFinalSubir = digitalRead(FinalCarreraSubir);
estadoFinalBajar = digitalRead(FinalCarreraBajar);

if(estadoFinalSubir == LOW){
  digitalWrite(SUBIR, HIGH);
  digitalWrite(LED, LOW);
}
else if(estadoBotonSubir == HIGH){
  digitalWrite(SUBIR, LOW);
  digitalWrite(BAJAR, HIGH);
  }

if(estadoFinalBajar == LOW){
  digitalWrite(BAJAR, HIGH);
  digitalWrite(LED, LOW);

  }
else if(estadoBotonBajar == HIGH){
  digitalWrite(LED, HIGH);
  delay(500);
  digitalWrite(LED, LOW);
  delay(500);
  digitalWrite(LED, HIGH);
  delay(500);
  digitalWrite(LED, LOW);
  delay(500);
  digitalWrite(BAJAR, LOW);
  digitalWrite(SUBIR, HIGH);
  digitalWrite(LED, LOW);
  while (estadoFinalBajar == HIGH){
    parpadeo();
  }
}
}

void parpadeo(){
  
  unsigned long currentMillis = millis();
 
  if(currentMillis - previousMillis >= interval){ 

    if(estadoLED == LOW){
      estadoLED = HIGH;
    }
    else{
      estadoLED = LOW;
    }
    previousMillis = currentMillis;
    estadoFinalBajar = digitalRead(FinalCarreraBajar);
  }
  digitalWrite(LED, estadoLED);
}

Saludos!