Arduino Protothreads, кажется, разделены двумя кнопками
Я столкнулся с проблемой, связанной с библиотекой Proththreading в Arduino. Я создал Button
класс, который представляет аппаратную кнопку. Теперь идея заключается в том, что вы можете прикрепить ButtonListener
к нему, который слушает кнопку. Если кнопка нажата, то clicked()
функция называется.
#include <Arduino.h>
#include <pt.h>
class ButtonListener {
public:
virtual void clicked() = 0;
virtual void longClicked() = 0;
virtual void tapped(int) = 0;
};
class Button {
static const int RECOIL_TIME = 200;
static const int LONG_CLICK_LENGTH = 1000;
private:
int _pin;
ButtonListener *_listener;
struct pt _thread;
unsigned long _timestamp = 0;
int listenerHook(struct pt *pt) {
PT_BEGIN(pt);
this->_timestamp = 0;
while (true) {
PT_WAIT_UNTIL(pt, millis() - _timestamp > 1);
_timestamp = millis();
if (&this->_listener != NULL) {
this->listenForClick();
}
}
PT_END(pt);
}
void listenForClick() {
boolean longClicked = true;
int state = digitalRead(this->_pin);
if (state == HIGH) {
unsigned long timestamp = millis();
while (true) {
longClicked = millis() - timestamp > LONG_CLICK_LENGTH;
state = digitalRead(this->_pin);
if (state == LOW) {
break;
}
}
if (&this->_listener != NULL) {
if (longClicked) {
(*this->_listener).longClicked();
}
else {
(*this->_listener).clicked();
}
}
}
}
public:
Button(int pin) {
this->_pin = pin;
}
void init() {
pinMode(this->_pin, OUTPUT);
PT_INIT(&this->_thread);
}
void setListener(ButtonListener *listener) {
this->_listener = listener;
}
void listen() {
this->listenerHook(&this->_thread);
}
};
Теперь я создал две реализации ButtonListener
:
class Button12Listener : public ButtonListener {
public:
void clicked() {
Serial.println("Button 12 clicked!");
}
}
Другая реализация является Button13Listener
и печатает "Кнопка 13 нажала!"
Тогда давайте запустим код:
// Instantiate the buttons
Button button12(12);
Button button13(13);
void setup() {
Serial.begin(9600);
button12.init();
button13.init();
// Add listeners to the buttons
button12.setListener(new Button12Listener());
button13.setListener(new Button13Listener());
}
void loop() {
while (true) {
// Listen for button clicks
button12.listen();
button13.listen();
}
Serial.println("Loop ended.");
delay(60000);
}
Я ожидаю "Кнопка 12 нажата!" когда я нажимаю кнопку на контакте 12, и "кнопка 13 нажата!" когда я нажимаю кнопку на контакте 13.
Но когда я пытаюсь нажать на любую из кнопок, она случайным образом печатает "Кнопка 12 нажата!" или "Кнопка 13 нажата!" независимо от того, какую кнопку я нажимаю.
Похоже, что протопотоки распределяются между кнопками или что-то в этом роде.
Если я проверю, в каком порядке вызываются кнопки, вот так:
button12.listen();
Serial.println("listen12");
button13.listen();
Serial.println("listen13");
затем следующие выводы:
12
13
12
13
12
12
Кажется, все в порядке.
Так в чем проблема? Что я пропустил?
1 ответ
Вы полностью исключаете весь смысл протопотоков, используя этот цикл while(true) в listenForClick. Я бы сделал это так:
PT_BEGIN(thr);
while(1){
// ensure that the pin is low when you start
PT_WAIT_UNTIL(thr, digitalRead(pin) == LOW);
// wait until pin goes high
PT_WAIT_UNTIL(thr, digitalRead(pin) == HIGH);
// insert delay here for minimum time the pin must be high
this->timeout = millis() + 20; // 20 ms
// wait until the delay has expired
PT_WAIT_UNTIL(thr, this->timeout - millis() > 0);
// wait until the pin goes low again
PT_WAIT_UNTIL(thr, digitalRead(pin) == LOW);
// call the click callback
this->clicked();
}
PT_END(thr);
Тогда просто вызывайте эту ветку несколько раз.
ПРИМЕЧАНИЕ: если у вас подключены кнопки, вы обычно имеете подтягивание на штыре, а кнопка между штырем и землей должна быть подключена - поэтому штырь НИЗКИЙ, когда кнопка нажата, и высокий, когда она не нажата. Это, безусловно, будет иметь место на Arduino. Таким образом, вам придется изменить код выше, чтобы дождаться отрицательного импульса вместо положительного.:)