一 .矩阵按键原理
矩阵按键有两种扫描方式:
方法一:
逐行扫描:我们可以通过低四位轮流输出低电平来对矩阵键盘进行逐行扫描,当高四位接收到的数据不全为1的时候,说明有按键按下,然后通过接收到的数据是哪一位为0来判断是哪一个按键被按下。
方法二:
行列扫描:我们可以通过高四位全部输出低电平,低四位输出高电平。当接收到的数据,低四位不全为高电平时,说明有按键按下,然后通过接收的数据值,判断是哪一列有按键按下,然后再反过来,高四位输出高电平,低四位输出低电平,然后根据接收到的高四位的值判断是那一行有按键按下,这样就能够确定是哪一个按键按下了。
此次采用的是行扫描方式,与单片机连接如下:
C4 -->PB7 C3–>PB6 C2–>PB5 C1–>PB4
R1–>PB3 R2–>PB2 R3–>PB1 R4–>PB0
**二.完整程序**
最开始我使用的是GPIOD的Pin0-Pin5,但是导致了LCD无法正常使用,猜测是GPIOD中的某个IO在LCD中也使用了,导致冲突,具体是哪一个还不知道(技术太菜,LCD里面太多内容,看不懂.....)
1.MatrixButton.h头文件:
#ifndef __MatrixButton_H
#define __MatrixButton_H
#include "sys.h"
#define DelayTimes 10
void GPIOF_Int_Init(void);
void GPIOB_Int_Init(void);
void KEY_Scan(void);
void Multiple_Control(void);
#endif
2.MatrixButton.c文件代码:
#include "MatrixButton.h"
#include "delay.h"
u16 KeyValue=17;//17只是为了在没有按键按下的时候给一个数值让LCD显示
void GPIOF_Int_Init(void) //(这个函数不属于矩阵按键配置,初始化所要控制的IO口)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);//使能GPIOF时钟
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;//IO输出引脚选用PF0-PF5
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;//输出模式
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//输出速度50MHZ
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_DOWN;//下拉
GPIO_Init(GPIOF,&GPIO_InitStructure);//初始化GPIOF
}
void GPIOB_Int_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);//使能GPIOB的时钟
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_OUT;//输出模式
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;
GPIO_Init(GPIOB,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN;//输入模式,用来检测哪一行按下
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;
GPIO_Init(GPIOB,&GPIO_InitStruct);
}
void KEY_Scan(void) //(行列扫描方式的矩阵按键配置)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_3); //第一行检测
GPIO_SetBits(GPIOB,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2);
if(((GPIOB->IDR )&0xF0)!=0xF0) //说明PD4-PD7状态发生变化,列检测
{
delay_ms(DelayTimes); //按键消抖
if(((GPIOB->IDR )&0xF0)!=0xF0) //再次判断是否有按键按下
{
switch((GPIOB->IDR )&0xF7)//检测输入数据寄存器PB4-PB7对应位的电平状态
{
case 0xE7:KeyValue=1;break;//说明PB4接收到低电平,第一行第一列对应第一个按键
case 0xD7:KeyValue=2;break;
case 0xB7:KeyValue=3;break;
case 0x77:KeyValue=4;break;
default:break;
}
}
}
GPIO_ResetBits(GPIOB,GPIO_Pin_2);
GPIO_SetBits(GPIOB,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_3);
if(((GPIOB->IDR )&0xF0)!=0xF0) //说明PD4-PD7状态发生变化,列检测
{
delay_ms(DelayTimes); //按键消抖
if(((GPIOB->IDR )&0xF0)!=0xF0) //再次判断是否有按键按下
{
switch((GPIOB->IDR )&0xFB)
{
case 0xEB:KeyValue=5;break;
case 0xDB:KeyValue=6;break;
case 0xBB:KeyValue=7;break;
case 0x7B:KeyValue=8;break;
default:break;
}
}
}
GPIO_ResetBits(GPIOB,GPIO_Pin_1); //Pin1输出低电平
GPIO_SetBits(GPIOB,GPIO_Pin_0|GPIO_Pin_2|GPIO_Pin_3);//Pin0,Pin2,Pin3输出高电平
if(((GPIOB->IDR )&0xF0)!=0xF0) //说明PD4-PD7状态发生变化,列检测
{
delay_ms(DelayTimes); //按键消抖
if(((GPIOB->IDR )&0xF0)!=0xF0) //再次判断是否有按键按下
{
switch((GPIOB->IDR )&0xFD)
{
case 0xED:KeyValue=9;break;
case 0xDD:KeyValue=10;break;
case 0xBD:KeyValue=11;break;
case 0x7D:KeyValue=12;break;
default: break;
}
}
}
GPIO_ResetBits(GPIOB,GPIO_Pin_0); //Pin0输出低电平
GPIO_SetBits(GPIOB,GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);//Pin1-Pin3输出高电平
if(((GPIOB->IDR )&0xF0)!=0xF0) //说明PD4-PD7状态发生变化,列检测
{
delay_ms(DelayTimes); //按键消抖
if(((GPIOB->IDR )&0xF0)!=0xF0) //再次判断是否有按键按下
{
switch((GPIOB->IDR )&0xFE)
{
case 0xEE:KeyValue=13;break;
case 0xDE:KeyValue=14;break;
case 0xBE:KeyValue=15;break;
case 0x7E:KeyValue=16;break;
default:break;
}
}
}
}
void Multiple_Control(void)//控制IO口输出(这个函数通过矩阵键盘的按键控制IO口输出)
{
if(KeyValue!=17) //说明有按键按下
{
switch(KeyValue)
{
case 1:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2);break;//000
}
case 2:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_1|GPIO_Pin_2);
GPIO_SetBits(GPIOF,GPIO_Pin_0);break;//001
}
case 3:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_0|GPIO_Pin_2);
GPIO_SetBits(GPIOF,GPIO_Pin_1);break;//010
}
case 4:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_2);
GPIO_SetBits(GPIOF,GPIO_Pin_0|GPIO_Pin_1);break;//011
}
case 5:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_0|GPIO_Pin_1);
GPIO_SetBits(GPIOF,GPIO_Pin_2);break;//100
}
case 6:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_1);
GPIO_SetBits(GPIOF,GPIO_Pin_0|GPIO_Pin_2);break;//101
}
case 7:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_0);
GPIO_SetBits(GPIOF,GPIO_Pin_1|GPIO_Pin_2);break;//110
}
case 8:
{
GPIO_SetBits(GPIOF,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2);break;//111
}
case 9:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5);break;//000
}
case 10:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_4|GPIO_Pin_5);
GPIO_SetBits(GPIOF,GPIO_Pin_3);break;//001
}
case 11:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_3|GPIO_Pin_5);
GPIO_SetBits(GPIOF,GPIO_Pin_4); break;//010
}
case 12:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_5);
GPIO_SetBits(GPIOF,GPIO_Pin_3|GPIO_Pin_4);break;//011
}
case 13:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_3|GPIO_Pin_4);
GPIO_SetBits(GPIOF,GPIO_Pin_5);break;//100
}
case 14:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_4);
GPIO_SetBits(GPIOF,GPIO_Pin_5|GPIO_Pin_3);break;//101
}
case 15:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_3);
GPIO_SetBits(GPIOF,GPIO_Pin_4|GPIO_Pin_5);break;//110
}
case 16:
{
GPIO_SetBits(GPIOF,GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5);break;//111
}
}
}
}
3.主函数main.c:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "MatrixButton.h"
#include "lcd.h"
extern u16 KeyValue;
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置系统中断优先级分组2
delay_init(168); //初始化延时函数
uart_init(115200); //初始化串口波特率为115200
LED_Init(); //初始化LED
GPIOF_Int_Init();
LED0=0;
LCD_Init(); //初始化LCD接口
GPIOB_Int_Init(); //初始化矩阵键盘所连接IO口
LCD_Display_Dir(1); //横屏显示
POINT_COLOR=RED;
while(1)
{
if(KeyValue!=KeyValue)//按键值改变时才清屏
LCD_Clear(WHITE);
LCD_ShowString(30,150,200,16,16,"KeyValue_is:"); //这里显示了KeyValue_is:
KEY_Scan(); //行扫描矩阵按键
LCD_ShowxNum(134,150,KeyValue,2,16,0);
Multiple_Control(); //矩阵按键控制IO口输出
LED0=!LED0;
delay_ms(50);
}
}
一 .矩阵按键原理
矩阵按键有两种扫描方式:
方法一:
逐行扫描:我们可以通过低四位轮流输出低电平来对矩阵键盘进行逐行扫描,当高四位接收到的数据不全为1的时候,说明有按键按下,然后通过接收到的数据是哪一位为0来判断是哪一个按键被按下。
方法二:
行列扫描:我们可以通过高四位全部输出低电平,低四位输出高电平。当接收到的数据,低四位不全为高电平时,说明有按键按下,然后通过接收的数据值,判断是哪一列有按键按下,然后再反过来,高四位输出高电平,低四位输出低电平,然后根据接收到的高四位的值判断是那一行有按键按下,这样就能够确定是哪一个按键按下了。
此次采用的是行扫描方式,与单片机连接如下:
C4 -->PB7 C3–>PB6 C2–>PB5 C1–>PB4
R1–>PB3 R2–>PB2 R3–>PB1 R4–>PB0
**二.完整程序**
最开始我使用的是GPIOD的Pin0-Pin5,但是导致了LCD无法正常使用,猜测是GPIOD中的某个IO在LCD中也使用了,导致冲突,具体是哪一个还不知道(技术太菜,LCD里面太多内容,看不懂.....)
1.MatrixButton.h头文件:
#ifndef __MatrixButton_H
#define __MatrixButton_H
#include "sys.h"
#define DelayTimes 10
void GPIOF_Int_Init(void);
void GPIOB_Int_Init(void);
void KEY_Scan(void);
void Multiple_Control(void);
#endif
2.MatrixButton.c文件代码:
#include "MatrixButton.h"
#include "delay.h"
u16 KeyValue=17;//17只是为了在没有按键按下的时候给一个数值让LCD显示
void GPIOF_Int_Init(void) //(这个函数不属于矩阵按键配置,初始化所要控制的IO口)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF,ENABLE);//使能GPIOF时钟
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5;//IO输出引脚选用PF0-PF5
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;//输出模式
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;//输出速度50MHZ
GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_DOWN;//下拉
GPIO_Init(GPIOF,&GPIO_InitStructure);//初始化GPIOF
}
void GPIOB_Int_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);//使能GPIOB的时钟
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_OUT;//输出模式
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_OType=GPIO_OType_PP;
GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;
GPIO_Init(GPIOB,&GPIO_InitStruct);
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN;//输入模式,用来检测哪一行按下
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStruct.GPIO_PuPd=GPIO_PuPd_UP;
GPIO_Init(GPIOB,&GPIO_InitStruct);
}
void KEY_Scan(void) //(行列扫描方式的矩阵按键配置)
{
GPIO_ResetBits(GPIOB,GPIO_Pin_3); //第一行检测
GPIO_SetBits(GPIOB,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2);
if(((GPIOB->IDR )&0xF0)!=0xF0) //说明PD4-PD7状态发生变化,列检测
{
delay_ms(DelayTimes); //按键消抖
if(((GPIOB->IDR )&0xF0)!=0xF0) //再次判断是否有按键按下
{
switch((GPIOB->IDR )&0xF7)//检测输入数据寄存器PB4-PB7对应位的电平状态
{
case 0xE7:KeyValue=1;break;//说明PB4接收到低电平,第一行第一列对应第一个按键
case 0xD7:KeyValue=2;break;
case 0xB7:KeyValue=3;break;
case 0x77:KeyValue=4;break;
default:break;
}
}
}
GPIO_ResetBits(GPIOB,GPIO_Pin_2);
GPIO_SetBits(GPIOB,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_3);
if(((GPIOB->IDR )&0xF0)!=0xF0) //说明PD4-PD7状态发生变化,列检测
{
delay_ms(DelayTimes); //按键消抖
if(((GPIOB->IDR )&0xF0)!=0xF0) //再次判断是否有按键按下
{
switch((GPIOB->IDR )&0xFB)
{
case 0xEB:KeyValue=5;break;
case 0xDB:KeyValue=6;break;
case 0xBB:KeyValue=7;break;
case 0x7B:KeyValue=8;break;
default:break;
}
}
}
GPIO_ResetBits(GPIOB,GPIO_Pin_1); //Pin1输出低电平
GPIO_SetBits(GPIOB,GPIO_Pin_0|GPIO_Pin_2|GPIO_Pin_3);//Pin0,Pin2,Pin3输出高电平
if(((GPIOB->IDR )&0xF0)!=0xF0) //说明PD4-PD7状态发生变化,列检测
{
delay_ms(DelayTimes); //按键消抖
if(((GPIOB->IDR )&0xF0)!=0xF0) //再次判断是否有按键按下
{
switch((GPIOB->IDR )&0xFD)
{
case 0xED:KeyValue=9;break;
case 0xDD:KeyValue=10;break;
case 0xBD:KeyValue=11;break;
case 0x7D:KeyValue=12;break;
default: break;
}
}
}
GPIO_ResetBits(GPIOB,GPIO_Pin_0); //Pin0输出低电平
GPIO_SetBits(GPIOB,GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);//Pin1-Pin3输出高电平
if(((GPIOB->IDR )&0xF0)!=0xF0) //说明PD4-PD7状态发生变化,列检测
{
delay_ms(DelayTimes); //按键消抖
if(((GPIOB->IDR )&0xF0)!=0xF0) //再次判断是否有按键按下
{
switch((GPIOB->IDR )&0xFE)
{
case 0xEE:KeyValue=13;break;
case 0xDE:KeyValue=14;break;
case 0xBE:KeyValue=15;break;
case 0x7E:KeyValue=16;break;
default:break;
}
}
}
}
void Multiple_Control(void)//控制IO口输出(这个函数通过矩阵键盘的按键控制IO口输出)
{
if(KeyValue!=17) //说明有按键按下
{
switch(KeyValue)
{
case 1:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2);break;//000
}
case 2:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_1|GPIO_Pin_2);
GPIO_SetBits(GPIOF,GPIO_Pin_0);break;//001
}
case 3:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_0|GPIO_Pin_2);
GPIO_SetBits(GPIOF,GPIO_Pin_1);break;//010
}
case 4:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_2);
GPIO_SetBits(GPIOF,GPIO_Pin_0|GPIO_Pin_1);break;//011
}
case 5:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_0|GPIO_Pin_1);
GPIO_SetBits(GPIOF,GPIO_Pin_2);break;//100
}
case 6:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_1);
GPIO_SetBits(GPIOF,GPIO_Pin_0|GPIO_Pin_2);break;//101
}
case 7:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_0);
GPIO_SetBits(GPIOF,GPIO_Pin_1|GPIO_Pin_2);break;//110
}
case 8:
{
GPIO_SetBits(GPIOF,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2);break;//111
}
case 9:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5);break;//000
}
case 10:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_4|GPIO_Pin_5);
GPIO_SetBits(GPIOF,GPIO_Pin_3);break;//001
}
case 11:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_3|GPIO_Pin_5);
GPIO_SetBits(GPIOF,GPIO_Pin_4); break;//010
}
case 12:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_5);
GPIO_SetBits(GPIOF,GPIO_Pin_3|GPIO_Pin_4);break;//011
}
case 13:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_3|GPIO_Pin_4);
GPIO_SetBits(GPIOF,GPIO_Pin_5);break;//100
}
case 14:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_4);
GPIO_SetBits(GPIOF,GPIO_Pin_5|GPIO_Pin_3);break;//101
}
case 15:
{
GPIO_ResetBits(GPIOF,GPIO_Pin_3);
GPIO_SetBits(GPIOF,GPIO_Pin_4|GPIO_Pin_5);break;//110
}
case 16:
{
GPIO_SetBits(GPIOF,GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5);break;//111
}
}
}
}
3.主函数main.c:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "MatrixButton.h"
#include "lcd.h"
extern u16 KeyValue;
int main(void)
{
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置系统中断优先级分组2
delay_init(168); //初始化延时函数
uart_init(115200); //初始化串口波特率为115200
LED_Init(); //初始化LED
GPIOF_Int_Init();
LED0=0;
LCD_Init(); //初始化LCD接口
GPIOB_Int_Init(); //初始化矩阵键盘所连接IO口
LCD_Display_Dir(1); //横屏显示
POINT_COLOR=RED;
while(1)
{
if(KeyValue!=KeyValue)//按键值改变时才清屏
LCD_Clear(WHITE);
LCD_ShowString(30,150,200,16,16,"KeyValue_is:"); //这里显示了KeyValue_is:
KEY_Scan(); //行扫描矩阵按键
LCD_ShowxNum(134,150,KeyValue,2,16,0);
Multiple_Control(); //矩阵按键控制IO口输出
LED0=!LED0;
delay_ms(50);
}
}
举报