Chinaunix首页 | 论坛 | 博客
  • 博客访问: 292493
  • 博文数量: 76
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 715
  • 用 户 组: 普通用户
  • 注册时间: 2015-05-20 20:38
文章分类
文章存档

2016年(20)

2015年(56)

分类: 嵌入式

2015-06-01 19:07:50

字符设备驱动之定时器防抖动
15年5月11日22:25:36
代码如下:
  1 #include
  2 #include
  3 #include
  4 #include
  5 #include
  6 #include
  7 #include
  8 #include
  9 #include
 10 #include
 11 #include
 12 #include
 13
 14 static struct timer_list buttons_timer;
 15
 16 static struct class *sixthdrv_class;
 17 static struct class_device  *sixthdrv_class_dev;
 18
 19 volatile unsigned long *gpfcon;
 20 volatile unsigned long *gpfdat;
 21
 22 volatile unsigned long *gpgcon;
 23 volatile unsigned long *gpgdat;
 24
 25 static DECLARE_WAIT_QUEUE_HEAD(button_waitq);
 26
 27 static volatile int ev_press = 0;
 28
 29 static struct fasync_struct *button_async;
 30
 31 struct pin_desc{
 32     unsigned int pin;
 33     unsigned int key_val;
 34 };
 35
 36
 37 static unsigned char key_val;
 38
 39 struct pin_desc pins_desc[4] = {
 40     {S3C2410_GPF0, 0x01},
 41     {S3C2410_GPF2, 0x02},
 42     {S3C2410_GPG3, 0x03},
 43     {S3C2410_GPG11, 0x04},
 44 };
 45
 46 static struct pin_desc * irq_pd;
 47
 48 //static atomic_t canopen = ATOMIC_INIT(1);   
 49
 50 static DECLARE_MUTEX(button_lock);
 51
 52 static irqreturn_t buttons_irq(int irq, void *dev_id)
 53 {
 54     irq_pd = (struct pin_desc *)dev_id;
 55     mod_timer(&buttons_timer, jiffies + HZ/100);
 56     return IRQ_RETVAL(IRQ_HANDLED);
 57 }
 58
 59 static int sixth_drv_open(struct inode *inode, struct file *file)
 60 {
 61 #if 0   
 62     if (!atomic_dec_and_test(&canopen))
 63     {
 64         atomic_inc(&canopen);
 65         return -EBUSY;
 66     }
 67 #endif
 68
 69     if (file->f_flags & O_NONBLOCK)
 70     {
 71         if (down_trylock(&button_lock))
 72             return -EBUSY;
 73     }
 74     else
 75     {
76         down(&button_lock);
 77     }
 78
 79     request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
 80     request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
 81     request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
 82     request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);
 83
 84     return 0;
 85 }
 86
 87 ssize_t sixth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
 88 {
 89     if (size != 1)
 90         return -EINVAL;
 91
 92     if (file->f_flags & O_NONBLOCK)
 93     {
 94         if (!ev_press)
 95             return -EAGAIN;
 96     }
 97     else
 98     {
 99         wait_event_interruptible(button_waitq, ev_press);
100     }
101
102     copy_to_user(buf, &key_val, 1);
103     ev_press = 0;
104
105     return 1;
106 }
107
108
109 int sixth_drv_close(struct inode *inode, struct file *file)
110 {
111     //atomic_inc(&canopen);
112     free_irq(IRQ_EINT0, &pins_desc[0]);
113     free_irq(IRQ_EINT2, &pins_desc[1]);
114     free_irq(IRQ_EINT11, &pins_desc[2]);
115     free_irq(IRQ_EINT19, &pins_desc[3]);
116     up(&button_lock);
117     return 0;
118 }
119
120 static unsigned sixth_drv_poll(struct file *file, poll_table *wait)
121 {
122     unsigned int mask = 0;
123     poll_wait(file, &button_waitq, wait);
124     if (ev_press)
125         mask |= POLLIN | POLLRDNORM;
126
127     return mask;
128 }
129
130 static int sixth_drv_fasync (int fd, struct file *filp, int on)
131 {
132     printk("driver: sixth_drv_fasync\n");
133     return fasync_helper (fd, filp, on, &button_async);
134 }
135
136
137 static struct file_operations sencod_drv_fops = {
138     .owner   =  THIS_MODULE,
139     .open    =  sixth_drv_open,
140     .read    =  sixth_drv_read,
141     .release =  sixth_drv_close,
142     .poll    =  sixth_drv_poll,
143     .fasync  =  sixth_drv_fasync,
144 };
145
146 void buttons_timer_function(unsigned long data)
147 {
148     struct pin_desc * pindesc = irq_pd;
149     unsigned int pinval;
150
151     if(!pindesc)
152         return;
153
154     pinval = s3c2410_gpio_getpin(pindesc->pin);
155
156     if (pinval)
157     {
158         key_val = 0x80 | pindesc->key_val;
159     }
160     else
161     {
162         key_val = pindesc->key_val;
163     }
164
165     ev_press = 1;
166     wake_up_interruptible(&button_waitq);
167
168     kill_fasync (&button_async, SIGIO, POLL_IN);
169 }
170
171 int major;
172 static int sixth_drv_init(void)
173 {
174     init_timer(&buttons_timer);
175     buttons_timer.function = buttons_timer_function;
176     add_timer(&buttons_timer);
177
178     major = register_chrdev(0, "sixth_drv", &sencod_drv_fops);
179
180     sixthdrv_class = class_create(THIS_MODULE, "sixth_drv");
181
182     sixthdrv_class_dev = class_device_create(sixthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */
183
184     gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
185     gpfdat = gpfcon + 1;
186
187     gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
188     gpgdat = gpgcon + 1;
189
190     return 0;
191 }
192
193 static void sixth_drv_exit(void)
194 {
195     unregister_chrdev(major, "sixth_drv");
196     class_device_unregister(sixthdrv_class_dev);
197     class_destroy(sixthdrv_class);
198     iounmap(gpfcon);
199     iounmap(gpgcon);
200     return 0;
201 }
202
203
204 module_init(sixth_drv_init);
205
206 module_exit(sixth_drv_exit);
207
208 MODULE_LICENSE("GPL");
测试代码与第六个驱动程序的测试代码相同,只是把非阻塞与休眠去掉了。

因为按键为金属的,可能出现抖动现象,如下图所示:

一次按键,可能出现两次上升沿,而只有一次下降沿。
我们希望通过定时器来消除这种现象,原理如下图所示:

我们定义一个定时器,约定10ms以后处理中断处理函数,这时候,如果发生第二次中断,两次中断之间的间隔肯定比10ms小很多,这时候定时器重置,继续10ms以后处理中断处理函数,如果发生第三次中断,执行同样的操作,继续延迟10ms执行中断处理函数,等按键不再抖动,10ms以后,最后处理一次中断处理函数,这样,在抖动的这一段时间里,只处理了一次中断处理函数,就达到了我们的目的,用定时器来防抖动。

首先声明一个定时器结构体,结构体如下:
struct timer_list{
    unsigned long expires;
    void (*function) (unsigned long );
    unsigned long data;
};
在本例中,我们用static struct timer_list buttons_timer; 来完成声明。

声明以后,调用init_timer(&buttons_timer);来初始化这个结构体,并用 buttons_timer.function = buttons_timer_function;指定定时器处理函数,然后调用add_timer(&buttons_timer);来注册定时器结构,通知内核。

然后编写定时器处理函数 buttons_timer_function,我们把原来按键中断函数 buttons_irq里面对按键值的处理都放在定时器处理函数 buttons_timer_function里面。而在中断处理函数中用mod_timer(&buttons_timer, jiffies + HZ/100); 来修改定时器结构体的到期时间(HZ表示jiffies在每秒递增HZ次,HZ即相当于1秒)。

在入口函数中,我们通过下面3个语句来声明注册定时器,
174     init_timer(&buttons_timer);
175     buttons_timer.function = buttons_timer_function;
176     add_timer(&buttons_timer);
其中174执行以后,没有指定jiffies,假设jiffies为n,那么在执行176的时候,jiffie > n,这时候定时器已经开始定时,但是没有按键按下,我们希望它能在按键按下以后开始计时,所以,在定时处理函数buttons_timer_function中,我们添加 if(!pindesc)       return; 的语句,直到有按键按下的时候,才继续向下执行。
阅读(946) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~