Включите и выключите светодиод с помощью переключателя

10

Я пытаюсь написать код, чтобы светодиод включался, когда он выключен, и выключался, когда он включался с помощью тактильного кнопочного переключателя. Я написал, как мне кажется, правильный код с библиотекой wiringPi, но я могу только включить его, когда он выключен, и не могу его отключить после этого. В очень редких случаях и после многократных нажатий светодиод гаснет, когда он включен, и я нажимаю кнопку, но я уверен, что это не так, как это должно работать.

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

Я приложил изображение, как схема подключена.LEDciruit


источник
2
Есть ли в вашей библиотеке какие-либо отказов от коммутатора? Если нет, возможно, вы успешно выключили светодиод, а затем немедленно включили его. Как только вы обнаружили изменение состояния, не обращайте внимания на дальнейшие обнаружения в течение короткого периода времени.
1
@MikeW Я так не думаю. Я попытаюсь вставить задержку после обработки оператора if.
6
@duskwuff Этот вопрос определенно касается программирования.
1
сохраняйте локальную переменную, которая содержит текущее состояние светодиода (вкл / выкл) (возможно, через перечисление), не пытайтесь прочитать состояние выходного контакта. Вместо этого определите изменение края входного состояния от высокого до низкого уровня входного контакта. затем обновите текущее состояние локальной переменной: outputimagevar = (outputimagevar == HIGH)? НИЗКО ВЫСОКО; затем digitalWrite (0, outputimagevar); затем, когда входной сигнал изменится с НИЗКОГО на ВЫСОКИЙ, сбросьте логику обнаружения ВЫСОКОГО на НИЗКОГО. Кроме того, обязательно «отмените» состояние ввода, возможно, убедившись (скажем), что 3 последовательных чтения показывают одно и то же состояние.
Что я только что сделал, это вставил половину секунды в гнездо каждого оператора if, и на этот раз он работает правильно. Что-то подсказывает мне, что это своего рода грубый метод, который не всегда работает, как я мог бы ожидать, если кнопка нажата быстрее, чем полсекунды, и, вероятно, она не будет работать так же в моем основном проекте, поэтому я рассмотрю остальные ответы. Я ценю вклад каждого.

Ответы:

4

Проводка выглядит правильно для кода.

Проблема в том, что код находится в очень узком цикле. Теоретически, когда кнопка нажата, тело цикла многократно включает и выключает светодиод. Теоретически, когда кнопка отпущена, светодиод будет включен (или выключен) с вероятностью 50/50. Вы заметили изменение яркости при нажатии кнопки. Там может быть недостаточно, чтобы быть замеченным.

На практике причина того, что светодиод остается включенным, заключается в том, как вы проверяете, включен ли он. Контактный вывод 0 HIGH подает 3,3 В на выход. Но этот провод подключен к светодиоду, а вывод настроен на выход. Светодиод может сбрасывать напряжение достаточно низко, чтобы не регистрироваться как ВЫСОКОЕ, когда он читается, но иногда это происходит, потому что он близок к отключению.

На практике код для выключения и включения светодиода при каждом нажатии кнопки будет использовать прерывание, вызванное падающим фронтом. Как указано в комментариях, вы бы хотели отменить прерывание в этом случае. Вы также можете сделать то же самое без прерываний, записав предыдущее состояние кнопки и меняя светодиод только тогда, когда состояние кнопки изменилось. Дебейсинг, когда код написан, теперь не имеет смысла.

#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

Вероятно, проще поддерживать «состояние» в нормальных переменных, чем пытаться вывести его из текущего состояния GPIO.

Также «занятый цикл» будет потреблять каждый цикл ЦПУ, который ОС будет разрешать процессу; для такого простого процесса вы увидите, что загрузка вашего процессора возрастет до 100%! Вы должны позволить процессу передавать ЦП другим задачам, например, с помощью usleep()вызова. Задержка также будет служить для сброса переключателя.

#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;
}
Клиффорд
источник