大家好,这段时间又重新在学习51单片机,单片机这东东真的是要一直学,一直做项目才行,之前做按键和数码管显示的时候,实际也只是了解了一点皮毛,再次深入学习后才体会到,要搞好这东东,真的要不同的思路去扩展。先简单说一下我的开发板硬件,数码管采用两片74HC573 来实现,段选P26,位选P27,采用共阳数码管,在P0口送对应数来实现数码管的显示;
四个独立按键P32,P33,P34,P35,LED发光管有八个,P10--P17,发光管在输出低电平时点亮,
那么关于按键和数码管的显示,网上也有很多例子了。
第一类:关于延时的程序,如果采用延时消抖动,那么有可能按下后显示不灵等,那么我建议用LED的显示来抵消这个延时的做法,但一般项目的开法都不会用延时来消抖,在这里只是提供一个思路。
sbit KEY1 = P3^2; //假定P3^2代表KEY1键,按下为0
if(!KEY1 ) //表明有键按下
{
// Delayms(10); 一般情况下我们都用Delay 10ms 来消抖
为了程序的效率,和显示等,我们这里可以用数码管显示的时间来抵消,
ledscan(); //数码管一般也以10MS 100HZ无闪烁设计的。
if(!KEY1 )
{
while(!KEY1) //释放消抖
{
KEY1 = 1; //先输出高电平
ledscan(); //在等待的这个时间来显示
}
// fun1(); 这里是我们按键按下的功能程序
}
}
第二类,我们直接以10MS定时器查询来实现,也可以采用定时器2MS,多读数几次,比如8次以上都是,则实现按键确认
unsigned char KeySta[1] = //该定义属于全局变量
{
0xff
};
//下面定义在定时器查询程序里面
static unsigned char Keybuf[1] = //按键扫描缓冲区,保存一段时间内的扫描值
{
0xFF
};
Keybuf[0] = (Keybuf[0]<< 1) | KEY1; //KEY1 循环8次
if( Keybuf[0] ==0) //连续8次都是0
{
KeySta[0] = 0 ; //0表示有按下
}
else if( Keybuf[0] ==1) ///连续8次都是1
{
KeySta[0] = 1 ;
}
else //未稳定状态,则不管他,这里是为了程序的完整性
{
}
}
第三类:采用状态机的写法
状态机也是按10MS定时中断去确认按键状态,以使程序简化
unsigned char keycode = 0; //这个是全局变量,表示按键代码
//下面在定时中断10MS到的函数中实现
static unsigned char Key_state = 0;
unsigned char Keypress = 0xff; //未按下为0xff;
P3 = 0xff;
Keypress &= P3
switch(Key_state )
{
case 0:
if(Keypress!=0xff)//表示有键按下
{
Key_state = 1;//进入S1
}
break;
case 1:
if(Keypress!=0xff) //表示确认有键按下
{
Key_state = 2;//进入S1
if( !KEY )
{
keycode = 0x01; //假如说我们KEY1按下的代码是0x01
}
}
else
{
Key_state = 0; //误动作,返回0
}
break;
case 2:
if(Keypress==0xff) //释放
{
switch(keycode)
{
case 0x01: //按键KEY1的功能函数
break;
default:
break;
}
Key_state = 0; //如果有长按,则可以进入长按的状态等等。
}
else //等待释放
{
Key_state = 2;
}
default:
break;
}
当然为了减轻定时中断的负担,关于按键功能的程序可在主程序中去执行,在此不再详述。
第四次:新型的TRG的写法
核心算法如下: unsigned char Trg;
unsigned char Cont;
void KeyRead( void )
{
unsigned char ReadData =P3^0xff; // 1
Trg = ReadData & (ReadData ^Cont); // 2
Cont = ReadData; // 3
}
在定时中断函数里每10MS去检测一次按键情况,并执行。
|