【问题标题】:How to detect how long a button was pressed in Arduino?如何检测在 Arduino 中按下按钮的时间?
【发布时间】:2015-09-06 19:49:11
【问题描述】:

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

【问题讨论】:

    标签: c arduino atmega


    【解决方案1】:

    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】:

      为了您的兴趣,这里有一个代码示例,它使用 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;
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-09-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-03-03
        相关资源
        最近更新 更多