zoukankan      html  css  js  c++  java
  • 6.驱动支持多按键操作

    多按键驱动程序优化

    优化的代码,支持两个按键的支持的代码:duokey.c:

    #include <linux/module.h>        /* For module specific items */

    #include <linux/fs.h>            /* For file operations */

    #include <linux/ioport.h>        /* For io-port access */

    #include <linux/io.h>            /* For inb/outb/... */

    #include <linux/init.h>

    #include <linux/miscdevice.h>

    #include <linux/interrupt.h>

    #include <linux/slab.h>

    #define GPNCON 0x7f008830

    #define GPNDAT 0x7f008834

    struct work_struct *work1;

    struct timer_list key_timer;//定义定时器

    unsigned int *gpio_data;

    void work1_func(struct work_struct *work)

    {

        //启动定时器 100毫秒超时=HZ/10,HZ=1秒。jiffies是系统当前时间

        mod_timer(&key_timer,jiffies+HZ/10);

    }

    void key_timer_func(unsigned long data)

    {    //定时器超时的函数需要修改,需要判断是哪个按键超时

        

        unsigned int key_val;

        //超时的时候,就要读取data

        key_val=readw(gpio_data)&0x01;//读出一个按键EINT0的值。

        //当他被按下,就是低电平的时候,就是被按下了。才是有效的按键

        if(0==key_val)//真正按下

            printk("<0> key1 down! ");

        key_val=readw(gpio_data)&0x02;//读出一个按键EINT1的值。

        //当他被按下,就是低电平的时候,就是被按下了。才是有效的按键

        if(0==key_val)//真正按下

            printk("<0> key2 down! ");

    }

    irqreturn_t key_int(int irq, void *dev_id)

    {

        //1.检测是否发生了按键中断

        //2.清除已经发生的按键中断

    //前面的都是硬件相关的工作,必须在中断里面执行

    //下面是硬件无关的工作,我们把它提到中断以外的work1_func函数去处理。

        //3.打印按键值

        schedule_work(work1);

        

        return 0;

    }

    void key_hw_init()

    {

        unsigned int *gpio_config;

        unsigned short data;

        gpio_config = ioremap(GPNCON,4);

        data = readw(gpio_config);

        data &= ~0b1111;//增加一个按键

        data |= 0b1010;

        writew(data,gpio_config);

        gpio_data = ioremap(GPNDAT,4);

    }

    int key_open(struct inode *node, struct file *filp)

    {

        return 0;

    }

    struct file_operations key_fops =

    {

        .open = key_open,

    };

    struct miscdevice key_miscdevice =

    {

        .minor = 200,

        .name = "OK6410key",

        .fops = &key_fops,

    };

    static int key_init()

    {

        misc_register(&key_miscdevice);

        //注册中断处理程序

        request_irq(IRQ_EINT(0),key_int, IRQF_TRIGGER_FALLING,"OK6410key",0);

        //增加一个按键的支持

        request_irq(IRQ_EINT(1),key_int, IRQF_TRIGGER_FALLING,"OK6410key",0);

        

        //硬件初始化

        key_hw_init();//相应的位进行设置

        //2. 创建工作

        work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);

        INIT_WORK(work1, work1_func);

        //定时器初始化

        init_timer(&key_timer);

        key_timer.function=key_timer_func;

        

        //注册定时器

        add_timer(&key_timer);

        return 0;

    }

    static void key_exit()

    {

        misc_deregister(&key_miscdevice);

        

    }

    module_init(key_init);

    module_exit(key_exit);

    /*优化:多一个中断,gpio也进行多按键初始化,中断产生的时候要判断是哪个按键产生的中断。*/

    Make的结果:

    生成.ko驱动文件,拷贝到板子运行。按下1,2号键会输出相应的信息。

    首先是创建相应的字符设备文件。

    mknod /dev/6410key c 10 200

    按键应用程序设计

    应用程序的代码key_app.c:主要的功能是读出按下键的值:

    #include <stdio.h>

    #include <stdlib.h>

    int main()

    {

    int fd;

    int key_num;

    //1.打开设备

    fd=open("/dev/6410key",0);

    if(fd<0)

    printf("open device fail! ");

    //2.读取设备

    read(fd,&key_num,4);

    printf("key is %d ",key_num);

    //3.关闭设备

    close(fd);

    return 0;

    }

    编译:arm-linux-gcc -static key_app.c -o key_app

    这就是我们的按键测试应用程序。

    其实现在还不能进行测试我们之前的驱动程序:因为我们之前的file_operations 结构里只有open函数。并不支持read。

    struct file_operations key_ops =

    {

        .open = key_open,

        

    };

    这些函数都不用记学会去内核代码找原型。

    编写完,make,出错:implicit declaration of function 'copy_to_user'没有他的头文件,头文件是linux/eaccess.h.最后make成功:

    改进后的duokey.c:

    #include <linux/module.h>        /* For module specific items */

    #include <linux/fs.h>            /* For file operations */

    #include <linux/ioport.h>        /* For io-port access */

    #include <linux/io.h>            /* For inb/outb/... */

    #include <linux/init.h>

    #include <linux/miscdevice.h>

    #include <linux/interrupt.h>

    #include <linux/slab.h>

    #include <linux/uaccess.h>

     

    #define GPNCON 0x7f008830

    #define GPNDAT 0x7f008834

     

     

    struct work_struct *work1;

    struct timer_list key_timer;//定义定时器

    unsigned int *gpio_data;

     

    //全局变量

    unsigned int key_num;

    //read按键

    ssize_t key_read(struct file *filp, char __user *buf, size_t size, loff_t *pos)

    {

        //返回内核的给用户

        copy_to_user(buf,&key_num,4);

        return 4;

    }

     

    void work1_func(struct work_struct *work)

    {

        //启动定时器 100毫秒超时=HZ/10,HZ=1秒。jiffies是系统当前时间

        mod_timer(&key_timer,jiffies+HZ/10);

    }

    void key_timer_func(unsigned long data)

    {    //定时器超时的函数需要修改,需要判断是哪个按键超时

        

        unsigned int key_val;

        //超时的时候,就要读取data

        key_val=readw(gpio_data)&0x01;//读出一个按键EINT0的值。

        //当他被按下,就是低电平的时候,就是被按下了。才是有效的按键

        if(0==key_val)//真正按下

            key_num=1;//读取按键编号

     

        key_val=readw(gpio_data)&0x02;//读出一个按键EINT1的值。

        //当他被按下,就是低电平的时候,就是被按下了。才是有效的按键

        if(0==key_val)//真正按下

            key_num=2;

    }

     

    irqreturn_t key_int(int irq, void *dev_id)

    {

        //1.检测是否发生了按键中断

        //2.清除已经发生的按键中断

    //前面的都是硬件相关的工作,必须在中断里面执行

    //下面是硬件无关的工作,我们把它提到中断以外的work1_func函数去处理。

        //3.打印按键值

        schedule_work(work1);

        

        return 0;

    }

     

    void key_hw_init()

    {

        unsigned int *gpio_config;

        unsigned short data;

        gpio_config = ioremap(GPNCON,4);

        data = readw(gpio_config);

        data &= ~0b1111;//增加一个按键

        data |= 0b1010;

        writew(data,gpio_config);

     

        gpio_data = ioremap(GPNDAT,4);

    }

    int key_open(struct inode *node, struct file *filp)

    {

        return 0;

    }

    struct file_operations key_fops =

    {

        .open = key_open,

        .read = key_read,//增加了读取操作

    };

    struct miscdevice key_miscdevice =

    {

        .minor = 200,

        .name = "6410key",

        .fops = &key_fops,

    };

     

    static int key_init()

    {

        misc_register(&key_miscdevice);

        //注册中断处理程序

        request_irq(IRQ_EINT(0),key_int, IRQF_TRIGGER_FALLING,"6410key",0);

        //增加一个按键的支持

        request_irq(IRQ_EINT(1),key_int, IRQF_TRIGGER_FALLING,"6410key",0);

        

        //硬件初始化

        key_hw_init();//相应的位进行设置

     

        //2. 创建工作

        work1 = kmalloc(sizeof(struct work_struct),GFP_KERNEL);

        INIT_WORK(work1, work1_func);

        //定时器初始化

        init_timer(&key_timer);

        key_timer.function=key_timer_func;

        

        //注册定时器

        add_timer(&key_timer);

        return 0;

    }

     

    static void key_exit()

    {

        misc_deregister(&key_miscdevice);

        

    }

     

    module_init(key_init);

    module_exit(key_exit);

     

    /*优化:多一个中断,gpio也进行多按键初始化,中断产生的时候要判断是哪个按键产生的中断。*/

    接下来就是开发板的测试:首先还是把生成的按键驱动文件拷贝到开发板:安装。

    接着是创建字符设备文件:

    mknod /dev/6410key c 10 200

    6410key是我们用到的设备文件,c是字符设备文件的标志,10是混杂设备的固定的主设备号,200是我们在字符驱动里定义的次设备号。

    创建好了之后,运行应用程序key_app:

    [root@FORLINX6410]# ./key_app

    key is 0

  • 相关阅读:
    hdu 6214 : Smallest Minimum Cut 【网络流】
    hdu 6205: card card card【输入挂】
    UVa 10054 : The Necklace 【欧拉回路】
    hdu 6127 : Hard challenge (2017 多校第七场 1008)(计算几何)
    hdu 6143: Killer Names (2017 多校第八场 1011)
    hdu 6134: Battlestation Operational (2017 多校第八场 1002)【莫比乌斯】
    hdu 4992 Primitive Roots 【求原根模板】
    poj 1284 : Primitive Roots
    codevs 2804 最大最小数质因数
    codevs 2370 小机房的树
  • 原文地址:https://www.cnblogs.com/FORFISH/p/5188563.html
Copyright © 2011-2022 走看看