國產MCU兆易GD32實現矩陣按鍵掃描

2023-06-24 18:01:11

一、矩陣鍵盤
    為了減少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();
  }
}

以上是行掃描實現思路,剩下的按鍵只需將剩下的三列依次保持一列輸出高,重複掃描行即可。

三、實驗現象

實際測試均能準確列印出鍵值。

四、程式優化

     行掃描程式有大量重複程式碼,可以使用迴圈語句巢狀條件選擇語句將四列依次置高,這樣就只需要一段通用的行掃描語句,降低重複率。