标题1:不使用Delay消抖的按键扫描
标题2:定时扫描按键思路
标题3:实验总结
不使用Delay消抖的按键扫描:
unsigned char value,ms,flag;
unsigned char key_value()
{
unsigned char key_press,key_flag,key_temp;
temp=(P3&0x0f); //按键状态初始化,此时状态为没有按键按下
if(temp!=0x0f) //如果有按键按下
key_press++;
else
key_press=0; //抖动key_press置0
if(key_press==5) //此处含义并不是按下5次才记录数值,此函数在无限循环里,51单片机执行速率很快
{
key_flag=1; //代表一定的时间内没有松手,配合抖动置0,从而达到消抖的效果
key_press=0;
switch(temp)
{
case 0x0e: value=1;break;
case 0x0d: value=2;break;
case 0x0b: value=3;break;
case 0x07: value=4;break;
}
}
if((key_flag==1)&&(temp==0x0f)) //连续五次检查到按键按下并最后松开了按键
return value;
return 0xff; //没有按下按键或者没有按下
}
void Timer0_Proc() interrupt 1 //已初始化1ms的定时器,此函数为中断服务函数,interrupt1为优先级
{
if(++ms==10)
{
ms=0;
flag=1; //flag为1表示在主函数内扫描按键,此处10ms扫描一次
}
}
void main()
{
unsigned char key_temp;
while(1)
{
if(flag) //10ms扫描
{
flag=0;
key_temp=key_value();
}
//接下来就是描述你想通过按键实现的效果
}
}
定时扫描的思路:
通过定时器的定时功能,设置一个flag变量,在一定的时间内flag在1、0之间变化,1表示扫描。在主函数main里设置一个变量来承接扫描所得值。
实验总结:
下面为在实验现象为在COM123显示的,按下独立按键S7(代表数值1),数码管上显示的数值+1,按下S6(代表数值2),数码管上显示的数值-1的实例代码:
#include <STC15F2K60S2.H>
code unsigned char tab[] = { 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90, 0xff};
unsigned char ms,flag;
unsigned char d[8]={10,10,10,10,10,10,10,10},w;
unsigned char key_press,key_flag,keyvalue;
void display();
unsignedx` char key_value();
//关闭蜂鸣器
void cls_buzz()
{
P2=(P2&0x1f)|0xa0;
P0=0x00;
P2&=0x1f;
}
//关闭LED
void cls_led()
{
P2=(P2&0x1f)|0x80;
P0=0xff;
P2&=0x1f;
}
//定时器初始化
void Timer0Init(void) //1毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xCD; //设置定时初值
TH0 = 0xD4; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA=1;
ET0=1;
}
//主函数
void main()
{
unsigned char num,temp1;
Timer0Init();
cls_buzz();
cls_led();
while(1)
{
if(flag)
{
flag=0;
temp1=key_value();
}
switch(temp1)
{
case 1:
num++;break;
case 2:
num--;break;
}
temp1=0; //完成按键处理程序 清理键值
if(num>=100)
d[5]=num/100;
else
d[5]=10;
if(num>=10)
d[6]=num%100/10;
else
d[6]=10;
d[7]=num%10;
}
}
//中断服务函数
void Timer0_Proc() interrupt 1
{
display();
if(++ms==10)
{
ms=0;
flag=1;
}
}
//按键处理
unsigned char key_value()
{
unsigned char temp;
temp=P3&0x0f;
if(temp!=0x0f) //有按键按下
key_press++;
else //有抖动
key_press=0;
if(key_press==5)
{
key_flag=1;
key_press=0;
switch(temp)
{
case 0x0e:
keyvalue=1;break;
case 0x0d:
keyvalue=2;break;
case 0x0b:
keyvalue=3;break;
case 0x07:
keyvalue=4;break;
}
}
if((key_flag==1)&&(temp==0x0f)) //连续5次检测到按键按下并已经松开
{
key_flag=0;
return keyvalue;
}
return 0xff; //无按键按下或者按下未松开
}
//数码管处理函数
void display()
{
//消影
P2=(P2&0x1f)|0xe0;
P0=0xff;
P2&=0x1f;
//位选
P2=(P2&0x1f)|0xc0;
P0=(1<<w);
P2&=0x1f;
//段选
P2=(P2&0x1f)|0xe0;
P0=tab[d[w]];
P2&=0x1f;
//刷新
if(++w==8)
{
w=0;
}
}
因为中断服务函数是按照初始化定时器时的定时时间来持续间断的执行的不需要放在主函数内,且扫描与按键扫描频率一致,而数码管显示的数字需要根据每次按键的变化而变化,故而将数码管显示的函数同样放在1ms的中断服务函数内,保持频率一致。