當按下一個按鍵時,系統是如何檢測到的呢?
我們通過LED燈的亮滅狀態來間接完成按鍵檢測。當按下按鍵時,LED燈亮,再次按下時,LED燈滅。
要完成這個實驗,我們就會用到GPIO外設的基本輸入功能。
查閱開發板的按鍵原理圖,如圖3-1。

圖3-1
圖中的K1、K2即為按鍵。以K1為例,當未按下按鍵時,其PA0引腳處於接地狀態,即低電平,按下按鍵時,引腳接到電源,輸入狀態為高電平。所以只要我們檢測按鍵對應引腳(這里是PA0)的輸入電平狀態,即可判斷按鍵是否被按下。這便是按鍵的檢測原理了。
有一點需要知道,由於機械按鍵的彈性作用,按下按鍵時並不會馬上穩定接通或斷開,即存在按鍵抖動。一般情況下我們需要通過軟件或硬件的方式消抖才能得到理想的實驗效果。軟件消抖如通過定時器延時等方式,忽略前后的抖動;而硬件消抖,如可以利用電容的充放電延時等方式。本文默認已經進行過消抖處理了。
直接開始編程環節的分析。
首先得使能GPIO端口的時鍾,然后初始化按鍵和LED燈的引腳,最后通過讀取引腳不同電平狀態控制LED燈的狀態切換。這便是這個實驗的大致步驟了。
使能GPIO端口時鍾
所有的GPIO外設都掛載在APB2總線上,所以其使能寄存器為RCC_APB2ENR,查閱固件庫手冊可得其固件函數為RCC_APB2PeriphClockCmd(該固件函數功能即為對RCC_APB2ENR寄存器操作的封裝)。我們需要使能的是GPIOA時鍾,所以可調用如下API實現使能時鍾:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
初始化按鍵和LED燈
在使能GPIOA時鍾后,便開始初始化按鍵和LED燈了。我們需要用到GPIO_Init固件函數(該函數實現對配置引腳模式的封裝),將引腳配置為浮空輸入模式。這一步我們可以寫一個函數將其封裝起來。如下代碼:
/** * @brief 初始化按鍵 * @param 無 * @retval 無 */ void Key_GPIO_Config(void){ GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; // 選擇按鍵引腳PA0 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; // 設置引腳模式為浮空輸入 GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化按鍵 }
注:IO口為輸入模式時,不用設置輸出速率。
同樣的,由於我們需要通過LED燈來間接完成按鍵檢測(這里我們使用的是RGB燈,使用G色的引腳PB0),所以以上步驟也需要對LED燈的PB0引腳重復一遍,其流程與按鍵初始化流程類似,這里就不再贅述了,讀者可參考按鍵流程完成。
檢測按鍵狀態
接下來就需要通過檢測按鍵引腳的電平狀態來判斷按鍵是否按下了。那么我們怎么獲取引腳的電平狀態呢,查閱參考手冊可知,我們可以通過讀取IDR寄存器的值來獲取。而這個操作同樣被STM32固件庫封裝了,其函數名為GPIO_ReadInputDataBit。查看源碼,其正是對IDR寄存器操作的封裝,如下圖3-2所示。

圖3-2
其最終會返回引腳的電平狀態,即返回1(高電平),返回0(低電平)。代碼里“Bit_RESET”和“Bit_SET”已經通過枚舉方式定義了,Bit_RESET=0(低電平),Bit_SET=1(高電平)。最后我們通過判斷函數返回值完成按鍵檢測。若按鍵按下,則引腳輸出高電平。我們將該檢測過程也封裝為一個函數Key_DETECTOR,具體如下:
/** * @brief 檢測按鍵狀態 * @param GPIOx:x可以是A, B, C, D, E * GPIO_Pin:對應引腳序號 * @retval 1(高電平,即按下按鍵)、0(低電平,即沒有按下按鍵) */ uint8_t Key_DETECTOR(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin){ uint16_t keyState = GPIO_ReadInputDataBit(GPIOx, GPIO_Pin); /* 檢測是否按下按鍵 */ if(keyState){ return 1; }else{ return 0; } }
萬事俱備,只欠東風,我們終於可以開始寫main函數了。main函數里,需要逐步調用以上所述的API,完成實驗功能。直接上代碼:
// 定義控制LED的引腳 #define LED_TOGGLE LED_Control(GPIOB, GPIO_Pin_0) // 使用帶參宏輸出LED燈的另一種狀態 #define LED_Control(GPIOx, GPIO_Pin) {GPIOx->ODR ^= GPIO_Pin;} int main(void){ uint8_t SaveStatus = 0; uint8_t State; LED_GPIO_Config(); Key_GPIO_Config(); while(1) { State = Key_DETECTOR(GPIOA, GPIO_Pin_0); if(SaveStatus != State) { if(State == 1) { LED_TOGGLE; } SaveStatus = State; } } }
至此,我們的按鍵檢測實驗也分析完成了。
轉自知乎。