欢迎您访问 最编程 本站为您分享编程语言代码,编程技术文章!
您现在的位置是: 首页

STM32 4*4 矩阵键盘实现原理(可对任意引脚进行编程)

最编程 2024-04-14 07:39:33
...

有的人的单片机的部分端口引脚被一些固定原件占用了,无法直接读取ABCD端口对应寄存器的值,于是矩阵键盘8个引脚*各连各的,比如读A2,B3,C4,等等,很麻烦。那就用我的方法把,可以适用任意端口的引脚连接你的矩阵键盘,并用一个函数将对应按键按下数字作为读取按键值。

切记:4*4矩阵键盘是由行线,列线,各四条线交叉形成的16个点组成的,我采用先扫描行线上的电平值,再扫描列上的电平值,这样的方法识别按下了哪个键的。

 

我购买的器件及原理图如上, 仔细观察正面R1R2R3R4对应一二三四行,反过来背面看,从上往下数C4C3C2C1分别对应四三二一列,

如果我们先初始化R1R2R3R4对应你接在stm32上引脚的初始状态为输入上拉(GPIO_Mode_IPU),C4C3C2C1对应引脚为推挽输出(GPIO_Mode_Out_PP)。那么此时R1R2R3R4均为高电平,然后如果按下R1第一行S1S2S3S4,任意一个键,此时读取到的R1电平值为低电平,R2R3R4依然是高电平,????,此时,你起码可以通过读取R1R2R3R4对应引脚电平信息分辨按下的是哪一行了。当然,本例你按下第一行(假设这是初始化状态1)

同理,如果我们再初始化R1R2R3R4对应你接在stm32上引脚的初始状态为推挽输出(GPIO_Mode_Out_PP),C4C3C2C1对应引脚为推挽输出输入上拉(GPIO_Mode_IPU)。那么此时C4C3C2C1均为高电平,然后如果按下C1第一行S1S5S9S13,任意一个键,此时读取到的C1电平值为低电平,C2C3C4依然是高电平,你可以通过读取C4C3C2C1对应引脚电平判断按下的是那一列了,当然本例你按下第一列。(假设这是初始化状态2)

两者结合:在程序里,你设置先进行初始化状态1,扫描行的电平信息,发现Rn是低电平,然后再进行初始化状态2,发现Cm是低电平,单片机于是知道你按下了第n行第m列对应的按键。如果n=m=1,那就是按下s1.

基本原理已经清楚,下面上程序。

KEYPAD4×4.h

#ifndef __KEYPAD4x4_H
#define __KEYPAD4x4_H	 
#include "sys.h"
#include "delay.h"


#define KEYPAD4x4PORT	GPIOA	//定义IO接口组
#define KEY4	GPIO_Pin_11	//定义IO接口
#define KEY3	GPIO_Pin_12	//定义IO接口
#define KEY2	GPIO_Pin_2	//定义IO接口
#define KEY1	GPIO_Pin_3	//定义IO接口
#define KEYa	GPIO_Pin_4	//定义IO接口
#define KEYb	GPIO_Pin_5	//定义IO接口
#define KEYc	GPIO_Pin_6	//定义IO接口
#define KEYd	GPIO_Pin_7	//定义IO接口


void KEYPAD4x4_Init(void);//初始化
void KEYPAD4x4_Init2(void);//初始化2(用于IO工作方式反转)
u8 KEYPAD4x4_Read (void);//读阵列键盘
		 				    
#endif

其中abcd对应行引脚(C1C2C3C4),4321对应列引脚(C4C3C2C1),放到你的板子上需要稍加改动。

KEYPAD4*4.c


#include "KEYPAD4x4.h"

void KEYPAD4x4_Init(void){ //微动开关的接口初始化
	GPIO_InitTypeDef  GPIO_InitStructure; //定义GPIO的初始化枚举结构	
    GPIO_InitStructure.GPIO_Pin = KEYa | KEYb | KEYc | KEYd; //选择端口号(0~15或all)                        
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //选择IO接口工作方式 //上拉电阻       
	GPIO_Init(KEYPAD4x4PORT,&GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = KEY1 | KEY2 | KEY3 | KEY4; //选择端口号(0~15或all)                        
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择IO接口工作方式   
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO接口速度(2/10/50MHz)     
	GPIO_Init(KEYPAD4x4PORT,&GPIO_InitStructure);

	GPIO_ResetBits(KEYPAD4x4PORT,KEY1|KEY2|KEY3|KEY4);
	GPIO_SetBits(KEYPAD4x4PORT,KEYa|KEYb|KEYc|KEYd);
}
void KEYPAD4x4_Init2(void){ //微动开关的接口初始化2(用于IO工作方式反转)
	GPIO_InitTypeDef  GPIO_InitStructure; //定义GPIO的初始化枚举结构	
    GPIO_InitStructure.GPIO_Pin = KEY1 | KEY2 | KEY3 | KEY4; //选择端口号(0~15或all)                        
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //选择IO接口工作方式 //上拉电阻       
	GPIO_Init(KEYPAD4x4PORT,&GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = KEYa | KEYb | KEYc | KEYd; //选择端口号(0~15或all)                        
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //选择IO接口工作方式 //上拉电阻  
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置IO接口速度(2/10/50MHz)     
	GPIO_Init(KEYPAD4x4PORT,&GPIO_InitStructure);

	GPIO_SetBits(KEYPAD4x4PORT,KEY1|KEY2|KEY3|KEY4);
	GPIO_ResetBits(KEYPAD4x4PORT,KEYa|KEYb|KEYc|KEYd);
} 
u8 KEYPAD4x4_Read (void){
		u8 b=17;
		KEYPAD4x4_Init();//阵列键盘初始化
	do{
if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYa)){
		delay_ms (20);//延时20毫秒
		KEYPAD4x4_Init2();
	if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY1)  	//查寻键盘口的值是否变化
){

	delay_ms(1000);
			while(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY1));  	//等待按键放开
			delay_ms (20);//延时20毫秒
	KEYPAD4x4_Init();
		return b=1;
		}
	if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY2)  	//查寻键盘口的值是否变化
){
		delay_ms (20);//延时20毫秒
			while(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY2))  	//等待按键放开
		delay_ms (20);//延时20毫秒
							KEYPAD4x4_Init();
				return b=2;
		}
	if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY3)  	//查寻键盘口的值是否变化
){

	delay_ms(1000);
				KEYPAD4x4_Init();
		delay_ms (20);//延时20毫秒
			while(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYa))  	//等待按键放开
		delay_ms (20);//延时20毫秒
				return b=3;
		}
	if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY4)  	//查寻键盘口的值是否变化
){

	delay_ms(1000);
				KEYPAD4x4_Init();
		delay_ms (20);//延时20毫秒
			while(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYa))  	//等待按键放开
			delay_ms (20);//延时20毫秒
				return b=4;
		}
	}
//keyb
	if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYb)  	){
		delay_ms (20);//延时20毫秒
		KEYPAD4x4_Init2();
		if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY1)  	//查寻键盘口的值是否变化
){

	delay_ms(1000);
				KEYPAD4x4_Init();
		delay_ms (20);//延时20毫秒
			while(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYb))
		delay_ms (20);//延时20毫秒
				return b=5;
		}
if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY2)  	//查寻键盘口的值是否变化
){

	delay_ms(1000);
				KEYPAD4x4_Init();
		delay_ms (20);//延时20毫秒
			while(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYb))  	//等待按键放开
		delay_ms (20);//延时20毫秒
				return b=6;
		}
if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY3)  	//查寻键盘口的值是否变化
){
	delay_ms(1000);
				KEYPAD4x4_Init();
		delay_ms (20);//延时20毫秒
			while(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYb))  	//等待按键放开
			delay_ms (20);//延时20毫秒
				return b=7;

		}
if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY4)  	//查寻键盘口的值是否变化
){
	delay_ms(1000);
				KEYPAD4x4_Init();
		delay_ms (20);//延时20毫秒
			while(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYb))  	//等待按键放开
			delay_ms (20);//延时20毫秒
				return b=8;
		}
	}
//keyC
	if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYc)  	){
		delay_ms (20);//延时20毫秒
		KEYPAD4x4_Init2();
		if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY1)  	//查寻键盘口的值是否变化
){
	delay_ms(1000);
				KEYPAD4x4_Init();
		delay_ms (20);//延时20毫秒
			while(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYc))
		delay_ms (20);//延时20毫秒
	return b=9;

}
if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY2)  	//查寻键盘口的值是否变化
){
	delay_ms(1000);
				KEYPAD4x4_Init();
		delay_ms (20);//延时20毫秒
			while(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYc))  	//等待按键放开
		delay_ms (20);//延时20毫秒
				return b=   0;

		}
if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY3)  	//查寻键盘口的值是否变化
){
	delay_ms(1000);
				KEYPAD4x4_Init();
		delay_ms (20);//延时20毫秒
			while(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYc))  	//等待按键放开
		delay_ms (20);//延时20毫秒
	return b=11;
		}
if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY4)  	//查寻键盘口的值是否变化
){
	delay_ms(1000);
				KEYPAD4x4_Init();
		delay_ms (20);//延时20毫秒
			while(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYc))  	//等待按键放开
			delay_ms (20);//延时20毫秒
	return b=12;
		}
	}
//keyD
	if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYd)  	){
		delay_ms (20);//延时20毫秒
		KEYPAD4x4_Init2();
		if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY1)  	//查寻键盘口的值是否变化
){
				KEYPAD4x4_Init();
		delay_ms (20);//延时20毫秒
			while(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYd)  	//等待按键放开
);
		delay_ms (20);//延时20毫秒
	return b=13;
		}
if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY2)  	//查寻键盘口的值是否变化
){
				KEYPAD4x4_Init();
		delay_ms (20);//延时20毫秒
			while(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYd))  	//等待按键放开
		delay_ms (20);//延时20毫秒
	return b=14;
		}
if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY3)  	//查寻键盘口的值是否变化
){
				KEYPAD4x4_Init();
		delay_ms (20);//延时20毫秒
			while(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYd))  	//等待按键放开
		delay_ms (20);//延时20毫秒
	return b=15;
		}
if(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEY4)  	//查寻键盘口的值是否变化
){
				KEYPAD4x4_Init();
		delay_ms (20);//延时20毫秒
			while(!GPIO_ReadInputDataBit(KEYPAD4x4PORT,KEYd))  	//等待按键放开
			{delay_ms (20);}//延时20毫秒
	return b=16;
		}
	}
	delay_ms(2000);
	delay_ms(2000);
	delay_ms(2000);
	delay_ms(2000);
	delay_ms(2000);

}while(b==17);
		return b;
}


/*
选择IO接口工作方式:
GPIO_Mode_AIN 模拟输入
GPIO_Mode_IN_FLOATING 浮空输入
GPIO_Mode_IPD 下拉输入
GPIO_Mode_IPU 上拉输入
GPIO_Mode_Out_PP 推挽输出
GPIO_Mode_Out_OD 开漏输出
GPIO_Mode_AF_PP 复用推挽输出
GPIO_Mode_AF_OD 复用开漏输出
*/

本质上就是双层if条件语句判断,先判断行引脚的高低电平信息,再判断列引脚高低电平信息。

你可以调用KEYPAD4x4_Read()函数;

用法,int Temp;

Temp=KEYPAD4x4_Read();//注意,在程序内使用这个函数,如果你不按下任意一个键,那它会永远卡在这一句直到你按下。S10对应的返回值我设置成了0,作为数字键0.

看到这里,相信你解决使用矩阵键盘了这个小问题了;可以作为软件中断使用。我没有使用任何中断NVIC内容的知识,方便你理解且好用。

打字不易,且打赏且珍惜。(有问题来下方评论区指出,感谢你的浏览,我是小兰,再见。)