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写代码

intit入口函数中使用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!!!\n");
  return -1;}

 while(1)
 {
      ret=read(fd,val,sizeof(val));
      if(ret<0)
      {
      printf("read err!\n");     
      continue;
      }

      if((val[0]&val[1]&val[2]&val[3])==0)
             printf("key0=%d,key1=%d,key2=%d,key3=%d\n",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");

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏九彩拼盘的叨叨叨

写爬小说的爬虫的一些心得

小说网站的页面内容编码用的 GBK,如果不做处理,中文内容会是乱码。解决方案是用 iconv-lite 来对内容用 GBK 的方式来解码。大概的写法:

813
来自专栏Coding01

简述 Laravel Model Events 的使用

最近一直在思考如何利用 Laravel,更进一步做出一套较为不一样的开发框架出来。反复看了很多有关 Laravel 框架的资料和文档,最后还是落在 Larave...

472
来自专栏大前端_Web

解析Web Workers

版权声明:本文为吴孔云博客原创文章,转载请注明出处并带上链接,谢谢。 https://blog.csdn.net/wkyseo/articl...

562
来自专栏程序猿DD

Spring Cloud构建微服务架构:分布式服务跟踪(收集原理)【Dalston版】

在本节内容之前,我们已经对如何引入Sleuth跟踪信息和搭建Zipkin服务端分析跟踪延迟的过程做了详细的介绍,相信大家对于Sleuth和Zipkin已经有了一...

3287
来自专栏IMWeb前端团队

网页性能监控利器---Performance

本文作者:IMWeb went 原文出处:IMWeb社区 未经同意,禁止转载 一、性能监测&数据上报 作为前端工程师,无论是业务需要还是我们对于自己开...

1919
来自专栏磨磨谈

rbd的image快照与Pool快照

这个错我之前也没见过,并且因为很少用到快照,所以可能也就没有触发这个问题,在查看了一些资料以后,明白了原因,这里就梳理一下

772
来自专栏柠檬先生

html5 离线存储 地理信息与本地存储

搭建离线应用程序   ①服务器设置头信息 :     AddType text/cache-manifest .manifest   ② html标签...

1859
来自专栏Linyb极客之路

web前端性能优化

网站的划分一般为二:前端和后台。我们可以理解成后台是用来实现网站的功能的,比如:实现用户注册,用户能够为文章发表评论等等。而前端呢?其实应该是属于功能的表现。并...

652
来自专栏AhDung

【C#】给无窗口的进程发送消息

一个winform程序,我希望它不能多开(但是如何防多开不是本文要讲的),那么在用户启动第二个实例的时候,作为第二个实例来说,大概可以有这么几种做法:

753
来自专栏编程

2017最全的Java学习方向

方向不对努力白费,Java技术的学习并不是一蹴而就的,正确的学习方向能让你事半功倍,如果你想在自己的Java学习之初就了解学Java又好又快的方法,那么这篇文章...

1875

扫码关注云+社区