前言
做完了GPIO點燈實驗,成就感滿滿,不知道小白的我是不是入門了,哈哈!開始做下一個GPIO按鍵檢測的實驗。
一、硬件電路設計
1.開發板用戶按鍵硬件電路
輕觸按鍵又稱輕觸開關(下文簡稱按鍵),是電路中常用的一種開關元器件,也是一種常用的人機接口。廣泛用于家電、數碼產品、便攜儀產品、電腦產品等電子設備中。
STC8A8K64S4A12開發板上設計了4個用戶按鍵KEY1、KEY2、KEY3、KEY4,當使用KEY1和KEY2時,可短接J26端子的P37||KEY1、P36||KEY2。程序中通過讀取這些按鍵對應的GPIO的狀態(高電平或低電平)可判斷該按鍵是否按下,這種電路的形式稱為高低電平接法,這種檢測按鍵的方法稱為按鍵高低電平檢測。
圖1:開發板按鍵檢測電路及實物圖
表1:用戶按鍵引腳分配
輕觸按鍵,顧名思義我們只需要施加很小的力量即可改變開關連接的狀態。輕觸按鍵在所需外力作用下(按下按鍵)觸點導通,無外力作用時(釋放按鍵)觸點斷開,如下圖所示:
圖2:輕觸按鍵原理
2.按鍵檢測接法
高低電平式接法是最常見的按鍵檢測的接法,顧名思義,該接法就是需要單片機引腳具有高低電平的檢測能力,也就是常見的GPIO引腳即可。高低電平式接法又可分為兩種:獨立式接法和行列式接法。
行列式接法是利用單片機的 GPIO口組成行與列,在行與列的每一個交點處連接按鍵。 故也稱為矩陣式按鍵,該接線方法最大的優勢是可以使用較少的GPIO口實現較多按鍵的檢測,這個在矩陣按鍵掃描實驗中會詳細介紹。
獨立式接法的含義就是使用單片機的一個GPIO引腳檢測一個按鍵的狀態,有多少按鍵需檢測就需要多少個GPIO引腳,對每個按鍵的檢測相互獨立。
獨立式按鍵接法一般會用低電平有效的方式,即按鍵按下是GPIO輸入為低電平,如下圖所示。
圖3:獨立式接法
上圖中的電阻R的作用是將GPIO輸入端口不確定的信號通過該電阻鉗位在高電平狀態。我們知道數字電路有三種狀態:高電平、低電平和高阻狀態,有些應用場合并不希望出現高阻狀態,這時加上拉電阻即可讓GPIO輸入端口保持確定的狀態。
按鍵釋放時,因為上拉電阻R的關系,GPIO輸入檢測是高電平,按鍵閉合時,GPIO短接到GND,輸入檢測是低電平。這樣,單片機根據GPIO的輸入狀態即可確定按鍵是否按下。
■ 按鍵檢測知識擴展:ADC通過電阻分壓檢測多個按鍵
按鍵檢測除了高低電平檢測的方法之外,還有一種方法是使用ADC通過電阻分壓檢測多個按鍵,這種按鍵檢測的電路形式稱為分壓式接法。
分壓式接法,使用的單片機引腳必須具有ADC功能,根據檢測口測得的不同的電壓值來識別是哪個按鍵被按下。如下圖所示,是分壓式接法的原理示意圖。這種方法最大的好處是節省IO資源,它只需一個具有ADC功能的IO即可實現多個按鍵的檢測,它適用于IO資源緊張的場合,如一些電磁爐的按鍵使用的就是這種方法。
相對于高低電平檢測,這種方法在編程上要復雜一些,需要事先計算好分壓的電壓值,存儲于“表”中,程序運行時,采樣到電壓值后查表即可獲知是哪個按鍵按下。
圖4:分壓式接法原理
3.按鍵檢測電路考慮因素
按鍵檢測電路設計的時候,需要我們考慮兩個方面:按鍵釋放時GPIO口狀態的確定和按鍵消抖。
1)按鍵釋放時GPIO口狀態的確定
按鍵檢測電路中,當按鍵釋放后要能保證GPIO口電平是確定的,即按鍵釋放時GPIO口固定為高電平或低電平。開發板RN1排阻就是滿足用戶按鍵釋放時,在單片機GPIO口上保持高電平。
2)按鍵消抖
對于按鍵硬件上的消抖,一般常用的方式是在按鍵上并接一個容值約0.1uF左右電容,利用電容兩端的電壓不能突變的特性,消除抖動時產生的毛刺電壓。雖然電容可以起到消除抖動的作用,但是在考慮按鍵靈敏度的情況下,電容時無法完全消除抖動的,消除抖動還需要軟件的配合。
開發板上按鍵電路沒有增加硬件消抖,開發板使用的是軟件消抖,這對于一般的按鍵檢測已經完全足夠。
3)GPIO口保護
開發板按鍵檢測電路中還串有排阻RN12,該排阻阻值100歐姆,串在單片機GPIO口和按鍵引腳中,起到保護GPIO口的目的。
分析:如果GPIO口不小心誤配置為輸出模式,并且輸出高電平,則分析下電路可知,此時如果沒有排阻RN12,若按下用戶按鍵,則單片機GPIO口(控制輸出高電平)直接和GND相連,會損壞GPIO口。
二、軟件設計
1.寄存器解析
1.1.端口數據寄存器
下圖是對端口數據寄存器P0、P1、P2、P3、P4、P5、P6、P7的描述,端口數據寄存器各位代表對應端口的GPIO口,在完成對配置寄存器設置后,可直接讀取端口引腳電平。
圖5:端口數據寄存器
1.2.端口上拉電阻控制寄存器
下圖是對端口上拉電阻控制寄存器P0PU、P1PU、P2PU、P3PU、P4PU、P5PU、P6PU、P7PU的描述,這些特殊功能寄存器不支持位尋址。端口上拉電阻控制寄存器各位代表對應端口的GPIO口是否使能其上拉電阻,在完成對該寄存器設置后,相應GPIO端口便在單片機內部有了上拉電阻。該功能使得GPIO口在硬件電路設計時具有了更多的靈活性。但務必知曉端口上拉電阻控制寄存器為擴展SFR,邏輯地址位于XDATA區域,訪問前需先將P_SW2寄存器的最高位(EAXFR)置1。
圖6:端口數據寄存器
2.GPIO輸入按鍵檢測實驗(單個c文件)
2.1.頭文件引用和路徑設置
■ 需要宏定義部分及引用的頭文件
因為在“main.c”文件中使用了STC8的頭文件“STC8.h”,所以需要引用下面的頭文件。在頭文件“STC8.h”中需要確定主時鐘取值,所以宏定義主時鐘值。
#define MAIN_Fosc 11059200L //定義主時鐘
#include "STC8.H"
在程序設計中會用到定義變量的類型,為了定義變量方便,將較為復雜的“unsigned int”和“unsigned char ”進行了宏定義。
#define uint16 unsigned int
#define uint8 unsigned char
這樣,再定義變量時可直接使用“uint16”和“uint8”來取代“unsigned int”和“unsigned char ”即可。
■ 需要包含的頭文件路徑
本例需要包含的頭文件路徑如下表:
表2:頭文件包含路徑
MDK中點擊魔術棒,打開工程配置窗口,按照下圖所示添加頭文件包含路徑。
圖7:添加頭文件包含路徑
2.2.編寫代碼
首先根據開發板按鍵及指示燈GPIO分配,定義寄存器位變量,代碼如下。
/**********************
引腳別名定義
***********************/
sbit KEY=P0^7; //用戶按鍵KEY3用IO口P07
sbit LED_D3=P7^2; //用戶指示燈D3用IO口P72
然后,在主函數中先對P7.2和P0.7口進行模式配置,后主循環中檢測按鍵狀態,確認按鍵按下控制藍色指示燈D3亮。
int main(void)
{
P7M1 &= 0xFB; P7M0 &= 0xFB; //設置P7.2為準雙向口
P0M1 &= 0x7F; P0M0 &= 0x7F; //設置P0.7為準雙向口
// P0M1 |= 0x80; P0M0 &= 0x7F; //設置P0.7為高阻輸入
while(1)
{
if(KEY == 0) //檢測用戶按鍵KEY3對應引腳P0.7是否是低電平 (按鍵按下,引腳為低電平)
{
delay_ms(10); //軟件延時10ms,如果延時后按鍵KEY3的電平依然沒有變化,說明按鍵確實被有效操作,簡稱按鍵消抖
if(KEY== 0) //檢測用戶按鍵KEY3對應引腳P0.7是否依然是低電平
{
LED_D3=0; //點亮用戶指示燈D3
while(KEY == 0) //等待按鍵KEY3釋放,即如果P0.7一直為低電平,會一直執行空命令
{
; //條件KEY == 0成立,會執行這個空命令
}
LED_D3=1; //按鍵KEY3釋放,熄滅用戶指示燈D3
}
}
}
}
3.流水燈實驗(多個c文件)
3.1.工程需要用到的c文件
本例需要用到的c文件如下表所示,工程需要添加下表中的c文件。
表3:實驗需要用到的c文件
3.2.頭文件引用和路徑設置
■ 需要引用的頭文件
因為在“main.c”文件中使用了控制led的函數和延時函數(延時函數沒有在main.c中定義),所以需要引用下面的頭文件。
#include "led.h"
#include "delay.h"
#include "key.h"
■ 需要包含的頭文件路徑
本例需要包含的頭文件路徑如下表:
表4:頭文件包含路徑
MDK中點擊魔術棒,打開工程配置窗口,按照下圖所示添加頭文件包含路徑。
圖8:添加頭文件包含路徑
3.3.編寫代碼
首先在key.h中,宏定義4個用戶按鍵,引用延時函數的頭文件,聲明按鍵檢測函數供外部調用。代碼如下。
#include "delay.h"
#define KEY_ON 0
#define KEY_OFF 1
#define KEYS_OFF 0 //沒有按鍵按下
#define KEY1_ON 1 //按鍵KEY1按下
#define KEY2_ON 2 //按鍵KEY2按下
#define KEY3_ON 3 //按鍵KEY3按下
#define KEY4_ON 4 //按鍵KEY4按下
/********************************************
引腳別名定義
*********************************************/
sbit KEY_S1=P3^7; //用戶按鍵KEY1用IO口P37
sbit KEY_S2=P3^6; //用戶按鍵KEY2用IO口P36
sbit KEY_S3=P0^7; //用戶按鍵KEY3用IO口P07
sbit KEY_S4=P0^5; //用戶按鍵KEY4用IO口P05
extern uint8 Keys_Scan(uint8 mode);
然后,在key.c文件中編寫一個按鍵檢測函數Keys_Scan,代碼如下。
程序清單:延時函數
/**************************************************************************
功能描述:檢測開發板上的4個用戶按鍵(KEY1、KEY2、KEY3、KEY4)
入口參數:uint8 mode 是否支持連按
返回值:按鍵編號
*************************************************************************/
uint8 Keys_Scan(uint8 mode)
{
static uint8 Key_up=1; //標志變量
if(mode==1) //支持連按
{
Key_up=1; //變量 Key_up會被重新賦值為1
}
//檢測按鍵KEY1、按鍵KEY2、按鍵KEY3、按鍵KEY4用IO口電平是否為低電平
if(Key_up&&((KEY_S1 == KEY_ON ) || (KEY_S2 == KEY_ON ) || (KEY_S3 == KEY_ON ) || (KEY_S4 == KEY_ON )))
{
delay_ms(10); //軟件延時10ms,去抖
Key_up=0; //變量 Key_up會被賦值為0
if(KEY_S1 == KEY_ON )
{
return KEY1_ON;
}
else if(KEY_S2 == KEY_ON )
{
return KEY2_ON;
}
else if(KEY_S3 == KEY_ON )
{
return KEY3_ON;
}
else if(KEY_S4 == KEY_ON )
{
return KEY4_ON;
}
}
else if((KEY_S1 == KEY_OFF )&&(KEY_S2 == KEY_OFF ) &&(KEY_S3 == KEY_OFF )&&(KEY_S4 == KEY_OFF ) )
{
Key_up=1; //變量 Key_up會被賦值為1
}
return KEYS_OFF;
}
因為按鍵檢測函數Keys_Scan中使用了控制led的函數、有關KEY的宏定義和延時函數,所以需要在key.c文件中引用下面的頭文件。
#include "led.h"
#include "key.h"
最后,在主函數中先對4個用戶指示燈和4個用戶按鍵用到的GPIO口進行模式配置,后主循環中調用按鍵檢測函數,可觀察各用戶按鍵按下后用戶指示燈變化情況。
代碼清單:主函數
int main(void)
{
uint8 temp;
P2M1 &= 0x3F; P2M0 &= 0x3F; //設置P2.6~P2.7為準雙向口
P7M1 &= 0xF9; P7M0 &= 0xF9; //設置P7.1~P7.2為準雙向口
P0M1 &= 0x5F; P0M0 &= 0x5F; //設置P0.5,P0.7為準雙向口
// P0M1 |= 0xA0; P0M0 &= 0x5F; //設置P0.5,P0.7為高阻輸入
P3M1 &= 0x3F; P3M0 &= 0x3F; //設置P3.6~P3.7為準雙向口
// P3M1 |= 0xC0; P3M0 &= 0x3F; //設置P3.6~P3.7為高阻輸入
// P_SW2 |= 0x80; //將EAXFR位置1,以訪問在XDATA區域的擴展SFR
// P0PU |= 0xA0; //設置P0.5,P0.7口有上拉電阻
// P3PU |= 0xC0; //設置P3.6~P3.7口有上拉電阻
// P_SW2 &= 0x7F; //將EAXFR位置0,恢復訪問XRAM
while(1)
{
temp=Keys_Scan(0); //獲取開發板用戶按鍵檢測值,不支持連按
if(temp == KEY1_ON) //如果按鍵KEY1被操作
{
led_toggle(LED_1); //控制用戶指示燈D1翻轉
}
else if(temp == KEY2_ON) //如果按鍵KEY2被操作
{
led_toggle(LED_2); //控制用戶指示燈D2翻轉
}
else if(temp == KEY3_ON) //如果按鍵KEY3被操作
{
led_toggle(LED_3); //控制用戶指示燈D3翻轉
}
else if(temp == KEY4_ON) //如果按鍵KEY4被操作
{
led_toggle(LED_4); //控制用戶指示燈D4翻轉
}
}
}
總結
以上就是今天要講的內容,希望對你有所幫助!
-
元器件
+關注
關注
112文章
4716瀏覽量
92313 -
寄存器
+關注
關注
31文章
5343瀏覽量
120365 -
開發板
+關注
關注
25文章
5050瀏覽量
97471 -
GPIO
+關注
關注
16文章
1204瀏覽量
52098 -
按鍵檢測
+關注
關注
0文章
23瀏覽量
4836
發布評論請先 登錄
相關推薦
評論