Как переключить светодиод при нажатии кнопки?
Я хочу, чтобы светодиод включался, когда я нажимаю кнопку, и выключался, когда я нажимаю кнопку второй раз.
Этот код не работает:
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);
}
Что может быть не так?
@Coderboy, 👍2
Обсуждение10 ответов
Не забудьте включить светодиод:
digitalWrite(ledPin, HIGH);
И ВЫКЛ:
digitalWrite(ledPin, LOW);
Вы вообще не занимаетесь устранением дребезга. Механические кнопки обычно подпрыгивают в течение нескольких миллисекунд после нажатия «вкл». Программное обеспечение Arduino (или какое-то специальное оборудование) должно справиться с этим. Это действительно важно, когда вы ожидаете, что кнопка будет переключать какой-либо выходной контакт.
На данный момент у вас есть две основные проблемы. Во-первых, оба ваших оператора 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;
}
Как отмечалось в другом месте, вам все равно нужно устранить дребезг кнопки, иначе вы, скорее всего, получите ложные срабатывания. Это можно сделать аппаратно или программно. Очень простой способ временно обойти это — установить задержку в несколько миллисекунд каждый раз, когда вы обнаруживаете изменение состояния кнопки. Это не идеально, но этого может быть достаточно для начала.
привет, Сачлин, попробуй этот код, он работает, я отредактировал твой код
// Это сохранит последнее известное состояние кнопки
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
Я просто взял версию из приведенных выше и сделал ее немного меньше с точки зрения кода. Не стесняйтесь использовать его в своем приложении Arduino.
// Это сохранит последнее известное состояние кнопки
int lastButtonState = LOW;
void loop()
{
// Получаем текущее состояние кнопки
int currentButtonState = digitalRead(buttonPin);
// Нажата ли кнопка с тех пор, как мы в последний раз читали ее?
if (currentButtonState == HIGH && lastButtonState == LOW) {
// Переключить состояние выхода
digitalWrite(ledPin, !digitalRead(ledPin));
}
// Сохраняем состояние кнопки, чтобы мы могли сказать, изменилось ли оно в следующий раз
lastButtonState = currentButtonState;
}
Распиновка, подтягивания и логические ошибки были рассмотрены в другом месте, поэтому я сосредоточусь на устранении дребезга переключателей. С устранением дребезга, на мой взгляд, лучше всего справиться программно (а не аппаратно) для крупных производственных затрат и ленивых программистов (таких как я). Для небольших проектов простая схема 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); // выключаем светодиод
}
}
Наконец, просто не забудьте проверить состояние переключателя в различных точках внутри цикла(). Я использую этот переключатель в качестве аварийного выключателя, а встроенный светодиод обеспечивает его срабатывание.
// Когда программа запускается в первый раз, ее смущает двойное нажатие кнопки. Ну замени на это
if (x == 1) {
// Включить
digitalWrite(ledPin, HIGH);
x = 0;
} else {
// Выключить
digitalWrite(ledPin, LOW);
x = 1;
}
Что произойдет, если я удержу кнопку? Подумай об этом., @Avamander
Вам не нужна отдельная переменная для хранения состояния светодиода. Регистр выходного контакта уже делает это. Таким образом, вы можете переключать светодиод просто с помощью
digitalWrite(ledPin, !digitalRead(ledPin));
или, если хотите
if(digitalRead(ledPin))
digitalWrite(ledPin, 0);
else
digitalWrite(ledPin, 1);
В вашем коде цикл выполняется много раз, пока ключ отскакивает. Если вы сделаете задержку не менее 50 мс после первого обнаружения нажатия клавиши, а также переключите светодиод и включите двигатель, то вы фактически устранили дребезг кнопки. Если вы будете удерживать клавишу постоянно, светодиод будет переключаться каждые 50 мс (плюс небольшие накладные расходы)
успешный случай проверен успешно, модифицировано из примеров 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);
}
}
проверьте этот код. Я внес некоторые изменения в ваш код. работает.
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);
}
- Определение того, была ли нажата и отпущена кнопка
- Нажать клавишу Windows, используя «keyboard.press();»
- Устранение дребезга кнопки с помощью прерывания
- Хорошая кнопка debouncing/Библиотека StateChange
- Напряжение меняется, но цифровой поток всегда HIGH
- Остановить мигание светодиодов
- Интеграция 2 кнопок для включения и выключения светодиода.
- Код Arduino для управления 4 светодиодами с 4 кнопок
Так ваш светодиод подключен к контакту 6 или контакту 10? У вас есть контакт 6 с именем «ledPin», но вы меняете «motorPin» в своем цикле., @Greg Hewgill
Какая у тебя схема? Можете ли вы предоставить схему? Кроме того, что такое "не работает"? Он горит *любое* количество времени?, @Anonymous Penguin
Читая ваш вопрос, я также подозреваю, что у вас нет подтягивающего резистора на входном контакте., @Gerben