如何使用C中的wiringpi确定按钮按下持续时间

How to determine button press duration with wiringpi in C

对于 aspberry pi 项目,我有连接到 GPIO 的按钮,我想根据按下按钮的时间长短采取不同的操作。以下 python 代码(提取)按预期工作:

on_button2(channel):
    t1 = time.time()
    # Wait for button release
    while GPIO.input(channel) == 0:
        pass
    duration = time.time() - t1
    print "duration: %f" % (duration)
    if duration > 0.75:
        mpd_client.previous()
    else:
        mpd_client.next()

GPIO.add_event_detect(BUTTON2_PIN, GPIO.FALLING, callback=on_button2, bouncetime=700);

我想把它转换成C程序(别问为什么,我真的不喜欢python而且我对C更熟悉,所以我想做它在 C)

试图用 wiringPi 将其转换为 C,我想出了这个,但它没有按预期工作:

unsigned long btn2_t0;

static void on_button_2_pressed() {
    unsigned long duration, t1;
    int level;

    level = digitalRead(BUTTON_2_PIN);

    // Debounce button
    t1 = millis();
    if (t1 - btn2_t0 < 700) {
        return;
    }
    btn2_t0 = t1;

    // Wait for button being released
    while (digitalRead(BUTTON_2_PIN) == LOW) {
        delay(100);
    }

    duration = millis() - t1;

    if (duration > 5000) {
        printf("Self destruction sequence initiated!\n");
    }
    else if (duration > 700) {
        player_previous();
    }
    else {
        player_next();
    }
}

int main() {
    // Setup WiringPi Lib
    wiringPiSetupGpio();
    pinMode(BUTTON_2_PIN, INPUT);

    // Register callbacks on button press
    wiringPiISR(BUTTON_2_PIN, INT_EDGE_FALLING, on_button_2_pressed);

    for (;;) {
        delay(500);
    }
    return 0;
}

似乎应该等待按钮释放的循环没有被执行,或者 while 条件始终为真,因此持续时间始终为零。

digitalRead(BUTTON_2_PIN) 函数是否等同于 python 代码中的 GPIO.input(channel)

如果有人能指出正确的方向,告诉我如何检测按钮按下(软件去抖动)并测量 C 中按钮按下的持续时间。

非常感谢。

编辑:工作解决方案

在 Francesco Boi 的帮助下玩了很多之后,我找到了一个可行的解决方案,虽然我不太明白为什么与 python 代码相比,HIGH / LOW 的比较逻辑被交换了(我认为按下按钮会导致引脚下降到低电平,释放它会使其上升到高电平...)

static void on_button_2_pressed() {

    unsigned long duration;
    static unsigned long button_pressed_timestamp;
    int level = digitalRead(BUTTON_2_PIN);

    if (level == HIGH) { // Why HIGH ?!?
        button_pressed_timestamp = millis();
    }
    else {
        duration = millis() - button_pressed_timestamp;
        button_pressed_timestamp = millis();

        if (duration < 100) {
            // debounce...
            return;
        }
        else if (duration < 700) {
            syslog(LOG_NOTICE, ">> NEXT\n");
        }
        else if (duration < 3000) {
            syslog(LOG_NOTICE, "<< PREV\n");
        }
        else {
            syslog(LOG_NOTICE, "!! REBOOT\n");
        }
    }
}

int main() {
    ...
    wiringPiISR(BUTTON_2_PIN, INT_EDGE_BOTH, on_button_2_pressed);
    ...
}

首先,您将引脚的值读入 level,然后在 while 循环中重新读取它:这是为什么呢?你不能做这样的事情吗:

// Wait for button being released
while (level == LOW) {
    delay(100);
}

?

即使时间小于 700 毫秒,您也不想重新分配 btn2_t0 = t1; 吗?喜欢:

t1 = millis();
if (t1 - btn2_t0 < 700) {
  btn2_t0 = t1;  
  return;
}

行为取决于您构建电子电路的方式:按下按钮会使引脚变高还是变低?通过连接 LED 和电阻器或使用电压表,确保行为符合您的预期。

然而,由于你的 Python 代码有效,我假设电子是正确的,你的算法也是正确的。

当然要确保您按下按钮的时间足够长。在您的代码中添加一些打印以了解它正在执行哪些分支,因为当涉及电子时,仅通过代码很难理解。

在等待您的消息时,我认为最好执行以下操作:将回调定义为:INT_EDGE_BOTH 以便在按下底部和释放按钮时调用它。您可以使用静态变量来保持经过的时间。

void yourCallback()
{
    unsigned long ela, t;
    int level = digitalRead(BUTTON_2_PIN);
    static unsigned long button_pressed_timestamp;
    //if button pressed:
    if(level==LOW)
    {
      //start counting
      button_pressed_timestamp = millis();
    }
    else //button released
    {
       duration = millis()-button_pressed_timestamp;
       button_pressed_timestamp = millis(); //just to be sure....
       if (duration > 5000) {
          printf("Self destruction sequence initiated!\n");
       }  
       else if (duration > 700) {
          player_previous();
       }
       else {
          player_next();
       }
    }


}