一、矩陣鍵盤
為了減少I/O口的佔用,通常將按鍵排列成矩陣形式。在矩陣式鍵盤中,每條水平線和垂直線在交叉處不直接連通,而是通過一個按鍵加以連線。使用8個io口來進行16個按鍵的控制讀取,可以減小io口的使用,用4條I/O線作為行線,4條I/O線作為列線組成的鍵盤。矩陣鍵盤檢測方法主要有兩種,一種是逐行掃描、一種是行列掃描。
1、逐行掃描
通過在矩陣按鍵的每一條行線上輪流輸出低(高)電平,檢測矩陣按鍵的列線,當檢測到的列線不全為高(低)電平的時候,說明有按鍵按下。然後,根據當前輸出低電平的行號和檢測到低電平的列號組合,判斷是哪一個按鍵被按下。
2、行列掃描
首先,在全部行線上輸出低電平,檢測矩陣按鍵的列線,當檢測到的列線不全為高電平的時候,說明有按鍵按下,並判斷是哪一列有按鍵按下。然後,反過來,在全部列線上輸出低電平,檢測矩陣按鍵的行線,當檢測到的行線不全為高電平的時候,說明有按鍵按下,並判斷是哪一行有按鍵按下。最後,根據檢測到的行號和檢測的列號組合,以判斷是哪一個按鍵被按下。
二、程式設計
實現效果:逐行掃描矩陣鍵盤並列印出鍵值。
思路:保持一列輸出高,重複掃描行。
key.c
#include "key.h"
uint8_t i=0,j=0;//行、列號
/************************************************
*@Function :key_Init
*@brief :按鍵GPIO初始化函數
*@param :void
*@retval : void
*************************************************/
void Key_Init(void)
{
//使能GPIO時鐘
rcu_periph_clock_enable(RCU_GPIOA);
rcu_periph_clock_enable(RCU_GPIOB);
//四列 PB1 PB2 PB10 PB11 作為輸出
gpio_init(GPIOB,GPIO_MODE_OUT_PP,GPIO_OSPEED_10MHZ,GPIO_PIN_1);
gpio_init(GPIOB,GPIO_MODE_OUT_PP,GPIO_OSPEED_10MHZ,GPIO_PIN_2);
gpio_init(GPIOB,GPIO_MODE_OUT_PP,GPIO_OSPEED_10MHZ,GPIO_PIN_10);
gpio_init(GPIOB,GPIO_MODE_OUT_PP,GPIO_OSPEED_10MHZ,GPIO_PIN_11);
//四行 PA3 PA4 PA5 PA6 下拉輸入 預設為低電平
gpio_init(GPIOA,GPIO_MODE_IPD,GPIO_OSPEED_10MHZ,GPIO_PIN_3);
gpio_init(GPIOA,GPIO_MODE_IPD,GPIO_OSPEED_10MHZ,GPIO_PIN_4);
gpio_init(GPIOA,GPIO_MODE_IPD,GPIO_OSPEED_10MHZ,GPIO_PIN_5);
gpio_init(GPIOA,GPIO_MODE_IPD,GPIO_OSPEED_10MHZ,GPIO_PIN_6);
//列初始化為低電平
gpio_bit_reset(GPIOB, GPIO_PIN_1);
gpio_bit_reset(GPIOB, GPIO_PIN_2);
gpio_bit_reset(GPIOB, GPIO_PIN_10);
gpio_bit_reset(GPIOB, GPIO_PIN_11);
}
/************************************************
*@Function :Rank1_Scan(void)
*@brief :第一行掃描函數
*@param :void
*@retval : 0(可以返回行號i)
*************************************************/
uint8_t Rank1_Scan(void)
{
//第一列輸出高,其它三列輸出低
gpio_bit_set(GPIOB, GPIO_PIN_1);
gpio_bit_reset(GPIOB, GPIO_PIN_2);
gpio_bit_reset(GPIOB, GPIO_PIN_10);
gpio_bit_reset(GPIOB, GPIO_PIN_11);
//檢測第一行按鍵狀態,為高則按下
if(gpio_input_bit_get(GPIOA, GPIO_PIN_3)==1)
{
delay_1ms(10);//消抖
while(gpio_input_bit_get(GPIOA, GPIO_PIN_3)==1)
delay_1ms(10);
printf("KeyNumber:%d\r\n",KEY1);
}
//檢測第二行按鍵狀態,為高則按下
if(gpio_input_bit_get(GPIOA, GPIO_PIN_4)==1)
{
delay_1ms(10);;
while(gpio_input_bit_get(GPIOA, GPIO_PIN_4)==1)
delay_1ms(10);;
printf("KeyNumber:%d\r\n",KEY5);
}
//檢測第三行按鍵狀態
if(gpio_input_bit_get(GPIOA, GPIO_PIN_5)==1)
{
delay_1ms(10);;
while(gpio_input_bit_get(GPIOA, GPIO_PIN_5)==1)
delay_1ms(10);
printf("KeyNumber:%d\r\n",KEY9);
}
//檢測第四行按鍵狀態
if(gpio_input_bit_get(GPIOA, GPIO_PIN_6)==1)
{
delay_1ms(10);
while(gpio_input_bit_get(GPIOA, GPIO_PIN_6)==1)
delay_1ms(10);
printf("KeyNumber:%d\r\n",KEY13);
}
gpio_bit_reset(GPIOB, GPIO_PIN_1);//將第一列拉低迴原狀態
return 0;
}
主函數
#include "gd32f10x.h"
#include "gd32f103c_eval.h"
#include "systick.h"
#include "key.h"
#include "usart.h"
int main(void)
{
systick_config();//系統時鐘
//USART相關設定
Usart_Init();
Key_Init();
printf("Init OK!\r\n");
while(1)
{
Rank1_Scan();
}
}
以上是行掃描實現思路,剩下的按鍵只需將剩下的三列依次保持一列輸出高,重複掃描行即可。
三、實驗現象
實際測試均能準確列印出鍵值。
四、程式優化
行掃描程式有大量重複程式碼,可以使用迴圈語句巢狀條件選擇語句將四列依次置高,這樣就只需要一段通用的行掃描語句,降低重複率。