1、去抖动概述
按键去抖动的方式有两种:(1)硬件电路去抖动 (2)软件延时去抖动:①for循环等待n微妙;②做一个定时器延时。本节主要介绍一下如何实现软件定时器去抖动(例如:按下去10ms判断按键按下)。
2、内核定时器
linux内核使用struct time_list来描述一个定时器。
struct timer_list {
struct list_head entry;
unsigned long expires;
void (*function)(unsigned long); 处理函数
unsigned long data;
struct tvec_base *base;
};
3、定时器使用流程
(1)定义定时器变量
(2)初始化定时器:①init_timer ②设置超时函数
(3)add_timer注册定时器
(4)mod_timer启动定时器
4、编程流程
(1)注册按键中断,中断处理函数中会启动定时器,mod_timer(&buttoms_timer, jiffies + (HZ)/10)
(2)初始化按键中断
(3)创建工作队列中的工作
(4)INIT_WORK(work1, work1_func )
(5)初始化定时器,指定定时器的处理函数init_timer(&buttons_timer)
(6)向内核注册定时器add_timer(&button_timer)
#include <linux/module.h> #include <linux/init.h> #include <linux/miscdevice.h> #include <linux/interrupt.h> #include <linux/io.h> #include <linux/fs.h> #define GPFCON 0x56000050 #define GPFDAT 0x56000054 struct work_struct *work1; struct timer_list buttons_timer; unsigned int *gpio_data; void work1_func(struct work_struct *work) { mod_timer(&buttons_timer, jiffies + (HZ /10));//jiffies表示现在的时间,tick数。HZ/10表示要延时的时间,一个HZ是1s } //按下按键之后进入定时器函数,定时器的注册处理函数 void buttons_timer_function(unsigned long data) { unsigned int key_val; key_val = readw(gpio_data)&0x1; if (key_val == 0) printk("key down!\n"); } irqreturn_t key_int(int irq, void *dev_id) { //1. 检测是否发生了按键中断 //2. 清除已经发生的按键中断 //3. 提交下半部 schedule_work(work1); //return 0; return IRQ_HANDLED; } void key_hw_init() { unsigned int *gpio_config; unsigned short data; gpio_config = ioremap(GPFCON,4); data = readw(gpio_config); data &= ~0b11; data |= 0b10; writew(data,gpio_config); gpio_data = ioremap(GPFDAT,4); } int key_open(struct inode *node,struct file *filp) { return 0; } struct file_operations key_fops = { .open = key_open, }; struct miscdevice key_miscdev = { .minor = 200, .name = "key", .fops = &key_fops, }; static int button_init() { misc_register(&key_miscdev); //注册中断处理程序 request_irq(IRQ_EINT0,key_int,IRQF_TRIGGER_FALLING,"key",0); //按键初始化 key_hw_init(); //. 创建工作 work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL); INIT_WORK(work1, work1_func); /* 初始化定时器 */ init_timer(&buttons_timer); buttons_timer.function = buttons_timer_function; /* 向内核注册一个定时器 */ add_timer(&buttons_timer); return 0; } static void button_exit() { misc_deregister(&key_miscdev); } module_init(button_init); module_exit(button_exit);