从单片机基础到程序框架(全集 2019pdf版).pdf - 第439页
/* 注释一: * “长按”与 “短按”的识 别过程: * 第一步:平 时只要 K1 没有 被按下,按键 的自锁标 志 Su8KeyLo ck1 和去抖动延 时计数器 Su 16KeyCnt1 * 一直被清零。此时属于按 键“ 松手时间” ,因 此同时检 测“短按”标志 Su8KeyShort Flag * 是否有效,如果有效就触 发一次 “短按” 。 * 第二步:一 旦 K1 按键被按下 ,去抖动延时 计数器 Su 16KeyCnt1…

{
P3_4=0;
}
void BeepClose(void)
{
P3_4=1;
}
void LedOpen(void)
{
P1_4=0;
}
void LedClose(void)
{
P1_4=1;
}
void VoiceScan(void)
{
static unsigned char Su8Lock=0;
if(1==vGu8BeepTimerFlag&&vGu16BeepTimerCnt>0)
{
if(0==Su8Lock)
{
Su8Lock=1;
BeepOpen();
}
else
{
vGu16BeepTimerCnt--;
if(0==vGu16BeepTimerCnt)
{
Su8Lock=0;
BeepClose();
}
}
}
}

/* 注释一:
* “长按”与“短按”的识别过程:
* 第一步:平时只要 K1 没有被按下,按键的自锁标志 Su8KeyLock1 和去抖动延时计数器 Su16KeyCnt1
* 一直被清零。此时属于按键“松手时间”,因此同时检测“短按”标志 Su8KeyShortFlag
* 是否有效,如果有效就触发一次“短按”。
* 第二步:一旦 K1 按键被按下,去抖动延时计数器 Su16KeyCnt1 开始在定时中断函数里累加,在还没
* 累加到阀值 KEY_SHORT_TIME 和 KEY_LONG_TIME 时,如果在这期间由于受外界干扰或者
* 按键抖动,而使 IO 口突然瞬间触发成高电平,这个时候马上把延时计数器 Su16KeyCnt1 清零,
* 这个过程非常巧妙,非常有效地去除瞬间的杂波干扰。
* 第三步:如果 K1 按键按下的时间超过了“短按”阀值 KEY_SHORT_TIME,马上把“短按”标志
* Su8KeyShortFlag 置 1,如果此时还没有松手,直到发现按下的时间超过“长按”阀值
* KEY_LONG_TIME 时,先把“短按”标志 ucShortTouchFlag1 清零,然后触发“长按”,同时,为
* 了防止按住按键不松手后一直触发,要及时把 Su8KeyLock1 置 1“自锁”。
* 第四步:等 K1 按键松手后,自锁标志 Su8KeyLock1 及时清零,为下一次自锁做准备,同时,也检测
* “短按”标志 Su8KeyShortFlag 是否有效,如果有效就触发一次“短按”。
*/
void KeyScan(void) //此函数放在定时中断里每 1ms 扫描一次
{
static unsigned char Su8KeyLock1;
static unsigned int Su16KeyCnt1;
static unsigned char Su8KeyShortFlag=0; //按键“短按”触发的标志
if(0!=KEY_INPUT1)//单个 K1 按键没有按下,及时清零一些标志。
{
Su8KeyLock1=0; //按键解锁
Su16KeyCnt1=0; //去抖动延时计数器清零,此行非常巧妙,是全场的亮点。
if(1==Su8KeyShortFlag) //松手的时候,如果“短按”标志有效就触发一次“短按”
{
Su8KeyShortFlag=0; //先清零“短按”标志避免一直触发。
vGu8SingleKeySec=1; //触发 K1 的“短按”
}
}
else if(0==Su8KeyLock1)//单个按键 K1 被按下
{
Su16KeyCnt1++; //累加定时中断次数
if(Su16KeyCnt1>=KEY_SHORT_TIME) //“短按”兼“滤波”的“稳定时间”KEY_SHORT_TIME
{
//注意,这里不能“自锁”。后面“长按”触发的时候才“自锁”。
Su8KeyShortFlag=1; //K1 的“短按”标志有效,待松手时触发。
}

if(Su16KeyCnt1>=KEY_LONG_TIME) //“长按”兼“滤波”的“稳定时间”KEY_LONG_TIME
{
Su8KeyLock1=1; //此时“长按”触发才“自锁”
Su8KeyShortFlag=0; //既然此时“长按”有效,那么就要废除潜在的“短按”。
vGu8SingleKeySec=2; //触发 K1 的“长按”
}
}
}
void SingleKeyTask(void) //单击按键任务函数,放在主函数内
{
if(0==vGu8SingleKeySec)
{
return; //按键的触发序号是 0 意味着无按键触发,直接退出当前函数,不执行此函数下面的代码
}
switch(vGu8SingleKeySec) //根据不同的按键触发序号执行对应的代码
{
case 1: //K1“短按”触发的任务
if(0==Gu8LedStatus)
{
Gu8LedStatus=1;
LedOpen(); //LED 亮
}
else
{
Gu8LedStatus=0;
LedClose(); //LED 灭
}
vGu8SingleKeySec=0; //响应按键服务处理程序后,按键编号必须清零,避免一直触发
break;
case 2: //K1“长按”触发的任务
vGu8BeepTimerFlag=0;
vGu16BeepTimerCnt=KEY_VOICE_TIME; //触发一次“长按”后,发出“嘀”一声
vGu8BeepTimerFlag=1;
vGu8SingleKeySec=0; //响应按键服务处理程序后,按键编号必须清零,避免一直触发
break;
}
}