从单片机基础到程序框架(全集 2019pdf版).pdf - 第445页

Su16KeyCon tinuityCn t1=0; //清零 ,为了继续连 击。 vGu8KeySec =1; //触发一次 K 1 按键 vGu8Shield VoiceFlag =1; //把当前按键 触发的声音屏 蔽掉 } } //K2 按键 if(0!=KEY_ INPUT2) { Su8KeyLock 2=0; Su16KeyCnt 2=0; Su16KeyCon tinuityCn t2=0; } else if(0= =…

100%1 / 836
* 间超过“从单击进入连击的间隔时间”阀值 KEY_ENTER_CONTINUITY_TIME 时,从此进入“连击”
* 的模式,连击计数器 Su16KeyContinuityCnt1 开始累加,每到达一次阀
* KEY_CONTINUITY_TIME 就触发 1 次按键,为了屏蔽按键声音及时把 vGu8ShieldVoiceFlag 也置 1,
* 同时,Su16KeyContinuityCnt1 马上清零为继续连击作准备。
* 第四步:等 K1 按键松手后,自锁标志 Su8KeyLock1、去抖动延时计数 Su16KeyCnt1、
* 连击计数器 Su16KeyContinuityCnt1,及时清零,为下一次按键触发做准备。
*/
void KeyScan(void) //此函数放在定时中断里每 1ms 扫描一次
{
static unsigned char Su8KeyLock1;
static unsigned int Su16KeyCnt1;
static unsigned int Su16KeyContinuityCnt1; //连击计数器
static unsigned char Su8KeyLock2;
static unsigned int Su16KeyCnt2;
static unsigned int Su16KeyContinuityCnt2; //连击计数器
//K1 按键
if(0!=KEY_INPUT1)//单个 K1 键没有按下,及时清零一些标志。
{
Su8KeyLock1=0; //按键解锁
Su16KeyCnt1=0; //去抖动延时计数器清零,此行非常巧妙,是全场的亮点
Su16KeyContinuityCnt1=0; //连击计数器
}
else if(0==Su8KeyLock1)//单个按键 K1 被按下
{
Su16KeyCnt1++; //累加定时中断次数,每一次累加额度是 1ms
if(Su16KeyCnt1>=KEY_SHORT_TIME) //按键的“滤波”时间 25ms
{
Su8KeyLock1=1; //“自锁”
vGu8KeySec=1; //触发一次 K1 按键
Su16KeyCnt1=0; //清零,为了下一步用来累加“从单击进入连击的间隔时间 300ms”
}
}
else if(Su16KeyCnt1<=KEY_ENTER_CONTINUITY_TIME)//按住不松手累加到 300ms
{
Su16KeyCnt1++; //累加定时中断次数,每一次累加额度是 1ms
}
else //按住累加到 300ms 后仍然不放手,这个时候进入有节奏的连续触发
{
Su16KeyContinuityCnt1++; //连击计数器开始累加,每一次累加额度 1ms
if(Su16KeyContinuityCnt1>=KEY_CONTINUITY_TIME) //按住没松手,每 0.08 秒就触发一
{
Su16KeyContinuityCnt1=0; //清零,为了继续连击。
vGu8KeySec=1; //触发一次 K1 按键
vGu8ShieldVoiceFlag=1; //把当前按键触发的声音屏蔽掉
}
}
//K2 按键
if(0!=KEY_INPUT2)
{
Su8KeyLock2=0;
Su16KeyCnt2=0;
Su16KeyContinuityCnt2=0;
}
else if(0==Su8KeyLock2)
{
Su16KeyCnt2++;
if(Su16KeyCnt2>=KEY_SHORT_TIME)
{
Su8KeyLock2=1;
vGu8KeySec=2; //触发一次 K2 按键
Su16KeyCnt2=0;
}
}
else if(Su16KeyCnt2<=KEY_ENTER_CONTINUITY_TIME)
{
Su16KeyCnt2++;
}
else
{
Su16KeyContinuityCnt2++;
if(Su16KeyContinuityCnt2>=KEY_CONTINUITY_TIME)
{
Su16KeyContinuityCnt2=0;
vGu8KeySec=2; //触发一次 K2 按键
vGu8ShieldVoiceFlag=1; //把当前按键触发的声音屏蔽掉
}
}
}
void KeyTask(void) //按键任务函数,放在主函数内
{
if(0==vGu8KeySec)
{
return; //按键的触发序号是 0 意味着无按键触发,直接退出当前函数,不执行此函数下面的代码
}
switch(vGu8KeySec) //根据不同的按键触发序号执行对应的代码
{
case 1: //K1 发的任务
if(Gu8LedStatus>0)
{
Gu8LedStatus--; //控制 LED“往左边跑”
Gu8DisplayUpdate=1; //刷新显示
}
if(0==vGu8ShieldVoiceFlag) //声音没有被屏蔽
{
vGu8BeepTimerFlag=0;
vGu16BeepTimerCnt=KEY_VOICE_TIME; //发出“嘀”一声
vGu8BeepTimerFlag=1;
}
vGu8ShieldVoiceFlag=0; //及时把屏蔽标志清零,避免平时正常的单击声音也被淹没。
vGu8KeySec=0; //响应按键服务处理程序后,按键编号必须清零,避免一直触
break;
case 2: //K2 发的任务
if(Gu8LedStatus<7)
{
Gu8LedStatus++; //控制 LED“往右边跑”
Gu8DisplayUpdate=1; //刷新显示
}
if(0==vGu8ShieldVoiceFlag) //声音没有被屏蔽
{
vGu8BeepTimerFlag=0;
vGu16BeepTimerCnt=KEY_VOICE_TIME; //发出“嘀”一声
vGu8BeepTimerFlag=1;
}
vGu8ShieldVoiceFlag=0; //及时把屏蔽标志清零,避免平时正常的单击声音也被淹没。
vGu8KeySec=0; //响应按键服务处理程序后,按键编号必须清零,避免一直触
break;
}
}