代码之家  ›  专栏  ›  技术社区  ›  Rafael Beckel

如何检测在Arduino中按下按钮的时间?

  •  5
  • Rafael Beckel  · 技术社区  · 9 年前

    如何检测在Arduino中按下/释放按钮的时间,然后打印一些自定义输出?

    2 回复  |  直到 6 年前
        1
  •  19
  •   Rafael Beckel    3 年前

    Arduino只能检测按钮的状态(按下或未按下)。

    您可以使用计时器变量(基于 this example 从他们的文档中),以节省您 按下 释放 按钮,这样您就可以检查两个变量之间的差异,以计算保持或空闲的时间。

    代码可能如下所示:

    const int buttonPin = 2;  
    
    int buttonState = 0;     // current state of the button
    int lastButtonState = 0; // previous state of the button
    int startPressed = 0;    // the moment the button was pressed
    int endPressed = 0;      // the moment the button was released
    int holdTime = 0;        // how long the button was hold
    int idleTime = 0;        // how long the button was idle
    
    void setup() {
      pinMode(buttonPin, INPUT); // initialize the button pin as a input
      Serial.begin(9600);        // initialize serial communication
    }
    
    void loop() {
      buttonState = digitalRead(buttonPin); // read the button input
    
      if (buttonState != lastButtonState) { // button state changed
         updateState();
      }
    
      lastButtonState = buttonState;        // save state for next loop
    }
    
    void updateState() {
      // the button has been just pressed
      if (buttonState == HIGH) {
          startPressed = millis();
          idleTime = startPressed - endPressed;
    
          if (idleTime >= 500 && idleTime < 1000) {
              Serial.println("Button was idle for half a second");
          }
    
          if (idleTime >= 1000) {
              Serial.println("Button was idle for one second or more"); 
          }
    
      // the button has been just released
      } else {
          endPressed = millis();
          holdTime = endPressed - startPressed;
    
          if (holdTime >= 500 && holdTime < 1000) {
              Serial.println("Button was held for half a second"); 
          }
    
          if (holdTime >= 1000) {
              Serial.println("Button was held for one second or more"); 
          }
    
      }
    }
    

    但是,如果您想触发事件 虽然 按钮仍然被按下(或者你想在某些显示器上增加一个计数器),你仍然可以做同样的计算。

    将循环函数中的条件更改为如下:

      if (buttonState != lastButtonState) { 
         updateState(); // button state changed. It runs only once.
      } else {
         updateCounter(); // button state not changed. It runs in a loop.
      }
    

    然后像这样实现新功能:

    void updateCounter() {
      // the button is still pressed
      if (buttonState == HIGH) {
          holdTime = millis() - startPressed;
    
          if (holdTime >= 1000) {
              Serial.println("Button is held for more than a second"); 
          }
    
      // the button is still released
      } else {
          idleTime = millis() - endPressed;
    
          if (idleTime >= 1000) {
              Serial.println("Button is released for more than a second");  
          }
      }
    }
    
        2
  •  1
  •   Sylvain    4 年前

    为了您的兴趣,这里有一个代码示例,它使用2个数组来存储提供给相应输入按钮的arduino引脚的按钮状态。在循环过程中,您可以使用所需的重复进行简单检查:

      if(button_down(But1_pin, BTN_LOOP_DELAY_MS))
      {
        // code here repeated if the button is either clicked or maintained
      }
    

    button_down() 也将第一次重复推迟到 DELAY_WAIT_BEFORE_REPEAT 太太

    这里是完整的测试示例:

    #define BTN_LOOP_DELAY_MS   100
    #define DELAY_WAIT_BEFORE_REPEAT  500
    #define NB_MAX_PIN_INPUT    13
    
    #define But1_pin    7
    #define But2_pin    6
    
    // array to check status change
    bool prev_button[NB_MAX_PIN_INPUT];
    unsigned long button_last_down[NB_MAX_PIN_INPUT];
    
    // macro : our read init with prev_button storage
    #define READ_INIT_BUTTON(pin)  \
      do{ \
        pinMode(pin, INPUT); \
        prev_button[pin] = digitalRead(pin); \
       } while(false)
    
    // function at the end of the code
    bool button_down(byte pin_num, unsigned int delay_repeated);
    
    void setup() {
      READ_INIT_BUTTON(But1_pin);
      READ_INIT_BUTTON(But2_pin);
      Serial.begin(115200);
    }
    
    void loop() {
      if(button_down(But1_pin, BTN_LOOP_DELAY_MS))
      {
        Serial.print("new inpulse");
        Serial.print(millis());
        Serial.println();
      }
    
      if(button_down(But2_pin, BTN_LOOP_DELAY_MS))
      {
        Serial.println("button2");
      }
    
    }
    
    bool button_down(byte pin_num, unsigned int delay_repeated)
    {
      bool b = digitalRead(pin_num);
      bool r = false;
    
      unsigned long currentMillis = millis();
    
      if(prev_button[pin_num] != HIGH && b == HIGH)
      {
        r = true;
        button_last_down[pin_num] = currentMillis + DELAY_WAIT_BEFORE_REPEAT;
      }
      else if(b == HIGH 
          && prev_button[pin_num] == HIGH
          && currentMillis > button_last_down[pin_num] 
          && currentMillis - button_last_down[pin_num] > delay_repeated
        )
      {
        // save the last time we give a button impusle at true
        button_last_down[pin_num] = currentMillis;
        r = true;
      }
    
      // store button state, if changed
      if(prev_button[pin_num] != b)
      {
        prev_button[pin_num] = b;
      }
        
      return r;
    }