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

{ Su16KeyInt ervalCnt1 =0; //时间计数器 清零 Su8KeyTouc hCnt1=0; //清零按键的 按下的次数 } } } else if(0= =Su8KeyLo ck1)//有按键按下 ,且是第一次 被按下。此 行如有疑 问,请看第 9 2 节的讲解。 { Su16KeyCnt 1++; //累加 定时中断次数 if(Su16Key Cnt1>=KEY _FILTER_TIME ) //滤波的“…

100%1 / 836
BeepClose();
}
}
}
}
/* 注释二:
* 双击按键扫描的详细过程
* 第一步:平时没有按键被触发时,按键的自锁标志,去抖动延时计数器一直被清零。
* 如果之前已经有按键触发 1 次单击,那么启动时间间隔计数器 Su16KeyIntervalCnt1,
* KEY_INTERVAL_TIME 这个允许的时间差范围内,如果一直没有第 2 次单击触发,
* 则把累加按键触发的次数 Su8KeyTouchCnt1 也清零,上一次累计的单击数被清零,
* 就意味着下一次新的双击必须重新开始累加两次单击数。
* 第二步:一旦有按键被按下,去抖动延时计数器开始在定时中断函数里累加,在还没累加到
* 阀值 KEY_FILTER_TIME 时,如果在这期间由于受外界干扰或者按键抖动,而使
* IO 口突然瞬间触发成高电平,这个时候马上把延时计数 Su16KeyTimeCnt1
* 清零了,这个过程非常巧妙,非常有效地去除瞬间的杂波干扰,以后凡是用到开关感应器的时候,
* 都可以用类似这样的方法去干扰
* 第三步:如果按键按下的时间超过了阀 KEY_FILTER_TIME,马上把自锁标志 Su8KeyLock1 1,
* 防止按住按键不松手后一直触发。与此同时,累加 1 次按键次数,如果按键次数累加 2 次,
* 则认为触发双击按键,并把编号 vGu8DoubleKeySec 赋值。
* 第四步:等按键松开后,自锁标志 Su8KeyLock1 及时清零解锁,为下一次自锁做准备。并且累加间隔时间,
* 防止两次按键的间隔时间太长。如果连续 2 次单击的间隔时间太长达到了 KEY_INTERVAL_TIME
* 的长度,立即清零当前按键次数的计数器,这样意味着上一次的累加单击数无效,下一次双击
* 必须重新累加新的单击数
*/
void KeyScan(void) //此函数放在定时中断里每 1ms 扫描一次
{
static unsigned char Su8KeyLock1; //1 号按键的自
static unsigned int Su16KeyCnt1; //1 号按键的计时器
static unsigned char Su8KeyTouchCnt1; //1 号按键的次数记录
static unsigned int Su16KeyIntervalCnt1; //1 号按键的间隔时间计数器
//1 号按键
if(0!=KEY_INPUT1)//IO 是高电平,说明按键没有被按下,这时要及时清零一些标志位
{
Su8KeyLock1=0; //按键解锁
Su16KeyCnt1=0; //按键去抖动延时计数器清零,此行非常巧妙。
if(Su8KeyTouchCnt1>=1) //之前已经有按键触发过一次,启动间隔时间的计数器
{
Su16KeyIntervalCnt1++; //按键间隔的时间计数器累加
if(Su16KeyIntervalCnt1>=KEY_INTERVAL_TIME) //达到最大允许的间隔时间,溢出无效
{
Su16KeyIntervalCnt1=0; //时间计数器清零
Su8KeyTouchCnt1=0; //清零按键的按下的次数
}
}
}
else if(0==Su8KeyLock1)//有按键按下,且是第一次被按下。此行如有疑问,请看第 92 节的讲解。
{
Su16KeyCnt1++; //累加定时中断次数
if(Su16KeyCnt1>=KEY_FILTER_TIME) //滤波的“稳定时间”KEY_FILTER_TIME,长度 25ms。
{
Su8KeyLock1=1; //按键的自锁,避免一直触
Su16KeyIntervalCnt1=0; //按键有效间隔的时间计数器清零
Su8KeyTouchCnt1++; //记录当前单击的次数
if(1==Su8KeyTouchCnt1) //只按了 1
{
vGu8SingleKeySec=1; //单击任务
}
else if(Su8KeyTouchCnt1>=2) //连续按了两次以上
{
Su8KeyTouchCnt1=0; //统计按键次数清零
vGu8SingleKeySec=1; //单击任务
vGu8DoubleKeySec=1; //双击任务
}
}
}
}
void SingleKeyTask(void) //单击按键任务函数,放在主函数内
{
if(0==vGu8SingleKeySec)
{
return; //按键的触发序号是 0 意味着无按键触发,直接退出当前函数,不执行此函数下面的代码
}
switch(vGu8SingleKeySec) //根据不同的按键触发序号执行对应的代
{
case 1: //单击任务
//通过 Gu8LedStatus 的状态切换,来反复切换 LED 的“灭”与“亮”的状
if(0==Gu8LedStatus)
{
Gu8LedStatus=1; //标识并且更改当前 LED 灯的状态。0 就变成 1。
LedOpen(); //点亮 LED
}
else
{
Gu8LedStatus=0; //标识并且更改当前 LED 灯的状态。1 就变成 0。
LedClose(); //关闭 LED
}
vGu8SingleKeySec=0; //响应按键服务处理程序后,按键编号必须清零,避免一直触发
break;
}
}
void DoubleKeyTask(void) //双击按键任务函数,放在主函数内
{
if(0==vGu8DoubleKeySec)
{
return; //按键的触发序号是 0 意味着无按键触发,直接退出当前函数,不执行此函数下面的代码
}
switch(vGu8DoubleKeySec) //根据不同的按键触发序号执行对应的代
{
case 1: //双击任务
vGu8BeepTimerFlag=0;
vGu16BeepTimerCnt=KEY_VOICE_TIME; //触发双击后,发出“嘀”一声
vGu8BeepTimerFlag=1;
vGu8DoubleKeySec=0; //响应按键服务处理程序后,按键编号必须清零,避免一直触发
break;
}
}