<acronym id="s8ci2"><small id="s8ci2"></small></acronym>
<rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
<acronym id="s8ci2"></acronym>
<acronym id="s8ci2"><center id="s8ci2"></center></acronym>
0
  • 聊天消息
  • 系統消息
  • 評論與回復
登錄后你可以
  • 下載海量資料
  • 學習在線課程
  • 觀看技術視頻
  • 寫文章/發帖/加入社區
會員中心
創作中心

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

3天內不再提示

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

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

一、按鍵檢測原理

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

二、硬件連接

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

圖片

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

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

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

三、程序設計

按鍵檢測主要有以下步驟

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

3.1 初始化GPIO

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

圖片

按鍵對應GPIO

根據上一節了解的初始化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會變為高電平。

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

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

這里按鍵的松手檢測也比較簡單粗暴,用一個while死循環等待松手。比如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亮滅狀態(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();   // 系統初始化
    
    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的亮滅狀態。

五、拓展

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

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

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

int main(void)
{
    Med_Mcu_Iint();   // 系統初始化
    
    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 按鍵長短按

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

這里給出一個例程,KEY1短按功能為熄滅LED1,長按功能為LED1和LED2交替閃爍兩輪后熄滅。按下持續時間在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
        }
聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容侵權或者其他違規問題,請聯系本站處理。 舉報投訴
  • STM32
    +關注

    關注

    2245

    文章

    10688

    瀏覽量

    349658
  • GPIO
    +關注

    關注

    16

    文章

    1149

    瀏覽量

    50738
  • LED控制器
    +關注

    關注

    0

    文章

    62

    瀏覽量

    20442
  • 按鍵電路
    +關注

    關注

    1

    文章

    35

    瀏覽量

    21644
  • 按鍵控制
    +關注

    關注

    0

    文章

    44

    瀏覽量

    8731
收藏 人收藏

    評論

    相關推薦

    STM32學習筆記-按鍵設計

    = ReadData & (ReadData ^ Cont); // 2 Cont = ReadData;// 3if(Trg)//按鍵一次則清除定時器計數值,{ ClickTimes++; Time
    發表于 10-07 15:49

    STM32速成

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

    求助STM32的GPIO做電容觸摸按鍵檢測會有問題嗎

    求助STM32的GPIO做電容觸摸按鍵檢測的一些問題:我的應用需要在顯示面板外接觸摸按鍵板,顯示板主控MCU是STM32F429,顯示板與
    發表于 02-17 16:22

    如何使用GPIO進行按鍵檢測

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

    STM32按鍵控制小車代碼

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

    STM32各模塊學習筆記

    STM32個模塊學習筆記 目錄 STM32筆記之一 中斷優先級.....................................................1
    發表于 11-30 03:32 ?3029次閱讀

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

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

    如何進行按鍵檢測按鍵FIFO的實現

    吧! 一、如何進行按鍵檢測 檢測按鍵有中斷方式和GPIO查詢方式兩種。推薦大家用GPIO查詢方式。 1.從裸機的角度分析 中斷方式 :中斷方式可以快速地
    的頭像 發表于 11-03 09:13 ?4522次閱讀

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

    第一次以寫博客的方式記錄自己在嵌入式學習過程中的學習經歷和踩的那些坑~Day1 那么開始叭!STM32G4系列MCU學習筆記按鍵模塊前言一、硬件操作1. 原理圖2. 硬件分析3. 初始化代碼
    發表于 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進行按鍵檢測寫在前面由于我們使用的是官方的開發板,所以在用STM32Cu
    發表于 12-20 18:59 ?8次下載
    <b class='flag-5'>STM32</b>F429I-Discovery學習<b class='flag-5'>筆記</b>--(3)使用GPIO進行<b class='flag-5'>按鍵</b><b class='flag-5'>檢測</b>

    STM32筆記按鍵KEY輸入

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

    STM32按鍵實驗學習筆記

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

    STM32G0開發筆記:GPIO接按鍵的使用方式

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

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

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

    STM32怎么實現按鍵開關機

    STM32按鍵開關機需要以下步驟: 1. 硬件連接。 2. 配置GPIO引腳。 3. 編程實現按鍵檢測。 4. 編程實現開關機控制功能。 詳細步驟將在下文中詳細介紹。 第一步:硬件連接
    的頭像 發表于 12-07 15:17 ?1982次閱讀
    亚洲欧美日韩精品久久_久久精品AⅤ无码中文_日本中文字幕有码在线播放_亚洲视频高清不卡在线观看
    <acronym id="s8ci2"><small id="s8ci2"></small></acronym>
    <rt id="s8ci2"></rt><rt id="s8ci2"><optgroup id="s8ci2"></optgroup></rt>
    <acronym id="s8ci2"></acronym>
    <acronym id="s8ci2"><center id="s8ci2"></center></acronym>