本文的主要内容:
一、内核定时器
二、按键输入子系统驱动程序的改进
一、内核定时器
1、内核定时器,
在Linux设备驱动编程中,可以利用内核定时器来完成定时触发工作或周期性的任务。
2、内核定时器的一般使用步骤
a、定义、初始化定时器
b、设置定时器:比如超时处理函数,超时时间
c、将定时器加入到内核的定时器链表当中
d、编写定时器超时处理函数以及修改定时器的超时时间
二、按键输入子系统的改进
1、上一节按键输入子系统驱动的缺点
在Tiny4412开发板上的按键是传统的机械按键,机械按键在按下和松开的时候会用抖动(也就是常说的毛刺),这就有可能导致按键的灵敏度下降甚至失灵。通过定时器在按键按下和松开的瞬时进行一定的延时将有助于对抖动的消除,可以有效的对按键进行消抖。
2、添加定时器相关的代码
2.1 定义一个定时器的结构体
static struct timer_list buttons_timer;
2.2 初始化、设置、注册这个定时器
init_timer(&buttons_timer);
buttons_timer.function = yl_buttons_timer_function;
add_timer(&buttons_timer);
2.3 按键中断程序
通过在按键中断程序当中来修改定时器的超时时间来对按键进行消抖,代码如下:
/* 按键中断处理程序 */
static irqreturn_t yl_buttons_irq(int irq, void *devid)
{
gl_buttons_desc = (struct yl_buttons_desc *)devid;
/* 修改定时器的时间,向后延时10ms */
mod_timer(&buttons_timer, jiffies + HZ/100);
return IRQ_HANDLED;
}
2.4 定时器超时处理函数
通过对定时器超时处理函数来判断按键是按下还是松开,上报事件和同步事件。
/* 定时器超时处理函数 */
static void yl_buttons_timer_function(unsigned long arg)
{
struct yl_buttons_desc *buttons_desc = gl_buttons_desc;
int pinval = gpio_get_value(buttons_desc->gpio);
if(pinval == 1) /* 判断按键是按下还是松开 */
{
/* 松开 */
input_event(buttons_dev, EV_KEY, buttons_desc->key_code, 0);
input_sync(buttons_dev);
}
else
{
/* 按下 */
input_event(buttons_dev, EV_KEY, buttons_desc->key_code, 1);
input_sync(buttons_dev);
}
}
附录:本文所实现的按键输入子系统的完整代码如下所示.
/* 包含的头文件 */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/sched.h>
#include <linux/irq.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <mach/hardware.h>
#include <linux/platform_device.h>
#include <linux/cdev.h>
#include <linux/miscdevice.h>
#include <linux/gpio.h>
#include <mach/map.h>
#include <mach/gpio.h>
#include <mach/regs-clock.h>
#include <mach/regs-gpio.h>
/* 输入子系统需要的头文件 */
#include <linux/input.h>
/** 按键映射:
* XEINT26 ---- GPX3_2
* XEINT27 ---- GPX3_3
* XEINT28 ---- GPX3_4
* XEINT29 ---- GPX3_5
*/
/* 定义一个结构体用来对输入按键进行描述 */
struct yl_buttons_desc{
int gpio; // 表示对于的按键的引脚
char *name; // 表示对应的按键请求中断时的中断名
int key_code; // 表示按键在输入子系统中对应的键值
};
/* 定义一个描述按键的数组 */
static struct yl_buttons_desc buttons_desc[] = {
{EXYNOS4_GPX3(2), "yl_buttons_L", KEY_L},
{EXYNOS4_GPX3(3), "yl_buttons_S", KEY_S},
{EXYNOS4_GPX3(4), "yl_buttons_ENTER", KEY_ENTER},
{EXYNOS4_GPX3(5), "yl_buttons_LEFTSHIFT", KEY_LEFTSHIFT},
};
static struct input_dev *buttons_dev; /* 定义一个输入子系统的结构体指针变量 */
static struct timer_list buttons_timer; /* 定义一个定时器的结构体指针变量 */
static struct yl_buttons_desc *gl_buttons_desc;
/* 按键中断处理程序 */
static irqreturn_t yl_buttons_irq(int irq, void *devid)
{
gl_buttons_desc = (struct yl_buttons_desc *)devid;
/* 修改定时器的时间,向后延时10ms */
mod_timer(&buttons_timer, jiffies + HZ/100);
return IRQ_HANDLED;
}
/* 定时器超时处理函数 */
static void yl_buttons_timer_function(unsigned long arg)
{
struct yl_buttons_desc *buttons_desc = gl_buttons_desc;
int pinval = gpio_get_value(buttons_desc->gpio);
if(pinval == 1) /* 判断按键是按下还是松开 */
{
/* 松开 */
input_event(buttons_dev, EV_KEY, buttons_desc->key_code, 0);
input_sync(buttons_dev);
}
else
{
/* 按下 */
input_event(buttons_dev, EV_KEY, buttons_desc->key_code, 1);
input_sync(buttons_dev);
}
}
/* 入口函数 */
static int __init yl_buttons_init(void)
{
int irq;
int i;
/* 1、分配一个input_dev结构体 */
buttons_dev = input_allocate_device();
if(!buttons_dev)
{
printk("input_allocate_device error!\n");
return -ENOMEM;
}
/* 2、设置input_dev结构体 */
/* 2.1、支持哪类事件 */
set_bit(EV_KEY, buttons_dev->evbit);
set_bit(EV_REP, buttons_dev->evbit);
/* 2.2、支持该类事件中的那些事件 */
for(i = 0; i < sizeof(buttons_desc)/sizeof(buttons_desc[0]); i++)
{
set_bit(buttons_desc[i].key_code, buttons_dev->keybit);
}
/* 3、注册input_dev结构体 */
input_register_device(buttons_dev);
/* 4、中断相关的操作 */
for(i = 0; i < sizeof(buttons_desc)/sizeof(buttons_desc[0]); i++)
{
irq = gpio_to_irq(buttons_desc[i].gpio);
request_irq(irq, yl_buttons_irq, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING, buttons_desc[i].name, (void*)&buttons_desc[i]);
}
/* 5、定时器相关的操作 */
init_timer(&buttons_timer);
buttons_timer.function = yl_buttons_timer_function;
add_timer(&buttons_timer);
return 0;
}
/* 出口函数 */
static void __exit yl_buttons_exit(void)
{
int irq;
int i;
del_timer(&buttons_timer);
for(i = 0; i < sizeof(buttons_desc)/sizeof(buttons_desc[0]); i++)
{
irq = gpio_to_irq(buttons_desc[i].gpio);
free_irq(irq, (void*)&buttons_desc[i]);
}
input_unregister_device(buttons_dev);
input_free_device(buttons_dev);
}
module_init(yl_buttons_init);
module_exit(yl_buttons_exit);
MODULE_LICENSE("GPL");