Arduino 入門學習筆記(五):KEY實驗
開發板:正點原子ESP32S3
例程源碼在文章頂部可免費下載(審核中…)
1. GPIO 輸入功能使用
1.1 GPIO 輸入模式介紹
在上一文章中提及到 pinMode 函數, 要對數字 I/O 進行檢測,首先把 I/O 設置為輸入模式, 然后使用數字 I/O 檢測函數為 digitalRead 函數檢測外部電平狀態。當外部輸入高電平時,返回值為 1;當外部輸入低電平時,返回值為 0。
pinMode 函數設置 I/O 為輸入,有三種選擇: INPUT、 INPUT_PULLUP、 INPUT_PULLDOWN。這里簡單設置的依據就跟這個按鍵電路相關。當我們存在上拉或者下拉按鍵電路的情況時,可以直接選擇 INPUT;如果當前的按鍵電路需要內部上拉電阻,這時候選擇 INPUT_PULLUP;如果當前的按鍵電路需要內部下拉電阻時,這時候選擇 INPUT_PULLDOWN。
在這里,簡單介紹一下上拉電阻電路、下拉電阻電路、內部上拉電路和內部下拉電路。
上拉電阻電路,如下圖所示:
當按鍵開關斷開時,即沒有被按下時, ESP32S3 的 IO0 通過電阻和 3.3V 電源相連接,產生高電平, digitalRead(0)函數的返回值為 1。當按鍵開關閉合時,即按下按鍵時, ESP32S3 的 IO0的電壓和地相連接,產生低電平, digitalRead(0)函數的返回值為 0。電路中的 1KΩ電阻成為上拉電阻。
下拉電阻電路,如下圖所示:
當按鍵開關斷開時,即沒有被按下時, ESP32S3 的 IO0 通過電阻和地相連接,產生低電平,digitalRead(0)函數的返回值為 0。當按鍵開關閉合時,即按下按鍵時, ESP32S3 的 IO0 的電壓和電源 3.3V 相連接,產生高電平, digitalRead(0)函數的返回值為 1。電路中的 1KΩ電阻成為下拉電阻。
當數字輸入引腳的工作模式設置為 INPUT 時,讀取按鍵值,一定要在電路中設置一個上拉電阻或者下拉電阻,電阻的阻值一般可以為 1~10KΩ 。采用上拉電阻時,當按鍵斷開時digitalRead(0)函數的返回值為 1。采用下拉電阻時,當按鍵斷開時, digitalRead(0)函數的返回值為 0。
內部上拉電阻電路, 除了上述的兩種電路外,在 ESP32S3 控制器內部還集成了上拉電阻,通過在 pinMode()函數中設置 mode 參數為 INPUT_PULLUP 來啟動內部上拉電阻。啟動控制器內部的上拉電阻后,按鍵開關電路就可以省略外接電阻。內部上拉電阻電路, 如下圖所示:
從上圖可以看出,當開關斷開時, digitalRead(0)函數的返回值為 1;當開關閉合時,digitalRead(0)函數的返回值為 0。當采用內部上拉電阻電路時,按鍵的一端和數字引腳相連,另外一端和地相連。
內部下拉電阻電路,在 ESP32S3 控制器內部除了集成上拉電阻,還有下拉電阻,通過在pinMode()函數中設置 mode 參數為 INPUT_PULLDOWN 來啟動內部下拉電阻。啟動控制器內部的下拉電阻后,按鍵開關電路就可以省略外接電阻。內部下拉電阻電路,如下圖所示:
從上圖可以看出,當開關斷開時, digitalRead(0)函數的返回值為 0;當開關閉合時,digitalRead(0)函數的返回值為 1。當采用內部下拉電阻電路時,按鍵的一端和數字引腳相連,另外一端和 VCC 相連。
1.2 獨立按鍵簡介
幾乎每個開發板都會板載有獨立按鍵,因為按鍵用處很多。常態下,獨立按鍵是斷開的,按下的時候才閉合。每個獨立按鍵會單獨占用一個 IO 口,通過 IO 口的高低電平判斷按鍵的狀態。但是按鍵在閉合和斷開的時候,都存在抖動現象,即按鍵在閉合時不會馬上就穩定的連接,斷開時也不會馬上斷開。這是機械觸點,無法避免。獨立按鍵抖動波形圖如下:
圖中的按下抖動和釋放抖動的時間一般為 5~10ms, 如果在抖動階段采樣, 其不穩定狀態可能出現一次按鍵動作被認為是多次按下的情況。為了避免抖動可能帶來的誤操作,我們要做的措施就是給按鍵消抖(即采樣穩定閉合階段)。消抖方法分為硬件消抖和軟件消抖,我們常用軟件的方法消抖。
軟件消抖:方法很多, 我們例程中使用最簡單的延時消抖。 檢測到按鍵按下后,一般進行10ms 延時,用于跳過抖動的時間段,如果消抖效果不好可以調整這個 10ms 延時,因為不同類型的按鍵抖動時間可能有偏差。待延時過后再檢測按鍵狀態,如果沒有按下,那我們就判斷這是抖動或者干擾造成的;如果還是按下,那么我們就認為這是按鍵真的按下了。對按鍵釋放的判斷同理。
硬件消抖:利用 RC 電路的電容充放電特性來對抖動產生的電壓毛刺進行平滑出來,從而實現消抖,但是成本會更高一點,本著能省則省的原則,我們推薦使用軟件消抖即可。
2. 硬件設計
2.1 例程功能
通過開發板上的 boot 獨立按鍵實現 LED 的亮滅。
2.2 硬件資源
1) LED 燈:LED-IO1
2)獨立按鍵:BOOT-IO0
2.3 原理圖
獨立按鍵硬件部分的原理圖,如下圖所示:
這里需要注意的是: BOOT 設計為采樣到按鍵另一端的低電平為有效電平。
3 軟件設計
3.1 程序流程圖
下面看看本實驗的程序流程圖:
3.2 程序解析
3.2.1 key 驅動代碼
這里我們只講解核心代碼,詳細的源碼請大家參考光盤本實驗對應源碼。 KEY 驅動源碼包括兩個文件: key.cpp 和 key.h。
下面我們先解析 key.h 的程序,我們把它分兩部分功能進行講解。
由硬件設計小節,我們知道 KEY 按鍵在硬件上連接到 IO0,我們做了下面的引腳定義。
/* 引腳定義 */
#define KEY_PIN 0 /* 開發板上 KEY 連接到 GPIO0 引腳 */
為了后續對 KEY 按鍵進行便捷的操作,我們為 KEY 按鍵操作函數做了下面的定義。
/* 宏函數定義 */
#define KEY digitalRead(KEY_PIN) /* 讀取 KEY 引腳的狀態 */
KEY 是讀取對應按鍵狀態的宏定義。用 digitalRead 函數實現,該函數返回值就是 IO 口的狀態, 0 或 1,代表的是低電平或高電平。
下面我們再解析 key.cpp 的程序,這里只有一個函數 key_init,這是 KEY 按鍵的初始化函數,其定義如下:
/**
* @brief 初始化 KEY 相關 IO 口
* @param 無
* @retval 無
*/
void key_init(void)
{
/* 結合原理圖設計,按鍵沒有按下時,KEY 引腳檢測到的是高電平 */
pinMode(KEY_PIN, INPUT_PULLUP); /* 設置 key 引腳為上拉輸入模式 */
}
KEY 按鍵的引腳設置為上拉輸入模式。 默認情況,讀取到的是高電平。
3.2.2 02_key.ino 代碼
在 02_key.ino 里面編寫如下代碼:
#include "led.h"
#include "key.h"
/**
* @brief 當程序開始執行時,將調用 setup()函數,通常用來初始化變量、函數等
* @param 無
* @retval 無
*/
void setup()
{
led_init(); /* LED 初始化 */
key_init(); /* KEY 初始化 */
}
/**
* @brief 循環函數,通常放程序的主體或者需要不斷刷新的語句
* @param 無
* @retval 無
*/
void loop()
{
if (KEY == 0) /* 讀取 KEY 狀態,如果按下 KEY */
{
delay(10);
if (KEY == 0)
{
LED(0); /* LED 引腳輸出接低電平,點亮 */
}
}
else /* 讀取 KEY 狀態,如果 KEY 沒有按下 */
{
LED(1); /* LED 引腳輸出接高電平,熄滅 */
}
}
在 setup 函數中, 除了要調用 key_init 函數對 KEY 進行初始化,還要調用 led_init 對 LED進行初始化。接下來,在 loop 函數中, 當按鍵被按下時, 會調用 delay 函數等待 10 毫秒實現消抖作用,然后再次確認按鍵狀態,如果按鍵確實被按下, 點亮 LED。 如果按鍵沒有被按下時,就會熄滅 LED。 然后程序進入檢測按鍵是否按下的循環中。
4. 下載驗證
下載完之后, 通過 BOOT 按鍵來控制 LED 燈的亮滅狀態。