一:什么是開關(guān)抖動(dòng)?
	當(dāng)我們按下按鈕或撥動(dòng)開關(guān)或微動(dòng)開關(guān)時(shí),兩個(gè)金屬部件會(huì)接觸以短路電源。但它們不會(huì)立即連接,而是金屬部件在實(shí)際穩(wěn)定連接之前連接和斷開幾次。
	釋放按鈕時(shí)也會(huì)發(fā)生同樣的事情。這會(huì)導(dǎo)致誤觸發(fā)或多次觸發(fā),例如多次按下按鈕。這就像一個(gè)彈跳的球從高處落下,它一直在表面彈跳,直到它靜止。
	
	
換句話說,我們可以說開關(guān)彈跳是任何開關(guān)的非理想行為,它會(huì)生成單個(gè)輸入的多個(gè)轉(zhuǎn)換。當(dāng)我們處理電源電路時(shí),開關(guān)彈跳不是主要問題,但當(dāng)我們處理邏輯或數(shù)字電路時(shí),它會(huì)引起問題。因此,為了消除電路中的抖動(dòng),使用了開關(guān)去抖動(dòng)電路。
二:電路及波形
首先,我們將演示沒有開關(guān)去抖動(dòng)的電路
	
	
您還可以在按下按鈕時(shí)在示波器中看到波形。它顯示在按鈕切換期間發(fā)生了多少?gòu)椞?/p>
三:硬件去抖動(dòng)
防止電路開關(guān)彈跳的常用方法有3種。
硬件去抖
RC 去抖
開關(guān)去抖IC
01
硬件電路去抖
在硬件去抖動(dòng)技術(shù)中,我們使用 S-R 觸發(fā)器來(lái)防止電路發(fā)生開關(guān)抖動(dòng)。這是所有方法中最好的去抖動(dòng)方法。
	
	
	
	該電路由兩個(gè)與非門(74HC00 IC)組成,形成一個(gè) SR 觸發(fā)器。正如您在電路圖中看到的,只要撥動(dòng)開關(guān)切換到 A 側(cè),輸出邏輯就會(huì)變?yōu)椤案摺?。在這里,我們使用示波器來(lái)檢測(cè)彈跳。而且,正如您在下面給出的波形中看到的那樣,邏輯正在以輕微的曲線移動(dòng)而不是彈跳。電路中使用的電阻是上拉電阻。 每當(dāng)開關(guān)在觸點(diǎn)之間移動(dòng)以產(chǎn)生反彈時(shí),觸發(fā)器都會(huì)保持輸出,因?yàn)椤?”是從與非門的輸出反饋的。 
	02
R-C 去抖
R-C 僅由其名稱定義,該電路使用 RC 網(wǎng)絡(luò)來(lái)防止開關(guān)彈跳。電路中的電容器濾除開關(guān)信號(hào)的瞬間變化。當(dāng)開關(guān)處于打開狀態(tài)時(shí),電容器兩端的電壓保持為零。最初,當(dāng)開關(guān)打開時(shí),電容器通過 R1 和 R2 電阻器充電。
	
	當(dāng)開關(guān)閉合時(shí),電容器開始放電至零,因此反相施密特觸發(fā)器輸入端的電壓為零,因此輸出變?yōu)楦唠娖健?
	在彈跳情況下,電容器停止 Vin 處的電壓,直到它達(dá)到 Vcc 或接地。 
	為了提高 RC 去抖動(dòng)的速度,我們可以連接一個(gè)二極管,如下圖所示。因此,它減少了電容器的充電時(shí)間。
	
03
開關(guān)去抖IC
	市場(chǎng)上有用于開關(guān)去抖動(dòng)的 IC。一些去抖 IC 是 MAX6816、MC14490 和 LS118。 
	下面是使用MAX6818進(jìn)行開關(guān)去抖的電路圖。
	
	
	所以在這里,我們學(xué)習(xí)了按鈕如何產(chǎn)生開關(guān)反彈效應(yīng),以及如何通過使用硬件的方式來(lái)防止按鍵抖動(dòng)。 
四:軟件消抖
	我們都知道,并且也是我們使用最多的場(chǎng)合是通過軟件實(shí)現(xiàn)按鍵消抖。
	最簡(jiǎn)單的方式是增加延遲以消除軟件去抖。添加延遲會(huì)強(qiáng)制控制器在特定時(shí)間段內(nèi)停止,但在程序中添加延遲并不是一個(gè)好的選擇,因?yàn)樗鼤?huì)暫停程序并增加處理時(shí)間。最好的方法是在代碼中使用中斷來(lái)進(jìn)行軟件彈跳。 
	01
軟件延時(shí)
sbit KEY = P1^3;
///按鍵讀取函數(shù)
uint8_t GetKey(void)
{
    if(KEY == 1)
    {
        DelayMs(20);        //延時(shí)消抖
        if(KEY == 1)
        {
            return 1;
        }
        else 
        {
            return 0;
        }
    }
    else 
    {
        return 0;
    }
}
上面是最簡(jiǎn)單的軟件延時(shí)方法,也可以通過多個(gè)按鍵組合增加相關(guān)軟件濾波的方式進(jìn)行按鍵判斷,其實(shí)原理相似。 但是這種純延時(shí)的實(shí)現(xiàn)方式太過暴力,在延時(shí)的時(shí)候一直占用cpu的資源,如果在延時(shí)的時(shí)候,有其他外部中斷或者搶占事件,系統(tǒng)完全沒有響應(yīng)的。
所以我們CPU需要一個(gè)獨(dú)立的定時(shí)裝置,來(lái)完成這個(gè)計(jì)時(shí)工作,而且需要在計(jì)時(shí)時(shí)間到達(dá)時(shí)再檢測(cè)一次按鍵的電平值。
02
中斷消抖
首先初始化管腳,打開管腳的外部中斷:
/*Configure GPIO pins : KEY_1_Pin KEY_2_Pin */ GPIO_InitStruct.Pin = KEY_1_Pin|KEY_2_Pin; GPIO_InitStruct.Mode = GPIO_MODE_IT_FALLING; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOC, &GPIO_InitStruct); /* EXTI interrupt init*/ HAL_NVIC_SetPriority(EXTI15_10_IRQn, 5, 0); HAL_NVIC_EnableIRQ(EXTI15_10_IRQn);初始化TIM1,打開其update中斷:
static void MX_TIM1_Init(void)
{
  htim1.Instance = TIM1;
  htim1.Init.Prescaler = 7200 - 1;                // 72000000 / 7200 = 10000 hz  0.01ms
  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.Period = 200 - 1;                    // 200 * 0.01 = 20ms
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim1.Init.RepetitionCounter = 0;
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  
  if (HAL_TIM_Base_Init(&htim1) != HAL_OK)
  {
    _Error_Handler(__FILE__, __LINE__);
}
void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* htim_base)
{ 
    if(htim_base->Instance==TIM1) 
    {
   /* Peripheral clock enable */                 
        __HAL_RCC_TIM1_CLK_ENABLE();    
  /* USER CODE BEGIN TIM1_MspInit 1 */
        HAL_NVIC_SetPriority(TIM1_UP_IRQn,1,3); 
        HAL_NVIC_EnableIRQ(TIM1_UP_IRQn); 
    }
}
在stm32f1xx_hal_it.c中去注冊(cè)中斷回調(diào)函數(shù)(關(guān)鍵的步驟,需要在按鍵中斷處理函數(shù)中打開定時(shí)器,開始計(jì)時(shí)):
void EXTI15_10_IRQHandler(void)            // 按鍵的中斷處理函數(shù)
{
 
  HAL_TIM_Base_Start_IT(&htim1);    //  開啟定時(shí)器1,開始計(jì)時(shí)
 
  printf("key down
");
 
  __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_11);
  __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_12);
}
定時(shí)器的中斷處理函數(shù):
void TIM1_UP_IRQHandler(void)
{
  
  HAL_TIM_IRQHandler(&htim1);   //這個(gè)是所有定時(shí)器處理回調(diào)的入口,在這個(gè)函數(shù)里對(duì)應(yīng)定時(shí)器多種中斷情況的中斷回調(diào),需要找到update的回調(diào)函數(shù)
  printf("TIM IRQ
");
 
}
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)        // 定時(shí)器update中斷處理回調(diào)函數(shù)
{
   /* USER CODE BEGIN Callback 0 */
 
   /* USER CODE END Callback 0 */
   if (htim->Instance == TIM2) {
     HAL_IncTick();
   }
   
   if (htim->Instance == TIM1) {            // 在這里選擇tim1 
 
     printf("TIM1 updata
");
 
    HAL_TIM_Base_Stop_IT(&htim1);       //    關(guān)閉tim1 及清除中斷
 
     if (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_11) )    //再次判斷管腳的電平
     {
      printf("KEY1 be pressed!!!
");
     }
    
    if (GPIO_PIN_RESET == HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_12) )//再次判斷管腳的電平
    {
      printf("KEY2 be pressed!!!
");
    }
   }
   /* USER CODE BEGIN Callback 1 */
 
   /* USER CODE END Callback 1 */
}
總結(jié)一下,實(shí)現(xiàn)用定時(shí)器中斷來(lái)完成按鍵延時(shí)去抖的關(guān)鍵步驟:
1. 初始化GPIO腳,初始化TIM ,算好時(shí)間,填入分頻值。
2. 打開GPIO中斷,在中斷處理函數(shù)中打開定時(shí)器,讓其計(jì)數(shù)。
3. 定時(shí)器溢出中斷函數(shù)中,再次判斷按鍵電平值。關(guān)閉定時(shí)器,清除pending。
審核編輯:劉清
- 
                                示波器
                                +關(guān)注
關(guān)注
113文章
6914瀏覽量
193947 - 
                                定時(shí)器中斷
                                +關(guān)注
關(guān)注
0文章
49瀏覽量
11670 - 
                                按鍵消抖
                                +關(guān)注
關(guān)注
2文章
28瀏覽量
10781 
原文標(biāo)題:按鍵消抖常用的軟硬件方法
文章出處:【微信號(hào):玩轉(zhuǎn)單片機(jī)與嵌入式,微信公眾號(hào):玩轉(zhuǎn)單片機(jī)與嵌入式】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
如何實(shí)現(xiàn)軟件與硬件的開關(guān)抖動(dòng)設(shè)計(jì)
幾種常用的開關(guān)電源保護(hù)電路
請(qǐng)問有滑動(dòng)開關(guān)去抖動(dòng)電路的VHDL代碼嗎?
經(jīng)常用到的去抖動(dòng)方法有哪些?
常用電子設(shè)備開關(guān)電源檢修方法
    
按鍵彈跳消除模塊的程序設(shè)計(jì)與應(yīng)用
    
開關(guān)和繼電器觸點(diǎn)彈跳知識(shí)簡(jiǎn)介
防止電路開關(guān)彈跳的常用方法
    
NIDEC(尼得科)撥動(dòng)開關(guān)ET115A12-Z數(shù)據(jù)手冊(cè)
NIDEC(尼得科)撥動(dòng)開關(guān)ET125A12-Z數(shù)據(jù)手冊(cè)
NIDEC(尼得科)撥動(dòng)開關(guān)ET215N12-Z數(shù)據(jù)手冊(cè)
NIDEC(尼得科)撥動(dòng)開關(guān)ET225N12-Z數(shù)據(jù)手冊(cè)
無(wú)彈跳開關(guān)電路原理圖講解
    
          
        
        
什么是開關(guān)抖動(dòng)?防止電路開關(guān)彈跳的常用方法
                
 
    
           
            
            
                
            
評(píng)論