Понимание кода Debounce
Я не понимаю следующий код Debounce. (Полный код приведен внизу.) Насколько я понимаю, когда пин что-то считывает, мы ждем не менее 50 миллисекунд, прежде чем что-либо выполнить. Но разве переменная чтения не сбрасывается при каждой итерации цикла, поэтому чтение
равно нулю во внутреннем условии if на каждой итерации.
Я думаю, это последовательность событий: loop(), loop(), loop(), "loop(), нажатие кнопки, чтение=1, установка lastDebounceTime, сначала, если условие не выполняется, потому что нам нужно ждать, set lastButtonState=1", loop(), loop(),loop(), "loop()" прошло достаточно времени, но поскольку ни одна кнопка не нажата в этой и последних итерациях, чтение и lastButtonState равны нулю", цикл (), ... .
Однако этот код работает.
Почему мы сохраняем чтение
в локальной переменной? Тогда не будет ли код практически всегда таким:
if (reading != lastButtonState) {
// сброс таймера устранения дребезга
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
// каким бы ни было чтение, оно было там дольше, чем устранение дребезга
// задержка, так что примите это как фактическое текущее состояние:
// если состояние кнопки изменилось:
if 0 != buttonState) {
buttonState = 0;
...
Весь код:
/*
Debounce
Each time the input pin goes from LOW to HIGH (e.g. because of a push-button
press), the output pin is toggled from LOW to HIGH or HIGH to LOW. There's a
minimum delay between toggles to debounce the circuit (i.e. to ignore noise).
The circuit:
- LED attached from pin 13 to ground
- pushbutton attached from pin 2 to +5V
- 10 kilohm resistor attached from pin 2 to ground
- Note: On most Arduino boards, there is already an LED on the board connected
to pin 13, so you don't need any extra components for this example.
created 21 Nov 2006
by David A. Mellis
modified 30 Aug 2011
by Limor Fried
modified 28 Dec 2012
by Mike Walters
modified 30 Aug 2016
by Arturo Guadalupi
This example code is in the public domain.
http://www.arduino.cc/en/Tutorial/Debounce
*/
// константы не изменятся. Они используются здесь для установки номеров контактов:
const int buttonPin = 2; // номер вывода кнопки
const int ledPin = 13; // номер вывода светодиода
// Переменные изменятся:
int ledState = HIGH; // текущее состояние выходного вывода
int buttonState; // текущее чтение с входного вывода
int lastButtonState = LOW; // предыдущее чтение с входного вывода
// следующие переменные являются беззнаковыми длинными, потому что время, измеренное в
// миллисекунды, быстро станет большим числом, чем может быть сохранено в int.
unsigned long lastDebounceTime = 0; // последний раз, когда выходной пин был переключен
unsigned long debounceDelay = 50; // время устранения дребезга; увеличить, если выход мерцает
void setup() {
pinMode(buttonPin, INPUT);
pinMode(ledPin, OUTPUT);
// устанавливаем начальное состояние светодиода
digitalWrite(ledPin, ledState);
}
void loop() {
// прочитать состояние переключателя в локальную переменную:
int reading = digitalRead(buttonPin);
// проверяем, не нажали ли вы кнопку только что
// (т.е. входной сигнал изменился с НИЗКОГО на ВЫСОКИЙ), и вы ждали достаточно долго
// с момента последнего нажатия, чтобы игнорировать любой шум:
// Если переключатель изменился из-за шума или нажатия:
if (reading != lastButtonState) {
// сброс таймера устранения дребезга
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > debounceDelay) {
// каким бы ни было чтение, оно было там дольше, чем устранение дребезга
// задержка, так что примите это как фактическое текущее состояние:
// если состояние кнопки изменилось:
if (reading != buttonState) {
buttonState = reading;
// переключать светодиод только в том случае, если состояние новой кнопки ВЫСОКОЕ
if (buttonState == HIGH) {
ledState = !ledState;
}
}
}
// устанавливаем светодиод:
digitalWrite(ledPin, ledState);
// сохранить чтение. В следующий раз в цикле это будет lastButtonState:
lastButtonState = reading;
}
(Код устранения отказов взят из: https://www.arduino.cc/en/tutorial/debounce.<!-- а-->)
1 ответ
Лучший ответ:
loop() не требует времени и постоянно повторяется.
lastButtonState
читает
из предыдущего цикла.
Пока кнопка отскакивает, lastDebounceTime
обновляется.
Только когда кнопка зафиксирована (нажата или отпущена), условие
((millis() - lastDebounceTime) > debounceDelay)
становится true
и код выполняется -> если buttonState
(предыдущее состояние debounced) и reading
показывают изменение на HIGH, состояние индикатора переключается.
Не уверен, что это объяснение делает что-то более ясным, так как оно и так ясно, ИМО.
Почему мы не проверяем, вместо этого lastButtonState
показывает изменение на высокое? Чтение сбрасывается в каждом цикле () и практически всегда будет равно нулю (в моем ограниченном понимании)., @thegoodhunter-9115
Почему всегда 0? Это будет то, что написано на контакте. Каждый раз, когда цикл повторяется, он снова считывает вывод, и вы получаете новое чтение. Мы могли бы проверить lastButtonState или чтение, они будут одинаковыми в этом месте кода. Если они не совпадают, то lastDebounceTime устанавливается равным текущему времени, и мы не вводим этот второй оператор if., @Delta_G
Если цикл занимает микросекунду, а отскок занимает две миллисекунды, «чтение» будет оцениваться 2000 раз за эти 2 мс и изменяться пару раз в течение этого периода. Только если он стабилен в течение 50 мс (вы получили почти бесконечное количество одних и тех же значений чтения), вы принимаете это как новое состояние кнопки с отказом от дребезга., @DataFiddler
Я думаю, что это последовательность событий: loop(), loop(), loop(), "loop(), нажатие кнопки, чтение = 1, установка lastDebounceTime, сначала, если условие не выполняется, потому что мы должны ждать, установить lastButtonState = 1 ", loop(), loop(),loop(),"loop() прошло достаточно времени, но так как в этой и последних итерациях ни одна кнопка не нажата, чтение и lastButtonState равны нулю ", loop(), . .., @thegoodhunter-9115
@thegoodhunter-9115 серьезно подумай о том, что я сказал о свете и секундомере .... что бы ты сделал с секундомером, если бы свет включился или выключился?, @jsotola
@jsotola, кажется, я понял. Я (думаю) не мог этого понять из-за моего незнания того, насколько «длинным» является нажатие кнопки и сколько раз loop()
будет выполняться во время одного нажатия. Просто чтобы убедиться: в течение 50 мс (debounceDelay) кнопка будет оставаться в нажатом состоянии пользователем (даже если это был просто щелчок), и в течение этого времени loop()
будет выполняться несколько раз ( таким образом, он будет «запоминать», что такое чтение). Я думал, что 50 мс пройдут за один вызов loop()
. Я все еще могу ошибаться в своем понимании, но большое спасибо за вашу помощь и извините за раздражение., @thegoodhunter-9115
@DataFiddler Большое спасибо за вашу помощь и терпение. Я объяснил, почему (я думаю) у меня возникло это недоразумение, в моем комментарии выше к jsotola (в этой теме). Еще раз спасибо., @thegoodhunter-9115
@ thegoodhunter-9115 спасибо за объяснение вашего недопонимания ... сегодня я кое-что узнал от вас ... теперь я знаю, что время выполнения цикла () может быть источником путаницы, @jsotola
@ thegoodhunter-9115, вы можете выполнить простой тест ... написать скетч, который в setup () печатает значение millis () и устанавливает счетчик на ноль .... в цикле () увеличивает счетчик ... когда счетчик достигает 1000, снова печатает millis() .... это даст вам представление о том, сколько примерно времени занимает 1000 итераций loop(), @jsotola
Хорошо. Еще раз спасибо, @jsotola., @thegoodhunter-9115
- Как я могу прервать задержку() при нажатии кнопки?
- Объявление переменной внутри основного цикла
- Кодировщик + Библиотека Bounce2
- Светодиод мигает с помощью кнопки
- в то время как (1) внутри, если условно
- HTML-страница переменной ESP8266 Webserver ESP8266WebServer (не как один постоянный символ)
- ESP8266 Webserver ESP8266WebS сервер перемещает функцию обработчика в отдельный файл .h .c
- 24/14 секундный таймер обратного отсчета или часы для кнопки запуска/остановки баскетбольного мяча плохо реагируют
Что непонятного в комментариях? Кстати: последняя строка кода является частью алгоритма устранения дребезга., @DataFiddler
Ах, извини @jsotola. Кажется, я неправильно копирую/вставляю-d, @thegoodhunter-9115
@DataFiddler, я отредактировал вопрос. Я не понимаю часть алгоритма. Прости за это., @thegoodhunter-9115
подумайте об этом .... представьте, что у вас есть секундомер ... перед вами световой индикатор и кнопка ... свет включается и выключается через случайные промежутки времени ... ваша задача - нажимать кнопку, если состояние лампы не меняется в течение 10 секунд... как бы вы выполнили свою работу? ... алгоритм делает то же самое, @jsotola
Я снова отредактировал вопрос. Почему «чтение» является локальным?, @thegoodhunter-9115
потому что
чтение
должно существовать только в течение одной итерацииloop()
, @jsotola@jsotola, разве он нам не нужен для итерации, когда завершается lastDebounceTime?, @thegoodhunter-9115
нет завершения lastDebounceTime, @jsotola
Давайте [продолжим это обсуждение в чате](https://chat.stackexchange.com/rooms/113017/discussion-between-jsotola-and-thegoodhunter-9115)., @jsotola