在我提交的作品当中使用的是在主循环中轮询的方式来获得长短键值,简单实用,已经能够满足项目需要。正如广大坛友指出的那样,轮询方法在读取按键长短时MCU不能做其他事情,效率太低,在一些场合还会对MCU处理其他事务造成影响,不少坛友建议采用定时器的方法,但当时为了不影响项目作品提交进度,就先将就使用轮询法了。这段时间稍得空闲,我对项目代码中的按键获得进行优化,使用了定时器累计键值的方式来识别长短按键,经过测试,完全达到预计目的。
使用定时器法的基本思路是设置两个全局变量keys和keyf,前者计数,后者作按键结束标志,定时器的定时时间为10毫秒,keys是8位的变量,最大计数为255,可以分辨2.55秒之内的按键时间(大于2.55秒则按2.55秒计算),通过实验,快按快松(点击)按键时返回的键值通常在10左右,按下后再松开(短按)返回的键值约在30~40左右,按下后稍等片刻再松开(中按)返回的键值约在60~90左右,按下后数两下再松开(长按)返回的键值大约在120~180左右,按下后数四下再松开(超长按)返回的键值大约会大于200,在我的项目中,键值与功能的对应关系见下表:
keys |
分类 |
mode>6 |
chick=1 |
mode=1~6 |
报警设置 |
查询 |
日历设置 |
<20 |
点按 |
慢增 |
下翻 |
慢增 |
20~49 |
短按 |
快增 |
上翻 |
快增 |
50~99 |
中按 |
轮换 |
|
轮换 |
100~199 |
长按 |
|
进退 |
|
>200 |
超长按 |
进退 |
|
|
下面是定时器2配置的代码:
void timer_config(void)
{
/* -----------------------------------------------------------------------
TIMER2CLK is 100KHz定时器2 CLK为100kHz
TIMER2 channel0 duty cycle = (25000/ 50000)* 100 = 50%
----------------------------------------------------------------------- */
timer_oc_parameter_struct timer_ocintpara; //定义数据结构
timer_parameter_struct timer_initpara;
rcu_periph_clock_enable(RCU_TIMER2); //开启时钟
timer_deinit(TIMER2); //指定定时器
/* TIMER configuration 定时器配置*/
timer_initpara.prescaler = 719;
timer_initpara.alignedmode = TIMER_COUNTER_EDGE;
timer_initpara.counterdirection = TIMER_COUNTER_UP;
timer_initpara.period = 999; //定时10毫秒
timer_initpara.clockdivision = TIMER_CKDIV_DIV1;
timer_initpara.repetitioncounter = 0;
timer_init(TIMER2,&timer_initpara);
/* configurate CH0 in PWM mode0 在PWM模式0中配置CH0*/
timer_interrupt_enable(TIMER2, TIMER_INT_UP); //Enable TIMER2
nvic_irq_enable(TIMER2_IRQn, 0); //Set priority to 0(0-2)
/* auto-reload preload enable 自动重新加载预加载启用*/
timer_auto_reload_shadow_enable(TIMER2);
/* auto-reload preload enable */
timer_enable(TIMER2);
}
在我的项目中,定时器2除按键计数外还兼作报警声延时作用,详见下面的中断处理代码:
//The interrupt handler function of tmer2//
void TIMER2_IRQHandler(void)
{
if(RESET != timer_interrupt_flag_get(TIMER2, TIMER_INT_FLAG_UP))
{
if(time>0) //在报警状态,延时减1(10毫秒)
time--;
if(keyf==0) //按键处理等待状态(keyf=1时,上次按键尚未处理完毕)
{
if(1==gd_eval_key_state_get(KEY_WAKEUP)) //按键按下
{
if(keys<255)
keys++; //按键计数
}
else
{
if(keys>0)
keyf = 1;//置按键松开标志
}
}
}
timer_interrupt_flag_clear(TIMER2, TIMER_INT_FLAG_UP);
}
下面是在主循环中检测按键的代码,当检测到有按键事件时除调用按键处理函数外,还要将按键值归零并置按键事件处理完毕标志:
// 轮询按键处理
if(keyf > 0){ //有键按下
key_processing();
keys = 0;
keyf = 0; //置按键处理完毕标志
}
|