Ligar e desligar o LED com o interruptor

10

Estou tentando escrever um código para que um LED acenda quando está apagado e quando está aceso usando um botão de pressão tátil. Eu escrevi o que acredito ser o código certo com a biblioteca de fiaçãoPi, mas só consigo ligá-lo quando está desligado e depois não consigo. Em casos muito raros e após muitas repetidas repetições, o LED apaga quando está ligado e eu pressiono o botão, mas tenho certeza de que não é assim que deve 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;
}

Anexei uma imagem de como o circuito está conectado.LEDciruit


fonte
2
Sua biblioteca inclui alguma rejeição para a troca? Caso contrário, você provavelmente está apagando o LED com sucesso e ligando-o imediatamente imediatamente. Depois de detectar uma alteração de estado, ignore outras detecções por um curto período.
11
@ MikeW Eu não acredito nisso. Vou tentar inserir um atraso depois que uma instrução if for processada.
6
@duskwuff Esta questão é definitivamente sobre programação.
11
mantenha uma variável local que contenha o estado atual do led (ON / OFF) (provavelmente através de um enum), não tente ler o estado de um pino de saída. Em vez disso, detecte a borda da alteração do estado de entrada de alto para baixo do pino de entrada. atualize o estado atual da variável local: outputimagevar = (outputimagevar == HIGH)? BAIXO ALTO; então digitalWrite (0, outputimagevar); depois, quando a entrada mudar de LOW para HIGH, redefina a lógica de detecção HIGH para LOW. Além disso, certifique-se de 'rebater' o estado de entrada, talvez assegurando (digamos) três leituras consecutivas, todas mostrando o mesmo estado.
O que acabei de fazer é inserir um atraso de meio segundo dentro do ninho de cada instrução if e parece estar funcionando corretamente neste momento. Algo me diz que esse é um tipo de método de força bruta que nem sempre funciona como eu poderia antecipar se o botão for pressionado mais rápido do que meio segundo e provavelmente não funcionará assim no meu projeto principal, então analisarei o resto das respostas. Agradeço a contribuição de todos.

Respostas:

4

A fiação parece correta para o código.

O problema é que o código está em um loop muito restrito. Em teoria, quando o botão é pressionado, o corpo do loop liga e desliga repetidamente o LED. Em teoria, haveria uma chance de 50/50 de o LED permanecer aceso (ou apagado) quando o botão for liberado. Você percebe uma alteração no brilho quando o botão é pressionado. Pode não haver o suficiente para ser notado.

Na prática, o motivo da tendência de deixar o LED aceso é a maneira como você testa para verificar se ele já está aceso. O pino de escrita 0 HIGH aplica 3,3 V à saída. Mas esse fio está conectado ao LED e o pino configurado para ser uma saída. O LED pode estar reduzindo a voltagem baixa o suficiente para não se registrar como ALTO quando é lido, mas às vezes ocorre porque está próximo do ponto de corte.

Na prática, o código para desligar e ligar o LED a cada pressionamento de botão usaria uma interrupção acionada pela borda descendente. Como apontado nos comentários, você deseja renunciar à interrupção nesse caso. Você também pode fazer o mesmo sem interrupções gravando o estado anterior do botão e alterando o LED apenas quando o estado do botão tiver sido alterado. A renúncia à medida que o código é escrito agora não faz 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;
}

fonte
0

Provavelmente, é mais simples manter o "estado" em variáveis ​​normais do que tentar deduzi-lo do estado atual do GPIO.

Além disso, o "loop ocupado" consumirá todos os ciclos da CPU que o sistema operacional permitirá ao processo; para um processo tão simples, você verá que sua carga de CPU aumentará para 100%! Você deve permitir que o processo renuncie à CPU para outras tarefas com uma usleep()chamada, por exemplo. O atraso também servirá para cancelar a troca.

#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
fonte