Accendi e spegni il LED con l'interruttore


10

Sto cercando di scrivere un codice per far accendere un LED quando è spento e spegnerlo quando è acceso usando un interruttore a pulsante tattile. Ho scritto quello che credo sia il codice giusto con la libreria cablaggioPi, ma riesco a farlo accendere solo quando è spento e non riesco a spegnerlo dopo quello. In casi molto rari e dopo molte ripetute pressioni il LED si spegne quando è acceso e premo il pulsante, ma sono sicuro che non è così che dovrebbe funzionare.

#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;
}

Ho allegato un'immagine di come è cablato il circuito.LEDciruit

c 

2
La tua libreria include qualche debounce per lo switch? In caso contrario, probabilmente si sta spegnendo correttamente il LED e quindi si riaccende immediatamente. Dopo aver rilevato un cambio di stato, ignora eventuali ulteriori rilevamenti per un breve periodo.

1
@MikeW Non ci credo. Proverò a inserire un ritardo dopo l'elaborazione di un'istruzione if.

6
@duskwuff Questa domanda riguarda sicuramente la programmazione.

1
mantenere una variabile locale che contiene lo stato corrente del led (ON / OFF) (probabilmente tramite un enum) non tentare di leggere lo stato di un pin di uscita. Rileva invece il limite del cambiamento di stato dell'ingresso da alto a basso del pin di ingresso. quindi aggiornare lo stato corrente della variabile locale: outputimagevar = (outputimagevar == HIGH)? BASSO ALTO; quindi digitalWrite (0, outputimagevar); quindi, quando l'ingresso passa da BASSO a ALTO, reimpostare la logica di rilevamento DA ALTO a BASSO. Inoltre, assicurati di "rimbalzare" lo stato di input, forse assicurando (diciamo) che 3 letture consecutive mostrino tutte lo stesso stato.

Quello che ho appena fatto è inserire un ritardo di mezzo secondo nel nido di ciascuna istruzione if e sembra funzionare questa volta. Qualcosa mi dice che questo è un tipo di metodo bruteforce che non funzionerà sempre come potrei prevedere se il pulsante viene premuto più velocemente di mezzo secondo e probabilmente non funzionerà così nel mio progetto principale, quindi esaminerò il resto delle risposte. Apprezzo il contributo di tutti.

Risposte:


4

Il cablaggio sembra corretto per il codice.

Il problema è che il codice è in un ciclo molto stretto. In teoria, quando si preme il pulsante, il corpo del loop accende e spegne ripetutamente il LED. In teoria, ci sarebbe una probabilità 50/50 che il LED venga lasciato acceso (o spento) quando il pulsante viene rilasciato. Notate un cambiamento nella luminosità quando si preme il pulsante. Potrebbe non esserci abbastanza per essere notato.

In pratica, il motivo della tendenza a lasciare acceso il LED è il modo in cui testate per vedere se è già acceso. Il pin di scrittura 0 ALTO applica 3,3 V all'uscita. Ma quel filo è collegato al LED e il pin è configurato per essere un'uscita. Il LED potrebbe abbassare la tensione abbastanza basso da non registrarsi come ALTO quando viene letto, ma a volte lo fa perché è vicino al taglio.

In pratica, il codice per spegnere e accendere il LED ad ogni pressione di un pulsante userebbe un interrupt attivato dal fronte di discesa. Come sottolineato nei commenti, si vorrebbe rimandare l'interrupt in quel caso. Puoi anche fare la stessa cosa senza interruzioni registrando lo stato precedente del pulsante e cambiando il LED solo quando lo stato del pulsante è cambiato. Debouncare mentre il codice è scritto ora non ha senso.

#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;
}

0

È probabilmente più semplice mantenere lo "stato" nelle variabili normali piuttosto che provare a dedurlo dallo stato GPIO corrente.

Inoltre, il "ciclo occupato" consumerà ogni ciclo della CPU che il sistema operativo consentirà al processo; per un processo così semplice, vedrai che il tuo carico della CPU aumenterà al 100%! È necessario consentire al processo di abbandonare la CPU ad altre attività con una usleep()chiamata, ad esempio. Il ritardo servirà anche a rimbalzare l'interruttore.

#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;
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.