Włączaj i wyłączaj diody LED przełącznikiem

10

Próbuję napisać kod, aby dioda LED zaświeciła się, gdy jest wyłączona, i wyłącza się, gdy jest włączona za pomocą dotykowego przełącznika przyciskowego. Napisałem, co moim zdaniem jest właściwym kodem z biblioteką wiringPi, ale mogę go włączyć tylko wtedy, gdy jest wyłączony, a potem nie mogę go wyłączyć. W bardzo rzadkich przypadkach i po wielu powtarzających się naciśnięciach dioda LED zgaśnie, gdy jest włączona i nacisnę przycisk, ale jestem pewien, że nie tak powinno to działać.

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

Dołączyłem obraz okablowania obwodu.LEDciruit


źródło
2
Czy twoja biblioteka zawiera jakieś informacje zwrotne dotyczące przełącznika? Jeśli nie, prawdopodobnie z powodzeniem wyłączasz diodę LED, a następnie natychmiast ją włączasz. Po wykryciu zmiany stanu przez krótki czas ignoruj ​​wszelkie dalsze wykrycia.
1
@MikeW Nie wierzę tak. Spróbuję wstawić opóźnienie po przetworzeniu instrukcji if.
6
@duskwuff To pytanie zdecydowanie dotyczy programowania.
1
zachowaj zmienną lokalną, która zawiera bieżący stan diody LED (ON / OFF) (prawdopodobnie przez enum), nie próbuj odczytywać stanu pinów wyjściowych. Zamiast tego wykryj krawędź zmiany stanu wejściowego z wysokiej na niską szpilki wejściowej. następnie zaktualizuj aktualny stan zmiennej lokalnej: outputimagevar = (outputimagevar == HIGH)? NISKIE WYSOKIE; następnie digitalWrite (0, outputimagevar); następnie, gdy wejście zmieni się z LOW na HIGH, zresetuj logikę detekcji HIGH na LOW. Pamiętaj też, aby „ogłosić” stan wejściowy, być może zapewniając, powiedzmy, 3 kolejne odczyty wszystkie pokazują ten sam stan.
Właśnie wstawiłem półsekundowe opóźnienie do gniazda każdej instrukcji if i wydaje się, że tym razem działa poprawnie. Coś mi mówi, że jest to rodzaj brutalnej siły, która nie zawsze zadziała, jak bym się spodziewał, jeśli przycisk zostanie naciśnięty szybciej niż pół sekundy, i prawdopodobnie nie zadziała tak w moim głównym projekcie, więc przyjrzę się pozostałe odpowiedzi. Doceniam wkład wszystkich.

Odpowiedzi:

4

Okablowanie wygląda poprawnie dla kodu.

Problem polega na tym, że kod jest w bardzo ciasnej pętli. Teoretycznie po naciśnięciu przycisku korpus pętli wielokrotnie włącza i wyłącza diodę LED. Teoretycznie istnieje ryzyko 50/50, że dioda LED pozostanie włączona (lub wyłączona) po zwolnieniu przycisku. Czy zauważysz zmianę jasności po naciśnięciu przycisku. Być może nie wystarczy być zauważonym.

W praktyce przyczyną pozostawienia włączonej diody LED jest sposób, w jaki testujesz, czy jest już włączona. Zapisywanie pin 0 WYSOKIE doprowadza do wyjścia 3,3 V. Ale ten przewód jest podłączony do diody LED, a pin skonfigurowany jako wyjście. Dioda LED może obniżać napięcie na tyle niskie, aby nie rejestrować się jako WYSOKA podczas odczytu, ale czasami dzieje się tak, ponieważ znajduje się w pobliżu wartości granicznej.

W praktyce kod wyłączania i włączania diody LED przy każdym naciśnięciu przycisku używałby przerwania wyzwalanego zboczem. Jak wskazano w komentarzach, w takim przypadku chciałbyś ogłosić przerwanie. Możesz również zrobić to samo bez przerw, rejestrując poprzedni stan przycisku i zmieniając diodę LED tylko wtedy, gdy stan przycisku się zmienił. Odrzucanie w trakcie pisania kodu nie ma teraz sensu.

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

źródło
0

Prawdopodobnie łatwiej jest utrzymać „stan” w zmiennych normalnych niż próbować wywnioskować to z bieżącego stanu GPIO.

Również „pętla zajętości” będzie zużywać każdy cykl procesora, na który system operacyjny zezwoli; w przypadku tak prostego procesu zobaczysz, że obciążenie procesora wzrośnie do 100%! Powinieneś pozwolić procesowi zrezygnować z procesora na inne zadania, usleep()na przykład przez wywołanie. Opóźnienie służy również do odbicia przełącznika.

#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
źródło