Enciende y apaga el LED con el interruptor

10

Estoy tratando de escribir código para que un LED se encienda cuando está apagado y para apagarlo cuando está encendido usando un interruptor táctil. Escribí lo que creo que es el código correcto con la biblioteca cableadoPi, pero solo puedo encenderlo cuando está apagado y no puedo apagarlo después de eso. En casos muy raros y después de muchas pulsaciones repetidas, el LED se apaga cuando está encendido y presiono el botón, pero estoy seguro de que no es así como debería funcionar.

#include <wiringPi.h>
int main (void)
{
    wiringPiSetup ();
    pinMode (0, OUTPUT);
    pinMode (1, INPUT);
    digitalWrite (0, LOW);
    for(;;)
    {
        if(digitalRead (1) == LOW)
        {
            if(digitalRead (0) == HIGH)
                digitalWrite (0, LOW);
            else if(digitalRead (0) == LOW)
                digitalWrite (0, HIGH);
         }
     }
     return 0;
}

He adjuntado una imagen de cómo está conectado el circuito.LEDciruit


fuente
2
¿Su biblioteca incluye algún rebote para el cambio? Si no, probablemente esté apagando el LED con éxito y luego volviéndolo a encender de inmediato. Una vez que haya detectado un cambio de estado, ignore cualquier otra detección durante un breve período.
1
@MikeW No lo creo. Intentaré insertar un retraso después de que se procese una declaración if.
66
@duskwuff Esta pregunta definitivamente es sobre programación.
1
mantenga una variable local que contenga el estado actual del led (ON / OFF) (probablemente a través de una enumeración) no intente leer el estado de un pin de salida. En su lugar, detecte el borde del cambio de estado de entrada de mayor a menor del pin de entrada. luego actualice el estado actual de la variable local: outputimagevar = (outputimagevar == HIGH)? BAJO: ALTO; luego digitalWrite (0, outputimagevar); luego, cuando la entrada cambie de BAJA a ALTA, restablezca la lógica de detección ALTA a BAJA. Además, asegúrese de "eliminar el rebote" del estado de entrada, quizás asegurando (digamos) que 3 lecturas consecutivas muestran el mismo estado.
Lo que acabo de hacer es insertar un retraso de medio segundo dentro del nido de cada instrucción if y parece estar funcionando bien esta vez. Algo me dice que este es un método de fuerza bruta que no siempre funcionará como podría anticipar si el botón se presiona más rápido que medio segundo, y probablemente no funcionará así en mi proyecto principal, así que investigaré El resto de las respuestas. Agradezco el aporte de todos.

Respuestas:

4

El cableado se ve correcto para el código.

El problema es que el código está en un circuito muy cerrado. En teoría, cuando se presiona el botón, el cuerpo del bucle enciende y apaga el LED repetidamente. En teoría, habría una probabilidad de 50/50 de que el LED se deja encendido (o apagado) cuando se suelta el botón. ¿Notas un cambio en el brillo cuando se presiona el botón? Puede que no haya suficiente para ser notado.

En la práctica, la razón de la tendencia a dejar encendido el LED es la forma en que realiza la prueba para ver si ya está encendido. El pin de escritura 0 ALTO aplica 3,3 V a la salida. Pero ese cable está conectado al LED y el pin está configurado para ser una salida. El LED puede estar bajando el voltaje lo suficiente como para no registrarse como ALTO cuando se lee, pero a veces lo hace porque está cerca del límite.

En la práctica, el código para apagar y encender el LED con cada pulsación de botón utilizaría una interrupción activada por un borde descendente. Como se señaló en los comentarios, querrás eliminar la interrupción en ese caso. También puede hacer lo mismo sin interrupciones registrando el estado anterior del botón y solo cambiando el LED cuando el estado del botón haya cambiado. El rebote cuando se escribe el código ahora no tiene sentido.

#include <wiringPi.h>
int main (void)
{
    wiringPiSetup ();
    pinMode (0, OUTPUT);
    pinMode (1, INPUT);
    digitalWrite (0, LOW);

    int prevButton = HIGH, LED = 0;

    for(;;)
    {
        if(prevButton == HIGH && digitalRead(1) == LOW)  // a falling edge
        {
            prevButton = LOW;

            if(LED)
            {
                LED = 0;
                digitalWrite(0, LOW);
            }
            else
            {
                LED = 1;
                digitalWrite(0, HIGH);
            }
        }
        else if(prevButton == LOW && digitalRead(1) == HIGH)  // a rising edge, do nothing
        {
            prevButton = HIGH;
        )

        // Add a delay here to debounce the button 

    }
    return 0;
}

fuente
0

Probablemente sea más simple mantener el "estado" en variables normales en lugar de tratar de inferirlo del estado GPIO actual.

Además, el "bucle ocupado" consumirá cada ciclo de CPU que el sistema operativo permitirá el proceso; ¡para un proceso tan simple, verá que la carga de su CPU aumentará al 100%! Debe permitir que el proceso entregue la CPU a otras tareas con una usleep()llamada, por ejemplo. La demora también servirá para eliminar el interruptor.

#include <wiringPi.h>
#include <unistd.h>

int main (void)
{
  wiringPiSetup ();
  pinMode (0, OUTPUT);
  pinMode (1, INPUT);
  digitalWrite (0, LOW);

  // Initial state
  int led = LOW ;
  bool button_down = (digitalRead(1) == LOW) ;

  for(;;)
  {
    // If button-down event (Hi-lo transition)...
    if( !button_down && digitalRead(1) == LOW )
    { 
      // Keep button state
      button_down = true ;

      // Toggle LED state
      led = (led == LOW) ? HIGH : LOW ;
      digitalWrite( 0, led ) ;
    }
    // Button up event...
    else if( button_down && digitalRead(1) == HIGH ) 
    {
      // Keep button state
      button_down = false ;
    }

    usleep( 10000 ) ;
  }

  return 0;
}
Clifford
fuente