RT-Thread零基礎快速入門第4講——按鍵輸入

一、前言

上一講我給大家講解了如何點亮一個LED燈,因爲是入門的第一篇,所以講的囉嗦了一點,從這一講開始,一些最基礎的東西我就不再說了,如果有不懂的同學可以翻一下我之前發的博客。
這一講我我主要按鍵輸入的原理和編程方法,以及幾種按鍵輸入的進階用法。

源碼鏈接

我發佈的所有關於RT-thread的教程源代碼都在下面這個鏈接裏面,隨着我教程的更新,新的代碼也會加入進去。
教程源碼下載鏈接:https://pan.baidu.com/s/1N2D8dM31deKIqNqaIQfPiA
提取碼:7nsx

二、編程講解

按鍵輸入的電路原理

下圖是我教程所用開發板的按鍵原理圖(我用的是正點原子STM32F4探索者)

在這裏插入圖片描述
從圖我們可以看出,KEY_UP按鍵一頭接到電源,一頭接到單片機IO口,當按鍵沒有按下時,IO口處於懸空的狀態,如果IO口設置爲輸入模式,會處於低電平狀態,按下之後,IO口接通電源,處於高電平的狀態。KEY0、KEY1和KEY2則相反。
所以,我們可以通過判斷IO口的電平即可判斷按鍵是否按下。

按鍵輸入的編程方法

第一步:把IO配置成輸入模式
通過rt_pin_mode()函數可以把按鍵對應的引腳設置爲輸入模式。這個函數在上一講也講過了,這裏不再多說了。
在這裏插入圖片描述
第二步:讀取引腳電平
通過rt_pin_read() 函數可以讀取引腳的電平。
在這裏插入圖片描述
如果引腳處於高電平,該函數返回1,如果是低電平,則返回0。
所以我們用一個if語句判斷rt_pin_read()函數返回值即可知道引腳電平,從而判斷按鍵是否按下,示例代碼如下:

#define KEY0_PIN    GET_PIN(E, 4)
if (rt_pin_read(KEY0_PIN) == 0)//按鍵按下時爲低電平
{
	 rt_pin_write(LED1_PIN, 0);//點亮LED1
}

三、項目實戰

按鍵的基本用法

根據上面的原理,我們寫一個完整的按鍵輸入的示例。
下面的示例代碼運行效果:當KEY0按下,LED0點亮,鬆開後LED0熄滅;當KEY1按下後LED1點亮2秒然後熄滅,當KEY_UP按下後,LED1點亮,再按一次,LED1熄滅。

#include <rtthread.h>
#include <rtdevice.h>
#include <board.h>

#define LED0_PIN    GET_PIN(F, 9)
#define LED1_PIN    GET_PIN(F, 10)
#define KEY0_PIN    GET_PIN(E, 4)
#define KEY1_PIN    GET_PIN(E, 3)
#define KEY2_PIN    GET_PIN(E, 2)
#define KEY_UP_PIN  GET_PIN(A, 0)

/* 按鍵輸入基本用法 */
int main(void)
{
    int i = 0;

    /* 把LED引腳設置爲輸出 */
    rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);

    /* 把KEY引腳設置爲輸入 */
    rt_pin_mode(KEY0_PIN, PIN_MODE_INPUT);
    rt_pin_mode(KEY1_PIN, PIN_MODE_INPUT);
    rt_pin_mode(KEY2_PIN, PIN_MODE_INPUT);
    rt_pin_mode(KEY_UP_PIN, PIN_MODE_INPUT);

    /* 先把兩個燈都關掉 */
    rt_pin_write(LED0_PIN, PIN_HIGH);
    rt_pin_write(LED1_PIN, PIN_HIGH);

    while (1)
    {
        /* 讀取KEY0引腳電平 */
        if (rt_pin_read(KEY0_PIN) == PIN_LOW)//按鍵按下時爲低電平
        {
            rt_thread_mdelay(30);//延時消抖
            if (rt_pin_read(KEY0_PIN) == PIN_LOW)
            {
                rt_pin_write(LED0_PIN, PIN_LOW);//點亮LED0
            }
        }
        else
        {
            rt_pin_write(LED0_PIN, PIN_HIGH);//熄滅LED0
        }
        
        /* 讀取KEY1引腳電平 */
        if (rt_pin_read(KEY1_PIN) == PIN_LOW)//按鍵按下時爲低電平
        {
            rt_thread_mdelay(30);//延時消抖
            if (rt_pin_read(KEY1_PIN) == PIN_LOW)
            {
                rt_pin_write(LED1_PIN, PIN_LOW);//點亮LED1
                rt_thread_mdelay(2000);
                rt_pin_write(LED1_PIN, PIN_HIGH);//熄滅LED1
            }
        }

        /* 讀取KEY_UP引腳電平 */
        if (rt_pin_read(KEY_UP_PIN) == PIN_HIGH)//按鍵按下時爲高電平
        {
            rt_thread_mdelay(100);//這裏延時時間長一點,太快的話,按鍵會多次觸發
            if (rt_pin_read(KEY_UP_PIN) == PIN_HIGH)
            {
                i = ~i;
                if(i)
                {
                    rt_pin_write(LED1_PIN, PIN_LOW);//點亮LED1
                }
                else
                {
                    rt_pin_write(LED1_PIN, PIN_HIGH);//熄滅LED1
                }
            }
        }
    }
}

四、進階學習

按鍵連按和不連按

連按的意思是一直按住按鍵不放時,按鍵對應的代碼會循環執行。而不連按則相反,即使按鍵一直按着,按鍵對應的那部分代碼也只會執行一次。
連按和不連按都有各自的用途,沒有優劣之分,比如,我們用的電子手錶或者電子鐘,如果支持連按的話,我們在設置時間的時候就可以按住讓時間一直加,如果不支持連按的話,我們就需要連續按很多次。而用按鍵開關燈的時候,如果按鍵支持連按,那我們按住的時候,燈就會一直閃,所以這個時候我們是不希望按鍵支持連按的。
下面的示例代碼運行效果:當KEY_UP一直按住時,LED1會一直閃爍,即KEY_UP支持連按。而KEY0和KEY1均不支持連按。

/* 按鍵支持連按和不支持連按 */
int main(void)
{
    int i = 0;
    int key_up = 1;

    /* 把LED引腳設置爲輸出 */
    rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);

    /* 把KEY引腳設置爲輸入 */
    rt_pin_mode(KEY0_PIN, PIN_MODE_INPUT);
    rt_pin_mode(KEY1_PIN, PIN_MODE_INPUT);
    rt_pin_mode(KEY2_PIN, PIN_MODE_INPUT);
    rt_pin_mode(KEY_UP_PIN, PIN_MODE_INPUT);

    /* 先把兩個燈都關掉 */
    rt_pin_write(LED0_PIN, PIN_HIGH);
    rt_pin_write(LED1_PIN, PIN_HIGH);

    while (1)
    {
        /* 讀取KEY_UP引腳電平 */
        if (rt_pin_read(KEY_UP_PIN) == PIN_HIGH)//按鍵按下時爲高電平
        {
            rt_thread_mdelay(100);//這裏延時時間長一點,太快的話,按一下會觸發幾次
            if (rt_pin_read(KEY_UP_PIN) == PIN_HIGH)
            {
                i = ~i;
                if(i)
                {
                    rt_pin_write(LED1_PIN, PIN_LOW);//點亮LED1
                }
                else
                {
                    rt_pin_write(LED1_PIN, PIN_HIGH);//熄滅LED1
                }
            }
        }

        /* 讀取KEY0引腳電平 */
        if (key_up && rt_pin_read(KEY0_PIN) == PIN_LOW)//按鍵按下時爲低電平
        {
            rt_thread_mdelay(30);//延時消抖
            key_up = 0;//如果按鍵沒有鬆開,key_up一直爲0,就不會再進入這裏了
            if (rt_pin_read(KEY0_PIN) == PIN_LOW)
            {
                i = ~i;
                if(i)
                {
                    rt_pin_write(LED1_PIN, PIN_LOW);//點亮LED1
                }
                else
                {
                    rt_pin_write(LED1_PIN, PIN_HIGH);//熄滅LED1
                }
            }
        }
        else if(rt_pin_read(KEY0_PIN) != PIN_LOW)//按鍵鬆開了
        {
            key_up = 1;
        }

        /* 讀取KEY1引腳電平 */
        if (rt_pin_read(KEY1_PIN) == PIN_LOW)//按鍵按下時爲低電平
        {
            rt_thread_mdelay(30);//延時消抖
            while (rt_pin_read(KEY1_PIN) == PIN_LOW)
            {
                //等待按鍵鬆開
            }
            i = ~i;
            if(i)
            {
                rt_pin_write(LED1_PIN, PIN_LOW);//點亮LED1
            }
            else
            {
                rt_pin_write(LED1_PIN, PIN_HIGH);//熄滅LED1
            }
            
        }
    }
}

按鍵短按和長按

下面的示例代碼運行效果:按鍵KEY0長按2秒之後,LED1點亮,鬆開後再長按2秒,LED1熄滅。按鍵KEY0按下不到2秒鬆開,LED0點亮,再按一次,LED0熄滅。

/* 按鍵同時支持長按和短按 */
int main(void)
{
    int i = 0, j = 0;
    int key_up = 1;
    rt_uint16_t t = 0;

    /* 把LED引腳設置爲輸出 */
    rt_pin_mode(LED0_PIN, PIN_MODE_OUTPUT);
    rt_pin_mode(LED1_PIN, PIN_MODE_OUTPUT);

    /* 把KEY引腳設置爲輸入 */
    rt_pin_mode(KEY0_PIN, PIN_MODE_INPUT);
    rt_pin_mode(KEY1_PIN, PIN_MODE_INPUT);
    rt_pin_mode(KEY2_PIN, PIN_MODE_INPUT);
    rt_pin_mode(KEY_UP_PIN, PIN_MODE_INPUT);

    /* 先把兩個燈都關掉 */
    rt_pin_write(LED0_PIN, PIN_HIGH);
    rt_pin_write(LED1_PIN, PIN_HIGH);

    while (1)
    {
        /* 讀取KEY0引腳電平 */
        if (rt_pin_read(KEY0_PIN) == PIN_LOW)//按鍵按下時爲低電平
        {
            rt_thread_mdelay(10);//延時消抖
            t++;
            if (t == 200)
            {//長按兩秒
                j = ~j;
                if(j)
                {
                    rt_pin_write(LED1_PIN, PIN_LOW);//點亮LED1
                }
                else
                {
                    rt_pin_write(LED1_PIN, PIN_HIGH);//熄滅LED1
                }
            }
        }
        else if(rt_pin_read(KEY0_PIN) != PIN_LOW)//按鍵鬆開
        {
            if(t >=3 && t<= 200)
            {//短按
                i = ~i;
                if(i)
                {
                    rt_pin_write(LED0_PIN, PIN_LOW);//點亮LED0
                }
                else
                {
                    rt_pin_write(LED0_PIN, PIN_HIGH);//熄滅LED0
                }    
            }
            t = 0;
        }
    }
}

五、結束語

好了,關於按鍵輸入的編程講解就到這裏,如果還有什麼問題可以私信給我。如果需要本文對應的源碼的話可以在博文前言部分的鏈接下載。
如果覺得這篇文章對你有用,可以賞個贊給博主。
後續我會繼續更新RT-thread入門教程系列,如果感興趣的同學可以關注一下博主,謝謝!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章