矩阵键盘的原理及应用 - MARS的博客 - CSDN博客 https://blog.csdn.net/qq_40642465/article/details/80334530
矩阵键盘原理图:
第一行的行控制线接到p17,第二行的行控制线接到p16,第三行的行控制线接到p15,第4行的行控制线接到p14
第一列的列控制线接到p13,第二列的列控制线接到p12,第三列的列控制线接到p11,第四列的列控制线接到p10
矩阵键盘的原理和独立按键类似,另外我们可以把矩阵键盘的任意一行或一列作为一个独立键盘使用,假如我们把第一行作为独立键盘,那么我们只需要让P17输出高电平,其余7个io口输出低电平即可,假如我们按下了s1,那么p13的电平就会被拉低,变为低电平,所以我们可以通过查找低4位里哪一位为低电平就可以知道哪个按键按下了。
下面来说说矩阵按键扫描原理(即当我们按下一个矩阵键盘的按键时,如何获取按键的位置)
方法有2种,一种是逐行扫描,一种是行列扫描.接下来就主要讲讲行列扫描.
1、行列扫描法
行列扫描的话,就是一开始让p1口高4位输出高电平,低4位输出低电平,若这4行按键里,有按键按下了,那么那一行按键对应的io的电平就会被拉低,我们就可以知道按键的行坐标.获取按键列坐标的方法也是类似的,就是一开始让p1口高4位输出低电平,低4位输出高电平,若这4列按键里,有按键按下了,那么那一列按键对应的io的电平就会被拉低,我们就可以知道按键的列坐标,获得了行坐标x,列坐标y后,4*(x-1)+y就是按键的编号.
接下来贴份应用的代码,目的就是赋予16个按键键值,分别对应的键值是从0~F。按下一个键,第一个数码管就显示对应的键值
- #include<reg52.h>
- sbit lsa=P2^2;
- sbit lsb=P2^3;
- sbit lsc=P2^4;
- #define duanxuan P0
- #define keyboard P1
- int zxm[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
- int x,y;
- void delay(int i)
- {
- while(i--);
- }
- void keyproc()
- {
- int a=0;
- P1=0x0f;//检测是哪一列有按键按下;
- if(P1!=0x0f)
- {
- delay(1000);
- if(P1!=0x0f)
- {
- P1=0x0f;
- switch(P1)
- {
- case(0x07):y=1;break;
- case(0x0b):y=2;break;
- case(0x0d):y=3;break;
- case(0x0e):y=4;break;
- }
- }
- P1=0xf0;//检测是哪一行有按键按下
- switch(P1)
- {
- case(0x70):x=1;break;
- case(0xb0):x=2;break;
- case(0xd0):x=3;break;
- case(0xe0):x=4;break;
- }
- while(a<50&&P1!=0xf0)//当按键按下的时间超过了500ms或者按键松开了就退出while循环
- {
- delay(1000);
- a++;
- }
- }
- }
- int main()
- {
- lsa=0;
- lsb=0;
- lsc=0;//位选选中第一个数码管
- P0=0x00;//第一个数码管先什么都不显示
- while(1)
- {
- keyproc();
- P0=zxm[(x-1)*4+y-1];//送入段选信息
- }
- return 0;
- }
2、行扫描法
原文:https://blog.csdn.net/zxnsirius/article/details/51088946
-
根据原理图
键盘扫描方法是:行线P10~P13为输出线,列线P14~P17为输入线。一开始单片机将行线(P10~P13)全部输出低电平,此时读入列线数据,若列线全为高电平则没有键按下,当列线有出现低电平时调用延时程序以此来去除按键抖动。延时完成后再判断是否有低电平,如果此时读入列线数据还是有低电平,则说明确实有键按下。最后一步确定键值。现在我们以第二行的S5键为例,若按下S5后我们应该怎么得到这个键值呢?当判断确实有键按下之后,行线轮流输出低电平,根据读入列线的数据可以确定键值。首先,单片机将P10输出为低电平,其它P11~P13输出高电平,此时读取列线的数据全为高电平,说明没有在第一行有键按下;其次,单片机将P11输出低电平,其它P10、P12、P13仍为高电平,此时再来读取列线数据,发现列线读到的数据有低电平,数值为1011(0x0B),如果我们的键盘布局已经确定,那么0x0B就代表S5的值了。转到S5键功能处理子程序就可以达到目的。/*
功能:矩阵键盘扫面,按键显示键值程序
作者:siriuszxn
*/
#include "reg51.h"
#define KEYPORT = P1unsigned char i;
unsigned char Keynum;
unsigned char Line; //行
unsigned char Mask;
unsigned char Col; //列
unsigned char ScanCode;unsigned char code psegs_table[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e}; //共阳极数码管0-F
void delay_ms(unsigned int t) //ms延时程序
{
unsigned char i;
unsigned int x;
x=t;
while(x--)
{
for(i=0;i<113;i++);
}
}
/* 键盘扫描程序 */
void keyscan()
{
while (1) //循环扫描键盘
{
P1 = 0xff; //开始
Line = 1;
Mask = 0x01;for(i = 0; i < 4; i++)
{
P1 = ~Mask;ScanCode = P1 & 0xf0;
if (ScanCode != 0xf0)
{
delay_ms(5);
}ScanCode = P1 & 0xf0;
switch(ScanCode)
{
case 0xe0:Col=1;break;
case 0xd0:Col=2;break;
case 0xb0:Col=3;break;
case 0x70:Col=4;break;
default :Col=0;break;
}if (Col > 0)
{
//根据行列计算键值
Keynum = (Line - 1) * 4 + Col;
//通过P0口接数码管显示
P0 = psegs_table[Keynum-1];while(1)
{
ScanCode = P1 & 0xf0;
if(ScanCode == 0xf0)
{
break;
}
}
Mask <<= 1;
Line++;
}
}
}
}void main()
{
while(1)
{
keyscan();
}
}
STM32 >> 矩阵键盘(代码风格优美,简明易懂) -
原文:https://blog.csdn.net/weixin_40973138/article/details/86607562
key.h
- /**
- ******************************************************************************
- * @file bsp_key.h
- * @author Waao
- * @version V1.0.0
- * @date 23-Jan-2019
- * @brief This file contains some board support package's definition for the KEY.
- *
- ******************************************************************************
- * @attention
- *
- * None
- *
- ******************************************************************************
- */
- #ifndef __BSP_KEY_H_
- #define __BSP_KEY_H_
- #include <stm32f4xx.h>
- #include <bsp_systick.h>
- #include <bsp_usart.h>
- // Column1, Column2, Column3, Column4
- #define C1_PIN GPIO_Pin_2
- #define C1_GPIO_PORT GPIOE
- #define C1_GPIO_CLK RCC_AHB1Periph_GPIOE
- #define C2_PIN GPIO_Pin_3
- #define C2_GPIO_PORT GPIOE
- #define C2_GPIO_CLK RCC_AHB1Periph_GPIOE
- #define C3_PIN GPIO_Pin_4
- #define C3_GPIO_PORT GPIOE
- #define C3_GPIO_CLK RCC_AHB1Periph_GPIOE
- #define C4_PIN GPIO_Pin_5
- #define C4_GPIO_PORT GPIOE
- #define C4_GPIO_CLK RCC_AHB1Periph_GPIOE
- // Row1, Row2, Row3, Row4
- #define R1_PIN GPIO_Pin_12
- #define R1_GPIO_PORT GPIOB
- #define R1_GPIO_CLK RCC_AHB1Periph_GPIOB
- #define R2_PIN GPIO_Pin_13
- #define R2_GPIO_PORT GPIOB
- #define R2_GPIO_CLK RCC_AHB1Periph_GPIOB
- #define R3_PIN GPIO_Pin_14
- #define R3_GPIO_PORT GPIOB
- #define R3_GPIO_CLK RCC_AHB1Periph_GPIOB
- #define R4_PIN GPIO_Pin_15
- #define R4_GPIO_PORT GPIOB
- #define R4_GPIO_CLK RCC_AHB1Periph_GPIOB
- // detect and output
- #define DETECT_C1 GPIO_ReadInputDataBit(C1_GPIO_PORT, C1_PIN)
- #define DETECT_C2 GPIO_ReadInputDataBit(C2_GPIO_PORT, C2_PIN)
- #define DETECT_C3 GPIO_ReadInputDataBit(C3_GPIO_PORT, C3_PIN)
- #define DETECT_C4 GPIO_ReadInputDataBit(C4_GPIO_PORT, C4_PIN)
- #define DETECT_R1 GPIO_ReadInputDataBit(R1_GPIO_PORT, R1_PIN)
- #define DETECT_R2 GPIO_ReadInputDataBit(R2_GPIO_PORT, R2_PIN)
- #define DETECT_R3 GPIO_ReadInputDataBit(R3_GPIO_PORT, R3_PIN)
- #define DETECT_R4 GPIO_ReadInputDataBit(R4_GPIO_PORT, R4_PIN)
- // Keys
- #define S1 0x77
- #define S2 0xB7
- #define S3 0xD7
- #define S4 0xE7
- #define S5 0x7B
- #define S6 0xBB
- #define S7 0xDB
- #define S8 0xEB
- #define S9 0x7D
- #define S10 0xBD
- #define S11 0xDD
- #define S12 0xED
- #define S13 0x7E
- #define S14 0xBE
- #define S15 0xDE
- #define S16 0xEE
- void GPIO_RCC_Config(void);
- void ROCI_GPIO_Config(void);
- void RICO_GPIO_Config(void);
- void KEY_GPIO_ConfigAndDetect(void);
- #endif
有关输入输出管脚的选择可以多试验几组,有的管脚即使你配置成上拉输入,当你松开按键之后依然不会返回高电平,我在此就因为这个问题被卡了一阵子
关于我的矩阵键盘检测的原理简明阐述如下:
首先设置为行输出低电平,列上拉输入(即无外部干扰时保持高电平);
检测到按键按下,此时通过检测列的电平情况从而得知哪一列有按键被按下;
然后确定有按键被按下后,设置为列输出低电平,行上拉输入;
通过检测行的电平情况从而得知哪一行有按键被按下;
最后通过“不平行的两条直线相交于一点”原理,推知具体被按下的按键。
key.c
- /**
- ******************************************************************************
- * @file bsp_key.c
- * @author Waao
- * @version V1.0.0
- * @date 23-Jan-2019
- * @brief This file contains some board support package's functions for the KEY.
- *
- ******************************************************************************
- * @attention
- *
- * None
- *
- ******************************************************************************
- */
- #include <bsp_key.h>
- /**
- * @brief Initialize the RCC of the 8 GPIO line.
- * @param None
- * @retval None
- */
- void GPIO_RCC_Config(void)
- {
- RCC_AHB1PeriphClockCmd(C1_GPIO_CLK, ENABLE);
- RCC_AHB1PeriphClockCmd(C2_GPIO_CLK, ENABLE);
- RCC_AHB1PeriphClockCmd(C3_GPIO_CLK, ENABLE);
- RCC_AHB1PeriphClockCmd(C4_GPIO_CLK, ENABLE);
- RCC_AHB1PeriphClockCmd(R1_GPIO_CLK, ENABLE);
- RCC_AHB1PeriphClockCmd(R2_GPIO_CLK, ENABLE);
- RCC_AHB1PeriphClockCmd(R3_GPIO_CLK, ENABLE);
- RCC_AHB1PeriphClockCmd(R4_GPIO_CLK, ENABLE);
- }
- /**
- * @brief Initialize the Row out Column in.
- * @param None
- * @retval None
- */
- void ROCI_GPIO_Config(void)
- {
- GPIO_InitTypeDef GPIO_Structure;
- //============ Column =============
- GPIO_Structure.GPIO_Mode = GPIO_Mode_IN;
- GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Structure.GPIO_OType = GPIO_OType_PP;
- GPIO_Structure.GPIO_PuPd = GPIO_PuPd_UP;
- GPIO_Structure.GPIO_Pin = C1_PIN;
- GPIO_Init(C1_GPIO_PORT, &GPIO_Structure);
- GPIO_Structure.GPIO_Pin = C2_PIN;
- GPIO_Init(C2_GPIO_PORT, &GPIO_Structure);
- GPIO_Structure.GPIO_Pin = C3_PIN;
- GPIO_Init(C3_GPIO_PORT, &GPIO_Structure);
- GPIO_Structure.GPIO_Pin = C4_PIN;
- GPIO_Init(C4_GPIO_PORT, &GPIO_Structure);
- //============== Row ===============
- GPIO_Structure.GPIO_Mode = GPIO_Mode_OUT;
- GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Structure.GPIO_OType = GPIO_OType_PP;
- GPIO_Structure.GPIO_PuPd = GPIO_PuPd_DOWN;
- GPIO_Structure.GPIO_Pin = R1_PIN;
- GPIO_Init(R1_GPIO_PORT, &GPIO_Structure);
- GPIO_Structure.GPIO_Pin = R2_PIN;
- GPIO_Init(R2_GPIO_PORT, &GPIO_Structure);
- GPIO_Structure.GPIO_Pin = R3_PIN;
- GPIO_Init(R3_GPIO_PORT, &GPIO_Structure);
- GPIO_Structure.GPIO_Pin = R4_PIN;
- GPIO_Init(R4_GPIO_PORT, &GPIO_Structure);
- GPIO_ResetBits(R1_GPIO_PORT, R1_PIN);
- GPIO_ResetBits(R2_GPIO_PORT, R2_PIN);
- GPIO_ResetBits(R3_GPIO_PORT, R3_PIN);
- GPIO_ResetBits(R4_GPIO_PORT, R4_PIN);
- }
- /**
- * @brief Initialize the Row in Column out.
- * @param None
- * @retval None
- */
- void RICO_GPIO_Config(void)
- {
- GPIO_InitTypeDef GPIO_Structure;
- //============== Row ==================
- GPIO_Structure.GPIO_Mode = GPIO_Mode_IN;
- GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Structure.GPIO_OType = GPIO_OType_PP;
- GPIO_Structure.GPIO_PuPd = GPIO_PuPd_UP;
- GPIO_Structure.GPIO_Pin = R1_PIN;
- GPIO_Init(R1_GPIO_PORT, &GPIO_Structure);
- GPIO_Structure.GPIO_Pin = R2_PIN;
- GPIO_Init(R2_GPIO_PORT, &GPIO_Structure);
- GPIO_Structure.GPIO_Pin = R3_PIN;
- GPIO_Init(R3_GPIO_PORT, &GPIO_Structure);
- GPIO_Structure.GPIO_Pin = R4_PIN;
- GPIO_Init(R4_GPIO_PORT, &GPIO_Structure);
- //============ Column ================
- GPIO_Structure.GPIO_Mode = GPIO_Mode_OUT;
- GPIO_Structure.GPIO_Speed = GPIO_Speed_50MHz;
- GPIO_Structure.GPIO_OType = GPIO_OType_PP;
- GPIO_Structure.GPIO_PuPd = GPIO_PuPd_DOWN;
- GPIO_Structure.GPIO_Pin = C1_PIN;
- GPIO_Init(C1_GPIO_PORT, &GPIO_Structure);
- GPIO_Structure.GPIO_Pin = C2_PIN;
- GPIO_Init(C2_GPIO_PORT, &GPIO_Structure);
- GPIO_Structure.GPIO_Pin = C3_PIN;
- GPIO_Init(C3_GPIO_PORT, &GPIO_Structure);
- GPIO_Structure.GPIO_Pin = C4_PIN;
- GPIO_Init(C4_GPIO_PORT, &GPIO_Structure);
- GPIO_ResetBits(C1_GPIO_PORT, C1_PIN);
- GPIO_ResetBits(C2_GPIO_PORT, C2_PIN);
- GPIO_ResetBits(C3_GPIO_PORT, C3_PIN);
- GPIO_ResetBits(C4_GPIO_PORT, C4_PIN);
- }
- /**
- * @brief Configure the GPIO, and detect whether the key was pressed down
- * @param None
- * @retval None
- */
- void KEY_GPIO_ConfigAndDetect(void)
- {
- u8 TEMP_COMBINE = 0, TEMP_ROCI = 0, TEMP_RICO = 0;
- GPIO_RCC_Config();
- printf("\nWhy so serious ?\tThe game just begin!");
- while(1)
- {
- ROCI_GPIO_Config();
- TEMP_ROCI = (u8)(((u8)DETECT_C1) << 3) |
- (((u8)DETECT_C2) << 2) |
- (((u8)DETECT_C3) << 1) |
- (((u8)DETECT_C4) << 0);
- if(TEMP_ROCI != 0x0f)
- {
- Delay(1000); // Eliminate the shaking. The parameter's unit is 10us
- if(TEMP_ROCI != 0x0f) // Ensure one of the keys was pressed down indeed.
- {
- RICO_GPIO_Config();
- TEMP_RICO = (u8)(((u8)DETECT_R1) << 3) |
- (((u8)DETECT_R2) << 2) |
- (((u8)DETECT_R3) << 1) |
- (((u8)DETECT_R4) << 0);
- TEMP_COMBINE = (u8)((TEMP_ROCI << 4) | TEMP_RICO); // Combine the two situation and we can know which key was pressed down.
- switch(TEMP_COMBINE)
- {
- case S1:
- printf("\nS1 was pressed down!");
- break;
- case S2:
- printf("\nS2 was pressed down!");
- break;
- case S3:
- printf("\nS3 was pressed down!");
- break;
- case S4:
- printf("\nS4 was pressed down!");
- break;
- case S5:
- printf("\nS5 was pressed down!");
- break;
- case S6:
- printf("\nS6 was pressed down!");
- break;
- case S7:
- printf("\nS7 was pressed down!");
- break;
- case S8:
- printf("\nS8 was pressed down!");
- break;
- case S9:
- printf("\nS9 was pressed down!");
- break;
- case S10:
- printf("\nS10 was pressed down!");
- break;
- case S11:
- printf("\nS11 was pressed down!");
- break;
- case S12:
- printf("\nS12 was pressed down!");
- break;
- case S13:
- printf("\nS13 was pressed down!");
- break;
- case S14:
- printf("\nS14 was pressed down!");
- break;
- case S15:
- printf("\nS15 was pressed down!");
- break;
- case S16:
- printf("\nS16 was pressed down!");
- break;
- default:
- break;
- }
- while(TEMP_RICO != 0x0F)
- {
- TEMP_RICO = (u8)(((u8)DETECT_R1)<<3) |
- (((u8)DETECT_R2)<<2) |
- (((u8)DETECT_R3)<<1) |
- (((u8)DETECT_R4)<<0);
- }
- }
- }
- }
- }