01_使用定时器实现按键防抖

接着1-2期衔接课程的最后一节(阻塞方式),使用定时器来消除按键抖动的问题。

1、原理

定时器原理

2、程序思路

2.1、定义一个定时器

static struct timer_list buttons_timer;

2.2、发生中断时的引脚描述

static struct pin_desc *irq_pd;

2.3、在入口函数sixth_drv_init中

/* 1 初始化定时器 */
init_timer(&buttons_timer);
/* 2 定时器的处理函数 */
buttons_timer.function = buttons_timer_function;
//buttons_timer.expires = 0;
/* 3 将定时器告诉内核 */
add_timer(&buttons_timer);

2.4、在按键中断处理函数buttons_irq中

超时时间可以设置成“当前值”加上某个值。如 1 秒就是 HZ,从定义中可以看到 HZ 是 100.这里的意思是 1 秒钟里这个当前的 jiffies 值会增加 100.add_timer(&buttons_timer,jiffies+HZ);是指当前 jiffies 时间过了 100 个系统时钟中断(系统滴答)后,这个定时器的超时时间“buttons_timer”就到达了。HZ 是 1 秒,那么定时器在 10ms时启动的话,就是 HZ/100 即 10ms。假设现在,jiffies 的值为“50”,HZ 为“100”,那么这个定时器 buttons_timer 的超时时间为:
Buttons_times.expires = 50+100/100(jieeies+HZ/100) = 51.
系统是每隔 10ms 产生一个系统时钟中断,系统时钟中断中这个 jiffies 的值会累加。这里假
设 jiffies 为 50,则下一个系统时钟时,jiffies 就变成 51 了,51 一到,在这个系统时钟中断处
理函数里面会从这个定时器链表里面把这里的定时器找出来,看看哪个定时器的时间已经到
了(buttons_timer 这个定时器就在这个链表中)。若这里的 jiffies 已经大于等于这个“buttons_timer”的定时器超时时间“expires”时(jiffies>=buttons_timer.expirs),就去调用与这个定时器相关的定时器处理函数。这里要是buttons_timer.expirs 已经超时,就会调用上面自已定义的“buttons_timer_function()”这个定时器处理函数。

static irqreturn_t buttons_irq(int irq, void *dev_id)
{
	/* 修改定时器的 超时时间 = jiffies + HZ/100 = 51
	 * HZ相当于1s HZ/100 = 10ms
	 * 每隔10ms,会产生系统时钟中断,jiffies的值就会累加
	 * 当buttons_timer.expire = 51时
	 * 就会执行定时器处理函数buttons_timer_function
	 */
	irq_pd = (struct pin_desc *)dev_id;
	mod_timer(&buttons_timer, jiffies + HZ/100);
	return IRQ_RETVAL(IRQ_HANDLED);
}

2.5、在buttons_timer_function函数中

/* 判断按键状态,若没按下直接返回 */
if(!pinval)
	return;

这里要判断下,因为在入口函数中没有设置超时时间,这样超时时间就为 0,一旦 add_timer()
把这个定时器放到内核中去,那么在这个系统时钟中断里面,就会 jiffies >= 0 .这样就立即
调用了定时器处理函数buttons_timer_function()。但这个时间并没按键中断产生。所以上面的“pindesc”要判断一下。

static void buttons_timer_function(unsigned long data)
{
	struct pin_desc *pindesc = irq_pd;
	unsigned int pinval;
	
	/* 判断按键状态,若没按下直接返回 */
	if(!pinval)
		return;

	/* 读取引脚值pin */
	pinval = s3c2410_gpio_getpin(pindesc->pin);

	/* 确定按键值 */
	if(pinval)
	{
		/* 按下 */
		key_val = 0x80 | pindesc->key_val;
	}
	else
	{
		/* 松开 */
		key_val = pindesc->key_val;
	}

	ev_press = 1;	/* 表示中断发生了 */
	wake_up_interruptible(&button_waitq);	/* 唤醒休眠的进程 */

	kill_fasync (&button_async, SIGIO, POLL_IN);
}

3、程序运行流程

1、应用程序运行,阻塞方式,一直等待按键按下才会返回
2、按键按下后,触发按键中断,运行按键处理函数buttons_irq并等待10ms后运行定时器处理函数buttons_timer_function。在此期间若发生抖动,则重新触发按键中断,并等待10ms后运行定时器处理函数buttons_timer_function。
3、直到最后一次出发按键中断,等待10ms后执行定时器处理函数buttons_timer_function在此函数中判断按键值并处理。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
好的,使用定时器也是一种实现按键长按短按双击的方法。 具体实现方法可以参考以下步骤: 1. 初始化定时器。选择合适的定时器,并设置定时器的时钟源、计数模式、计数周期等参数。一般推荐使用定时器的计数模式为向上计数,并且设置一个合适的计数周期。 2. 初始化按键。选择合适的引脚作为按键输入,配置引脚的输入模式和上拉/下拉电阻。一般推荐使用上拉电阻,使按键默认为高电平。 3. 在定时器中断服务函数中实现按键状态的检测和处理。在定时器中断服务函数中,读取按键状态,并根据当前状态和前一次状态的变化,判断按键事件的类型。如果按键被按下,则记录按下时间;如果按键被释放,则记录释放时间,并根据时间间隔判断按键事件的类型。 4. 根据按键事件的类型,执行相应的操作。例如,长按事件可以用于开启或关闭某个功能;短按事件可以用于切换不同的模式;双击事件可以用于执行快速操作。 注意事项: 1. 在定时器中断服务函数中,需要注意防抖处理。对于按键输入信号,由于存在抖动现象,因此需要使用软件或硬件方式进行防抖处理,以确保检测到的按键状态是稳定的。 2. 在定时器中断服务函数中,需要注意按键状态的检测间隔。检测间隔过短会导致系统负载过高,检测间隔过长会影响按键检测的灵敏度,因此需要选择一个合适的检测间隔。 3. 在定时器中断服务函数中,需要注意定时器的溢出问题。如果定时器的计数周期比较短,容易出现定时器溢出的情况,需要进行相应的处理。 总之,使用定时器实现按键长按短按双击需要结合具体的硬件平台和软件环境进行综合考虑,根据实际需求选择合适的方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「已注销」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值