- 当按键程序用固定延时的时候,会显的很呆板,并且还很长很长,这样显的程序也臃肿,所以我在网上查了很多按键程序,见到了各种各样的形式,最后只有一种在定时器里扫描按键的这个最合我心意,但代码都杂乱,下面是我自己修改的代码
#define S7 0x0E //按下s7拉低P30,下面同理
#define S6 0x0D
#define S5 0x0B
#define S4 0x07
unsigned char key_one=0;//按一次的标志位
unsigned char key_long=0;//长按的标志位
unsigned char key_scan()//独立按键,扫描函数
{
static unsigned char key_buf = 0x00;
static unsigned int key_time = 0;
static unsigned char key_one_temp = 0;
static unsigned char key_temp = 0;
P3=0x0F;
if(P3 != 0x0f)
{
key_temp = P3;
if(P3 != key_buf) //用来实现长按功能,如果不需要可以不加else
{
key_buf = P3;
key_one_temp = 1;
}
else
{
key_time++; //按键时间 = key_time *扫描时间
if(key_time == 100) //自己设定的时间,规定按键时长为多少
//就是长按
key_long = 1; //其实长按程序你可以自己发挥,是依具
//体情况来实现的
}
}
else
{
if(key_long !=0) //如果添加了长按,这是防止长按和按一次功能重叠
if(key_one_temp)//这是为了实现按下释放才算按一次,如果想
//按下就实现功能,可以不需要这功能,直接用key_one替换
//上面的key_one_temp
{
key_one = 1;
}
key_one_temp = 0;
key_long = 0;
key_buf = 0x00;
}
return key_temp;
}
//上面的程序我在2ms的扫描里面使用很稳定,但是只是相当于消抖2ms,可能会觉得
//不稳定,这是改进版,同样放在2ms扫描中,最高消抖时间为8ms
unsigned char key_scan()//改进版扫描函数
{
static unsigned char key_buf = 0x0E;
static unsigned int key_time = 0;
static unsigned char key_one_temp = 0;
static unsigned char key_temp = 0;
P3=0x0F;
if(P3 != 0x0f)
{
if(P3 == key_buf) //用来实现长按功能,如果不需要可以不加else
{
key_temp = P3;
key_one_temp = 1;
key_time++;
if(key_time > 100) //延时时间=key_time*扫描时间*4 800ms
{
key_one_temp=0;//同样是为了防止按一次和长按功能同时出现
//这里换成大于是有原因的,是因为长时间按
//会一直进来,然后key_one_temp会一直
//置1.
key_long=1;
}
}
}
else
{
if(key_one_temp)
{
key_one_temp = 0;
key_one = 1;
}
key_long = 0;
}
key_buf = _crol_(key_buf |0xF0,1);//循环左移 intrins.h里面
key_buf &= 0x0F;
if(key_buf == 0x0F)
key_buf= 0x0E;
return key_temp;
}
void key_handle(unsigned char val)//按键处理函数
{
if(key_one)
{
key_one=0;
switch(val)
{
case S7://你要处理是事件
break;
case S6://你要处理是事件
break;
case S5://你要处理是事件
break;
case S4://你要处理是事件
break;
}
}
if(key_long)
{
switch(val)
{
case S7://你要处理是事件
break;
case S6://你要处理是事件
break;
case S5://你要处理是事件
break;
case S4://你要处理是事件
break;
}
}
}
下面是矩阵的,和上面的大致差不多,只是蓝桥杯上用的stc15转接板,p36是p42,p37是p44,我先以正常的写一遍,然后在写一遍关于蓝桥杯的例程。
#define S7 0x7E //这是行扫描出来的结果,就是以行一行的拉低,
#define S6 0x7D //就比如先是让P3=0xFE,然后按下S7
#define S5 0x7B //P30 P37都被拉低,就是0x7E
#define S4 0x77
#define S11 0xBE
#define S10 0xBD
#define S9 0xBB
#define S8 0xB7
#define S15 0xDE
#define S14 0xDD
#define S13 0xDB
#define S12 0xD7
#define S19 0xEE
#define S18 0xED
#define S17 0xEB
#define S16 0xE7
unsigned char key_scan()
{
static unsigned char key_buf = 0;
static unsigned char key_sca = 0x01;
static unsigned int key_time = 0;
static unsigned char key_one_temp = 0;
static unsigned char key_temp = 0;
P3 = (~key_sca);
if(P3 != (~key_sca))
{
key_temp = P3;
if(P3 == key_buf)
{
key_buf = P3;
key_one_temp = 1;
}
else
{
key_time++;
if(key_time == 100) //按键时间=key_time*扫描时间*4
{
key_one_temp=0;
key_long=1;
}
}
}
else
{
if(key_one_temp)
{
key_one_temp = 0;
key_one = 1;
}
key_long = 0;
key_buf = 0;
}
key_sca <<=1;
if(key_sca == 0x10)
key_sca =0x01;
//也可以直接用 key_sca = _crol_(key_sca,1);
return key_temp;
}
//然后处理和独立按键是一样的,只不过case语句多一点
//下面就是关于蓝桥杯的处理方法
unsigned cahr key_read()
{
unsigned char temp = P3&0x3f;//清掉高两位,以便读取P42 P44
if(P42 == 1)
{
temp |= 0x40;
}
if(P44 == 1)
{
temp |= 0x80;
}
return temp;
}
unsigned char key_scan()
{
static unsigned char key_buf = 0;
static unsigned char key_sca = 0x01;
static unsigned int key_time = 0;
static unsigned char key_one_temp = 0;
static unsigned char key_temp = 0;
P3 = (~key_sca);
P42 = (~key_sca)>>6;
P44 = (~key_sca)>>7;
if(key_read() != (~key_sca))
{
key_temp = P3;
if(key_read() == key_buf)
{
key_buf = P3;
key_one_temp = 1;
}
else
{
key_time++;
if(key_time == 100) //按键时间=key_time*扫描时间*4
{
key_one_temp=0;
key_long=1;
}
}
}
else
{
if(key_one_temp)
{
key_one_temp = 0;
key_one = 1;
}
key_long = 0;
key_buf = 0;
}
key_sca <<=1;
if(key_sca == 0x10)
key_sca =0x01;
//也可以直接用 key_sca = _crol_(key_sca,1);
return key_temp;
}
很忏愧,没有检验就把代码贴出来了,只是凭自己的思路写代码漏洞还是比较多的,下面是更改后的代码,因为按键扫描的扫描线在变化,就不能想独立按键那样处理了。废话不多说,下面是测验过的代码
unsigned char key_scan()
{
static unsigned char scan = 0x01;
static bit key_flag = 0;
static bit key_one_flag = 0;
static unsigned int key_time = 0;
static unsigned char key_dat = 0;
unsigned char temp;
static unsigned char scan_time = 0;
P3 = (~scan)&0x3F;
P42 = 1;
P44 = 1;
temp = key_read();
if(temp != (~scan))
{
key_flag = 1;
key_one_flag = 1;
key_dat = temp;
key_time++; //2ms*4 加一次 1s代表长按键
if(key_time >= 125)
{
key_long = 1;
key_one_flag = 0;
}
}
else
{
if(key_flag)
scan_time++;
else
{
scan_time=0;
if(key_one_flag == 1)
{
key_one = 1;
key_one_flag = 0;
}
key_time = 0;
key_long = 0;
}
if(scan_time == 3)//如果按键还按着,那么会是key_flag在一次之1.反之就不会代表结束按键。
{
key_flag = 0;
scan_time = 0;
}
}
scan <<= 1;
if(scan == 0x10)
scan = 0x01;
return key_dat;
}
希望对大家有所帮助,如果有什么问题,可以留言,让我们共同解决,如果能和你们交流,是我莫大的荣幸。