Chinaunix首页 | 论坛 | 博客
  • 博客访问: 632844
  • 博文数量: 75
  • 博客积分: 988
  • 博客等级: 准尉
  • 技术积分: 1269
  • 用 户 组: 普通用户
  • 注册时间: 2011-05-10 15:44
文章分类

全部博文(75)

文章存档

2022年(1)

2019年(1)

2018年(1)

2016年(9)

2015年(7)

2013年(6)

2012年(40)

2011年(10)

分类: LINUX

2012-03-14 10:26:19

 字符设备驱动程序之定时器防抖动

之前的按键驱动程序,在连续按快点的时候会出现偶尔“失灵”的情况,一按一松并没有完全如所预料的那样执行,如果在现场应用中出现这种问题,可能会导致很严重的后果。之前写单片机程序的时候,按键的消抖是通过一个延时来判定(当检测到有按键按下的时候,延时一段时间,然后再次判断,如果有按键按下,就判定按键按下了)。
使用定时器的两要素:1,超时时间、2,处理函数。


点击(此处)折叠或打开

  1. #include <linux/module.h>
  2. #include <linux/kernel.h>
  3. #include <linux/fs.h>
  4. #include <linux/init.h>
  5. #include <linux/delay.h>
  6. #include <linux/irq.h>
  7. #include <asm/uaccess.h>
  8. #include <asm/irq.h>
  9. #include <asm/io.h>
  10. #include <asm/arch/regs-gpio.h>
  11. #include <asm/hardware.h>
  12. #include <linux/poll.h>


  13. static struct class *sixthdrv_class;
  14. static struct class_device    *sixthdrv_class_dev;

  15. volatile unsigned long *gpfcon;
  16. volatile unsigned long *gpfdat;

  17. volatile unsigned long *gpgcon;
  18. volatile unsigned long *gpgdat;

  19. static struct timer_list buttons_timer;     // 定义一个结构体 buttons_timer


  20. static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

  21. /* 中断事件标志, 中断服务程序将它置1,sixth_drv_read将它清0 */
  22. static volatile int ev_press = 0;

  23. static struct fasync_struct *button_async;


  24. struct pin_desc{
  25.     unsigned int pin;
  26.     unsigned int key_val;
  27. };


  28. /* 键值: 按下时, 0x01, 0x02, 0x03, 0x04 */
  29. /* 键值: 松开时, 0x81, 0x82, 0x83, 0x84 */
  30. static unsigned char key_val;

  31. struct pin_desc pins_desc[4] = {
  32.     {S3C2410_GPF0, 0x01},
  33.     {S3C2410_GPF2, 0x02},
  34.     {S3C2410_GPG3, 0x03},
  35.     {S3C2410_GPG11, 0x04},
  36. };

  37. static struct pin_desc *irq_pd;

  38. //static atomic_t canopen = ATOMIC_INIT(1); //定义原子变量并初始化为1

  39. static DECLARE_MUTEX(button_lock); //定义互斥锁

  40. /*
  41.   * 确定按键值
  42.   */
  43. static irqreturn_t buttons_irq(int irq, void *dev_id)
  44. {
  45.     /* 10ms后启动定时器 */
  46.     irq_pd = (struct pin_desc *)dev_id;
  47.     mod_timer(&buttons_timer, jiffies+HZ/100); // mod就是modify修改定时器超时间,jiffies是一个全局变量,jiffies每隔10ms就会产生一个系统时钟中断,超时时间为jiffies+HZ/100,HZ/100即为100ms.时间到调用处理函数buttons_timer_function();
  48.     return IRQ_RETVAL(IRQ_HANDLED);   
  49. }

  50. static int sixth_drv_open(struct inode *inode, struct file *file)
  51. {
  52. #if 0    
  53.     if (!atomic_dec_and_test(&canopen))
  54.     {
  55.         atomic_inc(&canopen);
  56.         return -EBUSY;
  57.     }
  58. #endif        

  59.     if (file->f_flags & O_NONBLOCK)
  60.     {
  61.         if (down_trylock(&button_lock))
  62.             return -EBUSY;
  63.     }
  64.     else
  65.     {
  66.         /* 获取信号量 */
  67.         down(&button_lock);
  68.     }

  69.     /* 配置GPF0,2为输入引脚 */
  70.     /* 配置GPG3,11为输入引脚 */
  71.     request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
  72.     request_irq(IRQ_EINT2, buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
  73.     request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
  74.     request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);    

  75.     return 0;
  76. }

  77. ssize_t sixth_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
  78. {
  79.     if (size != 1)
  80.         return -EINVAL;

  81.     if (file->f_flags & O_NONBLOCK)
  82.     {
  83.         if (!ev_press)
  84.             return -EAGAIN;
  85.     }
  86.     else
  87.     {
  88.         /* 如果没有按键动作, 休眠 */
  89.         wait_event_interruptible(button_waitq, ev_press);
  90.     }

  91.     /* 如果有按键动作, 返回键值 */
  92.     copy_to_user(buf, &key_val, 1);
  93.     ev_press = 0;
  94.     
  95.     return 1;
  96. }


  97. int sixth_drv_close(struct inode *inode, struct file *file)
  98. {
  99.     //atomic_inc(&canopen);
  100.     free_irq(IRQ_EINT0, &pins_desc[0]);
  101.     free_irq(IRQ_EINT2, &pins_desc[1]);
  102.     free_irq(IRQ_EINT11, &pins_desc[2]);
  103.     free_irq(IRQ_EINT19, &pins_desc[3]);
  104.     up(&button_lock);
  105.     return 0;
  106. }

  107. static unsigned sixth_drv_poll(struct file *file, poll_table *wait)
  108. {
  109.     unsigned int mask = 0;
  110.     poll_wait(file, &button_waitq, wait); // 不会立即休眠

  111.     if (ev_press)
  112.         mask |= POLLIN | POLLRDNORM;

  113.     return mask;
  114. }

  115. static int sixth_drv_fasync (int fd, struct file *filp, int on)
  116. {
  117.     printk("driver: sixth_drv_fasync\n");
  118.     return fasync_helper (fd, filp, on, &button_async);
  119. }


  120. static struct file_operations sencod_drv_fops = {
  121.     .owner = THIS_MODULE, /* 这是一个宏,指向编译模块时自动创建的__this_module变量 */
  122.     .open = sixth_drv_open,
  123.     .read     =    sixth_drv_read,    
  124.     .release = sixth_drv_close,
  125.     .poll = sixth_drv_poll,
  126.     .fasync     = sixth_drv_fasync,
  127. };


  128. int major;

  129. static void buttons_timer_function(unsigned long data)
  130. {
  131.     struct pin_desc * pindesc = irq_pd;
  132.     unsigned int pinval;

  133.     if (!pindesc)
  134.         return;
  135.     
  136.     pinval = s3c2410_gpio_getpin(pindesc->pin);

  137.     if (pinval)
  138.     {
  139.         /* 松开 */
  140.         key_val = 0x80 | pindesc->key_val;
  141.     }
  142.     else
  143.     {
  144.         /* 按下 */
  145.         key_val = pindesc->key_val;
  146.     }

  147.     ev_press = 1; /* 表示中断发生了 */
  148.     wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */
  149.     
  150.     kill_fasync (&button_async, SIGIO, POLL_IN);
  151. }


  152. static int sixth_drv_init(void)
  153. {
  154.     init_timer(&buttons_timer);             // 对timer进行初始化
  155.     buttons_timer.function = buttons_timer_function;
  156.     //buttons_timer.expires = 0;            // 超时时间不用(因为是在中断处理函数里面用的定时器)
  157.     add_timer(&buttons_timer);

  158.     major = register_chrdev(0, "sixth_drv", &sencod_drv_fops);

  159.     sixthdrv_class = class_create(THIS_MODULE, "sixth_drv");

  160.     sixthdrv_class_dev = class_device_create(sixthdrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */

  161.     gpfcon = (volatile unsigned long *)ioremap(0x56000050, 16);
  162.     gpfdat = gpfcon + 1;

  163.     gpgcon = (volatile unsigned long *)ioremap(0x56000060, 16);
  164.     gpgdat = gpgcon + 1;

  165.     return 0;
  166. }

  167. static void sixth_drv_exit(void)
  168. {
  169.     unregister_chrdev(major, "sixth_drv");
  170.     class_device_unregister(sixthdrv_class_dev);
  171.     class_destroy(sixthdrv_class);
  172.     iounmap(gpfcon);
  173.     iounmap(gpgcon);
  174.     return 0;
  175. }


  176. module_init(sixth_drv_init);

  177. module_exit(sixth_drv_exit);

  178. MODULE_LICENSE("GPL");
测试程序可以用之前提供的。

阅读(1967) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~