前言
? ? ? ? 本文以初學(xué)者角度切入,詳細(xì)剖析按鍵檢測(cè)原理,實(shí)現(xiàn)按鍵短按、短按抬起、首次長(zhǎng)按、持續(xù)長(zhǎng)按次數(shù)、長(zhǎng)按抬起功能;
目錄
前言
波形圖分析
抖動(dòng)原因
為什么要消抖
如何消抖
原理圖分析
程序設(shè)計(jì)思路
代碼實(shí)踐
按鍵配置
按鍵檢測(cè)
實(shí)驗(yàn)結(jié)果
留下反思
波形圖分析
? ? ? ? 如圖為按鍵按下→釋放過(guò)程的波形圖
可以從圖中看到,實(shí)際波形在按下與釋放時(shí)都有一段雜亂的波形,期間存在著多次高電平與低電平,這就是抖動(dòng)。
抖動(dòng)原因
????????機(jī)械原因:由于按鍵內(nèi)部構(gòu)造常為彈簧、金屬?gòu)椘冉佑|器件,當(dāng)按鍵按下或釋放時(shí),這些器件的反彈、震動(dòng)等原因?qū)е滤矔r(shí)的接觸和斷開(kāi),從而產(chǎn)生抖動(dòng);
????????電氣原因:電路噪聲、環(huán)境干擾、電容充放電等因素;
為什么要消抖
? ? ? ? 為了確保按鍵信號(hào)的穩(wěn)定性和可靠性。由于上述機(jī)械原因與電氣原因,軟件在讀取到一個(gè)有效電平時(shí),是無(wú)法百分百分辨出是真實(shí)的按鍵按下/釋放還是由于抖動(dòng)、干擾等造成的。如果不進(jìn)行消抖會(huì)導(dǎo)致在一次按鍵按下釋放過(guò)程中出現(xiàn)判斷為多次的按鍵短按與釋放,這是對(duì)系統(tǒng)功能有破壞性與不可靠性的。
如何消抖
? ? ? ? 硬件層面:添加合適電容消除機(jī)械原因(注意電容過(guò)大會(huì)影響按鍵響應(yīng)時(shí)間,過(guò)小則作用不佳)。添加上拉電阻抵抗電氣原因;
? ? ? ? 軟件層面:在一段時(shí)間內(nèi),對(duì)引腳電平進(jìn)行多次判斷,如果每次都滿足了觸發(fā)條件則認(rèn)為是有效的;
原理圖分析
圖一為最簡(jiǎn)單的按鍵原理圖
????????優(yōu)點(diǎn):簡(jiǎn)單,降低了成本和電路設(shè)計(jì)的復(fù)雜性;
????????缺點(diǎn):沒(méi)有硬件消抖,且抗干擾能力差;
圖二為加了上拉電阻的按鍵原理圖
????????優(yōu)點(diǎn):與圖一方式比較,提高了抗干擾能力;
????????缺點(diǎn):沒(méi)有硬件消抖;
圖三為加了上拉電阻與電容的按鍵原理圖
????????優(yōu)點(diǎn):與圖一二方式比較,有了抗干擾能力與硬件消抖;
????????缺點(diǎn):提高了成本和電路設(shè)計(jì)的復(fù)雜性;
程序設(shè)計(jì)思路
? ? ? ? 當(dāng)檢測(cè)電平有按鍵按下時(shí),等待一段時(shí)間(即抖動(dòng)時(shí)間)之后,再次檢測(cè)電平是否按下,如果仍然檢測(cè)為有按鍵按下則認(rèn)為有效。檢測(cè)釋放也同理,下圖為大致流程圖,省略了釋放的消抖以便閱讀。
代碼實(shí)踐
詳細(xì)代碼工程鏈接
按鍵配置
#include "stm32f10x.h"
#define KEY_GPIO_PORT GPIOA /* 按鍵引腳端口號(hào) */
#define KEY_GPIO_PIN GPIO_Pin_0 /* 按鍵引腳編號(hào) */
#define KEY_GPIO_CLK_ENABLE() RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE) /* GPIO時(shí)鐘使能 */
/*按鍵初始化*/
void Key_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*GPIO時(shí)鐘使能*/
KEY_GPIO_CLK_ENABLE();
/*GPIO配置*/
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; /* 上拉輸入 */
GPIO_InitStructure.GPIO_Pin = KEY_GPIO_PIN;
GPIO_Init(KEY_GPIO_PORT, &GPIO_InitStructure);
}
詳細(xì)代碼工程鏈接?
按鍵檢測(cè)
#include "stdio.h"
/* 按鍵檢測(cè) */
void KeyCheck(void)
{
unsigned char tempDownCount = 0; /* 按下計(jì)數(shù) */
unsigned char tempUpCount = 0; /* 釋放計(jì)數(shù) */
unsigned char tempLongFlag = 0; /* 長(zhǎng)按標(biāo)志 */
unsigned int tempContinueCount = 0; /* 持續(xù)長(zhǎng)按次數(shù) */
if(0 == GPIO_ReadInputDataBit(KEY_GPIO_PORT, KEY_GPIO_PIN)) /* 讀取按鍵電平有效 */
{
Delay_ms(20); /* 按下階段消抖(合理范圍10~50ms) */
if(0 == GPIO_ReadInputDataBit(KEY_GPIO_PORT, KEY_GPIO_PIN)) /* 再次讀取按鍵電平仍然有效 */
{
printf("按鍵按下\n");
//按鍵短按需要干嘛。。。
/*檢測(cè)長(zhǎng)按*/
while(1)
{
if(0 == GPIO_ReadInputDataBit(KEY_GPIO_PORT, KEY_GPIO_PIN))
{
tempUpCount = 0; /* 復(fù)位釋放計(jì)數(shù) */
if(++tempDownCount >= 10)
{
tempDownCount = 0; /* 復(fù)位按下計(jì)數(shù) */
if(0 == tempLongFlag)
{
tempLongFlag = 1;
tempContinueCount = 1;
printf("按鍵首次長(zhǎng)按\n");
//按鍵首次長(zhǎng)按需要干嘛。。。
}
else
{
++tempContinueCount;
printf("按鍵持續(xù)長(zhǎng)按次數(shù)【%d】\n", tempContinueCount);
//按鍵多次持續(xù)長(zhǎng)按需要干嘛。。。
}
}
}
/*檢測(cè)釋放*/
if(1 == GPIO_ReadInputDataBit(KEY_GPIO_PORT, KEY_GPIO_PIN))
{
if(++tempUpCount >= 2) /* 釋放階段消抖 */
{
if(0 == tempLongFlag)
{
printf("按鍵短按抬起\n\n");
//按鍵短按抬起需要干嘛。。。
}
else
{
printf("按鍵長(zhǎng)按抬起\n\n");
//按鍵長(zhǎng)按抬起需要干嘛。。。
}
return;
}
}
Delay_ms(20); /* 時(shí)間間隔 */
}
}
}
}
int main(void)
{
Delay_Init(); /* 滴答延時(shí)初始化 */
Usart1_Init(9600); /* 串口初始化 */
Key_Init(); /* 按鍵初始化 */
printf("按鍵檢測(cè)測(cè)試\n");
while(1)
{
KeyCheck(); /* 按鍵檢測(cè) */
}
}
詳細(xì)代碼工程鏈接
實(shí)驗(yàn)結(jié)果
短按測(cè)試
長(zhǎng)按測(cè)試
留下反思
? ? ? ? 細(xì)心的同學(xué)應(yīng)該能發(fā)現(xiàn),雖然按鍵檢測(cè)的功能是實(shí)現(xiàn)了,但是當(dāng)后續(xù)其他功能的加入時(shí),如果按鍵一直按住不松是不是就一直在KeyCheck()里的while(1)里不出來(lái)了?這時(shí)其他功能是不是就跑不了了?那么該怎么辦呢?
????????敬請(qǐng)關(guān)注“我的按鍵驅(qū)動(dòng)編年史”專欄,里面有你想要的答案。
????????分享先到這里,希望能給大家?guī)?lái)啟發(fā)與幫助。如果對(duì)內(nèi)容存在疑問(wèn)或想法,歡迎在評(píng)論區(qū)留言,我會(huì)積極回復(fù)大家的問(wèn)題。在我的“我的按鍵驅(qū)動(dòng)編年史”專欄中,還有一些關(guān)于按鍵驅(qū)動(dòng)不同寫法的教程,歡迎一起探討、一起學(xué)習(xí)。
????????終版驅(qū)動(dòng)gitee倉(cāng)庫(kù):文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-794471.html
XxxSwitchScan_Driver: XxxSwitchScan_Driver可以簡(jiǎn)單的看作為一個(gè)C語(yǔ)言的按鍵驅(qū)動(dòng),使用簡(jiǎn)單、靈活且解耦,以面向?qū)ο笏枷虢Y(jié)合狀態(tài)機(jī)編寫,同時(shí)適用于裸機(jī)與操作系統(tǒng)。最終實(shí)現(xiàn)響應(yīng)事件有:短按/短按抬起/長(zhǎng)按/持續(xù)長(zhǎng)按/長(zhǎng)按抬起/連擊/單邊沿觸發(fā)。一開(kāi)始僅為了實(shí)現(xiàn)按鍵驅(qū)動(dòng)。后面把按鍵結(jié)合如高低電平的傳感器、開(kāi)關(guān)量的限位等進(jìn)一步抽象為開(kāi)關(guān)量的輸入設(shè)備。由此我常會(huì)把項(xiàng)目中的開(kāi)關(guān)量的輸入設(shè)備通過(guò)該驅(qū)動(dòng)統(tǒng)一管理。https://gitee.com/wx_372d4eb42f/xxx-switch-scan_-driver文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-794471.html
到了這里,關(guān)于初學(xué)者思路-實(shí)現(xiàn)獨(dú)立按鍵檢測(cè)(以STM32為例)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!