矩阵键盘和独立键盘类似,此篇只讲矩阵键盘。
![](https://img-blog.csdnimg.cn/3a59b207887342a6ae07a2fa93f8cc6d.png?x-oss-process=image/watermark,type_d3F5LXplbmhlaQ,shadow_50,text_Q1NETiBA5YeJ5rKz,size_20,color_FFFFFF,t_70,g_se,x_16)
利用状态机进行消抖:
代码演示:数码管显示按键键值
#include <STC15F2K60S2.H>
bit Key_Flag; //按键读取标志
unsigned char Key_Flag_Cnt; //按键读取时间计数
unsigned char Key_Value; //装载按键值
unsigned char code t_display[]={ //标准字库
// 0 1 2 3 4 5 6 7 8 9 A B C D E F
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71,
//black - H J K L N o P U t G Q r M y
0x00,0x40,0x76,0x1E,0x70,0x38,0x37,0x5C,0x73,0x3E,0x78,0x3d,0x67,0x50,0x37,0x6e,
0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF,0x46}; //0. 1. 2. 3. 4. 5. 6. 7. 8. 9. -1
unsigned char code T_COM[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //位码
void Set_Hc573(unsigned char Yx) //需要开启的锁存器YX,4 = LED;5 = 蜂鸣器和继电器。
{
P2 &= 0X1F;
P2 |= Yx << 5;
P2 &= 0X1F;
}
void Init_Sys(void) //关闭蜂鸣器继电器、LED
{
P0 = 0XFF;
Set_Hc573(4);
//
P0 &= 0XAF;
Set_Hc573(5);
}
unsigned char Read_Key() //状态机按键识别
{
static unsigned char Key_State,Key_Dat;//静态变量存储状态和按键值,进入时数值被更改
unsigned char Key_Press,Key_L,Key_H; //行列值
P30 = 0;P31 = 0;P32 = 0;P33 = 0; //低位0
P34 = 1;P35 = 1;P42 = 1;P44 = 1; //高位1
if(P44 == 0) //如果P44变低电平
Key_L = 0X70; //列值为0x70
else if(P42 == 0)
Key_L = 0XB0;
else if(P35 == 0)
Key_L = 0XD0;
else if(P34 == 0)
Key_L = 0XE0;
else
Key_L = 0XF0; //没有按键按下,则等于0xF0
P30 = 1;P31 = 1;P32 = 1;P33 = 1; //低位1
P34 = 0;P35 = 0;P42 = 0;P44 = 0; //高位0
if(P30 == 0) //如果P30变低电平
Key_H = 0X07; //行值变0x07
else if(P31 == 0)
Key_H = 0X0B;
else if(P32 == 0)
Key_H = 0X0D;
else if(P33 == 0)
Key_H = 0X0E;
else
Key_H = 0X0F; //没有按键按下,则等于0x0F
Key_Press = Key_L | Key_H; //行列进行组合,确定是哪一个按键按下
switch(Key_State) //判断状态
{
case 0: //如果一直没有按键按下,则一直在状态0
if(Key_Press != 0XFF) //如果组合起来不等于0xFF,则说明有按键按下
Key_State = 1; //进入下一个状态,过滤掉抖动,10ms
else
Key_Dat = 0;
break;
case 1:
if(Key_Press == (Key_L | Key_H)) //如果键值没有改变
{
switch(Key_Press) //判断是哪一个按键按下
{
case 0X7E:Key_Dat = 4;break;//如果是0x7E的话说明是S4按下
case 0X7D:Key_Dat = 5;break;
case 0X7B:Key_Dat = 6;break;//如果是0x7B的话说明是S6按下
case 0X77:Key_Dat = 7;break;//**其他也一样,不就一一说明**
//
case 0XBE:Key_Dat = 8;break;
case 0XBD:Key_Dat = 9;break;
case 0XBB:Key_Dat = 10;break;
case 0XB7:Key_Dat = 11;break;
//
case 0XDE:Key_Dat = 12;break;
case 0XDD:Key_Dat = 13;break;
case 0XDB:Key_Dat = 14;break;
case 0XD7:Key_Dat = 15;break;
//
case 0XEE:Key_Dat = 16;break;
case 0XED:Key_Dat = 17;break;
case 0XEB:Key_Dat = 18;break;
case 0XE7:Key_Dat = 19;break;
}
Key_State = 2; //更改到下一个状态
}
else
Key_State = 0; //如果键值不一致(不到10ms就松手了,或者误触到)则返回到状态0
break;
case 2:
if(Key_Press == 0XFF) //等待按键松手,返回到状态0
Key_State = 0;
break;
}
return Key_Dat; //返回按键的键值
}
void Set_SMG(unsigned char Dat1,unsigned char Dat2) //设置显示
{
P0 = T_COM[Dat1]; //位选
Set_Hc573(6); //开位选
P0 = ~ t_display[Dat2]; //段选
Set_Hc573(7);
P0 = 0XFF; //消隐
Set_Hc573(7); //开段选
}
void Timer0Init(void) //1毫秒@12.000MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x20; //设置定时初始值
TH0 = 0xD1; //设置定时初始值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA = 1;
ET0 = 1;
}
void main()
{
unsigned char G;
unsigned char S;
Init_Sys(); //系统初始化,关掉其他无用设备
Timer0Init(); //初始化中断
while(1)
{
S = Key_Value / 10; //获取键值十位
G = Key_Value % 10; //获取键值个位
Set_SMG(0,S); //在第一个数码管显示按键的十位
Set_SMG(1,G); //在第二个数码管显示按键的个位
if(Key_Flag) //读取键值,10ms读取一次
{
Key_Value = Read_Key(); //读取按键,获取键值
Key_Flag = 0; //清除标志位
}
}
}
void Timer0() interrupt 1 //中断服务函数
{
Key_Flag_Cnt ++; //计数
if(Key_Flag_Cnt >= 10) //10ms读取一次
{
Key_Flag = 1; //允许按键扫描
Key_Flag_Cnt = 0;//清除计数
}
}