zoukankan      html  css  js  c++  java
  • 4.查询方式来写按键驱动程序(详解)

    本节目标:

       写second程序,内容:通过查询方式驱动按键

    1.写出框架

    1.1写file_oprations结构体,second_drv_open函数,second_drv_read函数

    1.2写入口函数,并自动创建设备节点,修饰入口函数

    1.3写出口函数,并自动注销设备节点,修饰出口函数

    1.4 写MODULE_LICENSE(“GPL v2”)声明函数许可证

    1.5 在入口函数中,利用class_create和class_device_create自动创建设备节点

    在出口函数中,利用class_destroy和class_device_unregister注销设备节点

    2.写Makefile并编译后,放在板子上insmod后,看看lsmod、cat /porc/devices、 ls -l /dev/second是否加载成功,如下图:

    3.在框架中实现硬件操作

    3.1看原理图,确定用什么寄存器控制按键引脚,如下图

     

    按键0~3分别是GPF0,GPF2,GPG3,GPG11

    由于是使用查询模式,并不是外部中断模式

    所以配置 GPFCON(0x56000050)的位[0:1]、位[4:5]等于0x00(输入模式)

    GPGCON(0x56000060)的位[6:7]、位[22:23]等于0x00

    通过GPGDAT (0x56000054) 和GPGDAT(0x56000064)来查询按键状态

    3.2写代码

    init入口函数中使用ioremap()函数映射寄存器虚拟地址

    exit出口函数中使用iounmap()函数注销虚拟地址

    open函数中配置GPxCON初始化按键

    read函数中先检查读出的字符是否是4个,然后获取GPxDAT状态,用key_vals[4]数组保存4个按键值,最后使用 copy_to_user(buf, key_vals,sizeof(key_vals)) 上传给用户层

    4.写测试程序Secondtext.c

    用法就是./ Secondtext

    使用read(fd,val,sizeof(val));函数读取内核层的数据

    5.然后输入./ Secondtext进行测试,按下key2时,如下图:

     

    6.使用./ Secondtext & 后台运行测试程序

    后台会一直运行这个程序,当我们有按键按下时,就会打印数据出来,如下图:

     

    7.通过top命令可以发现这个./ Secondtext占了CPU的99%时间

    因为,我们的Secondtext测试程序一直在while中通过查询方式读取按键状态,这样的效率是非常低的.

    接下来开始使用中断方式来改进按键驱动程序,提高效率,先来分析内核里中断如何运行的。 

    本节Secondtext测试程序代码如下:

    #include <sys/types.h>    //调用sys目录下types.h文件
    #include <sys/stat.h>      //stat.h获取文件属性
    #include <fcntl.h>
    #include <stdio.h>
    #include <string.h>
    

    /*secondtext while一直获取按键信息 */ int main(int argc,char **argv) { int fd,ret; unsigned char val[4]; fd=open("/dev/buttons",O_RDWR); if(fd<0) {printf("can't open!!! "); return -1;} while(1) { ret=read(fd,val,sizeof(val)); if(ret<0) { printf("read err! "); continue; } if((val[0]&val[1]&val[2]&val[3])==0) printf("key0=%d,key1=%d,key2=%d,key3=%d ",val[0],val[1],val[2],val[3]); } return 0; }

    本节second.c按键驱动代码如下:

    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/fs.h>
    #include <linux/init.h>
    #include <linux/delay.h>
    #include <asm/irq.h>
    #include <asm/arch/regs-gpio.h>
    #include <asm/hardware.h>
    #include <asm/uaccess.h>
    #include <asm/io.h>
    
    
    
    static struct class *seconddrv_class;               //创建一个class类
    static struct class_device   *seconddrv_class_devs; //创建类的设备
    
    volatile unsigned long *GPFcon;       
    volatile unsigned long *GPFdat;
    volatile unsigned long *GPGcon;       
    volatile unsigned long *GPGdat;
    
    static int second_drv_open(struct inode *inode, struct file  *file)
    {
        /*初始化按键*/   
       /* 配置 GPFCON(0x56000050)的位[0:1]、位[4:5]等于0x00(输入模式)
          GPGCON(0x56000060)的位[6:7]、位[22:23]等于0x00*/
        *GPFcon&=~((0x3<<0)|(0x3<<4));
        *GPGcon&=~((0x3<<6)|(0x3<<22));
    
       return 0;
    }
    
    static int second_drv_read(struct file *file, const char __user *buf, size_t count, loff_t * ppos)
    {
             unsigned char key_vals[4];
    
           /*按键0~3分别是GPF0,GPF2,GPG3,GPG11*/
            if(count!=sizeof(key_vals))
                     return EINVAL;       
    
              key_vals[0]=(*GPFdat>>0)&0X01;   
              key_vals[1]=(*GPFdat>>2)&0X01;           
              key_vals[2]=(*GPGdat>>3)&0X01; 
              key_vals[3]=(*GPGdat>>11)&0X01;   
    
         /*上传给用户层*/
           if(copy_to_user(buf,key_vals,sizeof(key_vals)))
            return EFAULT;
      return 0;
    
    }
    
     
    
    static struct file_operations second_drv_fops={
           .owner = THIS_MODULE,
           .open = second_drv_open,
           .read = second_drv_read,};
    volatile int second_major; //保存主设备号 static int second_drv_init(void) { second_major=register_chrdev(0,"second_drv",&second_drv_fops); //创建驱动 seconddrv_class=class_create(THIS_MODULE,"second_dev"); //创建类名 seconddrv_class_devs=class_device_create(seconddrv_class, NULL, MKDEV(second_major,0), NULL,"buttons");
    /*申请虚拟地址,然后配置寄存器*/ /* GPFCON(0x56000050) GPGCON(0x56000060) */ GPFcon=ioremap(0x56000050,16); GPFdat=GPFcon+1; GPGcon=ioremap(0x56000060,16); GPGdat=GPGcon+1; return 0; } static int second_drv_exit(void) { unregister_chrdev(second_major,"second_drv"); //卸载驱动 class_device_unregister(seconddrv_class_devs); //卸载类设备 class_destroy(seconddrv_class); //卸载类 /*注销虚拟地址*/ iounmap(GPFcon); iounmap(GPGcon);
    return 0; } module_init(second_drv_init); module_exit(second_drv_exit); MODULE_LICENSE("GPL v2");

    接下来,下章学习内核中的中断如何实现的,来使用中断按键:

    5.分析内核中断运行过程,以及中断3大结构体:irq_desc、irq_chip、irqaction(详解)

  • 相关阅读:
    好理解的堆排序
    SpringCloud 整合 Python 服务
    SpringCloud入门总结
    Spring异常集中处理和日志集中打印
    Java枚举类型的理解及在后台响应中的使用
    Elasticsearch合并高亮字段
    Elasticsearch分析器结构组成
    Elasticsearch实现英文区分大小写搜索
    Nginx三大功能
    Elasticsearch Java Client 版本区别及起步(5.X 和6.X)
  • 原文地址:https://www.cnblogs.com/lifexy/p/7506387.html
Copyright © 2011-2022 走看看