Та же кнопка одним кликом и двойным кликом
Я надеюсь получить помощь с моим кодом.
Я пытаюсь отличить одиночное нажатие от быстрого двойного нажатия кнопки с устранением дребезга.
Я делаю какую-то глупую ошибку в своем коде и не могу понять, в чем проблема. Если я дважды нажму кнопку, на последовательном мониторе будут напечатаны как «одиночный», так и «двойной».
Заранее спасибо за помощь.
const int buttonPin = 5;
unsigned long lastPressTime;
int buttonState = 0;
int singlePress = 0;
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
lastPressTime = millis();
Serial.begin(9600);
}
void loop() {
if (!digitalRead(buttonPin) == HIGH && buttonState == 0) {
unsigned long currentPressTime = millis();
//два нажатия в течение 500 мс
if (currentPressTime - lastPressTime < 500) {
singlePress = 0;
// Делаем двойное нажатие
Serial.println("double");
} else {
singlePress = 1;
}
//обновляем время последнего нажатия
lastPressTime = currentPressTime;
buttonState = 1;
} else if (!digitalRead(buttonPin) == LOW) {
buttonState = 0;
}
//проверяем, прошло ли 500 мс без нажатия второй кнопки
if (singlePress == 1 && lastPressTime - millis() > 500) {
singlePress = 0;
// Делаем однократное нажатие
Serial.println("single");
}
}
@Carlos Costa, 👍0
Обсуждение2 ответа
Проблема заключается в следующем утверждении:
lastPressTime - millis() > 500
Поскольку время хранится как unsigned long, этот тест в том виде, в каком он написан сейчас, всегда верен.
Вы хотите измерить время, прошедшее с момента последнего нажатия, поэтому вам следует вычесть отметку времени последнего нажатия из текущего времени. Замените его на:
millis() - lastPressTime > 500
И код будет работать нормально.
Если ваш «ответ» на 100% получен из чьего-то предыдущего комментария, указывающего на очевидную ошибку, было бы вежливо хотя бы признать это. Еще лучше было бы подождать, пока создатель кода не исправит свой код и не сообщит о результатах, прежде чем делать заявление типа «И код будет работать нормально». . (Я не верю, что это так), @6v6gt
Спасибо всем за помощь...
Определенно проблема в моем коде, чтобы заставить работать один щелчок и двойной щелчок, как написал @mhopeng, заключалась в следующем утверждении:
lastPressTime - millis() > 500
изменить его на это
millis() - lastPressTime > 500
заработало.
Но я понимаю, что мой подход недостаточно гибок. Использование подхода @6v6gt намного лучше моего. Реакция намного более отзывчивая и плавная.
// обратите внимание, что скорость симуляции составляет около одной трети реального времени
// настроить тайминги при использовании на реальном оборудовании.
const int buttonPin = 5;
unsigned long inStateAtMs = millis() ;
int buttonState ; // 0 = ожидание нажатия, 1 = ожидание отпускания 2 = различение одиночного или двойного 3 = ожидание отпускания кнопки (двойное)
void setup() {
pinMode(buttonPin, INPUT_PULLUP);
Serial.begin(9600);
}
void loop() {
if ( buttonState == 0 ) {
// ждем нажатия кнопки
if ( millis() - inStateAtMs > 100 ) {
if (!digitalRead(buttonPin)) {
buttonState = 1 ;
inStateAtMs = millis();
}
}
}
else if ( buttonState == 1 ) {
// ждем стабильного отпускания кнопки 1
if ( millis() - inStateAtMs > 100 && digitalRead(buttonPin) ) {
buttonState = 2 ;
inStateAtMs = millis();
}
}
else if ( buttonState == 2 ) {
// различаем одинарное и двойное нажатие
if ( millis() - inStateAtMs > 400 ) {
// таймаут - однократное нажатие
Serial.println("single");
buttonState = 0 ;
inStateAtMs = millis() ;
}
else if ( ( ! digitalRead(buttonPin) ) && (millis() - inStateAtMs > 100 ) ) {
// получено второе нажатие в течение тайм-аута - double
Serial.println("double");
buttonState = 3 ;
inStateAtMs = millis() ;
}
}
else if ( buttonState == 3 ) {
// ждем стабильного отпускания кнопки 2
if ( millis() - inStateAtMs > 100 && digitalRead(buttonPin) ) {
buttonState = 0 ;
inStateAtMs = millis();
}
}
}
Еще раз спасибо всем за помощь
Я рад, что у вас есть что-то, что работает для вас. Я поместил ваш оригинальный скетч, но с исправлением, в тот же симулятор, и он не работает. Тем не менее, он [симулятор], похоже, реализует преувеличенный отскок кнопки, который вы можете не встретить на физическом Arduino. Он здесь, если вы хотите поиграть с ним: https://wokwi.com/projects/347070013621928531, @6v6gt
Я заметил, что в симуляторе мой код не работает, а на физической Ардуино работает., @Carlos Costa
- Торговый автомат Arduino для мониторинга ввода монет в слот во время ожидания ввода пользователя
- Кнопка переключения переключает между операторами обращения с разблокированием кнопки
- Как запустить 4 светодиода последовательно на основе кнопочного входа?
- Как включить 3 светодиода в повторяющейся последовательности, чтобы все три светодиода затем выключались при отпускании используемой кнопки?
- Как использовать Multipile millis()
- DS3231 + кнопка для включения подсветки
- Закодируйте и подключите ЖК-дисплей и кнопку
- Нужно сделать кнопку, чтобы выключить будильник на часах
почему бы не использовать библиотеку? например Bounce2, @Juraj
@Juraj ... Я знаю, что для таких ситуаций есть несколько библиотек. Я знаю Bounce2 и обычно использую библиотеку OneButton. В этом случае я пытаюсь заставить его работать без использования библиотеки., @Carlos Costa
оба 'single' и 'double' печатаются на последовательном мониторе
... вы почти у цели... добавьте код, чтобы выбрать один, затем напечатайте, @jsotolaЭто выглядит странно,
lastPressTime - millis() > 500
, так как lastPressTime будет меньше, чем millis(), но я не думаю, что это ваша единственная проблема. Я реструктурировал ваше решение как более явный конечный автомат и поместил его в симулятор: https://wokwi.com/projects/347070000856564307., @6v6gt