我对c和Raspberry Pi相对较新,我正在尝试简单的程序。我想要的是当按下按钮时printfs一次并且不再打印,直到再次按下按钮,即使按下按钮(类似闩锁)。我想可能会添加第二个while循环来解决这个问题,但有时它仍然没有检测到按下按钮。
#include <bcm2835.h>
#include <stdio.h>
#define PIN RPI_GPIO_P1_11
int main()
{
if(!bcm2835_init())
return 1;
bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_INPT);
while(1)
{
if(bcm2835_gpio_lev(PIN))
{
printf("The button has been pressed\n");
}
while(bcm2835_gpio_lev(PIN)){}
}
bcm2835_close();
return 0;
}
答案 0 :(得分:2)
你的逻辑是正确的,如果按钮完美,这将有效。但他们不是。您必须去抖动按钮的信号。实现这一目标的两种方法(组合时效果最佳):
予。在按钮的两个引脚之间添加一个电容(或尝试an even more sophisticated button debouncer circuitry)和/或
II。使用软件去抖(伪C):
while (1) {
while (!button_pressed)
;
printf("Button pressed!\n");
while (elapsed_time < offset)
;
}
等
编辑:正如@jerry所指出的那样,按住按钮时,上述操作无法正常工作。以下是您可以用来满足所有要求的几个more professional code snippets。
答案 1 :(得分:1)
以下功能以1毫秒的间隔轮询按钮,并要求状态保持“释放”到20个连续的民意调查。这通常足以在保留响应性的同时去抖大多数交换机。
通过调用while(bcm2835_gpio_lev(PIN)){}
替换您的waitButtonRelease()
循环。
#include <unistd.h>
#define DEBOUNCE_MILLISEC 20
void waitButtonRelease()
{
int debounce = 0 ;
while( debounce < DEBOUNCE_MILLISEC )
{
usleep(1000) ;
if( bcm2835_gpio_lev(PIN) )
{
debounce = 0 ;
}
else
{
debounce++ ;
}
}
}
您可能会发现还需要去除按钮按下以及释放按钮。这是以相同的方式完成的,但计算相反的状态:
void waitButtonPress()
{
int debounce = 0 ;
while( debounce < DEBOUNCE_MILLISEC )
{
usleep(1000) ;
if( !bcm2835_gpio_lev(PIN) )
{
debounce = 0 ;
}
else
{
debounce++ ;
}
}
}
也许是一个去抖动状态的功能:
#include <stdbool.h>
void waitButton( bool state )
{
int debounce = 0 ;
while( debounce < DEBOUNCE_MILLISEC )
{
usleep(1000) ;
if( bcm2835_gpio_lev(PIN) == state )
{
debounce++ ;
}
else
{
debounce = 0 ;
}
}
}
鉴于此最后一个函数,您的主while循环可能如下所示:
while(1)
{
waitButton( true )
printf("The button has been pressed\n");
waitButton( false ) ;
}
如果您可以访问数字存储示波器,则可以直接探测开关信号,以准确查看开关反弹的样子。它可以帮助您理解问题,并根据特定开关的特性定制去抖动。
答案 2 :(得分:1)
对于像这样的简单程序,使用像你已经完成的繁忙循环很好。但是,我建议戒掉这个习惯,因为除了玩具项目之外,这通常是不可接受的。
有很多方法可以去除按钮,因为有人在编写代码。在某些情况下,在硬件中执行它可能是一种方法,但它并非没有缺点。在任何情况下,由于这是一个编程站点,我们假设您不能(或不想)更改硬件。
快速而肮脏的修改是定期检查主循环中的按钮,并且仅在其已更改时才执行。由于你是C和嵌入式编程的新手,我会避免使用定时器和中断,但是一旦你了解它们就知道你可以使代码更容易理解和维护。
#include <bcm2835.h>
#include <stdio.h>
#define PIN RPI_GPIO_P1_11
// A decent value for the number of checks varies with how "clean" your button is, how
// responsive you need the system to be, and how often you call the helper function. That
// last one depends on how fast your CPU is and how much other stuff is going on in your
// loop. Don't pick a value above UINT_MAX (in limits.h)
#define BUTTON_DEBOUNCE_CHECKS 100
int ButtonPress()
{
static unsigned int buttonState = 0;
static char buttonPressEnabled = 1;
if(bcm2835_gpio_lev(PIN))
{
if(buttonState < BUTTON_DEBOUNCE_CHECKS)
{
buttonState++;
}
else if(buttonPressEnabled)
{
buttonPressEnabled = 0;
return 1;
}
}
else if(buttonState > 0 )
{
buttonState--;
// alternatively you can set buttonState to 0 here, but I prefer this way
}
else
{
buttonPressEnabled = 1;
}
return 0;
}
int main()
{
if(!bcm2835_init())
return 1;
bcm2835_gpio_fsel(PIN, BCM2835_GPIO_FSEL_INPT);
while(1)
{
if(ButtonPress())
{
printf("The button has been pressed\n");
}
// the rest of your main loop code
}
bcm2835_close();
return 0;
}