Как переключить светодиод при нажатии кнопки?

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

Этот код не работает:

const int buttonPin = 4;    
const int motorPin =  10;  
const int ledPin = 6;
 int x = 1;
// переменные изменятся:
int buttonState = 0;         

void setup() {
  // инициализируем вывод светодиода как выход:
  pinMode(motorPin, OUTPUT);      
  // инициализируем контакт кнопки как вход:
  pinMode(buttonPin, INPUT);   
  pinMode(ledPin, OUTPUT);  
}

void loop(){
  buttonState = digitalRead(buttonPin);
  if (buttonState == HIGH && x==1) { 
     digitalWrite(motorPin , 1);
     x=0;
    } 
  if (buttonState == HIGH && x==0){
    digitalWrite(motorPin, 0);
    x=1;
  } 
  delay(1);
}

Что может быть не так?

, 👍2

Обсуждение

Так ваш светодиод подключен к контакту 6 или контакту 10? У вас есть контакт 6 с именем «ledPin», но вы меняете «motorPin» в своем цикле., @Greg Hewgill

Какая у тебя схема? Можете ли вы предоставить схему? Кроме того, что такое "не работает"? Он горит *любое* количество времени?, @Anonymous Penguin

Читая ваш вопрос, я также подозреваю, что у вас нет подтягивающего резистора на входном контакте., @Gerben


10 ответов


4

Не забудьте включить светодиод:

digitalWrite(ledPin, HIGH);

И ВЫКЛ:

digitalWrite(ledPin, LOW);
,

2

Вы вообще не занимаетесь устранением дребезга. Механические кнопки обычно подпрыгивают в течение нескольких миллисекунд после нажатия «вкл». Программное обеспечение Arduino (или какое-то специальное оборудование) должно справиться с этим. Это действительно важно, когда вы ожидаете, что кнопка будет переключать какой-либо выходной контакт.

,

5

На данный момент у вас есть две основные проблемы. Во-первых, оба ваших оператора if запускаются один за другим. Это связано с тем, что первый оператор if устанавливает x в 0, что является частью условия, которое ищет второй оператор if.

Вторая проблема заключается в том, что вы не отслеживаете предыдущее состояние кнопки. buttonState будет отображаться HIGH каждый раз при цикле, даже если кнопка удерживается нажатой в течение нескольких секунд. В результате выходной контакт будет постоянно быстро включаться и выключаться.

Что вам нужно сделать, так это сохранить последнее известное состояние кнопки. На каждой итерации основного цикла реагируйте на кнопку, только если она в настоящее время HIGH, и если она была LOW в прошлый раз цикла. Вам также необходимо убедиться, что два ваших оператора if являются взаимоисключающими; т. е. если вы активируете один, не запускайте другой по ошибке, иначе он отменит его.

Что-то вроде этого должно работать лучше:

// Это сохранит последнее известное состояние кнопки
int oldButtonState = LOW;

void loop()
{
  // Получаем текущее состояние кнопки
  int newButtonState = digitalRead(buttonPin);

  // Нажата ли кнопка с тех пор, как мы в последний раз читали ее?
  if (newButtonState == HIGH && oldButtonState == LOW) {

    if (x == 0) {
      // Включить
      digitalWrite(ledPin, HIGH);
      x = 1;

    } else {
      // Выключить
      digitalWrite(ledPin, LOW);
      x = 0;
    }
  }

  // Сохраняем состояние кнопки, чтобы мы могли сказать, изменилось ли оно в следующий раз
  oldButtonState = newButtonState;
}

Как отмечалось в другом месте, вам все равно нужно устранить дребезг кнопки, иначе вы, скорее всего, получите ложные срабатывания. Это можно сделать аппаратно или программно. Очень простой способ временно обойти это — установить задержку в несколько миллисекунд каждый раз, когда вы обнаруживаете изменение состояния кнопки. Это не идеально, но этого может быть достаточно для начала.

,

0

привет, Сачлин, попробуй этот код, он работает, я отредактировал твой код

// Это сохранит последнее известное состояние кнопки
const int buttonPin = A15;   // изменить в соответствии с прикрепленной кнопкой.
const int motorPin =  12;   //
const int ledPin = 13;
 int x = 1;
// переменные изменятся:
int buttonState = 0;         
int oldButtonState = LOW;


void setup() {
  // инициализируем вывод светодиода как выход:
  pinMode(motorPin, OUTPUT);      
  // инициализируем контакт кнопки как вход:
  pinMode(buttonPin, INPUT);   
  pinMode(ledPin, OUTPUT);  
}




void loop()
{
  // Получаем текущее состояние кнопки
  int newButtonState = digitalRead(buttonPin);

  // Нажата ли кнопка с тех пор, как мы в последний раз читали ее?
  if (newButtonState == HIGH && oldButtonState == LOW) {

    if (x == 0) {
      // Включить
      digitalWrite(ledPin, HIGH);
      x = 1;

    } else {
      // Выключить
      digitalWrite(ledPin, LOW);
      x = 0;
    }
  }

  // Сохраняем состояние кнопки, чтобы мы могли сказать, изменилось ли оно в следующий раз
  oldButtonState = newButtonState;
}
,

Рахул, в следующий раз, пожалуйста, выберите свой код и нажмите Ctrl+K, чтобы сделать отступ на 4 символа. Так он лучше отображается на странице., @Nick Gammon


2

Я просто взял версию из приведенных выше и сделал ее немного меньше с точки зрения кода. Не стесняйтесь использовать его в своем приложении Arduino.

// Это сохранит последнее известное состояние кнопки
int lastButtonState = LOW;

void loop()
{
  // Получаем текущее состояние кнопки
  int currentButtonState = digitalRead(buttonPin);

  // Нажата ли кнопка с тех пор, как мы в последний раз читали ее?
  if (currentButtonState == HIGH && lastButtonState == LOW) {
     // Переключить состояние выхода
     digitalWrite(ledPin, !digitalRead(ledPin));
  }

  // Сохраняем состояние кнопки, чтобы мы могли сказать, изменилось ли оно в следующий раз
  lastButtonState = currentButtonState;
}
,

1

Распиновка, подтягивания и логические ошибки были рассмотрены в другом месте, поэтому я сосредоточусь на устранении дребезга переключателей. С устранением дребезга, на мой взгляд, лучше всего справиться программно (а не аппаратно) для крупных производственных затрат и ленивых программистов (таких как я). Для небольших проектов простая схема pullup/cap обеспечивает большую надежность и повышенную скорость, но я просто ленив в старости. Также имейте в виду, что дребезг переключателя значительно ухудшается в течение срока службы переключателя. Я видел новые PB с bounce < 20 мс ухудшится до более чем 300 мс при разумном использовании, так что имейте это в виду с проектами, которые становятся полупостоянными.

Вот что я использую для программного решения на довольно упругой кнопке SPST NO. В этом случае я использую NO PB на GND с внешними подтяжками 1K, так как лично я не хочу зависеть от того, работает ли внутренняя подтяжка на старых устройствах, которыми я, возможно, злоупотреблял в прошлой жизни.... Конечно, можно привести аргументы в пользу различных областей, которые все еще нуждаются в очистке, улучшенной инкапсуляции, более быстром ответе, более высоком качестве и т. д., но пока это работает для меня.

inSw.h:

class inSw
{
private:
    volatile boolean swState;           // текущее состояние ( 0 / 1 ) переключателя

public:
    uint8_t  pinNum;
    volatile unsigned long lastPush;    // Время (millis()), когда обнаружено последнее нажатие переключателя
    unsigned long debTime = 30;         // Время (micros()), необходимое для устранения дребезга переключателя

    void init(uint8_t sw);
    boolean readState(void);
} ;

inSw.cpp:

void inSw::init(uint8_t sw) {
    pinNum = sw;
    pinMode(sw, INPUT);
    swState = 0;
    lastPush = millis();
};

boolean inSw::readState() {
//  swState = digitalRead(pinNum);
return swState;
}
void setupSwitches(void) {
    swS1.init(I2C_SOA);     // pin D20
    attachInterrupt(digitalPinToInterrupt(swS1.pinNum), swS1Press, FALLING);
}

Подпрограммы обслуживания прерываний размещаются вне Setup() и Loop(), а attachInterrupt (см. выше) вызывается внутри Setup(). Это позволяет переключателю прерывать длительные процедуры, такие как Stepper.step(10000), который ударяет по концевому выключателю на шаге 14....

void swS1Press() {
    unsigned long now = millis();
    if (swS1.lastPush < (now - swS1.debTime)) { // если только что нажал
        RunStop.toggle();
        swS1.lastPush = millis();       // последнее нажатие sw сейчас

        if (RunStop.val == RS_RUN)
            digitalWrite(LED_PIN, HIGH);   // включаем светодиод
        else
            digitalWrite(LED_PIN, LOW);   // выключаем светодиод
    }
}

Наконец, просто не забудьте проверить состояние переключателя в различных точках внутри цикла(). Я использую этот переключатель в качестве аварийного выключателя, а встроенный светодиод обеспечивает его срабатывание.

,

1
// Когда программа запускается в первый раз, ее смущает двойное нажатие кнопки. Ну замени на это

if (x == 1) {
    // Включить
    digitalWrite(ledPin, HIGH);
    x = 0;
} else {
    // Выключить
    digitalWrite(ledPin, LOW);
    x = 1;
}
,

Что произойдет, если я удержу кнопку? Подумай об этом., @Avamander


2

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

    digitalWrite(ledPin, !digitalRead(ledPin)); 

или, если хотите

    if(digitalRead(ledPin))
       digitalWrite(ledPin, 0);
    else
       digitalWrite(ledPin, 1);

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

,

1

успешный случай проверен успешно, модифицировано из примеров arduino.UNO r3,atmega 328 попробуй!!!!!

/* Схема:
- кнопка подключена к контакту 2 от +5В
- Резистор 10 кОм подключен к контакту 2 от земли
- Светодиод, подключенный от контакта 13 к земле (или используйте встроенный светодиод на большинстве
платы ардуино)
*/

// эта константа не изменится:
const int  buttonPin = 2;    // контакт, к которому прикреплена кнопка
const int ledPin = 8;       // контакт, к которому подключен светодиод

// Переменные изменятся:
int buttonPushCounter = 0;   // счетчик количества нажатий кнопок
int buttonState = 0;         // текущее состояние кнопки
int lastButtonState = 0;     // предыдущее состояние кнопки

void setup() {
  // инициализируем вывод кнопки как ввод:
  pinMode(buttonPin, INPUT);
  // инициализируем светодиод как выход:
  pinMode(ledPin, OUTPUT);
  // инициализируем последовательную связь:
  Serial.begin(9600);
}

void loop() {
  // прочитать входной контакт кнопки:
  buttonState = digitalRead(buttonPin);

  // сравниваем состояние кнопки с предыдущим состоянием
  if (buttonState != lastButtonState) {
    // если состояние изменилось, увеличиваем счетчик
    if (buttonState == HIGH) {
      // если текущее состояние ВЫСОКОЕ, то кнопка переключилась с выключенного состояния на включенное:
      buttonPushCounter++;
      Serial.println("on");
      Serial.print("number of button pushes: ");
      Serial.println(buttonPushCounter);
    } else {
      // если текущее состояние LOW, то кнопка перешла из включенного состояния в выключенное:
      Serial.println("off");
    }
    // Небольшая задержка, чтобы избежать подпрыгивания
    delay(10);
  }
  // сохранить текущее состояние как последнее состояние для следующего прохода цикла
  lastButtonState = buttonState;


  // включает светодиод каждые четыре нажатия кнопки, проверяя модуль
  // счетчик нажатий кнопок. функция по модулю дает вам остаток от
  // деление двух чисел:
  if (buttonPushCounter % 2 == 0) {
    digitalWrite(ledPin, LOW);
  } else {
    digitalWrite(ledPin, HIGH);
  }
}
,

1

проверьте этот код. Я внес некоторые изменения в ваш код. работает.

const int buttonPin = 2;
const int motorPin =  6;
const int ledPin = 13;
int x = 1;
// переменные изменятся:
int buttonState = 0;

void setup() {
  // инициализируем вывод светодиода как выход:
  Serial.begin(9600); 
  pinMode(motorPin, OUTPUT);
  // инициализируем контакт кнопки как вход:
  pinMode(buttonPin, INPUT);
  pinMode(ledPin, OUTPUT);
}

void loop() {

  buttonState = digitalRead(buttonPin);
// Serial.println(x);
  if(buttonState == LOW && x == 1)
  {
    Serial.println("buttonState == HIGH && x == 1");
    digitalWrite(ledPin, HIGH);
    delay(500);
    x = 0;
    Serial.println("x == 0");
  }
  else if (buttonState == LOW && x == 0)
  {
    Serial.println("buttonState == HIGH && x == 0");
    digitalWrite(ledPin, LOW);
    delay(500);
    x = 1;
    Serial.println("x == 1");
  }
  delay(1);
}
,