1

对于 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)函数是否完全等同GPIO.input(channel)于python代码中的函数?

如果有人能指出我如何检测按钮按下(软件去抖动)并测量 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);
    ...
}

4

1 回答 1

1

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

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

?

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

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();
       }
    }


}
于 2019-01-21T11:42:18.807 回答