有的人的单片机的部分端口引脚被一些固定原件占用了,无法直接读取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内容的知识,方便你理解且好用。
打字不易,且打赏且珍惜。(有问题来下方评论区指出,感谢你的浏览,我是小兰,再见。)