原理圖分析

根據原理圖,當按鍵沒有按下的時候,單片機引腳BTN1通過10K的電阻接VCC,為高電平;當按鍵按下的時候,BTN1通過10K的電阻接地,為低電平,此時這個10K的電阻起限流作用,一般程序限流電阻。那么理想情況下,按鍵沒有按下的時候為高電平1,按下為低電平0,但是實際情況下,由於機械的抖動,實際情況產生的波形如下圖所示:

信號由於機械的抖動,導致在1和0之間多次跳變,一般抖動時間為5-10ms。單片機的處理速度很快,如果不做處理,那么會導致程序多次執行按鍵后的操作,從而導致邏輯錯誤。例如,要實現按下燈亮,再次按下燈滅,如果不消抖,就可能導致一次按下,多次處理,燈的開關狀態就有可能沒有變化。
實現按鍵消抖
一個簡單的消抖辦法是檢測到按鍵按下,則等待10ms之后,再次檢測是否在按下狀態,如果是按下的狀態,那么才確定是在按下狀態。偽代碼如下:
if (key == 0) { //檢測到按鍵按下
DelayMs(10); //等待10個毫秒
if (key == 0) { //按鍵仍然保持在按下的狀態
led = !led; //切換LED的開關狀態
while (key == 0); //等待松手
}
}
編寫程序並測試
#include <ioCC2530.h>
#define LED1 P1_0 //定義LED1所在引腳
#define KEY1 P0_1 //定義BTN1所在引腳
void DelayMs(int ms)
{
while (ms--) {
volatile int x = 500;//注意:這個數字是估計的,不准確
while (x--);
}
}
void main(void)
{
//配置P0_1引腳的按鍵1
P0SEL &= ~0x02; //普通GPIO模式<0為IO模式,1為外設模式>
P0DIR &= ~0x02; //輸入功能<0為輸入,1為輸出>
P0INP &= ~0x02; //上拉或下拉模式<0為上拉或下拉模式,1為三態模式>
//配置P1_0引腳的LED1
P1SEL &= ~0x01; //普通GPIO模式<0為IO模式,1為外設模式>
P1DIR |= 0x01; //輸出功能<0為輸入,1為輸出>
P1INP &= ~0x01; //上拉或下拉模式<0為上拉或下拉模式,1為三態模式>
P2INP |= 0xe0; //P0,P1,P2都設置為上拉模式
while (1)
{
if (0 == KEY1) {
DelayMs(10);
if (0 == KEY1) {
LED1 = !LED1;
while (0 == KEY1);
}
}
}
}
注意事項
上面這個方法比較常用,但是存在如下問題:
- 如果用戶一直按着,會導致程序停在等待松手的位置。
- 在等待10ms期間,程序什么也不能做,浪費了處理器的性能。
下一篇介紹一個比較靠譜的按鍵檢測方法。
