Как определить, было ли нажато более одной кнопки
Я проектирую велосипедный указатель поворота, использующий в качестве входных данных две кнопки, по одной с каждой стороны, с соответствующей подсветкой для каждой кнопки. Идея такова:
- Нажатие на одну сторону заставляет эту же сторону начать мигать;
- Повторное нажатие на ту же сторону выключает ее;
- Нажатие на другую сторону выключает эту сторону и включает другую сторону;
- (а теперь самое интересное!) если нажаты обе кнопки (или, точнее, если одна кнопка нажата до того, как отпущена другая), то — и только тогда — я начинаю мигать обеими сторонами (функция «предупреждающего сигнала»).
На мой взгляд, проблема в том, что мне нужно дождаться, пока я отпущу одну кнопку (это будет один полный щелчок), чтобы включить одну сторону, потому что если я нажму вторую, пока первая остается нажатой, это будет другое событие/жест («both_click», за неимением лучшего названия).
Другой вариант дизайна — включить один индикатор сразу при нажатии, и если я нажму второй, прежде чем отпущу первый, то также включится другой индикатор (таким образом, включив режим «предупреждения», когда оба индикатора мигают). Хотя это звучит осуществимо, в классе Button («Botao») есть вся логика устранения дребезга, и я боюсь, что загнал себя в угол конкретными объектно-ориентированными решениями по дизайну, которые я сделал.
ПРАВКА: третий вариант дизайна — добавить метод run
для каждой кнопки и, вместо того, чтобы запускать только тестируемый метод «псевдособытия», сохранять текущее состояние и событие в переменных, проверяя эти переменные в loop()
(например, свойство button.wasPressed
вместо метода button.wasPressed()
).
Я публикую свой текущий код (только соответствующие части). Обратите внимание, что в цикле есть комментарий, где, как мне кажется, я должен обнаружить двойной щелчок.
Основной файл .ino:
#include "PiscaPisca.cpp"
#include "Botao.cpp"
PiscaPisca pisca;
Botao botao1;
Botao botao4;
void setup() {
pisca.configure(LEFT, RIGHT, BUZZER);
botao1.configure(BUTTON1);
botao4.configure(BUTTON4);
}
void loop() {
// КАК Я МОГУ ОПРЕДЕЛИТЬ, ЧТО ОБЕ КНОПКИ БЫЛИ НАЖАНЫ??
// если (bothPressed()) { pisca.toggleWarning(); }
if (botao1.wasPressed()) { pisca.toggleLeft(); }
if (botao4.wasPressed()) { pisca.toggleRight(); }
pisca.run();
}
Botao.cpp (это класс кнопки с функцией устранения дребезга)
#include <Arduino.h>
class Botao
{
int _pino;
const int DEBOUNCE_DELAY = 30;
int buttonState;
int lastState = HIGH;
int lastDebounceTime;
public : void configure(int pino)
{
_pino = pino;
pinMode(pino, INPUT_PULLUP);
}
public : boolean wasPressed()
{
return debounce(LOW);
}
public : boolean wasReleased()
{
return debounce(HIGH);
}
public : boolean debounce(int state)
{
boolean gotEvent = false;
int reading = digitalRead(_pino);
if (reading != lastState) {
lastDebounceTime = millis();
}
if ((millis() - lastDebounceTime) > DEBOUNCE_DELAY) {
if (reading != buttonState) {
buttonState = reading;
if (buttonState == state) {
gotEvent = true;
}
}
}
lastState = reading;
return gotEvent;
}
};
PiscaPisca.cpp (сама конечная машина)
#include "Arduino.h"
#include "PwmPin.cpp"
#include "Beeper.cpp"
typedef enum {
NONE = 0,
RIGHT_LIGHT = 1,
LEFT_LIGHT = 2,
BOTH = 3
};
class PiscaPisca
{
PwmPin _left;
PwmPin _right;
Beeper _beeper;
long _timeReference = 0;
const int PERIOD = 350;
boolean
_running = false,
_lightState = false;
int _sides_to_turn = NONE;
public : void configure(int leftPin, int rightPin, int buzzerPin)
{
_left.configure(leftPin);
_right.configure(rightPin);
_beeper.configure(buzzerPin);
}
public : void run()
{
evaluateBlink();
}
public : void toggleLeft()
{
checkRestart(LEFT_LIGHT);
}
public : void toggleRight()
{
checkRestart(RIGHT_LIGHT);
}
void checkRestart(int lightSide)
{
_timeReference = 0;
// немного хитрой манипуляции никогда не повредит:
_sides_to_turn = lightSide & ~_sides_to_turn;
Serial.println(lightSide);
Serial.println(_sides_to_turn);
if (_sides_to_turn > 0)
{
_running = true;
}
else
{
lightsOff();
_running = false;
_lightState = false;
}
}
void evaluateBlink()
{
if (!_running)
{
return;
}
else
{
long currentMillis = millis();
if (currentMillis - _timeReference > PERIOD) {
_timeReference = currentMillis;
_lightState = !_lightState;
performBlink();
}
}
}
void performBlink()
{
if (_lightState)
{
_beeper.beepIn();
lightsOn();
}
else
{
_beeper.beepOut();
lightsOff();
}
}
void lightsOn()
{
if (isLightSet(LEFT_LIGHT))
{
_left.on();
}
if (isLightSet(RIGHT_LIGHT))
{
_right.on();
}
}
boolean isLightSet(int lightSide)
{
return (_sides_to_turn & lightSide) == lightSide;
}
void lightsOff()
{
_left.off();
_right.off();
}
};
@heltonbiker, 👍2
0
- Как масштабировать растровое изображение (массив uint8_t) в Arduino?
- Использование функции millis() вместо функции delay() при воспроизведении мелодии
- Матрица и пространство состояний Реализация Arduino
- Какие накладные расходы и другие соображения существуют при использовании структуры по сравнению с классом?
- Что лучше использовать: #define или const int для констант?
- Функции со строковыми параметрами
- Как работать с аналоговыми контактами в цикле?
- Какие есть другие IDE для Arduino?