按键利用定时器消抖:
1.定义timer_list结构体的变量。
2.初始化定时器,
3.增加定时器,启动定时器。
所用到的结构体和函数等:
/*初始化时一般设置,expires,function,data*/
struct timer_list {
/*定时器列表*/
struct list_head entry;
/*定时器的到期时间,是jiffies和HZ一起设置*/
unsigned long expires;
/*定时器的处理函数*/
void (*function)(unsigned long);
/*定时器的函数函数的参数*/
unsigned long data;
struct tvec_base *base;
#ifdef CONFIG_TIMER_STATS
void *start_site;
char start_comm[16];
int start_pid;
#endif
#ifdef CONFIG_LOCKDEP
struct lockdep_map lockdep_map;
#endif
};
/*初始化函数,timer是timer_list结构体指针*/
#define init_timer(timer)\
init_timer_key((timer), NULL, NULL)
/*用setup_timer函数也可以初始定时器
* timer:timer_list的结构体指针,fn:定时器处理函数,
*data:定时器处理函数的参数
*/
#define setup_timer(timer, fn, data)\
setup_timer_key((timer), NULL, NULL, (fn), (data))
/*增加一个定时器,启动定时器,就是把定时器加入到内核定时器链表中*/
void add_timer(struct timer_list *timer)
/*修改定时器的超出时间的,timer;timer_list结构体指针,expires;定时器的超时时间*/
int mod_timer(struct timer_list *timer, unsigned long expires)
关于其它的函数及结构体和中断(linux中断体系架构与注册讲了)已经在前面讲述,不再多讲
驱动程序:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/device.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <mach/irqs.h>
#include <mach/regs-gpio.h>
/*不同的linux内核,头文件会有所不同*/
/*用来保存主设备号*/
static unsigned long major;
/*定义类*/
static struct class *second_key_class;
/*定义类下的设备*/
static struct device *second_key_device;
/*中断时间标志,置1,用于唤醒休眠,睡眠时,将其置0*/
static volatile int en_press = 0;
/*用于保存按键值*/
static int key_val;
/*定义一个等待队列头文件*/
static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
/*定义一个定时器*/
static struct timer_list key_timer;
void key_timer_function(unsigned long data);
struct pindec{
unsigned long pin;
unsigned long val;
};
struct pindec * irq_dec;
/*松开按键的值为0x01,0x02,0x3,0x04*/
/*按下按键时值为0x81,0x82,0x83,0x84*/
struct pindec pin_dec[4] = {
{S3C2410_GPF0,0x04},
{S3C2410_GPF1,0x01},
{S3C2410_GPF2,0x03},
{S3C2410_GPF4,0x02},
};
#if 0
struct pin_desc pins_desc[4] = {
{S3C2410_GPF1,0x01},
{S3C2410_GPF4,0x02},
{S3C2410_GPF2,0x03},
{S3C2410_GPF0,0x04},
};
#endif
/*中断处理函数*/
static irqreturn_t buttons_irq(int irq,void *dev_id)
{
irq_dec = (struct pindec *)dev_id;
mod_timer(&key_timer,jiffies+HZ/100);
return IRQ_RETVAL(IRQ_HANDLED);
}
/*根据file_operations的open函数写*/
static int second_key_open(struct inode *inode, struct file *file)
{
request_irq(IRQ_EINT1,buttons_irq,IRQ_TYPE_EDGE_BOTH,"s1",&pin_dec[1]);
request_irq(IRQ_EINT4,buttons_irq,IRQ_TYPE_EDGE_BOTH,"s2",&pin_dec[3]);
request_irq(IRQ_EINT2,buttons_irq,IRQ_TYPE_EDGE_BOTH,"s3",&pin_dec[2]);
request_irq(IRQ_EINT0,buttons_irq,IRQ_TYPE_EDGE_BOTH,"s4",&pin_dec[0]);
return 0;
}
/*根据file_operations的close函数写*/
static int second_key_close(struct inode *inode, struct file *file)
{
free_irq(IRQ_EINT1,&pin_dec[1]);
free_irq(IRQ_EINT4,&pin_dec[3]);
free_irq(IRQ_EINT2,&pin_dec[2]);
free_irq(IRQ_EINT0,&pin_dec[0]);
return 0;
}
/*根据file_operations的read函数写*/
static ssize_t second_key_read(struct file *file, char __user *user_buffer,
size_t count, loff_t *ppos)
{
if(count != 1)
return -EINVAL;
/*松开按键时*/
wait_event_interruptible(button_waitq,en_press);
/*按下按键时*/
copy_to_user(user_buffer,&key_val,1);
/*置0,睡眠*/
en_press = 0;
return 1;
}
/*定义一个file_operations结构*/
static struct file_operations secong_key_fops =
{
.owner = THIS_MODULE,
.open = second_key_open,
.read = second_key_read,
.release = second_key_close,
};
/*入口函数*/
static int second_key_init(void)
{
/*注册*/
major = register_chrdev(0,"second_buttons",&secong_key_fops);
/*创建类*/
second_key_class = class_create(THIS_MODULE,"second_class");
/*在second_key_class类下创建设备*/
second_key_device =
device_create(second_key_class,NULL,MKDEV(major,0),NULL,"second_device");
/*初始化定时器*/
init_timer(&key_timer);
key_timer.function = key_timer_function;
/*启动定时器*/
add_timer(&key_timer);
return 0;
}
/*超时处理函数*/
void key_timer_function(unsigned long data)
{
struct pindec * pindesc = irq_dec;
/*获取引脚值*/
unsigned long pinval = s3c2410_gpio_getpin(pindesc->pin);
/*松开时*/
if(pinval)
key_val = pindesc->val;
/*按下时*/
else
key_val = pindesc->val|0x80;
/*中断事件标志置1,唤醒*/
en_press = 1;
wake_up_interruptible(&button_waitq);
}
/*出口函数*/
static void second_key_exit(void)
{
/*注销*/
unregister_chrdev(major,"second_buttons");
/*注销设备*/
device_unregister(second_key_device);
/*销毁类*/
class_destroy(second_key_class);
/*删除定时器*/
del_timer(&key_timer);
}
/*修饰*/
module_init(second_key_init);
module_exit(second_key_exit);
MODULE_LICENSE("GPL");
测试程序:
#include<stdio.h>
#include<fcntl.h>
#include<unistd.h>
void main(int argc,char **argv)
{
unsigned long key_val;
int fd;
fd = open("/dev/second_device",O_RDWR);
if(fd < 0)
printf("can't open!");
while(1)
{
read(fd,&key_val,1);
printf("key_val = 0x%x\n",key_val);
}
}
测试:
1.加载驱动程序,利用insmod.
2.运行驱动的测试程序,
|