天天看點

Linux驅動程式開發之三----按鍵驅動(Tiny6410)

在Linux驅動程式開發之三----按鍵驅動(Tiny6410)博文中讨論了使用中斷來實作按鍵驅動,毫無疑問,中斷方式效率相當高,但是在此之前,CPU要想獲知按鍵的狀态都是通過查詢方式來實作的,查詢方式就是CPU不停的檢查按鍵的狀态,如果有變化則立即輸出,而中斷是外設向CPU傳遞消息,告訴CPU自己狀态改變了,要求CPU進行處理,而其他時間CPU可以做自己想做的事情,和微機原理以及作業系統課程中講的一樣,代碼實作如下:

首先編寫驅動架構,然後配置KEY值的GPIO管腳為輸入,然後實作read函數,在read函數中讀取KEY值,并拷貝到使用者空間,使用者程式則不停的讀取按鍵的狀态,如果變低則輸出一條消息,否則不輸出。Tiny6410中按鍵的電路圖如下:

Linux驅動程式開發之三----按鍵驅動(Tiny6410)

當未按下時,K1~K8為高電平,當按下後為低電平。

按鍵對應GPIO

KEY GPIO管腳
KEY1 GPN0
KEY2 GPN1
KEY3 GPN2
KEY4 GPN3
KEY5 GPN4
KEY6 GPN5
KEY7 GPL11
KEY8 GPL12

詳細代碼如下:

[cpp] view plain copy print ?

Linux驅動程式開發之三----按鍵驅動(Tiny6410)
Linux驅動程式開發之三----按鍵驅動(Tiny6410)
  1. #include <linux/module.h>//MODULE_LICENSE,MODULE_AUTHOR  
  2. #include <linux/init.h>//module_init/module_exit  
  3. #include <linux/fs.h>//file_operations  
  4. #include <asm/io.h>//ioread32,iowrite32  
  5. #include <linux/cdev.h>//cdev  
  6. #include <mach/map.h>//定義了S3C64XX_VA_GPIO  
  7. #include <mach/regs-gpio.h>//定義了gpio-bank-n中使用的S3C64XX_GPN_BASE  
  8. #include <mach/gpio-bank-n.h>//定義了GPNCON  
  9. #include <mach/gpio-bank-l.h>//定義了GPNCON  
  10. #include <linux/wait.h>//wait_event_interruptible(wait_queue_head_t q,int condition);  
  11. //wake_up_interruptible(struct wait_queue **q)  
  12. #include <linux/sched.h>//request_irq,free_irq  
  13. #include <asm/uaccess.h>//copy_to_user  
  14. #include <linux/irq.h>//IRQ_TYPE_EDGE_FALLING  
  15. #include <linux/interrupt.h>//request_irq,free_irq  
  16. #include <linux/device.h>//class device  
  17. MODULE_AUTHOR("jefby");  
  18. MODULE_LICENSE("Dual BSD/GPL");  
  19. MODULE_DESCRIPTION("Tiny 6410 buttons with search");  
  20. #define GPNCON 0x7F008830  
  21. #define GPLCON0 0x7F008810  
  22. static volatile unsigned int * gpncon = NULL;  
  23. static volatile unsigned int * gpndat = NULL;  
  24. static volatile unsigned int * gplcon = NULL;  
  25. static volatile unsigned int * gpldat = NULL;  
  26. //按鍵裝置的主裝置号  
  27. static int buttons_major = 0;  
  28. //裝置号  
  29. dev_t dev;  
  30. //字元裝置  
  31. struct cdev * buttons_cdev;  
  32. static struct class * tiny6410_buttons_class = NULL;  
  33. static struct device * tiny6410_buttons_device = NULL;  
  34. //裝置打開操作,主要完成BUTTONS所對應的GPIO的初始化,注冊使用者中斷處理函數  
  35. int  buttons_open(struct inode *inode,struct file *filp)  
  36. {  
  37.     unsigned val;  
  38.     gpncon = (volatile unsigned int*)ioremap(GPNCON,16);  
  39.     gpndat = gpncon + 1;  
  40.     val = ioread32(gpncon);//讀取GPNCON的值  
  41.     val = (val & ~(0xFFF));//設定GPIO 0~5為輸入  
  42.     iowrite32(val,gpncon);  
  43.     //設定KEY7,KEY8為輸入,gpl11,gpl12  
  44.     gplcon = (volatile unsigned int*)ioremap(GPLCON0,16);  
  45.     gpldat = gplcon + 2;//gpldat  
  46.     val = ioread32(gplcon+1);//讀取GPNCON1的值  
  47.     val = (val & ~(0xFF<<12));//設定GPL11和12為輸入  
  48.     iowrite32(val,gplcon+1);  
  49.     printk("buttons open.\n");  
  50.     return 0;  
  51. }  
  52. //按鍵讀若沒有鍵被按下,則使程序休眠;若有按鍵被按下,則拷貝資料到使用者空間,然後清零  
  53. int buttons_read(struct file *filp, char __user *buf, size_t len, loff_t * pos)  
  54. {  
  55.     unsigned char keyval[8]={0};  
  56.     unsigned int temp=0;  
  57.     int i=0;  
  58.     if(len != 8)  
  59.         return -1;  
  60.     temp=ioread32(gpndat);  
  61.     //讀取KEY1~KEY6的值  
  62.     for(i=0;i<6;++i){  
  63.         keyval[i] = (temp&(0x1<<i))?1 : 0;  
  64.     }  
  65.     temp = ioread32(gpldat);  
  66.     //讀取KEY7和KEY8的值  
  67.     keyval[6]=(temp&(0x1<<11))?1:0;  
  68.     keyval[7]=(temp&(0x1<<12))?1:0;  
  69.     copy_to_user(buf,keyval,sizeof(keyval));  
  70.     return 0;  
  71. }  
  72. //主要是解除安裝使用者中斷處理程式  
  73. int buttons_close(struct inode *inode,struct file *filp)  
  74. {  
  75.     printk("buttons close.\n");  
  76.     return 0;  
  77. }  
  78. static struct file_operations buttons_fops = {  
  79.     .owner = THIS_MODULE,  
  80.     .read = buttons_read,  
  81.     .release = buttons_close,  
  82.     .open = buttons_open,  
  83. };  
  84. static int module_buttons_init(void)  
  85. {  
  86.     int err=0;  
  87.     int result=0;  
  88.     printk("Tiny6410 buttons module init.\n");    
  89.     if(buttons_major){  
  90.         dev = MKDEV(buttons_major,0);  
  91.         result = register_chrdev_region(dev,1,"buttons");  
  92.     }else{  
  93.         result = alloc_chrdev_region(&dev,0,1,"buttons");  
  94.         buttons_major = MAJOR(dev);  
  95.     }  
  96.     if(result < 0){  
  97.         printk(KERN_WARNING "buttons : can't get major %d\n",buttons_major);  
  98.     }  
  99.     printk("buttons major is %d",buttons_major);  
  100.     buttons_cdev = cdev_alloc();  
  101.     buttons_cdev ->ops = &buttons_fops;  
  102.     cdev_init(buttons_cdev,&buttons_fops);  
  103.     cdev_add(buttons_cdev,dev,1);  
  104.     tiny6410_buttons_class = class_create(THIS_MODULE, "tiny6410buttons");  
  105.     if (IS_ERR(tiny6410_buttons_class)) {  
  106.         err = PTR_ERR(tiny6410_buttons_class);  
  107.         printk("create class error.\n");  
  108.     }  
  109.     tiny6410_buttons_device = device_create(tiny6410_buttons_class, NULL, MKDEV(buttons_major, 0), NULL,  
  110.                   "buttons");  
  111.     printk("buttons add ok.\n");  
  112.     return 0;  
  113. }  
  114. static void module_buttons_exit(void)  
  115. {  
  116.     iounmap(gpncon);  
  117.     device_destroy(tiny6410_buttons_class, MKDEV(buttons_major, 0));  
  118.     class_destroy(tiny6410_buttons_class);  
  119.     cdev_del(buttons_cdev);  
  120.     unregister_chrdev_region(dev,1);  
  121.     printk("Tiny6410 buttons module exit");  
  122. }  
  123. module_init(module_buttons_init);  
  124. module_exit(module_buttons_exit);  

使用者程式的代碼如下:

[cpp] view plain copy print ?

Linux驅動程式開發之三----按鍵驅動(Tiny6410)
Linux驅動程式開發之三----按鍵驅動(Tiny6410)
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4. #include <sys/ioctl.h>  
  5. int main(int argc,char **argv)  
  6. {  
  7.     int i;  
  8.     int ret;  
  9.     int fd;  
  10.     unsigned char keyval[8]={1,1,1,1,1,1,1,1};  
  11.     static int cnt = 0;  
  12.     //打開裝置  
  13.     fd = open("/dev/buttons",0);  
  14.     if(fd < 0){  
  15.         printf("can't open /dev/buttons\n");  
  16.         return -1;  
  17.     }  
  18.     while(1){  
  19.         for(i=0;i<8;++i){  
  20.             ret = read(fd,keyval,sizeof(keyval));  
  21.             if(ret < 0){  
  22.                 printf("read err.\n");  
  23.                 return -1;  
  24.             }  
  25.             if(keyval[i] == 0){  
  26.                 printf("%d:KEY%d entered.\n",cnt++,i+1);  
  27.             }  
  28.         }//for  
  29.     }//while(1)  
  30.     close(fd);  
  31.     return 0;  
  32. }  

運作截圖如下:

Linux驅動程式開發之三----按鍵驅動(Tiny6410)

可以看出每按下一次就會列印出一串消息,說明那個按鍵被按下。使用top指令檢視目前的CPU使用率,截圖如下:可以看出,查詢方式下确實效率太低了,CPU被占用了90%多以上

Linux驅動程式開發之三----按鍵驅動(Tiny6410)

繼續閱讀