引言
這一節通過按鍵輸入的實驗,完成對IO口配置輸入的學習,同時學習如何通過軟件去抖動。這一節最終可以實現利用WK_UP按鍵控制LED亮滅的效果。
准備環節
與上一節點亮LED相類似,這一節也需要在 HARDWARE
文件夾內新建文件 key.h
和 key.c
。同時將相應的文件加入到工程中。
查看原理圖,獲取WK_UP按鍵的相關信息。對應IO口 PA0
。高電平為有效電平,且沒有外接下拉電阻。需要利用軟件設置IO口為下拉狀態。
GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
該函數可以獲取到相應IO口的電平狀態。
編碼
步驟:
- 使能IO口所在總線的時鍾
- 配置按鍵相應IO口
- 配置按鍵檢測函數
- main函數調用
key.h
#ifndef __KEY_H
#define __KEY_H
#include "sys.h"
#define WK_UP GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0) //WK_UP作為相應IO口狀態讀取的簡寫
//#define WK_UP PAin(0) 上一行代碼與該行效果相同
void KEY_Init(void); //相應IO口配置初始化
u8 KEY_Scan(void); //WK_UP按鍵處理函數
#endif
key.c
#include "key.h"
#include "sys.h"
#include "delay.h"
void KEY_Init(void){
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能時鍾
//IO口配置 由於是輸入模式,所以不需要配置輸出速度
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //WK_UP對應PA0
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //初始化 下拉
GPIO_Init(GPIOA, &GPIO_InitStructure); //用上述配置的結構體初始化
}
u8 KEY_Scan(void){ //按鍵檢測
static char flag = 0; //默認WK_UP按鍵沒有按下
if (WK_UP == 1){ //此時按鍵按下,可能是誤觸
delay_ms(10);
if (WK_UP == 1){ //延遲10ms,再次判斷,可以排除誤觸的情況,稱為“軟件消抖”
flag = 1; //代表按鍵已經按過,但還未對其處理
}
}
if (WK_UP == 0 && flag == 1){ //此時上一次按鍵未處理,且上次按鍵已經釋放
flag = 0; //復位flag
return 1; //主函數根據返回值的不同,進行不同的按鍵處理
}
return 0;
}
//以下是按鍵檢測的另一種寫法
//mode為1時,按鍵支持連按;為0時不支持連按
u8 KEY_Scan(u8 mode){
static u8 flag = 1;
if (mode) flag = 1; //mode為1時,進入檢測函數時,flag就始終為1,即實現按鍵連按
if (flag && WK_UP){
delay_ms(10);
flag = 0; //flag復位,若mode為0,則下次檢測不會再成功,即可阻止按鍵連按
if(WK_UP) return 1;
}else if(!WK_UP){ //若上次flag被復位,這次按鍵檢測中將會對其置位,使得下次按鍵檢測正常進行
flag = 1;
}
return 0; //未檢測到按鍵按下,就會返回0
}
main.c
//此處省略頭文件,之后一般都會省略頭文件
int main(void){
delay_init();
LED_Init(); //LED相應IO口初始化
KEY_Init(); //按鍵相應IO口初始化
LED1 = 0; //點亮LED1
while(1){
u8 key = KEY_Scan(); //檢測按鍵狀態,返回值是1或0
if(key == 1){ //按鍵按下未處理
LED1 = !LED1; //點亮或熄滅LED1
}else{
delay_ms(10); //未檢測到按鍵,進行下一次按鍵檢測
}
}
}
至此,將程序燒寫進單片機,就可以實現開篇提到的按鍵控制LED亮滅的功能了。這是不是非常的“阿美zing”呢?
補充
main.c中的LED_Init()
相關配置代碼可以參看之前的這篇文章: