Interrupción en arduino

Hola, buenas noches...

He estado trabajando en un proyecto personal para montar un sistema de luces en mi bicicleta. Hace un par de días leí por ahí de que se pueden implementar interrupciones en Arduino (yo uso Arduino Uno, o más bien una imitación...). Buscando en la internet encontré algunas páginas que me ayudaron a entender un poco todo esto.

http://www.educachip.com/como-y-por-que-usar-las-interrupciones-en-arduino

El asunto con todo esto es que tengo un botón de motocicleta al cual necesito asociar dos interrupciones simples, virar a la derecha o izquierda mientras dos luces parpadean (delantera y trasera). La botonera tiene un interruptor de tres contactos que son para señalización, y pensé en escribir el código, basándome en el en link de la página que mencioné más arriba y en este vídeo:

El asunto con el código es que no funciona, no sé en que parte me he equivocado o he hecho mal, espero que me puedan ayudar...

int trasero = 8;
int delantero = 9;
int led_izquierdo = 11;
int pulsador_izq = 2;

volatile int izquierdo = LOW;

void setup (){
pinMode (8,OUTPUT);
pinMode (9,OUTPUT);
pinMode (10,OUTPUT);
pinMode (11,OUTPUT);
pinMode (pulsador_izq, INPUT);
attachInterrupt (digitalPinToInterrupt(pulsador_izq), fun_izquierdo, RISING);
digitalWrite (led_izquierdo,LOW);
}

void loop (){
digitalWrite (8,1);
delay (50);
digitalWrite (8,0);
delay (50);
digitalWrite(9,1);
delay (50);
digitalWrite (9,0);
delay (50);
digitalWrite(led_izquierdo,izquierdo);
}
void fun_izquierdo(){
led_izquierdo = !led_izquierdo;
}

A ver si esta página te ayuda: Interrupciones con Arduino

En teoría las interrupciones de los pines se usan básicamente por tres motivos.

Uno: porque no queremos estar continuamente comprobando el estado del pin ya que nos complica el resto del programa. Así que hacemos el programa "despreocupándonos" del pin y que la interrupción lo "atienda".

Dos: porque aunque estemos dispuestos a estar continuamente comprobando el estado del pin, el atender el resto del programa hace que exista la posibilidad de que no "veamos" el cambio del pin a tiempo (por ser demasiado rápido) y "se nos pase", en estos casos sí que no suele haber más remedio que usar interrupciones.

Tres: queremos ahorrar energía al máximo, así que cuando no hay nada que hacer "dormimos" el Arduino y un cambio en la entrada del pin hace que se genere una interrupción que "despierte" el Arduino y haga lo que ha de hacer, para volver a "dormirse" cuando ya no hay nada más que hacer que esperar el próximo "despertar". En este otro caso también se hace imprescindible el uso de las interrupciones.

Pero el uso de interrupciones no es todo lo fantástico que se pueda esperar. Tiene algunos inconvenientes y uno de ellos es que, para que el resto del programa funciones con cierta "normalidad", han de ser "breves" y su ejecución ha de durar lo menos posible. La regla de oro es "en una interrupción has lo imprescindible, el resto hazlo fuera de la interrupción, cuando se pueda".

Dicho esto, teniendo en cuenta lo que quieres hacer, el único sentido que le encuentro el uso de las interrupciones es el uso tres. Queremos ahorrar energía al máximo y dormir el Arduino mientras no se quieran poner los intermitentes. Si no es para eso, en tu caso, sería como matar moscas a cañonazos.

Si, por ahora, no te importa mucho el consumo: yo no usaría las interrupciones. Basta con controlar con dos entradas del Arduino si el interruptor está en alguna de las dos posiciones de intermitencia y controlar el tiempo que se tiene encendido los intermitentes de un lado u otro. Si acaso, usar un par de transistores a las salidas del Arduino para conectar las luces de los intermitentes (ya sean de incandescencia o LEDs) para proteger las salidas del Arduino (incluso dado el caso te recomendará octoacopladores) y listo.

Hola, buen día.

Lo que mencionas o leí, y aunque por ahora mi código es realmente básico, sólo necesito que dos pines ejecuten de forma periódica la emisión de HIGH/LOW para que los leds conectados a estos sean alternos en cuanto a su iluminación, se me había ocurrido crear un "if anidado" para las luces intermitentes, pero la arduino tendría que estar revisando esa estructura del código, lo cual no creo que sea muy optimo, por eso se me ocurrió implementar las interrupciones (además que pienso añadir otras partes al código a futuro)... Por otro lado, considero las opciones que planteas y me siento en duda honestamente de como estructurar el código...

Quizá es mi falta de experiencia programando y armando circuitos electrónicos, ¿pero se podría crear un pequeño bucle para las luces señalizadoras para que queden permanentemente apagandose/prendiendose usando un while?

Te adjunto link de otra pregunta que realicé en otro post de Arduino relacionada con los relay y una placa Uno (solucionada).

Aquí tienes una posible solución para los intermitentes sin usar interrupciones. Usando interrupciones no creas que es mucho más sencilla.

Es aplicando el concepto de no usar delay() que detengan la ejecución del programa, sino millis() y una máquina de estados.

El código está comentado para ayudarte a entender cómo funciona y saber configurarlo a tu gusto.

Cualquier duda, preguntar por aquí.

Adjunto fichero.

foro_intermitentes.ino (10.3 KB)

Hola otra vez...

No me había percatado de tu mensaje, mientras, busqué una solución que creo es la que necesitaba para las luces señalizadoras (y así me guardo las interrupciones para algo realmente urgente, ya veré para que). El código lo escribí a mano en mi libreta de ideas usando whiles, así que llegué a mi casa y lo escribí en mi pc y monté el circuito, te lo dejo para que me digas que opinas acerca de él y su funcionamiento en un vídeo.

int luz_senal_derecha = 13;
int luz_senal_izquierda = 12;
int int_doblar_izquierda = 11;
int int_doblar_derecha = 10;
int iluminacion_delantera = 9;
int iluminacion_trasera = 8;

void setup () {
  pinMode (luz_senal_derecha, OUTPUT);
  pinMode (luz_senal_izquierda, OUTPUT);
  pinMode (int_doblar_izquierda, INPUT_PULLUP);
  pinMode (int_doblar_derecha, INPUT_PULLUP);
  pinMode (iluminacion_delantera, OUTPUT);
  pinMode (iluminacion_trasera, OUTPUT);
}

void loop (){
  digitalWrite (iluminacion_delantera, HIGH);
  delay (50);
  digitalWrite (iluminacion_delantera, LOW);
  delay (50);
  digitalWrite (iluminacion_trasera, HIGH);
  delay (50);
  digitalWrite (iluminacion_trasera, LOW);
  delay (50);
  
  while (digitalRead (int_doblar_derecha) == HIGH){
    digitalWrite (luz_senal_derecha, HIGH);
    delay (40);
    digitalWrite (luz_senal_derecha, LOW);
    delay (40);
    digitalWrite (iluminacion_delantera, HIGH);
    delay (40);
    digitalWrite (iluminacion_delantera, LOW);
    delay (40);
    digitalWrite (iluminacion_trasera, HIGH);
    delay (40);
    digitalWrite (iluminacion_trasera, LOW);
    delay (40);
  }
  while (digitalRead (int_doblar_izquierda) == HIGH){
    digitalWrite (luz_senal_izquierda, HIGH);
    delay (40);
    digitalWrite (luz_senal_izquierda, LOW);
    delay (40);
    digitalWrite (iluminacion_delantera, HIGH);
    delay (40);
    digitalWrite (iluminacion_delantera, LOW);
    delay (40);
    digitalWrite (iluminacion_trasera, HIGH);
    delay (40);
    digitalWrite (iluminacion_trasera, LOW);
    delay (40);
  }

}

Vídeo :smiley:

Sobre el código que me acabas de escribir, te doy las gracias por dedicar el tiempo, lo he mirado y honestamente me pilló por sorpresa, tengo que revisarlo con calma (pienso imprimirlo para saber como lo estructurasté). Gracias.

Hay algo que no me cuadra de tu solución. Se supone que el loop() hace que la luz delantera destelle (se enciende y apaga rápidamente), después destella la luz trasera y luego, si el interruptor del intermitente está activo, destella un mínimo de tres veces el intermitente y ha de seguir destellando tres veces mientras esté puesto el intermitente, sin que las otras luces puedan destellar. Pero al ver el vídeo creo que no está continuamente en el while, sino que se sale del bucle y vuelve a ejecutar el loop(), con lo que vuelve a destellar la luz delantera, luego la trasera y de nuevo el intermitente. Esto concuerda con que estuvieras usando un if en lugar del while. Si no es así, no le encuentro otra explicación más que no esté haciendo buen contacto el interruptor y esto haga que dé diferentes lecturas y haga que se salga del while.

Lo que "el truco" de usar destellos está bien, siempre que sean eso, destellos (encender y apagar rápidamente la luz) ya que nunca tendrás dos luces encendidas a la vez porque para encender una estás apagando antes la otra. Los intermitentes afectan a la frecuencia de destello de la luces delanteras y traseras, pero no se nota mucho si los tiempos son muy pequeños. Pero si quieres tiempos más grandes... entonces sí que se notará.

Mi propuesta es "asíncrona" y podría tener los intermitentes encendidos a la vez que las luces delantera y trasera, con lo que puedes tenerlos más tiempo encendidos. Si te convence o quieres probarla con las luces delantera y trasera, para implementar estas luces puedes usar el ejemplo "oficial" de Arduino de usar millis() para sustituir los delay(). El ejemplo hace parpadear un LED sin que el loop() se vea "bloqueado" por los delay(). El principio que usa ese ejemplo es el mismo que he usado para los intermitentes (con "un poco" más de complejidad). Sólo has de copiar el ejemplo dentro de mi código y adaptarlo a tus necesidades. Para ello lo que está antes del setup() y del loop() lo pones antes del setup() y del loop(). Lo que está dentro del setup() lo pones dentro del setup(). Y lo que está en el loop() lo pones dentro del loop(). El ejemplo está aquí: https://www.arduino.cc/en/Tutorial/BlinkWithoutDelay. Si no te importa que la luces delanteras y traseras vayan al mismo ritmo, puedes encender y apagar las dos a la vez con la adaptación del ejemplo y así te ahorras el control independiente de cada una de ellas.

Lo que programé es lo siguiente. El código del loop () ejecuta el parpadeo de las luces delantera y trasera (amarilla y roja, de izquierda a derecha en protoboard) y se mantiene ahí permanentemente (de hecho mientras escribo tengo el circuito en ejecución dentro del loop), al hacer contacto con derecha o izquierda usando el interruptor, la Arduino ejecuta el while asociado a la derecha o izquierda y se mantiene ahí hasta que no cambie la posición del interruptor de tres patas (puedes verlo en el vídeo de derecha a izquierda, donde derecha es roja e izquierda es verde). Ahora, leyendo tu recomendación, usar millis () la había considerado desde un principio, pero a mi parecer es mejor que las luces permanezcan parpadeando, creo que así llaman mejor la atención de las personas (sobretodo en las carreteras de atardecer). Eso, no sé que piensas.