|
矩陣鍵盤的掃描原理很多教材都介紹過,在這里再贅述一遍。
以4X4鍵盤為例,首先按照下圖制作電路。
51hei截圖20211115141944.png (74.36 KB, 下載次數(shù): 132)
下載附件
2021-11-15 14:19 上傳
然后將HOR1-HOR4連接到單片機(jī)的輸入引腳上去;LON1-LON4連接到單片機(jī)的開漏輸出引腳上去,注意這4個(gè)引腳必須設(shè)置為開漏模式!
程序上首先將LON1所連接的IO輸出低電平其余3個(gè)IO輸出高電平,同時(shí)檢測(cè)HOR1-HOR4的電平來獲取K1-K4的按鍵狀態(tài);然后將LON2所連接的IO輸出低電平其余3個(gè)IO輸出高電平,同時(shí)檢測(cè)HOR1-HOR4的電平來獲取K5-K8的按鍵狀態(tài);依次類推。
但是這個(gè)電路是有BUG的,比如同時(shí)按下K1、K5和K6,當(dāng)LON1為低電平的時(shí)HOR1檢測(cè)到是低電平?jīng)]有問題;因?yàn)镵2沒有被按下所以我們希望HOR2是高電平,但是由于K1、K5、K6同時(shí)按下電流從VCC通過R2再通過K6再通過K5再通過K1流到LON1,所以實(shí)際上HOR2也是低電平這時(shí)候程序就認(rèn)為K2被按下了導(dǎo)致出錯(cuò)。
51hei截圖20211115141944.png (85.7 KB, 下載次數(shù): 126)
下載附件
2021-11-15 14:40 上傳
解決這個(gè)問題很簡(jiǎn)單只需要在合適的位置加一個(gè)二極管,利用其單向?qū)щ娦宰钃蹼娏骺缌辛鲃?dòng)就行了。
51hei截圖20211115144223.png (83.52 KB, 下載次數(shù): 126)
下載附件
2021-11-15 14:42 上傳
好了,接下來是單片機(jī)代碼時(shí)間
- #ifndef __Key_matrix_H
- #define __Key_matrix_H
- #include "gpio.h"
- #include "gpio_bool.h"
- /*務(wù)必把這4個(gè)輸出IO設(shè)置為上拉輸入*/
- #define KEY_HOR1 PAin(7)
- #define KEY_HOR2 PAin(6)
- #define KEY_HOR3 PAin(5)
- #define KEY_HOR4 PAin(4)
- /*務(wù)必把這4個(gè)輸出IO設(shè)置為開漏*/
- #define KEY_LON1 PBout(0)
- #define KEY_LON2 PCout(5)
- #define KEY_LON3 PCout(4)
- #define KEY_LON4 PCout(3)
- #define KEY_PRESS_TIME 20//消抖常數(shù)
- #define KEY_LONG_PRESS_TIME 3000//單個(gè)按鍵長(zhǎng)按閾值3s
- /*通過讀取(只讀)這三個(gè)變量即可獲得按鍵的單按、長(zhǎng)按和組合鍵信息*/
- extern volatile uint16_t Key_Phy_Num;
- extern volatile uint8_t Key_Pulse_Num;
- extern volatile uint16_t Key_LP_Num;
- typedef enum
- {
- KPL_DISABLE=0,
- KPL_ENABLE
- }K_L_P;//按鍵的長(zhǎng)按狀態(tài)
- typedef struct
- {
- K_L_P KEY_LONG_PRESS;
- uint16_t KeyOpenCount;
- uint8_t KOC_EN;
- uint16_t KeyCloseCount;
- uint8_t KCC_EN;
- }Key_Para;
- exter Key_Par Key_1,Key_2,Key_3,Key_4,Key_5,Key_6,Key_7,Key_8,Key_9,Key_10,Key_11,Key_12,Key_13,Key_14,Key_15,Key_16;
- void Clear_Key_Pulse_Num(void);//當(dāng)讀取完Key_Pulse_Num后調(diào)用
- void KeyCount_Run(void);//在1ms滴答里調(diào)用
- void Key_Scan(void);//大循環(huán)或者滴答里邊都行
- #endif
復(fù)制代碼- #include "Key_matrix.h"
- Key_Par Key_1,Key_2,Key_3,Key_4,Key_5,Key_6,Key_7,Key_8,Key_9,Key_10,Key_11,Key_12,Key_13,Key_14,Key_15,Key_16;
- volatile uint16_t Key_Phy_Num=0; //Key_Phy_Num每一個(gè)bit代表一個(gè)按鍵的狀態(tài)
- volatile uint8_t Key_Pulse_Num=0;//當(dāng)某一個(gè)按鍵從按下到彈起的過程中(非長(zhǎng)按)始終只有該按鍵被操作,則Key_Pulse_Num被修改為該鍵的序號(hào)
- volatile uint16_t Key_LP_Num=0; //Key_LP_Num每一個(gè)bit代表一個(gè)按鍵的長(zhǎng)按狀態(tài)
- uint8_t KeyCom=0;//組合鍵是否出現(xiàn)
- static void Key_Num_Read(Key_Para* Key,uint16_t KPN,uint8_t Pulse,uint8_t Key_Hor)
- {
- if(Key_Hor == 0)
- {
- Key->KOC_EN=0;//按鍵按下立即清除(松開)計(jì)數(shù)
- if(Key->KeyCloseCount > KEY_PRESS_TIME)
- {
- /*消抖方法為檢測(cè)到按鍵被(持續(xù))按下超過20ms*/
- Key_Phy_Num|=KPN;//消抖完畢后記錄被按下的按鍵的鍵值
- if(Key->KeyCloseCount > KEY_LONG_PRESS_TIME)
- {
- /*檢測(cè)到按鍵被(持續(xù))按下超過3秒*/
- Key->KEY_LONG_PRESS=KPL_ENABLE;
- Key_LP_Num|=KPN;
- Key->KCC_EN=0;
- }
- else
- {
- /*時(shí)間不夠啟動(dòng)計(jì)數(shù)*/
- Key->KCC_EN=1;
- }
- }
- else
- {
- /*時(shí)間不夠啟動(dòng)計(jì)數(shù)*/
- Key->KCC_EN=1;
- }
- }
- else
- {
- Key->KCC_EN=0;//按鍵松開立即清除(按下)計(jì)數(shù)
- if(Key->KeyOpenCount > KEY_PRESS_TIME)
- {
- if((Key_Phy_Num==KPN)&&(KeyCom==0)&&(Key->KEY_LONG_PRESS!=KPL_ENABLE))
- {
- //按鍵被按下過&&非長(zhǎng)按&&不是在組合鍵周期,該按鍵釋放時(shí)發(fā)出生命周期為直到被讀取或者直到有新按鍵被按下的脈沖
- Key_Pulse_Num=Pulse;
- }
- //清除該位
- Key_Phy_Num&=(~KPN);
- Key_LP_Num&=(~KPN);
- /*檢測(cè)到(持續(xù))松開20ms*/
- Key->KEY_LONG_PRESS=KPL_DISABLE;
- Key->KOC_EN=0;
- }
- else
- {
- Key->KOC_EN=1;
- }
- }
- }
- /********************************************************/
- static void Key_Count(Key_Para *Key)
- {
- if(Key->KOC_EN==0)
- {
- Key->KeyOpenCount=0;
- }
- else if(Key->KeyOpenCount>=50000)
- {
- Key->KeyOpenCount=50000;
- }
- else
- {
- Key->KeyOpenCount++;
- }
- if(Key->KCC_EN==0)
- {
- Key->KeyCloseCount=0;
- }
- else if(Key->KeyCloseCount>=50000)
- {
- Key->KeyCloseCount=50000;
- }
- else
- {
- Key->KeyCloseCount++;
- }
- }
- /********************************************************/
- void Clear_Key_Pulse_Num(void)
- {
- Key_Pulse_Num=0;
- }
- /********************************************************/
- void KeyCount_Run(void)
- {
- Key_Count(&Key_1);
- Key_Count(&Key_2);
- Key_Count(&Key_3);
- Key_Count(&Key_4);
- Key_Count(&Key_5);
- Key_Count(&Key_6);
- Key_Count(&Key_7);
- Key_Count(&Key_8);
- Key_Count(&Key_9);
- Key_Count(&Key_10);
- Key_Count(&Key_11);
- Key_Count(&Key_12);
- Key_Count(&Key_13);
- Key_Count(&Key_14);
- Key_Count(&Key_15);
- Key_Count(&Key_16);
- }
- /********************************************************/
- static void Recognition_KeyCombination(void)
- {
- uint8_t i=0,j=0;
- uint16_t Data=0;
-
- Data=Key_Phy_Num;
- for(i=0;i<16;i++)
- {
- if(Data&0x8000)
- {
- j++;
- }
- Data<<=1;
- }
- /*發(fā)現(xiàn)多個(gè)bit為1,那指定多個(gè)按鍵按下了*/
- if(j>1)
- {
- KeyCom=1;
- }
- /*一切歸于平靜,又是一個(gè)因果循環(huán)*/
- if(Key_Phy_Num==0x0)
- {
- KeyCom=0;
- }
- }
- /********************************************************/
- void Key_Scan(void)
- {
- static uint8_t ScanCount=0;
-
- Recognition_KeyCombination();
- switch(ScanCount)
- {
- case 0:
- {
- KEY_LON1=0;KEY_LON2=1;KEY_LON3=1;KEY_LON4=1;
- Key_Num_Read(&Key_1,(uint16_t)0x0001 ,1,KEY_HOR1);
- Key_Num_Read(&Key_2,(uint16_t)0x0001<<1,2,KEY_HOR2);
- Key_Num_Read(&Key_3,(uint16_t)0x0001<<2,3,KEY_HOR3);
- Key_Num_Read(&Key_4,(uint16_t)0x0001<<3,4,KEY_HOR4);
- KEY_LON1=1;KEY_LON2=0;KEY_LON3=1;KEY_LON4=1;
- ScanCount++;
- }break;
- case 1:
- {
- KEY_LON1=1;KEY_LON2=0;KEY_LON3=1;KEY_LON4=1;
- Key_Num_Read(&Key_5,(uint16_t)0x0001<<4,5,KEY_HOR1);
- Key_Num_Read(&Key_6,(uint16_t)0x0001<<5,6,KEY_HOR2);
- Key_Num_Read(&Key_7,(uint16_t)0x0001<<6,7,KEY_HOR3);
- Key_Num_Read(&Key_8,(uint16_t)0x0001<<7,8,KEY_HOR4);
- KEY_LON1=1;KEY_LON2=1;KEY_LON3=0;KEY_LON4=1;
- ScanCount++;
- }break;
- case 2:
- {
- KEY_LON1=1;KEY_LON2=1;KEY_LON3=0;KEY_LON4=1;
- Key_Num_Read(&Key_9 ,(uint16_t)0x0001<<8 , 9,KEY_HOR1);
- Key_Num_Read(&Key_10,(uint16_t)0x0001<<9 ,10,KEY_HOR2);
- Key_Num_Read(&Key_11,(uint16_t)0x0001<<10,11,KEY_HOR3);
- Key_Num_Read(&Key_12,(uint16_t)0x0001<<11,12,KEY_HOR4);
- KEY_LON1=1;KEY_LON2=1;KEY_LON3=1;KEY_LON4=0;
- ScanCount++;
- }break;
- case 3:
- {
- KEY_LON1=1;KEY_LON2=1;KEY_LON3=1;KEY_LON4=0;
- Key_Num_Read(&Key_13,(uint16_t)0x0001<<12,13,KEY_HOR1);
- Key_Num_Read(&Key_14,(uint16_t)0x0001<<13,14,KEY_HOR2);
- Key_Num_Read(&Key_15,(uint16_t)0x0001<<14,15,KEY_HOR3);
- Key_Num_Read(&Key_16,(uint16_t)0x0001<<15,16,KEY_HOR4);
- KEY_LON1=0;KEY_LON2=1;KEY_LON3=1;KEY_LON4=1;
- ScanCount=0;
- }break;
- default:
- {
- ScanCount=0;
- }break;
- }
- }
復(fù)制代碼
|
評(píng)分
-
查看全部評(píng)分
|