Allumez et éteignez la LED avec l'interrupteur

10

J'essaie d'écrire du code pour qu'une LED s'allume lorsqu'elle est éteinte et s'éteigne lorsqu'elle est allumée à l'aide d'un bouton-poussoir tactile. J'ai écrit ce que je pense être le bon code avec la bibliothèque de câblagePi, mais je ne peux le faire s'allumer que lorsqu'il est éteint et je ne peux pas le faire s'éteindre après cela. Dans de très rares cas et après de nombreuses pressions répétées, la LED s'éteint lorsqu'elle est allumée et j'appuie sur le bouton, mais je suis sûr que ce n'est pas comme cela que cela devrait fonctionner.

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

J'ai joint une image de la façon dont le circuit est câblé.LEDciruit


la source
2
Votre bibliothèque inclut-elle un anti-rebond pour le commutateur? Sinon, vous éteignez probablement la LED avec succès, puis la rallumez immédiatement. Une fois que vous avez détecté un changement d'état, ignorez toute autre détection pendant une courte période.
1
@MikeW Je ne le crois pas. Je vais essayer d'insérer un délai après le traitement d'une instruction if.
6
@duskwuff Cette question concerne définitivement la programmation.
1
garder une variable locale qui contient l'état actuel de la led (ON / OFF) (probablement via une énumération) n'essayez pas de lire l'état d'une broche de sortie. Détectez plutôt le bord du changement d'état d'entrée de haut en bas de la broche d'entrée. puis mettez à jour l'état actuel de la variable locale: outputimagevar = (outputimagevar == HIGH)? BAS: ÉLEVÉ; puis digitalWrite (0, outputimagevar); puis, lorsque l'entrée passe de LOW à HIGH, réinitialisez la logique de détection HIGH à LOW. Assurez-vous également de «rebondir» l'état d'entrée, peut-être en garantissant (disons) que 3 lectures consécutives affichent toutes le même état.
Ce que je viens de faire est d'insérer un délai d'une demi-seconde à l'intérieur du nid de chaque instruction if et cela semble fonctionner cette fois. Quelque chose me dit que c'est une sorte de méthode bruteforce qui ne fonctionnera pas toujours car je pourrais anticiper si le bouton est pressé plus rapidement qu'une demi-seconde, et cela ne fonctionnera probablement pas comme ça dans mon projet principal, donc je vais examiner le reste des réponses. J'apprécie la contribution de tout le monde.

Réponses:

4

Le câblage semble correct pour le code.

Le problème est que le code est dans une boucle très serrée. En théorie, lorsque le bouton est enfoncé, le corps de boucle allume et éteint la LED à plusieurs reprises. En théorie, il y aurait 50/50 de chances que la LED reste allumée (ou éteinte) lorsque le bouton est relâché. Avez-vous remarqué un changement de luminosité lorsque vous appuyez sur le bouton. Il n'y en a peut-être pas assez pour être remarqué.

En pratique, la raison de la tendance à laisser la LED allumée est la façon dont vous testez pour voir si elle est déjà allumée. L'écriture de la broche 0 HIGH applique 3,3 V à la sortie. Mais ce fil est connecté à la LED et la broche est configurée pour être une sortie. La LED baisse peut-être la tension suffisamment bas pour ne pas s'enregistrer comme ÉLEVÉE lorsqu'elle est lue, mais parfois c'est parce qu'elle est proche de la coupure.

En pratique, le code pour éteindre et rallumer la LED à chaque pression sur un bouton utiliserait une interruption déclenchée par un front descendant. Comme indiqué dans les commentaires, vous voudrez peut-être rebondir l'interruption dans ce cas. Vous pouvez également faire la même chose sans interruption en enregistrant l'état précédent du bouton et en ne modifiant la LED que lorsque l'état du bouton a changé. Débondir pendant l'écriture du code n'a plus de sens.

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

la source
0

Il est probablement plus simple de conserver "état" dans des variables normales plutôt que d'essayer de le déduire de l'état GPIO actuel.

De plus, la «boucle occupée» consommera chaque cycle de CPU que le système d'exploitation autorisera le processus; pour un processus aussi simple, vous verrez que votre charge CPU augmentera à 100%! Vous devez autoriser le processus à abandonner le CPU à d'autres tâches avec un usleep()appel par exemple. Le retard servira également à rebondir l'interrupteur.

#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
la source