Semáforo 2 Vías doble peatón, ¿Como interrumpo un ciclo?

hola, tengo un pequeño problema, y es que tengo un codigo el cual funciona bien, hace lo que debe hacer sin embargo al momento de presionar cualquiera de mis 2 botones, no interrumpe el ciclo como debería, y quisiera saber si alguien puede ayudarme, les dejare el código por aquí:

/*
SEMAFORO 2 UNIDADES
NIBBLE BOT

CONEXIONES DE LOS LEDS:
- PIN 13 LED VERDE 1
- PIN 12 LED AMARILLO 1
- PIN 11 LED ROJO 1
- PIN 10 LED VERDE 2
- PIN 9 LED AMARILLO 2
- PIN 8 LED ROJO 2
- PIN 7 BOTON PASO PEATON 1
- PIN 6 BOTON PASO PEATON 2
- PIN 5 LED VERDE PEATON 1
- PIN 4 LED VERDE PEATON 2
-PIN 2 LED AMARILLO PEATON1
-PIN 3 LED AMARILLO PEATON1

*/

// Definir pines de salidas para los semáforos
// SEMÁFORO 1
const int ledVerde1    = 13;
const int ledAmarillo1 = 12;
const int ledRojo1     = 11;
// SEMÁFORO 2
const int ledVerde2    = 10;
const int ledAmarillo2 = 9;
const int ledRojo2     = 8;

// Definir pines de los botones
const int botonPeaton1 = 7; // Botón para paso de peatón en la vía 1
const int botonPeaton2 = 6; // Botón para paso de peatón en la vía 2

// Definir pines de los LEDs verdes para peatones
const int ledVerdePeaton1 = 5; // LED verde de peatón en la vía 1
const int ledVerdePeaton2 = 4; // LED verde de peatón en la vía 2
const int ledAmarilloPeaton1 = 3; // LED verde de peatón en la vía 1
const int ledAmarilloPeaton2 = 2; // LED verde de peatón en la vía 2

void setup() {
  // Configurar los pines como salidas para los LEDs
  pinMode(ledVerde1,    OUTPUT);
  pinMode(ledAmarillo1, OUTPUT);
  pinMode(ledRojo1,     OUTPUT);
  pinMode(ledVerde2,    OUTPUT);
  pinMode(ledAmarillo2, OUTPUT);
  pinMode(ledRojo2,     OUTPUT);
  
  // Configurar los pines como entradas para los botones
  pinMode(botonPeaton1, INPUT_PULLUP);
  pinMode(botonPeaton2, INPUT_PULLUP);

  // Configurar los pines como salidas para los LEDs verdes y amarillos de peatones
  pinMode(ledVerdePeaton1, OUTPUT);
  pinMode(ledVerdePeaton2, OUTPUT);
  pinMode(ledAmarilloPeaton1, OUTPUT);
  pinMode(ledAmarilloPeaton2, OUTPUT);
}

void loop() {
  // Verificar si se presiona cualquiera de los botones
  if (digitalRead(botonPeaton1) == LOW || digitalRead(botonPeaton2) == LOW) {
    // Si se presiona cualquier botón, realizar el cruce de peatones
    crucePeatonal();
  } else {
    // De lo contrario, ejecutar el ciclo normal de los semáforos
    cicloSemaforo();
  }
}

// Función que simula el cruce de peatones
void crucePeatonal() {
  // Cambiar los semáforos a amarillo y hacerlos parpadear simultáneamente
  blinkSimultaneo(ledAmarillo1, ledAmarillo2, 5, 500);

  // Cambiar los semáforos a rojo para que los peatones crucen
  digitalWrite(ledRojo1, HIGH);
  digitalWrite(ledRojo2, HIGH);
  digitalWrite(ledVerde1, LOW);
  digitalWrite(ledVerde2, LOW);
  digitalWrite(ledVerdePeaton1, HIGH);
  digitalWrite(ledVerdePeaton2, HIGH);
  delay(20000); // Los peatones tienen 20 segundos para cruzar

  // Apagar los LEDs verdes de peatones
  digitalWrite(ledVerdePeaton1, LOW);
  digitalWrite(ledVerdePeaton2, LOW);

  // Parpadeo rápido de los LEDs amarillos de peatones durante 5 segundos
  blinkSimultaneo(ledAmarilloPeaton1, ledAmarilloPeaton2, 5, 500);
  
  // Después de 5 segundos, regresar a la secuencia normal
}

// Función que maneja el ciclo normal de los semáforos
void cicloSemaforo() {
  // SEMÁFORO 1 - Fase verde
  digitalWrite(ledVerde1, HIGH);   // LED VERDE 1
  digitalWrite(ledRojo1,  LOW);		// APAGA LED ROJO 1
  digitalWrite(ledRojo2,  HIGH);   // LED ROJO 2
  delay(5000);   // Mantener el verde por 5 segundos
  digitalWrite(ledVerde1, LOW);

  // Parpadeo rápido de verde
  blink(ledVerde1, 5, 500);

  // SEMÁFORO 1 - Fase amarilla
  digitalWrite(ledAmarillo1, HIGH);  // LED AMARILLO 1
  delay(500);
  digitalWrite(ledAmarillo1, LOW);
  blink(ledAmarillo1, 5, 500);

  // Cambiar a rojo
  digitalWrite(ledRojo1, HIGH);
  digitalWrite(ledRojo2, LOW);

  // SEMÁFORO 2 - Fase verde
  digitalWrite(ledVerde2, HIGH);    // LED VERDE 2
  delay(5000);   // Mantener el verde por 5 segundos
  digitalWrite(ledVerde2, LOW);

  // Parpadeo rápido de verde
  blink(ledVerde2, 5, 500);

  // SEMÁFORO 2 - Fase amarilla
  digitalWrite(ledAmarillo2, HIGH);  // LED AMARILLO 2
  delay(500);
  digitalWrite(ledAmarillo2, LOW);
  blink(ledAmarillo2, 5, 500);

  // Cambiar a rojo
  digitalWrite(ledRojo1, LOW);
}

// Función para encender y apagar un LED con una secuencia rápida
void blink(int pin, int times, int delayTime) {
  for (int i = 0; i < times; i++) {
    digitalWrite(pin, HIGH);
    delay(delayTime);
    digitalWrite(pin, LOW);
    delay(delayTime);
  }
}

// Función para hacer parpadear dos LEDs simultáneamente
void blinkSimultaneo(int pin1, int pin2, int times, int delayTime) {
  for (int i = 0; i < times; i++) {
    digitalWrite(pin1, HIGH);
    digitalWrite(pin2, HIGH);
    delay(delayTime);
    digitalWrite(pin1, LOW);
    digitalWrite(pin2, LOW);
    delay(delayTime);
  }
}

La palabra clave es “interrumpe”. La operación del semáforo no se interrumpe debido a que estás usando la función delay(). Recuerda que el Arduino no hará nada hasta que termine de ejecutarse cada delay.

Debes cambiar el uso de delay() por millis() si quieres que el semáforo reaccione “inmediatamente.

Un esquema basado en una máquina de estados haría el trabajo de forma más simple.

Estudia el ejemplo de Blink without delay y el concepto de máquinas de estados (fan por sus siglas en inglés)

De hecho estaba viendo eso de los millis, y lo intenté solo que no alcance a comprender, como acomodarlo a mi código, sin embargo, estaba seguro de que con eso se solucionaba

Imagina que en cuanto arranca el Arduino se inicia un cronómetro que no se detiene.

Todo lo que hacemos es registrar la lectura del cronómetro cada vez que ocurre un evento.

Para saber si ha llegado el momento, digamos, de encender o de apagar un LED, es decir, de cambiar el estado del LED, comparamos el tiempo actual con la lectura que habíamos registrado cuando el LED entró en el estado actual. Si ya pasó el tiempo apropiado cambiamos el LED al siguiente estado, registrando el instante en que ocurre este cambio de estado y ejecutando las acciones que correspondan a este nuevo estado (encender o apagar el LED).

La función millis() nos da el tiempo actual, expresado como la cantidad de milisegundos que han transcurrido desde que inició la operación del Arduino, y es el cronómetro del que estamos hablando.

Un semáforo tiene varios estados que se ejecutan en secuencia de forma cíclica. Una vez que ya logramos tener el semáforo funcionando como una máquina de estados resulta muy sencillo modificar el código para detectar cuando se ha oprimido el botón peatonal y cambiar a un estado en el que se active el semáforo peatonal, tal vez esperando a que se termine el ciclo actual del semáforo principal.

El diseño del semáforo implica decidir cuáles estados tiene, en qué secuencia ocurren, cuánto tiempo duran y qué ocurre en cada uno.

Por ejemplo, para una intersección de dos calles de un solo sentido podemos tener 6 luces sin considerar luces peatonales:
Verde1, Amarillo1, Rojo1, Verde2, Amarillo2, Rojo2

Usando este orden y para simplificar podemos decir que
100 001 representa sólo Verde1 y Rojo2 encendidos y 001 100 sólo Rojo1 y Verde2.

Un semáforo simple podría tener los siguientes estados
ESTADO-LUCES-SEGUNDOS

A-100 001-30
B-010 001-5
C-001 001-2
D-001 100-30
E-001 010-5
F-001 001-2
Y la secuencia sería A-B-C-D-E-F-A. Al entrar a cada estado registramos el tiempo en que estamos entrando y en activamos los LEDs correspondientes. Cada vez que se inicia el loop checamos en qué estado estamos y verificamos si ya llegó el momento de cambiar al siguiente estado. En caso negativo no hacemos nada más. Esto quiere decir que el loop se ejecuta probablemente más de mil veces por segundo.

Es fácil ver que se puede detectar rápidamente cuando se ha oprimido un botón y activar una bandera que nos altere el orden de los estados, digamos de ABCDEFA a ABCPQDEFA o a ABCDEFRSA, donde PQ/RS son estados en los que tenemos 001 001 en las luces principales y 10-01 en las peatonales.

@job_glz ,

:warning:

He trasladado su tema de una categoría de idioma inglés del foro a la categoría International > Español .

En adelante por favor usar la categoría apropiada a la lengua en que queráis publicar. Esto es importante para el uso responsable del foro, y esta explicado aquí la guía "How to get the best out of this forum".
Este guía contiene mucha información útil. Por favor leer.

De antemano, muchas gracias por cooperar.

2 Likes

En la sección Documentación tienes varios tutoriales sobre millis() y una muy buena guía con algunos ejemplos de máquina de estados. Busca también con la Lupa (nuestro buscador interno). Hay numerosos ejemplos que empezaron como el tuyo y fueron resueltos con máquinas de estados.

Moderador
Te envío un mensaje interno porque son varias las faltas que has cometido y no quiero desviar el tema.
Solo te pido que leas las normas del foro y que veas el mensaje que te he enviado y hagas las correcciones que solicito.

Bueno te pedí que vieras los tutoriales porque de otro modo no entenderás nada de lo que ahora he hecho.
Este código creo que esta aceptablemente bien.

Acá lo puedes simular.
Revisa a ver si si estoy en lo cierto.

#define LED_VERDE1    13
#define LED_AMARILLO1 12
#define LED_ROJO1     11
#define LED_VERDE2    10
#define LED_AMARILLO2  9
#define LED_ROJO2      8
#define BOTON_PEATON1  7
#define BOTON_PEATON2  6
#define LED_VERDE_PEATON1 5
#define LED_VERDE_PEATON2 4
#define LED_AMARILLO_PEATON1 3
#define LED_AMARILLO_PEATON2 2

unsigned long tiempoActual;
unsigned long tiempoAnterior = 0;
unsigned long intervalo = 1000;

enum Estado {
  CICLO_VERDE1,
  CICLO_AMARILLO1,
  CICLO_VERDE2,
  CICLO_AMARILLO2,
  CRUCE_PEATONAL
};

Estado estadoActual = CICLO_VERDE1;
int parpadeos = 0;
bool botonPeaton1Presionado = false;
bool botonPeaton2Presionado = false;

void setup() {
  pinMode(LED_VERDE1, OUTPUT);
  pinMode(LED_AMARILLO1, OUTPUT);
  pinMode(LED_ROJO1, OUTPUT);
  pinMode(LED_VERDE2, OUTPUT);
  pinMode(LED_AMARILLO2, OUTPUT);
  pinMode(LED_ROJO2, OUTPUT);
  pinMode(BOTON_PEATON1, INPUT_PULLUP);
  pinMode(BOTON_PEATON2, INPUT_PULLUP);
  pinMode(LED_VERDE_PEATON1, OUTPUT);
  pinMode(LED_VERDE_PEATON2, OUTPUT);
  pinMode(LED_AMARILLO_PEATON1, OUTPUT);
  pinMode(LED_AMARILLO_PEATON2, OUTPUT);

  digitalWrite(LED_ROJO2, HIGH);
}

void loop() {
  tiempoActual = millis();

  botonPeaton1Presionado = !digitalRead(BOTON_PEATON1);
  botonPeaton2Presionado = !digitalRead(BOTON_PEATON2);

  if ((botonPeaton1Presionado || botonPeaton2Presionado) && estadoActual != CRUCE_PEATONAL) {
    estadoActual = CRUCE_PEATONAL;
    tiempoAnterior = tiempoActual;
    parpadeos = 0;
  }

  switch (estadoActual) {
    case CICLO_VERDE1:
      if (tiempoActual - tiempoAnterior >= 5000) {
        digitalWrite(LED_VERDE1, LOW);
        digitalWrite(LED_AMARILLO1, HIGH);
        estadoActual = CICLO_AMARILLO1;
        tiempoAnterior = tiempoActual;
      } else {
        digitalWrite(LED_VERDE1, HIGH);
        digitalWrite(LED_ROJO2, HIGH);
        digitalWrite(LED_ROJO1, LOW);
      }
      break;

    case CICLO_AMARILLO1:
      if (tiempoActual - tiempoAnterior >= 3000) {
        digitalWrite(LED_AMARILLO1, LOW);
        digitalWrite(LED_ROJO1, HIGH);
        digitalWrite(LED_VERDE2, HIGH);
        estadoActual = CICLO_VERDE2;
        tiempoAnterior = tiempoActual;
      }
      break;

    case CICLO_VERDE2:
      if (tiempoActual - tiempoAnterior >= 5000) {
        digitalWrite(LED_VERDE2, LOW);
        digitalWrite(LED_AMARILLO2, HIGH);
        estadoActual = CICLO_AMARILLO2;
        tiempoAnterior = tiempoActual;
      } else {
        digitalWrite(LED_ROJO1, HIGH);
        digitalWrite(LED_VERDE2, HIGH);
        digitalWrite(LED_ROJO2, LOW);
      }
      break;

    case CICLO_AMARILLO2:
      if (tiempoActual - tiempoAnterior >= 3000) {
        digitalWrite(LED_AMARILLO2, LOW);
        digitalWrite(LED_ROJO2, HIGH);
        digitalWrite(LED_VERDE1, HIGH);
        estadoActual = CICLO_VERDE1;
        tiempoAnterior = tiempoActual;
      }
      break;

    case CRUCE_PEATONAL:
      if (parpadeos < 5) {
        if (tiempoActual - tiempoAnterior >= 500) {
          tiempoAnterior = tiempoActual;
          parpadeos++;
          toggle(LED_AMARILLO1);
          toggle(LED_AMARILLO2);
        }
      } else if (parpadeos == 5) {
        digitalWrite(LED_AMARILLO1, LOW);
        digitalWrite(LED_AMARILLO2, LOW);
        digitalWrite(LED_ROJO1, HIGH);
        digitalWrite(LED_ROJO2, HIGH);
        digitalWrite(LED_VERDE_PEATON1, HIGH);
        digitalWrite(LED_VERDE_PEATON2, HIGH);
        if (tiempoActual - tiempoAnterior >= 20000) {
          digitalWrite(LED_VERDE_PEATON1, LOW);
          digitalWrite(LED_VERDE_PEATON2, LOW);
          estadoActual = CICLO_VERDE1;
          tiempoAnterior = tiempoActual;
        }
      }
      break;
  }
}

void toggle(int pin) {
  digitalWrite(pin, !digitalRead(pin));
}

una disculpa, es primer post:C, tomare todo en cuenta para el siguiente :smiley:

Corregí algunos errores de sintaxis, pero estoy intententando hacer que los leds amarillos del peaton parpadeen pero al momento de agrregar un toggle extra me da error

adicional a esto, estaba intentando hacer que los leds del semáforo vial, parpadeen al momento de hacer cambio de estados, por ejemplo, cuando está en verde, antes de cambiar a amarillo debería parpadear e igual el amarillo debería parpadear un par de veces antes de cambiar al estado en rojo

:thinking:

No logro ver donde está el error. Vas a tener que publicar tu código…

Hablas del código que yo posteé en #7? No da error porque lo probé.

No se entiende.
Te manejas mal, porqué no publicas código y explicas que hiciste y que no funciona?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.