arduino

Semáforo en Arduino sin delay

Hace algún tiempo vimos cómo simular un semáforo con 3 leds en Arduino, en donde usamos delay. En este post veremos exactamente lo mismo, pero con una condición: no usar delay.

El enfoque que hoy veremos servirá para otros proyectos en donde no podemos usar delay, por ejemplo, en uno en donde debemos escuchar el botón presionado de un teclado pero además debemos usar el tiempo de alguna manera (en un cronómetro por poner una referencia).

Semáforo sin delay: un enfoque distinto

Para no usar delay usamos el tiempo, sí, el tiempo en milisegundos que ha transcurrido desde que encendimos el Arduino.

El enfoque es sencillo, en lugar de dormir y pausar toda la ejecución, miramos el tiempo.

Voy a poner un ejemplo sencillo:

Enciendo el led verde a las 8:00:00 (aunque en realidad en Arduino se obtienen los milisegundos desde que la placa se ha encendido) y guardo la hora de manera que diga “A las 8:00 encendí el verde”, dejo que el código se ejecute y  compruebo a cada momento (dentro del loop) la hora; cuando vea que son 8:00:05 entonces enciendo el led amarillo (apagando el verde), y guardo un registro de que a las 8:00:05 encendí el amarillo, dejo que el código se siga ejecutando y así infinitamente.

¿La ventaja? la ventaja es que podemos tener más código no bloqueante y podemos ejecutar distintas cosas sin necesidad de dormir o esperar.

Hablar es de mal gusto, muéstrame el código

Para obtener los milisegundos llamamos a la función millis, y almacenamos el resultado en una global llamada ultimosMilisegundos. Después de eso, dentro del loop comprobamos si ha pasado el tiempo suficiente como para cambiar de luz del semáforo.

Por cierto, este valor de milisegundos se va a resetear en unos días después de haber encendido la placa, pero no pasa nada, pues volverá a 0 ya que ocurrirá un desbordamiento de la variable; cosa nada grave si solo lo usamos para el tiempo transcurrido.

/*
  Prueba 1: Semáforo simple
  INSTRUCCIONES: Realizar un sketch en Arduino que permita
  encender tres LED’s con la lógica de funcionamiento de un
  semáforo simple. El proceso inicia con el encendido del VERDE.
  
  Extra: no usar delay
  @author parzibyte
  Visita: parzibyte.me/blog
*/unsigned long ultimosMilisegundos = 0,
              milisegundosActuales;

int ledRojo = 7,
    ledAmarillo = 8,
    ledVerde = 9,
    SEGUNDOS_DE_ESPERA_VERDE_Y_ROJO = 5 * 1000, // En mi caso puse que el verde y rojo duren 10 segundos (10,000 milisegundos)
    SEGUNDOS_DE_ESPERA_AMARILLO = 2 * 1000,      // En mi caso puse que el amarillo dure 2 segundos (2,000 milisegundos)
    LED_ACTUAL = 0; // Por defecto no hay led encendido

void setup() {
  /*
    Establecemos como salida los tres leds
  */  pinMode(ledRojo, OUTPUT);
  pinMode(ledAmarillo, OUTPUT);
  pinMode(ledVerde, OUTPUT);
}

void loop() {
  /*
    En el bucle simplemente llamamos a la función "semaforo"
  */  semaforo();
}

void semaforo() {
  milisegundosActuales = millis(); // Obtenemos los milisegundos actuales

  // Nos fijamos en cuál led está encendido...
  switch (LED_ACTUAL) {
    case 9:
      if (elTurnoDeVerdeORojoHaTerminado())
        cambiaA(ledAmarillo);
      break;
    case 8:
      if (elTurnoDeAmarilloHaTerminado())
        cambiaA(ledRojo);
      break;
    case 7:
      if (elTurnoDeVerdeORojoHaTerminado())
        cambiaA(ledVerde);
      break;

    // Por defecto encenderá el verde al inicio
    default:
      cambiaA(ledVerde);
      break;
  }
}

boolean elTurnoDeVerdeORojoHaTerminado() {
  /*
    Simple función que compara el tiempo que lleva encendido el led verde o rojo
    ya que ambos duran 10 segundos encendidos.
    Devuelve verdadero si ya estuvo encendido 10 segundos, falso en caso contrario
  */  if (milisegundosActuales - ultimosMilisegundos >= SEGUNDOS_DE_ESPERA_VERDE_Y_ROJO) {
    ultimosMilisegundos = milisegundosActuales;
    return true;
  }
  return false;
}

boolean elTurnoDeAmarilloHaTerminado() {
  /*
    Simple función que compara el tiempo que lleva encendido el led amarillo
    Devuelve verdadero si ya estuvo encendido 2 segundos, falso en caso contrario
  */  if (milisegundosActuales - ultimosMilisegundos >= SEGUNDOS_DE_ESPERA_AMARILLO) {
    ultimosMilisegundos = milisegundosActuales;
    return true;
  }
  return false;
}

void cambiaA(int nuevoLed) {
  /*
    Función ayudante que apaga el led y enciende el nuevo,
    además de asignar a LED_ACTUAL el valor del (valga la redundancia)
    led actual
  */  digitalWrite(LED_ACTUAL, LOW);
  LED_ACTUAL = nuevoLed;
  digitalWrite(LED_ACTUAL, HIGH);
}

Circuito del semáforo sin delay

Como solo cambiamos la lógica, el circuito queda intacto y es el mismo de la vez pasada:

1.1 Semáforo simple

Las resistencias son de 220 ohms.

Simular circuito

Si crees que no funciona, prueba el semáforo sin delay en este enlace.

Estoy aquí para ayudarte 🤝💻


Estoy aquí para ayudarte en todo lo que necesites. Si requieres alguna modificación en lo presentado en este post, deseas asistencia con tu tarea, proyecto o precisas desarrollar un software a medida, no dudes en contactarme. Estoy comprometido a brindarte el apoyo necesario para que logres tus objetivos. Mi correo es parzibyte(arroba)gmail.com, estoy como@parzibyte en Telegram o en mi página de contacto

No te pierdas ninguno de mis posts 🚀🔔

Suscríbete a mi canal de Telegram para recibir una notificación cuando escriba un nuevo tutorial de programación.
parzibyte

Programador freelancer listo para trabajar contigo. Aplicaciones web, móviles y de escritorio. PHP, Java, Go, Python, JavaScript, Kotlin y más :) https://parzibyte.me/blog/software-creado-por-parzibyte/

Entradas recientes

Creador de credenciales web – Aplicación gratuita

Hoy te voy a presentar un creador de credenciales que acabo de programar y que…

3 días hace

Desplegar PWA creada con Vue 3, Vite y SQLite3 en Apache

Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…

1 semana hace

Arquitectura para wasm con Go, Vue 3, Pinia y Vite

En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…

1 semana hace

Vue 3 y Vite: crear PWA (Progressive Web App)

En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…

1 semana hace

Errores de Comlink y algunas soluciones

Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…

1 semana hace

Esperar promesa para inicializar Store de Pinia con Vue 3

En este artículo te voy a enseñar cómo usar un "top level await" esperando a…

1 semana hace

Esta web usa cookies.