一.原理
实现长按,就是判断按键按下的时间,可以通过计时器实现,简单说就是在按下按键后开始计时,若计时小于一定阈值(如1s)则判定为短按,执行一定的操作,否则判定为长按,执行另一种操作.(如连加操作)
连加操作原理:在若识别为长按,则进入while 循环中判断时间(此处时间是自增的周期,与判断长短按不同,但都是利用计时器,以确保数码管正常显示)同时进行数码管的显示.
双击的实现原理:在检测按键按下的时候置一个标志位,并使其在一个while 中,同时打开定时器定时,如果在一定时间间隔内(如1ms)没有再次检测按键按下,则为单击,如果检测到按下,则为双击,同时为防止第一次按下时进入后面是否双击的判断,可以在前面加入一个循环,按键第一次按下的时候一直处于该循环
碎碎念:在涉及到长按的时候可以不用在扫描之后加上while防止多次触发,因为在读取按下时间的时候可以顺带的防止多次触发
二.练习
1.利用按键S4实现短按加1(若数据>100,则置0),和长按(按键按下时长大于1s)清零的效果.
2利用长按实现连加效果
3实现长按清零,单击加一,双击加五的操作
三.代码实现
1.
#include <REGX52.H>
unsigned char code SMG_NoDot[18]={0xc0,0xf9,
0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
0x88,0x80,0xc6,0xc0,0x86,0x8e,0xbf,0x7f};//数码管段选表
unsigned char Time_count=0;//按键按下时间
unsigned char Key_Flag=0;计时器开启标志位
unsigned char SMG_data=0;
void DelaySMG(unsigned int t)
{
while(t--);
}
void Select_HC573(unsigned char channel,unsigned char dat)//573选择
{
switch(channel)
{
case 4:
P2=(P2&0x1f)|0x80;
break;
case 5:
P2=(P2&0x1f)|0xa0;
break;
case 6:
P2=(P2&0x1f)|0xC0;
break;
case 7:
P2=(P2&0x1f)|0xe0;
break;
}
P0=dat;
P2=(P2&0x1f)|0x00;
}
void SMG_ShowBit(unsigned char pos,unsigned char dat)
{
Select_HC573(6,0x01<<(pos-1));
Select_HC573(7,dat);
DelaySMG(500);
Select_HC573(6,0x01<<(pos-1));
Select_HC573(7,0xff);
}
void SMG_Dynamic()//数码管动态显示
{
SMG_ShowBit(1,SMG_NoDot[15]);
SMG_ShowBit(6,SMG_NoDot[SMG_data/100]);
SMG_ShowBit(7,SMG_NoDot[(SMG_data/10)%10]);
SMG_ShowBit(8,SMG_NoDot[SMG_data%10]);
}
void ScanKey()
{
if(P3^2==0)
{
DelaySMG(500);
if(P3_3==0)
{
Time_count=0;//计时清零
Key_Flag=1;//打开计时标志位
while(P3_3==0)//松手前不执行操作
{
SMG_Dynamic();
}
Key_Flag=0;//按键抬起,计时结束
if(Time_count>=20)// 长按情况
{
SMG_data=0;
Time_count=0;
}
else//短按情况
{
SMG_data++;
if(SMG_data>100)
{
SMG_data=0;
}
}
}
}
}
void Timer0_Init()//定时器初始话
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
TMOD=0x01;
EA=1;
ET0=1;
TR0=1;
}
void Timer0Service() interrupt 1//定时器服务函数
{
TH0=(65536-50000)/256;
TL0=(65536-50000)%256;
if(Key_Flag==1)
{
Time_count++;
}
}
void Sys_Init()//系统初始化
{
Timer0_Init();
Select_HC573(4,0xff);
Select_HC573(5,0x00);
}
void main()
{
Sys_Init();
while(1)
{
SMG_Dynamic();
ScanKey();
}
}
2.将 ScanKey替换为下列代码
void ScanKey()
{
if(P3^2==0)
{
DelaySMG(500);
if(P3_3==0)
{
Time_count=0;
Key_Flag=1;
while(P3_3==0)
{
SMG_Dynamic();
if(Time_count>=20)//判断是否为长按
{
while(P3_3==0)
{
SMG_Dynamic();//在进入自增前仍然保持显示
if(Time_count>=5)
{
SMG_data++;
Time_count=0;//清零以维持周期
}
}
}
}
Time_count=0;
Key_Flag=0;//判断结束
if(Time_count<20)
{
SMG_data++;
if(SMG_data>100)
{
SMG_data=0;
}
}
}
}
}
3.三种模式复合
#include <STC15F2K60S2.H>
sbit S4=P3^3;
sbit S5=P3^2;
sbit S6=P3^1;
sbit S7=P3^0;
unsigned char times;
unsigned char Key_times;
unsigned char gap_times;
bit gap_Flag=0;
bit Key_Flag=0;
code unsigned char SMG_Nodot[] =
{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e};
void Delay_SMG(unsigned int t)
{
while(t--);
}
void SelectHC573(unsigned char channel,unsigned char dat)
{
P0=dat;
switch(channel)
{
case 4:
P2=(P2&0x1f)|0x80;
break;
case 5:
P2=(P2&0x1f)|0xa0;
break;
case 6:
P2=(P2&0x1f)|0xc0;
break;
case 7:
P2=(P2&0x1f)|0xe0;
break;
}
P2=(P2&0x1f)|0x00;
}
void SMG_Display(unsigned char pos,unsigned char dat)
{
SelectHC573(6,0x01<<(pos-1));
SelectHC573(7,dat);
Delay_SMG(500);
SelectHC573(6,0x01<<(pos-1));
SelectHC573(7,0xff);
}
void Displya_Dynamic()
{
SMG_Display(7,SMG_Nodot[times/10]);
SMG_Display(8,SMG_Nodot[times%10]);
}
void Timer1Init(void) //10??@12.000MHz
{
AUXR &= 0xBF; //?????12T??
TMOD &= 0x0F; //???????
TL1 = 0xF0; //??????
TH1 = 0xD8; //??????
TF1 = 0; //??TF1??
TR1 = 1; //???1????
ET1=1;
EA=1;
}
void Timer1_Service() interrupt 3
{
if(Key_Flag==1)
{
Key_times++;
}
if(gap_Flag==1)
{
gap_times++;
}
}
void Scan_Key()
{
if(S4==0)
{
Delay_SMG(500);
if(S4==0)
{
gap_Flag=0;
Key_Flag=1;
while(S4==0)
{
Displya_Dynamic();
}
Key_Flag=0;
if(Key_times>100)
{
times=0;
}
if(Key_times<100)
{
gap_Flag=1;
while(gap_Flag==1)
{
Displya_Dynamic();
if(gap_times>12)
{
times++;
gap_Flag=0;
}
if(S4==0&&gap_times<12)
{
times+=5;
gap_Flag=0;
}
}
}
gap_times=0;
Key_times=0;
}
while(S4==0)
{
Displya_Dynamic();
}
}
}
void Sys_Init()
{
SelectHC573(4,0xff);
SelectHC573(5,0x00);
Timer1Init();
}
void main()
{
Sys_Init();
while(1)
{
Displya_Dynamic();
Scan_Key();
}
}
四.疑问:
1.在编写代码时候误用P3^3来表示S4程序实现问题,不清楚P3^3与P3_3的区别.