三、蓝桥杯练习笔记之矩阵键盘

矩阵键盘和独立键盘类似,此篇只讲矩阵键盘。

CT107D-按键电路

 利用状态机进行消抖:

代码演示:数码管显示按键键值

#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;//清除计数
	}
}

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值