Chinaunix首页 | 论坛 | 博客
  • 博客访问: 829161
  • 博文数量: 281
  • 博客积分: 0
  • 博客等级: 民兵
  • 技术积分: 2770
  • 用 户 组: 普通用户
  • 注册时间: 2009-08-02 19:45
个人简介

邮箱:zhuimengcanyang@163.com 痴爱嵌入式技术的蜗牛

文章分类
文章存档

2020年(1)

2018年(1)

2017年(56)

2016年(72)

2015年(151)

分类: 嵌入式

2015-08-18 12:55:54

目的:
上一篇是不断查询按键的状态,CPU要一直占用。
这节主要利用中断方式,当按键没有被按下时,进入休眠状态;
当按下按键时,唤醒休眠进程,返回按键值。






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. static struct class *thirddrv_class;
  13. static struct class_device    *thirddrv_class_dev;

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

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


  18. static DECLARE_WAIT_QUEUE_HEAD(button_waitq);

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


  21. struct pin_desc{
  22.     unsigned int pin;
  23.     unsigned int key_val;
  24. };


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

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


  34. /*
  35.   * 当按键被按下的时候,会调用这个函数。在这个函数中:1. 确定按键值; 2. 置位按键被按下的标志位,并且唤醒进程。
  36.   */
  37. static irqreturn_t buttons_irq(int irq, void *dev_id)
  38. {
  39.     // void *dev_id 这个参数从注册函数传递过来。
  40.     struct pin_desc * pindesc = (struct pin_desc *)dev_id;
  41.     unsigned int pinval;
  42.     
  43.     pinval = s3c2410_gpio_getpin(pindesc->pin);

  44.     if (pinval)
  45.     {
  46.         /* 松开 */
  47.         key_val = 0x80 | pindesc->key_val;
  48.     }
  49.     else
  50.     {
  51.         /* 按下 */
  52.         key_val = pindesc->key_val;
  53.     }

  54.     ev_press = 1; /* 表示中断发生了 */
  55.     wake_up_interruptible(&button_waitq); /* 唤醒休眠的进程 */

  56.     
  57.     return IRQ_RETVAL(IRQ_HANDLED);
  58. }

  59. // 在打开的函数中,进行中断注册
  60. static int third_drv_open(struct inode *inode, struct file *file)
  61. {
  62.     // 注册按键的中断
  63.     // int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id)
  64.     /*  1. irq:      表示中断号
            2. handler:  表示中断处理函数
            3. irqflags: 表示中断类型。
            4. devname:   表示设备名字,自己定义的。
            5. dev_id:    传递给中断处理函数handler的参数。

  65.      */

  66.     request_irq(IRQ_EINT0, buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
  67.     request_irq(IRQ_EINT2, buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
  68.     request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
  69.     request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);    

  70.     return 0;
  71. }

  72. ssize_t third_drv_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
  73. {
  74.     if (size != 1)
  75.         return -EINVAL;

  76.     /* 如果没有按键动作,则进入休眠,不会运行下面的语句。通过判断ev_press的状态来唤醒进程。当按键按下时,ev_press为1,唤醒休眠进程。*/
  77.     wait_event_interruptible(button_waitq, ev_press);

  78.     
  79.     /* 程序运行到这里的时候,表示按键已经被按下,进程被唤醒,读取按键值,返回到应用空间, 并将按键状态值清除。*/
  80.     copy_to_user(buf, &key_val, 1);
  81.     ev_press = 0;
  82.     
  83.     return 1;
  84. }


  85. int third_drv_close(struct inode *inode, struct file *file)
  86. {
  87.     free_irq(IRQ_EINT0, &pins_desc[0]);
  88.     free_irq(IRQ_EINT2, &pins_desc[1]);
  89.     free_irq(IRQ_EINT11, &pins_desc[2]);
  90.     free_irq(IRQ_EINT19, &pins_desc[3]);
  91.     return 0;
  92. }


  93. static struct file_operations sencod_drv_fops = {
  94.     .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */
  95.     .open = third_drv_open,
  96.     .read = third_drv_read,    
  97.     .release = third_drv_close,    // 什么时候用???
  98. };


  99. int major;
  100. static int third_drv_init(void)
  101. {
  102.     major = register_chrdev(0, "third_drv", &sencod_drv_fops);

  103.     thirddrv_class = class_create(THIS_MODULE, "third_drv");
  104.     thirddrv_class_dev = class_device_create(thirddrv_class, NULL, MKDEV(major, 0), NULL, "buttons"); /* /dev/buttons */

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

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

  109.     return 0;
  110. }

  111. static void third_drv_exit(void)
  112. {
  113.     unregister_chrdev(major, "third_drv");
  114.     class_device_unregister(thirddrv_class_dev);
  115.     class_destroy(thirddrv_class);

  116.     iounmap(gpfcon);
  117.     iounmap(gpgcon);
  118. }


  119. module_init(third_drv_init);
  120. module_exit(third_drv_exit);
  121. MODULE_LICENSE("GPL");
中断函数原型
/**
 *    request_irq - allocate an interrupt line
 *    @irq: Interrupt line to allocate
 *    @handler: Function to be called when the IRQ occurs
 *    @irqflags: Interrupt type flags
 *    @devname: An ascii name for the claiming device
 *    @dev_id: A cookie passed back to the handler function
 *
 *    This call allocates interrupt resources and enables the
 *    interrupt line and IRQ handling. From the point this
 *    call is made your handler function may be invoked. Since
 *    your handler function must clear any interrupt the board
 *    raises, you must take care both to initialise your hardware
 *    and to set up the interrupt handler in the right order.
 *
 *    Dev_id must be globally unique. Normally the address of the
 *    device data structure is used as the cookie. Since the handler
 *    receives this value it makes sense to use it.
 *
 *    If your interrupt is shared you must pass a non NULL dev_id
 *    as this is required when freeing the interrupt.
 *
 *    Flags:
 *
 *    IRQF_SHARED        Interrupt is shared
 *    IRQF_DISABLED    Disable local interrupts while processing
 *    IRQF_SAMPLE_RANDOM    The interrupt can be used for entropy
 *
 */
int request_irq(unsigned int irq, irq_handler_t handler, unsigned long irqflags, const char *devname, void *dev_id)
// 参数说明:
1. irq: 表示中断号
2. handler: 表示中断处理函数
3. irqflags: 表示中断类型。
4. devname: 表示设备名字,自己定义的。
5. dev_id: 传递给中断处理函数handler的参数。


3. 测试程序

点击(此处)折叠或打开

  1. #include <sys/types.h>
  2. #include <sys/stat.h>
  3. #include <fcntl.h>
  4. #include <stdio.h>

  5. /* thirddrvtest
  6.   */
  7. int main(int argc, char **argv)
  8. {
  9.     int fd;
  10.     unsigned char key_val;
  11.     
  12.     fd = open("/dev/buttons", O_RDWR);
  13.     if (fd < 0)
  14.     {
  15.         printf("can't open!\n");
  16.     }

  17.     while (1)
  18.     {
  19.         read(fd, &key_val, 1)// 问题:这句话将调用驱动函数third_drv_read,而进入休眠状态,那么下面的打印语句还会运行吗??
  20.         printf("key_val = 0x%x\n", key_val);  //如果没有按键按下,则进入休眠,这句话不会被打印。
  21.     }
  22.     
  23.     return 0;
  24. }

4. 测试



5. 小结
利用中断 + 休眠的方式,来读取按键被按下时的状态。
中断的方式,不需要一直占用CPU。但是应用程序还是一直在查询,只不过当按键没被按下的时候,进入休眠态。




知识点:
(1)中断注册函数
(2)如何注册休眠进程,以及如何唤醒等等。

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