0
  • 聊天消息
  • 系統(tǒng)消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會員中心
創(chuàng)作中心

完善資料讓更多小伙伴認識你,還能領取20積分哦,立即完善>

3天內不再提示

STM32速成筆記(3)—按鍵檢測

冬至子 ? 來源:二土電子 ? 作者:二土電子 ? 2023-10-23 17:31 ? 次閱讀

一、按鍵檢測原理

按鍵檢測原理比較簡單,按鍵按下和不按下,其連接引腳的電平是不一樣的,按鍵檢測正是通過檢測按鍵引腳的電平變化來實現的。比如按鍵未按下時引腳電平為高電平,按鍵按下后為低電平。我們在檢測按鍵時只需要檢測按鍵引腳是否變?yōu)榈碗娖絹泶_定按鍵是否按下。

二、硬件連接

按鍵的硬件連接決定了我們在配置按鍵IO時IO的狀態(tài)。以我們使用的普中核心板為例,上面有三個按鍵

圖片

普中核心板按鍵硬件電路圖

其中K1一端接VCC,另一端接單片機。K2和K3一端接地,另一端接單片機。硬件電路不同,導致他們在進行按鍵檢測時IO的配置不同。

針對K1這種按鍵電路,按鍵按下時,單片機的引腳接到VCC,因此在未按下的情況下該引腳的默認電平為低電平,也就是要把IO設置為輸入下拉模式。同理,對于K2和K3這種連接方式,對應IO應該配置為輸入上拉模式,使得按鍵未被按下時,引腳處于高電平狀態(tài)。

三、程序設計

按鍵檢測主要有以下步驟

  • ? 初始化GPIO
  • ? 檢測按下按鍵
  • ? 消抖(防誤觸,一般通過延時實現)
  • ? 松手檢測
  • ? 執(zhí)行按鍵功能

3.1 初始化GPIO

根據原理圖,譜中的STM32核心板提供了三個按鍵,我們使用K1和K2來實現點亮和關閉LED的操作。K1對應的IO為PA0,K2對應的IO為PE4。

圖片

按鍵對應GPIO

根據上一節(jié)了解的初始化GPIO程序,初始化按鍵GPIO。

/*
 *==============================================================================
 *函數名稱:Drv_KeyGpio_Init 
 *函數功能:初始化KEY的GPIO
 *輸入參數:無
 *返回值:無
 *備  注:根據硬件電路確定GPIO模式
 *==============================================================================
 */
void Drv_KeyGpio_Init (void)
{
    GPIO_InitTypeDef GPIO_InitStructure;   // 定義結構體
    // 開啟時鐘
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOE,ENABLE);

    // 配置結構體 WK UP
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;   // 輸入下拉
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 配置結構體 KEY0,KEY1
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;   // 輸入上拉
    GPIO_Init(GPIOE, &GPIO_InitStructure);
}

3.2 按鍵掃描函數

按鍵掃描函數的功能是檢測是否有按鍵按下,按下的按鍵是哪一個。檢測方法上面已經敘述,通過檢測按鍵引腳的電平。以WK UP按鍵為例。當WK UP被按下時,其對應的引腳PA0會變?yōu)楦唠娖健?/p>

此時檢測PA0的輸入電平,如果確實是低電平,則說明WK UP可能被按下。說可能是因為PA0為低電平不一定是WK UP按下造成,也可能是抖動,所以這里就需要消抖操作。這里的消抖操作比較簡單粗暴,直接延時10ms看該引腳是否依舊是低電平。如果延時10ms后依舊是高電平,則認為確實是由按鍵按下導致的電平變化,而不是機械抖動。

確定檢測到按鍵按下后,需要等待按鍵被松開在執(zhí)行按鍵功能。為什么需要進行松手檢測?舉個例子,比如設置閾值時,按鍵按下閾值加1,如果不進行松手檢測,那么按下一次按鍵會加很多次,因為在不停地執(zhí)行按鍵功能。

這里按鍵的松手檢測也比較簡單粗暴,用一個while死循環(huán)等待松手。比如WK UP被按下后,其引腳會一直保持高電平,也就是PAin(0)一直等于1,此時用一個while (PAin(1));來等待松手,做松手檢測。

四、按鍵控制LED

這里做一個小練習,用普中核心板上的按鍵KEY0和KEY1來控制LED1的亮滅。步驟如下

  • ? 初始化LED和KEY的GPIO
  • ? 編寫LED控制函數
  • ? 編寫按鍵檢測函數(檢測按鍵)
  • ? 編寫按鍵服務函數(實現按鍵功能)

4.1 初始化LED和KEY的GPIO

/*
 *==============================================================================
 *函數名稱:Drv_LedGpio_Init
 *函數功能:初始化LED的GPIO
 *輸入參數:無
 *返回值:無
 *備  注:無
 *==============================================================================
 */
void Drv_LedGpio_Init (void)
{
    GPIO_InitTypeDef GPIO_InitStructure;   // 定義結構體
    // 開啟時鐘
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_GPIOE,ENABLE);

    // 配置結構體 LED0
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   // 推挽式輸出
    GPIO_Init(GPIOB, &GPIO_InitStructure);
    GPIO_SetBits(GPIOB,GPIO_Pin_5);   // 熄滅LED
    
    // 配置結構體 LED1
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   // 推挽式輸出
    GPIO_Init(GPIOE, &GPIO_InitStructure);
    GPIO_SetBits(GPIOE,GPIO_Pin_5);   // 熄滅LED
}
/*
 *==============================================================================
 *函數名稱:Drv_KeyGpio_Init 
 *函數功能:初始化KEY的GPIO
 *輸入參數:無
 *返回值:無
 *備  注:根據硬件電路確定GPIO模式
 *==============================================================================
 */
void Drv_KeyGpio_Init (void)
{
    GPIO_InitTypeDef GPIO_InitStructure;   // 定義結構體
    // 開啟時鐘
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOE,ENABLE);

    // 配置結構體 WK UP
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;   // 輸入下拉
    GPIO_Init(GPIOA, &GPIO_InitStructure);
    
    // 配置結構體 KEY0,KEY1
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3 | GPIO_Pin_4;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;   // 輸入上拉
    GPIO_Init(GPIOE, &GPIO_InitStructure);
}

4.2 編寫按鍵掃描函數

```c
/*
 *==============================================================================
 *函數名稱:Med_KeyScan
 *函數功能:檢測按下按鍵
 *輸入參數:無
 *返回值:按鍵鍵值 0:按鍵WK UP,1:KEY0,2:KEY1
 *備  注:無
 *==============================================================================
 */
u8 Med_KeyScan (void)
{
    // 按鍵WK UP
    if (KEY_UP == 1)
    {
        delay_ms (10);   // 延時10ms消抖
        if (KEY_UP == 1)
        {
            while (KEY_UP);   // 松手檢測
            return 1;
        }
    }
    
    // 按鍵KEY0
    else if (KEY0 == 0)
    {
        delay_ms (10);   // 延時10ms消抖
        if (KEY0 == 0)
        {
            while (!KEY0);   // 松手檢測
            return 2;
        }
    }
    
    // 按鍵KEY1
    else if (KEY1 == 0)
    {
        delay_ms (10);   // 延時10ms消抖
        if (KEY1 == 0)
        {
            while (!KEY1);   // 松手檢測
            return 3;
        }
    }
    
    // 沒有按鍵按下
    return 0xff;   // 用0xff表示沒有按鍵按下
}

4.2 編寫LED控制函數

/*
 *==============================================================================
 *函數名稱:Med_Led_StateCtrl
 *函數功能:控制LED亮滅
 *輸入參數:
           LEDx:可選擇的LED(0~1)
                     State:LED亮滅狀態(tài)(LED_ON,LED_OFF)
 *返回值:無
 *備  注:無
 *==============================================================================
 */
void Med_Led_StateCtrl (LED_TypeDef LEDx,u8 State)
{
    switch (LEDx)
    {
        case 0:
            PBout(5) = State;
        break;
        
        case 1:
            PEout(5) = State;
        break;
        
        default:
            break;
    }
}

下面是.h文件中的一些結構體和宏定義。

// 可選擇的LED
typedef enum
{
    LED1 = 0,
    LED2
}LED_TypeDef;

// 亮滅電平需要根據硬件電路確定
#define LED_ON   0
#define LED_OFF  1

4.3 編寫按鍵服務函數

這里沒有再單獨編寫按鍵服務函數,直接在main函數中編寫。KETY0按下點亮LED1,KEY1按下,熄滅LED1。

u8 gKeyValue = 0;   // 記錄按鍵鍵值變量

int main(void)
{
    Med_Mcu_Iint();   // 系統(tǒng)初始化
    
    while(1)
  {
        gKeyValue = Med_KeyScan();   // 獲取按鍵鍵值
        
        // 按鍵KEY0按下
        if (gKeyValue == 2)
        {
            Med_Led_StateCtrl(LED1,LED_ON);   // 點亮LED1
        }
        
        // 按鍵KEY1按下
        if (gKeyValue == 3)
        {
            Med_Led_StateCtrl(LED1,LED_OFF);   // 熄滅LED1
        }
    }
}

至此,實現了利用KEY0和KEY1控制LED的亮滅狀態(tài)。

五、拓展

5.1 一個按鍵單獨控制一個LED亮滅

單片機的IO資源是比較珍貴的,在實際用用時很少會用兩個IO資源來控制一個外設的開關,這里介紹一下方法并給出例程。比如使用普中核心板上的WK UP按鍵來控制LED2的亮滅狀態(tài)?;舅悸肥窃谏厦鎸W會按鍵檢測的基礎上,增加一個按鍵按下計次變量。按鍵按下一次,該變量加1。如果檢測到變量為1,那么點亮LED,如果檢測到變量為2,那么熄滅LED,同時將計數變量清零。程序設計如下

u8 gKeyValue = 0;   // 記錄按鍵鍵值變量
u8 gKeyWkUpCunt = 0;   // WK UP按下次數計數變量

int main(void)
{
    Med_Mcu_Iint();   // 系統(tǒng)初始化
    
    while(1)
  {
        gKeyValue = Med_KeyScan();   // 獲取按鍵鍵值
        
        // 按鍵WK UP按下
        if (gKeyValue == 1)
        {
            gKeyWkUpCunt = gKeyWkUpCunt + 1;   // 按鍵按下次數計數變量加1
            
            // 第一次被按下
            if (gKeyWkUpCunt <= 1)
            {
                Med_Led_StateCtrl(LED2,LED_ON);   // 點亮LED2
            }
            // 不是第一次被按下
            else if (gKeyWkUpCunt > 1)
            {
                gKeyWkUpCunt = 0;   // 清空計數變量
                Med_Led_StateCtrl(LED2,LED_OFF);   // 熄滅LED2
            }
        }
    }
}

5.2 按鍵長短按

除了上面介紹的一些常規(guī)操作外,有時還會用到一個按鍵分長按和短按。這里給出一種簡單粗暴的實現思路。需要檢測按鍵長短按時,修改一下松手檢測的邏輯。延時10ms后如果按鍵IO依舊保持按下狀態(tài),那么確定不是機械抖動,此時在之前的松手檢測while中進行粗略地計時。定義一個計數變量,每隔10ms加1。直到按鍵被松開。根據計數變量的值來判斷按鍵被按下的時間,從而來區(qū)別長短按。

這里給出一個例程,KEY1短按功能為熄滅LED1,長按功能為LED1和LED2交替閃爍兩輪后熄滅。按下持續(xù)時間在1s內,認為是短按,按下超過2s認為是長按。短按返回3,長按返回4。程序設計如下

u8 gKeyValue = 0;   // 記錄按鍵鍵值變量
u16 gKey1TimeCunt = 0;   // 按鍵KEY1的計時變量
/*
 *==============================================================================
 *函數名稱:Med_KeyScan
 *函數功能:檢測按下按鍵
 *輸入參數:無
 *返回值:按鍵鍵值 0:按鍵WK UP,1:KEY0,2:KEY1
 *備  注:無
 *==============================================================================
 */
u8 Med_KeyScan (void)
{
    // 按鍵WK UP
    if (KEY_UP == 1)
    {
        delay_ms (10);   // 延時10ms消抖
        if (KEY_UP == 1)
        {
            while (KEY_UP);   // 松手檢測
            return 1;
        }
    }
    
    // 按鍵KEY0
    else if (KEY0 == 0)
    {
        delay_ms (10);   // 延時10ms消抖
        if (KEY0 == 0)
        {
            while (!KEY0);   // 松手檢測
            return 2;
        }
    }
    
    // 按鍵KEY1
    // 按下1s內認為是短按,返回3
    // 按下超過2s認為是長按,返回4
    else if (KEY1 == 0)
    {
        delay_ms (10);   // 延時10ms消抖
        if (KEY1 == 0)
        {
            // 等待松手
            while (!KEY1)
            {
                delay_ms (10);
                gKey1TimeCunt = gKey1TimeCunt + 1;   // 計時變量加1
            }
        }
        
        // 判斷長短按
        if (gKey1TimeCunt <= 99)   // 小于等于1s
        {
            gKey1TimeCunt = 0;   // 清零計時變量
            return 3;   // 短按
        }
        else if (gKey1TimeCunt >= 199)   // 大于1s,等于2s
        {
            gKey1TimeCunt = 0;   // 清零計時變量
            return 4;   // 長按
        }
    }
    
    // 沒有按鍵按下
    return 0xff;   // 用0xff表示沒有按鍵按下
}

main函數中添加下述程序

// 長按KEY1
        if (gKeyValue == 4)
        {
            Med_Led_StateCtrl(LED1,LED_ON);   // 點亮LED1
            delay_ms (500);
            Med_Led_StateCtrl(LED1,LED_OFF);   // 熄滅LED1
            Med_Led_StateCtrl(LED2,LED_ON);   // 點亮LED2
            delay_ms (500);
            Med_Led_StateCtrl(LED2,LED_OFF);   // 熄滅LED2
            Med_Led_StateCtrl(LED1,LED_ON);   // 點亮LED1
            delay_ms (500);
            Med_Led_StateCtrl(LED1,LED_OFF);   // 熄滅LED1
            Med_Led_StateCtrl(LED2,LED_ON);   // 點亮LED2
            delay_ms (500);
            Med_Led_StateCtrl(LED1,LED_OFF);   // 熄滅LED1
            Med_Led_StateCtrl(LED2,LED_OFF);   // 熄滅LED1
        }
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發(fā)燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規(guī)問題,請聯(lián)系本站處理。 舉報投訴
  • STM32
    +關注

    關注

    2270

    文章

    10900

    瀏覽量

    355982
  • GPIO
    +關注

    關注

    16

    文章

    1204

    瀏覽量

    52091
  • LED控制器
    +關注

    關注

    0

    文章

    67

    瀏覽量

    20639
  • 按鍵電路
    +關注

    關注

    1

    文章

    35

    瀏覽量

    21774
  • 按鍵控制
    +關注

    關注

    1

    文章

    44

    瀏覽量

    8778
收藏 人收藏

    評論

    相關推薦

    STM32速成

    喲管STM32速成貼?求助
    發(fā)表于 01-23 14:34

    如何使用GPIO進行按鍵檢測

    STM32F429I-Discovery學習筆記–(3)使用GPIO進行按鍵檢測寫在前面由于我們使用的是官方的開發(fā)板,所以在用
    發(fā)表于 02-16 06:06

    STM32按鍵控制小車代碼

    好用的stm32小車代碼,STM32按鍵控制小車代碼,STM32按鍵控制小車代碼,STM32
    發(fā)表于 06-08 16:28 ?49次下載

    STM32各模塊學習筆記

    中斷......................................................3 STM32筆記之三 時鐘系統(tǒng)
    發(fā)表于 11-30 03:32 ?3160次閱讀

    STM32單片機的按鍵檢測程序設計

    STM32按鍵檢測相對比較簡單,首先按部就班的初始化連接的到的i/o,然后寫一個按鍵掃描函數,這個和51單片機的差不多。
    發(fā)表于 10-13 16:28 ?1.2w次閱讀
    <b class='flag-5'>STM32</b>單片機的<b class='flag-5'>按鍵</b><b class='flag-5'>檢測</b>程序設計

    STM32 獨立按鍵掃描功能大全-支持連擊、組合連擊、任意連擊

    STM32 獨立按鍵掃描功能大全-支持連擊、組合連擊、任意連擊本人剛學習STM32開發(fā),最近看了硬漢的按鍵檢測程序,進行了架構的深度優(yōu)化,所
    發(fā)表于 12-04 20:36 ?58次下載
    <b class='flag-5'>STM32</b> 獨立<b class='flag-5'>按鍵</b>掃描功能大全-支持連擊、組合連擊、任意連擊

    STM32G4系列MCU學習筆記按鍵模塊

    第一次以寫博客的方式記錄自己在嵌入式學習過程中的學習經歷和踩的那些坑~Day1 那么開始叭!STM32G4系列MCU學習筆記按鍵模塊前言一、硬件操作1. 原理圖2. 硬件分析3. 初
    發(fā)表于 12-05 20:51 ?10次下載
    <b class='flag-5'>STM32</b>G4系列MCU學習<b class='flag-5'>筆記</b>:<b class='flag-5'>按鍵</b>模塊

    STM32F429I-Discovery學習筆記--(3)使用GPIO進行按鍵檢測

    STM32F429I-Discovery學習筆記–(3)使用GPIO進行按鍵檢測寫在前面由于我們使用的是官方的開發(fā)板,所以在用
    發(fā)表于 12-20 18:59 ?8次下載
    <b class='flag-5'>STM32</b>F429I-Discovery學習<b class='flag-5'>筆記</b>--(<b class='flag-5'>3</b>)使用GPIO進行<b class='flag-5'>按鍵</b><b class='flag-5'>檢測</b>

    STM32筆記按鍵KEY輸入

    關于STM32學習分享第二章 按鍵輸入控制文章目錄前言二、代碼1.key.c2.key.h3.main.c總結前言開始!開始!單片機的按鍵配置為輸入模式獲取控制信號。# 一、
    發(fā)表于 12-31 19:49 ?7次下載
    <b class='flag-5'>STM32</b><b class='flag-5'>筆記</b>之<b class='flag-5'>按鍵</b>KEY輸入

    STM32按鍵實驗學習筆記

    讀取按鍵輸入引腳的信號,然后識別高低電平來判斷是否有按鍵觸發(fā)。為什么去抖動?按鍵的輸入引腳有低電平產生不代表一定是有按鍵按下,也許是干擾信號 , 因此,需要通過去抖動處理,將這些干擾信
    發(fā)表于 01-18 08:26 ?1次下載
    <b class='flag-5'>STM32</b><b class='flag-5'>按鍵</b>實驗學習<b class='flag-5'>筆記</b>

    STM32學習筆記按鍵實驗

    個人學習筆記按鍵實驗一.所使用的函數1.時鐘使能函數RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState
    發(fā)表于 01-18 08:52 ?1次下載
    <b class='flag-5'>STM32</b>學習<b class='flag-5'>筆記</b>:<b class='flag-5'>按鍵</b>實驗

    AN5597_STM32WB3或5xxx和STM32WB1xxx應用筆記

    AN5597_STM32WB3或5xxx和STM32WB1xxx應用筆記
    發(fā)表于 11-21 08:11 ?0次下載
    AN5597_<b class='flag-5'>STM32WB3</b>或5xxx和<b class='flag-5'>STM32</b>WB1xxx應用<b class='flag-5'>筆記</b>

    STM32G0開發(fā)筆記:GPIO接按鍵的使用方式

    使用Platformio平臺的libopencm3開發(fā)框架來開發(fā)STM32G0,下面為GPIO接按鍵的使用方式。
    的頭像 發(fā)表于 01-17 10:48 ?1782次閱讀

    【應用筆記】觸摸按鍵設計要點

    【應用筆記】觸摸按鍵設計要點
    的頭像 發(fā)表于 10-19 17:58 ?2199次閱讀
    【應用<b class='flag-5'>筆記</b>】觸摸<b class='flag-5'>按鍵</b>設計要點

    STM32怎么實現按鍵開關機

    STM32按鍵開關機需要以下步驟: 1. 硬件連接。 2. 配置GPIO引腳。 3. 編程實現按鍵檢測。 4. 編程實現開關機控制功能。 詳
    的頭像 發(fā)表于 12-07 15:17 ?2993次閱讀