需要知識(shí)點(diǎn)
按鍵的原理
GPIO輸入輸出
寄存器操作,如果學(xué)過51或者對(duì)C語言很熟練這里不存在問題。寄存器說白了就是操作他們的位(寄存器我理解就是一串羊肉串,讓你找出你先吃哪個(gè),比如我要吃中間的哪一個(gè)該怎么取出來)
矩陣按鍵原理
本實(shí)驗(yàn)使用STM32F103單片機(jī),主題代碼通用的。
如果每個(gè)按鍵占用一個(gè)GPIO引腳,對(duì)于使用多個(gè)按鍵來說就是一種資源的浪費(fèi),因此當(dāng)我們?cè)谠O(shè)計(jì)時(shí),可以考慮矩陣這種方式。本實(shí)驗(yàn)使用4*4也就是16個(gè)按鍵。
矩陣按鍵相對(duì)于獨(dú)立按鍵稍微麻煩一點(diǎn)。4x4矩陣按鍵按照矩陣方式分別分為4行4列。主要有兩種方式,一種是逐行掃描、一種是行列掃描。
原理圖:
逐行掃描
通過在矩陣按鍵的每一條行線上輪流輸出低電平,檢測(cè)矩陣按鍵的列線,當(dāng)檢測(cè)到的列線不全為高電平的時(shí)候,說明有按鍵按下。然后,根據(jù)當(dāng)前輸出低電平的行號(hào)和檢測(cè)到低電平的列號(hào)組合,判斷是哪一個(gè)按鍵被按下。
行列掃描
首先,在全部行線上輸出低電平,檢測(cè)矩陣按鍵的列線,當(dāng)檢測(cè)到的列線不全為高電平的時(shí)候,說明有按鍵按下,并判斷是哪一列有按鍵按下。
然后,反過來,在全部列線上輸出低電平,檢測(cè)矩陣按鍵的行線,當(dāng)檢測(cè)到的行線不全為高電平的時(shí)候,說明有按鍵按下,并判斷是哪一行有按鍵按下。
最后,根據(jù)檢測(cè)到的行號(hào)和檢測(cè)的列號(hào)組合,以判斷是哪一個(gè)按鍵被按下。
按鍵檢測(cè)說白了就是按鍵按下之后是不是導(dǎo)通的,而其他沒有按下的按鍵是沒有導(dǎo)通的,代碼也不唯一,是多種多樣的。這里就需要操作寄存器或者使用庫函數(shù)的位操作。
流程
矩陣按鍵程序?qū)崿F(xiàn)
根據(jù)是國內(nèi)棉矩陣按鍵電路圖,編寫矩陣按鍵應(yīng)用程序,輪徇K1~K8按鍵動(dòng)作,當(dāng)對(duì)應(yīng)的按鍵按下后,返回對(duì)應(yīng)的值:
矩陣按鍵:
/************
按鍵表盤為: 1 2 3 10
4 5 6 11
7 8 9 12
13 0 14 15
/K1-K4(行)/
/K5-K8(列)/
/************
K1--->PC0
K2--->PC1
K3--->PC2
K4--->PC3
K5--->PC4
K6--->PC5
K7--->PC6
***********************/
編程要點(diǎn)
(1)使能LED燈和矩陣按鍵的GPIO時(shí)鐘。調(diào)用函數(shù):
RCC_AHB1PeriphClockCmd();
(2)編寫矩陣按鍵掃描程序。
(3)同2-STM32GPIO輸入之按鍵
矩陣按鍵引腳配置
/************************************************************************
* @brief KEY_Config 按鍵初始化配置
* @brief 列檢測(cè)初始化
* @param 無
* @retval 無
***********************************************************************/
static void KEY_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
/*開啟RCC時(shí)鐘*/
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
/*K1-K4(行)*/
GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3);
//設(shè)置引腳為
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
//設(shè)置引腳速度50MHZ
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
/*K5-K8(列)*/
GPIO_InitStructure.GPIO_Pin = (GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7);
//設(shè)置引腳為推挽輸出模式
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD;
//設(shè)置引腳速度50MHZ
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
矩陣按鍵掃描程序
/************************************************************************
* @brief KEY_4_4_Scan 掃描函數(shù) 矩陣按鍵掃描,返回一個(gè)鍵值
* @brief 列檢測(cè)初始化
* @param 無
* @retval uint8_t
***********************************
按鍵表盤為: 1 2 3 10
4 5 6 11
7 8 9 12
13 0 14 15
************************************
矩陣按鍵:
/************************************
按鍵表盤為: 1 2 3 10
4 5 6 11
7 8 9 12
13 0 14 15
/************************************
K1--->PC0
K2--->PC1
K3--->PC2
K4--->PC3
K5--->PC4
K6--->PC5
K7--->PC6
***********************************************************************/
uint8_t KEY_4_4_Scan(void)
{
u8 KeyVal = 0;
GPIO_Write(GPIOC, (GPIOC->ODR & 0xff00 | 0x000f)); // PC0-PC3全部輸出高。
if (((GPIOC->IDR & 0X00F0)) == 0x0000) // PC4-PC7為0則沒有按鍵按下(第一次檢測(cè)按鍵是否有按下)
{
return 0xFF;
}
else
{
Delay_ms(10); //軟件延時(shí)
if (((GPIOC->IDR & 0X00F0)) == 0x0000) // PC4-PC7為0則沒有按鍵按下(第二次檢測(cè)按鍵是否有按下)
{
return 0xFF;
}
}
GPIO_Write(GPIOC, ((GPIOC->ODR & 0xfff0) | 0x0001)); //僅將PC0置高
switch ((GPIOC->IDR & 0X00f0)) //第一行,從PC4開始拉高,其余為0,PC5-PC7一樣
{
case 0x0010:
KeyVal = 1; // PC4
break;
case 0x0020:
KeyVal = 2; // PC5
break;
case 0x0040:
KeyVal = 3; // PC6
break;
case 0x0080:
KeyVal = 10; // PC7
break;
}
while (((GPIOC->IDR & 0X00F0)) > 0) //等待按鍵釋放,
GPIO_Write(GPIOC, 0x0000); //重新讓PC0到PC3全部輸出低。
GPIO_Write(GPIOC, ((GPIOC->ODR & 0xfff0) | 0x0002)); //僅將PC1置高
switch ((GPIOC->IDR & 0X00F0)) //第一行,從PC4開始拉高,其余為0,PC5-PC7一樣
{
case 0x0010:
KeyVal = 4;
break;
case 0x0020:
KeyVal = 5;
break;
case 0x0040:
KeyVal = 6;
break;
case 0x0080:
KeyVal = 11;
break;
}
while (((GPIOC->IDR & 0X00F0)) > 0) //等待按鍵釋放
GPIO_Write(GPIOC, 0x0000); //重新讓PC0到PC3全部輸出低。
GPIO_Write(GPIOC, ((GPIOC->ODR & 0xfff0) | 0x0004)); //僅將PC2置高
switch ((GPIOC->IDR & 0X00F0))
{
case 0x0010:
KeyVal = 7;
break;
case 0x0020:
KeyVal = 8;
break;
case 0x0040:
KeyVal = 9;
break;
case 0x0080:
KeyVal = 12;
break;
}
while (((GPIOC->IDR & 0X00F0)) > 0)
GPIO_Write(GPIOC, 0x0000); //重新讓PC0到PC3全部輸出低。
GPIO_Write(GPIOC, ((GPIOC->ODR & 0xfff0) | 0x0008)); //僅將PC3置高
switch ((GPIOC->IDR & 0X00F0))
{
case 0x0010:
KeyVal = 13;
break;
case 0x0020:
KeyVal = 0;
break;
case 0x0040:
KeyVal = 15;
break;
case 0x0080:
KeyVal = 16;
break;
}
while (((GPIOC->IDR & 0X00F0)) > 0) //等待按鍵釋放
GPIO_Write(GPIOC, 0x0000); //重新讓PC0到PC3全部輸出低。
return KeyVal;
}
主函數(shù)
int main(void)
{
uint8_t Key_value = 0;
// 來到這里的時(shí)候,系統(tǒng)的時(shí)鐘已經(jīng)被配置成72M。
LED_Config();
BEEP_Config();
SysTick_InitUP(); //配置10us中斷一次
USART_Config();
KEY_Init();
//矩陣按鍵代碼測(cè)試
while (1)
{
Key_value = KEY_4_4_Scan();
if (Key_value != 0xFF)
{
Delay_ms(200);
printf("Key_value=%d\\r\\n", Key_value);
}
Delay_ms(200);
}
}
實(shí)驗(yàn)現(xiàn)象
-
單片機(jī)
+關(guān)注
關(guān)注
6040文章
44594瀏覽量
636963 -
STM32F103
+關(guān)注
關(guān)注
33文章
478瀏覽量
63736 -
矩陣按鍵
+關(guān)注
關(guān)注
0文章
28瀏覽量
8380
發(fā)布評(píng)論請(qǐng)先 登錄
相關(guān)推薦
評(píng)論