Определение количества нажатий кнопок (одиночное нажатие, двойное нажатие и т. д.) двумя одновременными кнопками
нуб здесь
Итак, то, что я пытаюсь сделать, это вывести другое число в зависимости от количества нажатий кнопок, например, для 1 нажатия кнопки должно выводиться 1 и так далее. После этого мне действительно нужны выходы только от 1 до 4 нажатий. Я использую эти входы для игры. Прямо сейчас он работает и считает до 4, а затем сбрасывается до 0. Проблема, с которой я столкнулся, заключается в том, что он продолжается после 1 клика до 2 кликов; то, что я хочу, это подсчитать 1 клик, когда он щелкнул один раз, дважды, когда он щелкнул дважды и т. д. Я пытаюсь использовать код устранения дребезга, чтобы различать одиночное нажатие, двойное нажатие, тройное нажатие и т. д. @VE7JRO любезно предоставил отличное решение этой проблемы, хотя и для одной кнопки. Я пытаюсь настроить код для размещения двух отдельных кнопок (на разных контактах), но это выдает ошибку.
Это код:
#include <Bounce2.h>
// Соединяем обе кнопки последовательно одним соединением
// к GND, а другой к цифровому выводу.
const int buttonPin1 = 2;
const int buttonPin2 = 3;
class Button
{
private:
int m_buttonPin1;
int m_buttonPin2;
int m_counter;
unsigned long m_buttonPressTimeout;
unsigned long m_previousMillis;
public:
Button(int button):
m_buttonPin1(buttonPin1),
m_buttonPin2(buttonPin2),
m_counter(0),
m_buttonPressTimeout(1500), // Время ожидания нажатия кнопки 500 мс.
m_previousMillis(0){}
void Update()
{
int valA = digitalRead(button1); // чтение состояния кнопки
int valB = digitalRead(button2); // чтение состояния кнопки
if (valA == LOW &&valB == LOW)
{
if(m_counter > 0 && millis() - m_previousMillis >= m_buttonPressTimeout)
{
Serial.print("Count from Update() just before it's re-set to 0 = ");
Serial.println(GetCounter());
m_counter = 0;
}
}
void IncrementCounter(){
m_counter++;
if(m_counter > 4){m_counter = 4;}
if(m_counter == 1){
m_previousMillis = millis();
}
}
byte GetCounter(){
return m_counter;
}
};
Bounce button1Debouncer = Bounce();
Bounce button2Debouncer = Bounce();
Button MyButton(buttonPin1);
Button MyButton(buttonPin2);
void setup(){
Serial.begin(9600);
pinMode(buttonPin1, INPUT_PULLUP);
button1Debouncer.attach(buttonPin);
button1Debouncer.interval(5);
pinMode(buttonPin2, INPUT_PULLUP);
button2Debouncer.attach(buttonPin);
button2Debouncer.interval(5);
}
void loop(){
// Вызовите функцию обновления как можно быстрее.
MyButton.Update();
// Кнопка нажата.
if(button1Debouncer.update() && button2Debouncer.update())
{
if(button1Debouncer.fell() && button2Debouncer.fell()){
MyButton.IncrementCounter();
Serial.print("Count from Button Debouncer = ");
Serial.println(MyButton.GetCounter());
}
}
}
}
Ошибка: «'buttonPin1' не является типом», я не понимаю эту ошибку, поскольку она не выдавала эту ошибку при использовании одной кнопки.
@user19964, 👍0
Обсуждение4 ответа
Лучший ответ:
Если есть возможность соединить 2 кнопки последовательно, этот скетч может дать желаемый результат.
#include <Bounce2.h>
// Соединяем обе кнопки последовательно одним соединением
// к GND, а другой к цифровому выводу.
const byte buttonPin = 2;
class Button{
private:
byte m_buttonPin;
byte m_counter;
unsigned long m_buttonPressTimeout;
unsigned long m_previousMillis;
public:
Button(byte buttonPin):
m_buttonPin(buttonPin),
m_counter(0),
m_buttonPressTimeout(500), // Время ожидания нажатия кнопки 500 мс.
m_previousMillis(0){}
void Update(){
if(m_counter > 0 && millis() - m_previousMillis >= m_buttonPressTimeout){
Serial.print("Count from Update() just before it's re-set to 0 = ");
Serial.println(GetCounter());
m_counter = 0;
}
}
void IncrementCounter(){
m_counter++;
if(m_counter > 4){m_counter = 4;}
if(m_counter == 1){
m_previousMillis = millis();
}
}
byte GetCounter(){
return m_counter;
}
};
Bounce buttonDebouncer = Bounce();
Button MyButton(buttonPin);
void setup(){
Serial.begin(9600);
pinMode(buttonPin, INPUT_PULLUP);
buttonDebouncer.attach(buttonPin);
buttonDebouncer.interval(5);
}
void loop(){
// Вызовите функцию обновления как можно быстрее.
MyButton.Update();
// Кнопка нажата.
if(buttonDebouncer.update()){
if(buttonDebouncer.fell()){
MyButton.IncrementCounter();
Serial.print("Count from Button Debouncer = ");
Serial.println(MyButton.GetCounter());
}
}
}
На основе вашего последнего обновления вопроса:
Я пытаюсь настроить код для размещения двух отдельных кнопок (на разных контактах), но это выдает ошибку.
Я обновил скетч, чтобы использовать 2 кнопки на отдельных цифровых выводах.
#include <Bounce2.h>
// Соединяем каждую кнопку одним соединением
// к GND, а другой к цифровому выводу.
const byte buttonPin = 2;
const byte buttonPin2 = 3;
class Button{
private:
byte m_buttonPin;
byte m_counter = 0;
unsigned long m_buttonPressTimeout;
unsigned long m_previousMillis;
public:
Button(byte buttonPin):
m_buttonPin(buttonPin),
m_counter(0),
m_buttonPressTimeout(750), // Время ожидания нажатия кнопки в мс.
m_previousMillis(0){}
void Update(){
if(m_counter > 0 && millis() - m_previousMillis >= m_buttonPressTimeout){
Serial.print("Count from Update() just before it's reset to 0 = ");
Serial.println(GetCounter());
m_counter = 0;
}
}
void IncrementCounter(){
m_counter++;
if(m_counter > 4){m_counter = 4;}
if(m_counter == 1){
m_previousMillis = millis();
}
}
friend void IncrementCounter(Button&);
void IncrementCounter(Button&){
IncrementCounter();
}
byte GetCounter(){
return m_counter;
}
};
Bounce buttonOneDebouncer = Bounce();
Bounce buttonTwoDebouncer = Bounce();
Button ButtonOne(buttonPin);
Button ButtonTwo(buttonPin2);
void setup(){
Serial.begin(9600);
pinMode(buttonPin, INPUT_PULLUP);
pinMode(buttonPin2, INPUT_PULLUP);
buttonOneDebouncer.attach(buttonPin);
buttonTwoDebouncer.attach(buttonPin2);
buttonOneDebouncer.interval(25);
buttonTwoDebouncer.interval(25);
}
void loop(){
// Вызовите функцию обновления как можно быстрее.
ButtonOne.Update();
ButtonTwo.Update();
// Нажата первая кнопка.
if(buttonOneDebouncer.update()){
if(buttonOneDebouncer.fell()){
if(digitalRead(buttonPin2) == 0){
ButtonOne.IncrementCounter();
}
}
}
// Вторая кнопка нажата.
if(buttonTwoDebouncer.update()){
if(buttonTwoDebouncer.fell()){
if(digitalRead(buttonPin) == 0){
ButtonOne.IncrementCounter(ButtonTwo);
}
}
}
}
спасибо, я попробую это. Использует ли это внешнюю библиотеку? @VE7JRO, @user19964
Да, библиотека Bounce2. Он доступен в менеджере библиотек IDE., @VE7JRO
О, хорошо, я попробую это, спасибо @VE7JRO, @user19964
Спасибо; это работает довольно хорошо ... теперь просто нужно выяснить, как подключить две отдельные кнопки к двум отдельным контактам @ VE7JRO, @user19964
@user19964 user19964 - легко добавить еще одну кнопку. Определите другую переменную, такую как buttonPin2
, затем сделайте что-то вроде этого Bounce buttonDebouncer2 = Bounce();
и Button MyButton2(buttonPin2);
. Немного копирования/вставки должно заставить 2 кнопки работать быстро. Самым сложным будет изменить логику в loop()
для работы с двумя кнопками., @VE7JRO
для цикла() не могли бы вы просто добавить что-то вроде: if(button1Debouncer.update() && button2Debouncer.update()) { if(button1Debouncer.fell() && button2Debouncer.fell())}} ? @VE7JRO, @user19964
@ user19964 - Я думаю, вы могли бы сделать что-то подобное. Возможно, когда одна из кнопок нажата, функция "it's" в loop()
может также выполнить digitalRead
для "другой кнопки". Эта часть информации может быть полезна, чтобы определить, действительно ли обе кнопки нажаты одновременно, в этот самый момент времени., @VE7JRO
Давайте [продолжим это обсуждение в чате](https://chat.stackexchange.com/rooms/101256/discussion-between-ve7jro-and-user19964)., @VE7JRO
@ VE7RO Я увидел это только сейчас и сразу же протестировал. Поскольку я этого не видел, я все еще несколько дней боролся с этим вопросом :(. БОЛЬШОЕ СПАСИБО!! Только что протестировал, и он работает хорошо; я действительно ценю всю помощь, которую вы мне оказали с этим вопрос :). Удачного дня!, @user19964
Вероятно, у вас возникли проблемы, связанные с кнопкой связаться с отказом. Здесь процессор настолько быстр, что «видит» кнопку, выполняющую несколько контактов, когда пользователь хочет, чтобы программа увидела только 1 контакт. Рассмотрите возможность использования этой библиотеки подавления дребезга кнопок вместо чтения состояния кнопок непосредственно в скетче.
Код приведенной выше библиотеки для защиты от дребезга Arduino находится здесь, на github.com. Как правило, у людей, использующих github.com, будет папка «example» вместе с папками исходного кода и документации. папка с примерами библиотеки debounce для Arduino находится здесь. Существует около полудюжины примеров скетчей Arduino, включая этот пример с двумя кнопками, который может использоваться в качестве отправной точки для проекта в вопросе.
Может возникнуть логическая проблема в коде при интерпретации количества нажатий кнопок в "a", "b", "c" & "д". Используется оператор по модулю "%". И в первом тесте проверяется количество нажатий кнопки %1. Если результат равен нулю, тест верен. Поскольку любое число % 1 не имеет остатка, этот тест всегда будет равен нулю и, следовательно, всегда верен. Поскольку все остальные тесты вложены в операторы else, ни один из других тестов выполняться не будет. Вместо этого рассмотрите возможность использования оператора switch/case, где код переключает число нажатий кнопок и операторами case являются "case 1:", case 2:", "case 3:" & "default:". Хорошей практикой кодирования всегда является использование case "default:" в операторе switch. Здесь мы используем «по умолчанию:» вместо «случай 4:». После использования значения, представляющего количество нажатий кнопки, всегда не забывайте очищать это значение перед следующей итерацией. Помните, что любые «глобальные» значения (значения, определенные вне функции ) сохранят свои значения между вызовами этой функции. Любое "локальное" значение (значения, определенные внутри функции) не сохранит свои значения, и его необходимо инициализировать при каждом использовании.
есть ли какие-нибудь примеры, показывающие, как реализовать эту библиотеку... я импортировал ее в свой проект, но не знаю, как ее реализовать @st2000, @user19964
Я добавлю, где найти примеры в моем ответе. Кроме того, я ценю, что вы отредактировали свой вопрос, чтобы сделать его лучше. Я добавил текст к вашему вопросу, чтобы было ясно, что было добавлено больше информации и что эта информация показывает., @st2000
да, я вижу, что вы отредактировали мой вопрос: спасибо... теперь он читается намного лучше. Да, эти примеры были бы очень признательны @st2000, @user19964
@ st2000просто хотел упомянуть, что счетчик сейчас работает, но он работает не совсем так, как мне бы хотелось., @user19964
Вы используете оператор по модулю "%". Я не думаю, что это то, что вы хотите. Например, вы можете разделить любое целое число на 1 и не получить остатка. Таким образом, 1 % 1 равно 0, 2 % 1 равно 0, что угодно, % 1 равно 0. Этот оператор всегда истинен, и ничто ниже него не будет выполняться. Вы всегда будете печатать «а». Вы хотите, чтобы я снова изменил свой ответ?, @st2000
ах да, это имеет смысл ... так много смысла. Когда я использовал if(buttonPushCounter ==1) и т. д., это не сработало. Да, я был бы признателен за это @st2000, @user19964
Большое спасибо за ваш обширный ответ. Я просмотрел там решения и добавил их в свое собственное решение. Как требуется. Счетчик теперь работает, выдает как надо и сбрасывает когда надо тоже: все как задумано. Я соответственно отредактировал свой вопрос @st2000, @user19964
Вам СЛЕДУЕТ обратить внимание на следующие вопросы:
1. Проблема с плавающим вводом:
Симптом: значение, считанное с входного контакта, не соответствует состоянию нажатия кнопки.
Причина: входной контакт НЕ использует подтягивающий или подтягивающий резистор.
Решение. Используйте подтягивающий или подтягивающий резистор. См. раздел Кнопка Arduino (с вытягиванием вверх/вниз)
2. Феномен болтовни
Это следует учитывать только в некоторых приложениях, которым необходимо определять точное количество нажатий.
Симптом: кнопка нажата один раз, но код Arduino определяет это несколько раз.
Причина. Из-за механических и физических проблем состояние кнопки (или переключателя) быстро переключается между НИЗКИМ и ВЫСОКИМ несколько раз
Решение. Отказаться. См. раздел отказ кнопки Arduino
.Спасибо за советы. У меня есть подтягивающий резистор на обеих моих кнопках, и я реализовал код устранения дребезга в этом коде. Я получаю почти то же самое, что и раньше @Rozona Zoro, @user19964
В вашем обновленном коде много проблем. Чтобы устранить дребезг кнопок, попробуйте следующее:
//Настройте debounceTime по желанию. Более короткое время сделает кнопку быстрее
//ответить, но сделать устранение дребезга менее эффективным. 50 это 1/20 секунды.
#define debounceTime 50
unsigned long nextButtonCheckTime = 0;
bool buttonAState = false;
bool buttonBState = false;
void loop() {
//Проверять кнопки, только если прошло время устранения дребезга
if (millis() > nextButtonCheckTime)
bool newButtonAState = digitalRead(buttonAPin) == LOW;
bool newButtonBState = digitalRead(buttonBPin) == LOW;
//Если одна или обе кнопки изменили состояние
if (buttonAState != newButtonAState || buttonBState != newButtonBState)) {
nextButtonCheckTime = millis() + debounceTime;
buttonAState = newButtonAState;
buttonBState = newButtonBState;
//Обработка изменения состояния кнопки
}
}
}
Это псевдокод. Он почти наверняка содержит синтаксические ошибки. Вы должны использовать его в качестве руководства и переписать в соответствии с вашими потребностями. не говорите: «Я скопировал ваш код в свой скетч, и он не скомпилируется».
Спасибо; это действительно помогает в качестве ориентира. Я буду использовать его соответственно @DuncanC, @user19964
- Определение того, была ли нажата и отпущена кнопка
- Хорошая кнопка debouncing/Библиотека StateChange
- Остановить мигание светодиодов
- Интеграция 2 кнопок для включения и выключения светодиода.
- Код Arduino для управления 4 светодиодами с 4 кнопок
- Нужен ли подтягивающий/понижающий резистор для цепи светодиода кнопки?
- Как прервать функцию цикла и перезапустить ее?
- Как перезапустить счетчик в программе с помощью кнопки в настройке LDR Tripwire
Вы пишете, что хотите его для игры. Так что, возможно, вы хотите не считать нажатия, а просто посмотреть, какая кнопка была нажата правильно? Не вызывайте "digitalRead" много раз, если хотите быть быстрым. Лучшим решением было бы прочитать 7 контактов одним вызовом с помощью
PIND
, поэтому вы читаете контакты с 0 по 7 (дополнительно). Или, когда я анализирую ваш код, вы просто хотите получать уведомления об изменениях, вы можете использовать прерывания., @Adriano@ Adriano Мне действительно нужно количество нажатий. Я думаю, что я должен сделать это немного яснее: Справедливое замечание ... Я никогда не объяснял этого Итак, у меня есть игрок, которому нужно прыгать на разные платформы, чтобы собирать монеты, и на каждом уровне платформы и номера монет различаются, и поскольку я использую устройство ввода в качестве отвлечения внимания, поэтому на каждом уровне количество кликов, необходимых для перемещение персонажа, изменения Таким образом, на одном уровне вам нужно нажимать кнопки дважды, на следующем уровне трижды и т. д., @user19964
Я не понимаю проблемы, которую вы пытаетесь решить. Сколько у вас отдельных кнопок? Каждая кнопка на отдельном пине или у вас матрица кнопок? Может ли пользователь одновременно нажимать более одной кнопки, а вы хотите определить, сколько из них нажато одновременно? Давайте назовем это numberOfButtonsPressed. Тогда вы также ищете, чтобы пользователь нажимал одинарное, двойное, тройное нажатие и т. д., какое-то количество кнопок? Итак, у вас обоих есть количество нажатых кнопок и количество нажатий на них?, @Duncan C
Вам нужно будет обрабатывать «отстой» на входе, когда пользователь нажимает разные кнопки в несколько разное время. Если они пытаются нажать 4 кнопки, вы можете обнаружить, что сначала нажата одна, затем 2, затем 3, затем 4 кнопки. И из-за дребезга вы можете увидеть, как некоторые из этих кнопок быстро переключаются между ненажатыми и нажатыми в течение нескольких миллисекунд, прежде чем успокоиться., @Duncan C
Вы можете попробовать 20-50 мс. Если вы не обнаружите каких-либо изменений в состоянии кнопки в течение этого времени, вы можете считать состояние кнопки стабильным и снять показания., @Duncan C
@DuncanC У меня есть 2 кнопки, которые подключены к отдельным контактам, но пользователь должен нажать обе кнопки одновременно, чтобы зарегистрировать одно нажатие. Итак, проблема, с которой я столкнулся, заключается в том, как отличить один толчок от двух толчков и т. Д. Итак, вы предлагаете мне обрабатывать «отстой» в этом случае?, @user19964
Вам нужно устранить дребезг кнопок. Это можно сделать довольно легко в программном обеспечении. Выполните поиск в Google, но основная идея заключается в том, что когда вы обнаруживаете нажатие кнопки (или нажатие двух кнопок в вашем случае), вы записываете значение
millis()
и игнорируете изменения цифровых входов для некоторой константы. Период ожидания. (20-100 мс — хороший диапазон для работы, в зависимости от ситуации.), @Duncan C@DuncanC На самом деле я думал, что смогу уйти, не устраняя это (поскольку до этого момента он хорошо работает без этого), но, похоже, мне нужно вникнуть в это. Спасибо, @user19964
На самом деле написать собственный код для устранения дребезга довольно просто. Вам просто нужно записать чтение
millis()
, когда первая кнопка меняет состояние, и игнорировать дальнейшие изменения состояния в течение небольшого интервала времени., @Duncan C@DuncanC Сегодня я попробовал код устранения дребезга, но теперь последовательный монитор ничего не выводит. Не могли бы вы взглянуть на мой обновленный код?, @user19964