2015-09-27 298 views
1

我想爲Arduino項目中的一個按鈕實現三種不同的功能。點擊,雙擊並按住。 我必須使用中斷,並儘可能讓系統進入睡眠狀態,因爲最終產品必須在硬幣電池上運行幾個月。Arduino單擊,雙擊並按住按鈕

#include <Ports.h> 
#include <RF12.h> 
#include <avr/sleep.h> 
#include <PinChangeInt.h> 
#include <VirtualWire.h> 

ISR(WDT_vect) { Sleepy::watchdogEvent(); } 

char *controller; 

const int buttonPin = 3; 

bool stateSingle = false; 
bool stateDouble = false; 
bool stateLong = false; 

void setup() { 
    pinMode(13, OUTPUT); 
    pinMode(6, OUTPUT); 
    pinMode(7, OUTPUT); 
    pinMode(5, OUTPUT); 
// vw_set_ptt_inverted(true); 
// vw_set_tx_pin(12); 
// vw_setup(4000); 
// 
    Serial.begin(9600); 

    PCintPort::attachInterrupt(buttonPin, wakeUp, HIGH); 
} 

void wakeUp() { 
} 

void loop() { 
    cli(); 

    int i = 0; 
    while (digitalRead(buttonPin) == HIGH) { // Wait until button is LOW, or has been high for more than 600ms 
     Sleepy::loseSomeTime(50); 
     if (i > 12) 
     break; 
     i++; 
    } 

    if (digitalRead(buttonPin) == HIGH) 
     longTapAction(); 
    else { 
     i = 0; 
     while (digitalRead(buttonPin) == LOW) { // Wait for possible double press 
     Sleepy::loseSomeTime(50); 
     if (i > 8) 
      break; 
     i++; 
     } 

     if (digitalRead(buttonPin) == HIGH) { 
      doubleTapAction(); 

      while (digitalRead(buttonPin) == HIGH) 
      Sleepy::loseSomeTime(50); 
     } else 
     singleTapAction(); 
    } 
} 

void singleTapAction() { 
    stateSingle = !stateSingle; 
    digitalWrite(5, stateSingle ? HIGH : LOW); 

    sei(); 
    Sleepy::powerDown(); 
} 

void doubleTapAction() { 
    stateDouble = !stateDouble; 
    digitalWrite(6, stateDouble ? HIGH : LOW); 

    sei(); 
    Sleepy::powerDown(); 
} 

void longTapAction() { 
    stateLong = !stateLong; 
    digitalWrite(7, stateLong ? HIGH : LOW); 

    sei(); 
    Sleepy::powerDown(); 
} 

問題是,這並不總是正確的工作。 因爲我使用中斷,millis()裏面void loop()是不可靠的,出於某種原因。

對於任何雙擊和任何保持操作,單擊功能也會被調用。我懷疑這是由於多箇中斷觸發,但我無法測試這個。另外,有時候,雙擊似乎只需要一次點擊。我的思想錯了嗎,我忘記了什麼嗎?

回答

1

如果您看到singleTapActiondoubleTapAction觸發過於頻繁,這個問題可能是你的方法,並沒有真正的去抖按鈕輸入,這意味着你可以在任何點擊作爲單一按下鍵或雙擊按閱讀雜散噪聲。 E.G第一個while循環會在出現噪聲輸入時幾乎立即退出,這會使以下行爲難以預測。

https://www.arduino.cc/en/Tutorial/Debounce

如果你看一下在Arduino的網站鏈接的例子 - 一個可能的解決方案是記錄時間的輸入就一直存在的時期,而忽略小於一定時期的任何輸入。修改你的代碼來做到這一點可以阻止虛假的呼叫。

+0

這是有道理的,特別是對於額外的單擊功能調用,當你這樣說的時候。當設備進入睡眠狀態時,這個例子會不會更復雜一些,因爲睡眠時millis()不會增加?什麼是最好的方法仍然包括反彈? –

+0

添加類似'static unsigned long last_interrupt_time = 0; unsigned long interrupt_time = millis(); if(interrupt_time - last_interrupt_time> 200)',行爲仍然相同。 –