美文网首页
四 . 树莓派A20 GPIO中断程序编写(1基本处理)

四 . 树莓派A20 GPIO中断程序编写(1基本处理)

作者: wit_yuan | 来源:发表于2017-07-18 14:22 被阅读0次

    1 参考资料

    1. \marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\arch\arm\plat-sunxi\include\plat\Irqs.h
    2. \marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\drivers\input\touchscreen\Gt818_ts.c

    2 硬件原理图

    关于按键,在DVK521上为:


    按键

    我又从一份数据手册中看到,PI7,PI8,PI9是没有外部中断功能的。如下图所示:


    中断功能

    还好,目前的按键是通过短接帽来连接PI7PI9的,那么可以将短接帽拿掉,使用杜邦线连接PI10PI12。

    现在我将Key2连接到PI10上。那么KEY2的中断引脚为EINT22。

    配置sys_config.fex文件:

    [key_test_para]
    key_test_enable     = 1
    key2                = port:PI10<0><1><default><default>
    

    3 软件配置基础知识

    现在使用的树莓派A20,是一个双核A7的芯片,而这个属于SMP架构,中断处理方式也已经和原先的理念大有不同。所以还是要知道关于linux的中断原理,可以从网络中获取相关历史性技术知识。

    3.1 中断

    从A20的数据手册中,可以看到外部中断数到了EINT31。也就是说PIO中断功能有32个。

    3.2 一些关于IO功能的API函数

    下面列出的API函数是在 \linux-sunxi\arch\arm\plat-sunxi\Sys_config.c中。

    /*
     * CSP_GPIO_Request_EX
     * 函数名称:
     *
     * 参数说明:
     * main_name   传进的主键名称,匹配模块(驱动名称)
     * sub_name    传进的子键名称,如果是空,表示全部,否则寻找到匹配的单独GPIO
     *
     * 返回值  :0 :    err
     *          other: success
     *
     * 说明    :暂时没有做冲突检查
     */
    u32 gpio_request_ex(char *main_name, const char *sub_name)  /* 设备申请GPIO函数扩展接口 */
    
    /*
     * CSP_GPIO_Set_One_PIN_IO_Status
     * Description:
     * 修改用户申请过的GPIO中的某一个IO口的,输入输出状态
     * Arguments  :
     *  p_handler    :    handler
     *  if_set_to_output_status    :    设置成输出状态还是输入状态
     *  gpio_name    :    要操作的GPIO的名称
     */
    __s32  gpio_set_one_pin_io_status(u32 p_handler, __u32 if_set_to_output_status,
                      const char *gpio_name)
    
    
    /*
     * CSP_GPIO_Write_One_PIN_Value
     * Description:
     *  修改用户申请过的GPIO中的某一个IO口的端口的电平
     * Arguments:
     *  p_handler    :    handler
     *  value_to_gpio:  要设置的电平的电压
     *  gpio_name    :    要操作的GPIO的名称
     */
    __s32  gpio_write_one_pin_value(u32 p_handler, __u32 value_to_gpio,
                    const char *gpio_name)
    
    /*
     * CSP_GPIO_Set_One_PIN_Pull
     * Description:
     * 修改用户申请过的GPIO中的某一个IO口的,PULL状态
     * Arguments  :
     *        p_handler    :    handler
     *        if_set_to_output_status    :    所设置的pull状态
     *        gpio_name    :    要操作的GPIO的名称
     */
    __s32  gpio_set_one_pin_pull(u32 p_handler, __u32 set_pull_status,
                     const char *gpio_name)
    

    3.2 按键中断中用到的API

    1.gpio_request_ex(),获取sys_config.fex中设置的中断IO口。
    2.gpio_set_one_pin_io_status(),设置为输入状态。
    3.gpio_set_one_pin_pull(),设置输入引脚的上下拉状态。
    4.request_irq()注册中断函数。

    request_irq()函数:
    第一个参数为SW_INT_IRQNO_PIO,表示是外部端口的中断号。
    第二个参数为中断处理函数名。
    第三个参数为中断方式,如IRQ_TYPE_EDGE_RISING,上升沿触发,而IRQ_TYPE_EDGE_FALLING则是下降沿触发,IRQF_SHARED为共享。
    第四个参数为中断名。
    第五个参数为中断传递的数据。

    3.3 中断处理逻辑

    1.获取IO中断源信息
    由于内核使用的是虚拟地址寻址硬件地址,获取中断源就需要将IO硬件地址空间映射到虚拟地址上。可以使用ioremap(PIO_BASE_ADDRESS, PIO_RANGE_SIZE)进行映射。

    2.屏蔽中断源
    a.读取中断源寄存器的状态,可以使用readl(映射的IO地址 + PIO_INT_STAT_OFFSET);
    b.判断对应的中断,使用writel(reg_val&(1<<(CTP_IRQ_NO)),映射的IO地址 + PIO_INT_STAT_OFFSET);清除状态位。

    写到这里,本应该很顺利,可是,在驱动程序加载进内核的时候,明显是报错。错误我就不贴出来了,可是我可以将中断信息附上:

    root@marsboard:~# cat /proc/interrupts 
               CPU0       CPU1       
     29:       3989       2679       GIC  arch_timer
     30:          0          0       GIC  arch_timer
     32:          0          0       GIC  axp_mfd
     33:        286          0       GIC  serial
     39:       1396          0       GIC  sunxi-i2c.0
     40:          0          0       GIC  sunxi-i2c.1
     41:          0          0       GIC  sunxi-i2c.2
     54:          0          0       GIC  timer0
     55:         12          0       GIC  aw_clock_event
     56:          2          0       GIC  sunxi-rtc alarm
     59:      35778          0       GIC  dma_irq
     60:          0          0       GIC  sunxi-gpio
     64:          0          0       GIC  sunxi-mmc
     69:       5876          0       GIC  nand
     71:          0          0       GIC  ehci_hcd:usb2
     72:          0          0       GIC  ehci_hcd:usb4
     76:       7001          0       GIC  sunxi lcd0
     77:          0          0       GIC  sunxi lcd1
     78:          0          0       GIC  g2d
     79:       3495          0       GIC  sunxi scaler0
     80:          0          0       GIC  sunxi scaler1
     85:          0          0       GIC  cedar_dev
     87:        419          0       GIC  eth0
     88:          0          0       GIC  sw_ahci
     92:          0          0       GIC  ace_dev
     96:          0          0       GIC  ohci_hcd:usb3
     97:          0          0       GIC  ohci_hcd:usb5
    101:          0          0       GIC  mali_gp_irq_handlers
    102:          0          0       GIC  mali_mmu_irq_handlers
    103:          0          0       GIC  mali_pp_irq_handlers
    104:          0          0       GIC  mali_mmu_irq_handlers
    106:          0          0       GIC  mali_pp_irq_handlers
    107:          0          0       GIC  mali_mmu_irq_handlers
    IPI0:          0          0  Timer broadcast interrupts
    IPI1:       1564       4112  Rescheduling interrupts
    IPI2:          0          0  Function call interrupts
    IPI3:          4         20  Single function call interrupts
    IPI4:          0          0  CPU stop interrupts
    IPI5:          0          0  CPU backtrace
    Err:          0
    

    从这里,可以看出来,PIO中断号60已经注册进内核了。我们现在使用的一个IO中断是被包含在里面的。所以,需要在内核中找到sunxi-gpio是怎么去注册中断,而我们就需要将我们的中断程序内容附加到已经注册的中断上去。

    在 marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\drivers\gpio\Gpio-sunxi.c中我们可以找到函数:

    /* IRQ handler - redirect interrupts to virtual irq chip */
    static irqreturn_t sunxi_gpio_irq_handler(int irq, void *devid)
    {
        __u32 status = 0;
        int i = 0;
        struct sunxi_gpio_chip *sgpio = devid;
        status = readl(sgpio->gaddr + PIO_INT_STAT_OFFSET);
    
        for (i = 0; i < EINT_NUM; i++) {
            if ((status & (1 << i)) &&
                (gpio_eint_list[i].gpio >= 0)) {
                status &= ~(1 << i);
                SUNXI_CLEAR_EINT(sgpio->gaddr, i);
                generic_handle_irq(sgpio->irq_base + i);
            }
        }
    
        if (status)
            return IRQ_NONE;
    
        return IRQ_HANDLED;
    }
    
    

    里面最重要的函数是:

    /**
     * generic_handle_irq - Invoke the handler for a particular irq
     * @irq:    The irq number to handle
     *
     */
    int generic_handle_irq(unsigned int irq)
    

    最终调用的是:

    /*
     * Architectures call this to let the generic IRQ layer
     * handle an interrupt. If the descriptor is attached to an
     * irqchip-style controller then we call the ->handle_irq() handler,
     * and it calls __do_IRQ() if it's attached to an irqtype-style controller.
     */
    static inline void generic_handle_irq_desc(unsigned int irq, struct irq_desc *desc)
    {
        desc->handle_irq(irq, desc);
    }
    

    然而,它又被赋值了:

    /* caller has locked the irq_desc and both params are valid */
    static inline void __irq_set_handler_locked(unsigned int irq,
                            irq_flow_handler_t handler)
    {
        struct irq_desc *desc;
    
        desc = irq_to_desc(irq);
        desc->handle_irq = handler;
    }
    

    在一定程度的意义上,gpio-sunxi.c已经将中断基本处理做好了,我们要做的只是和它共享中断。

    3.4 实践逻辑

    sys_config.fex文件配置如下:


    sys_config.fex配置

    从上面的实验中,已经发现在request_irq中设置边沿等等触发,在安装ko文件的时候,都会报错,从这里看出,在共享中断的时候,是不允许设置其他的内容的。那么,只能去找A20寄存器中关于io口中断的设置。在这些设置已经设置好的情况下,中断应该就能响应了。这里贴出一个比较简单的驱动程序:

    #include "linux/init.h"
    #include <linux/kernel.h>
    #include <linux/module.h>
    #include <linux/leds.h>
    #include <plat/sys_config.h>
    #include <linux/major.h>
    #include <linux/fs.h>
    #include <linux/device.h>
    #include <asm/io.h>
    #include <asm/uaccess.h>
    #include <linux/interrupt.h>
    #include <linux/ioport.h>
    #include <asm/irq.h>
    #include <asm/io.h>
    #include <mach/irqs.h>
    #include <mach/system.h>
    #include <asm/uaccess.h>
    #include <mach/hardware.h>
    #include <linux/gpio.h>
    
    /* EINT type PIO controller registers */
    #define PIO_INT_CFG0_OFFSET 0x200
    #define PIO_INT_CFG1_OFFSET 0x204
    #define PIO_INT_CFG2_OFFSET 0x208
    #define PIO_INT_CFG3_OFFSET 0x20c
    
    #define PIO_INT_STAT_OFFSET (0x214)
    #define IRQ_EINT22          22
    #define PIO_BASE_ADDRESS    SW_PA_PORTC_IO_BASE
    #define PIO_RANGE_SIZE      (0x400)
    #define PIO_INT_CTRL_OFFSET (0x210)
    
    /* EINT type defines */
    #define POSITIVE_EDGE       0x0
    #define NEGATIVE_EDGE       0x1
    #define HIGH_LEVEL      0x2
    #define LOW_LEVEL       0x3
    #define DOUBLE_EDGE     0x4
    
    static int int_cfg_addr[] = {PIO_INT_CFG0_OFFSET,
                     PIO_INT_CFG1_OFFSET,
                     PIO_INT_CFG2_OFFSET,
                     PIO_INT_CFG3_OFFSET};
    
    /* Setup GPIO irq mode (FALLING, RISING, BOTH, etc */
    #define SUNXI_SET_GPIO_IRQ_TYPE(addr, offs, mode) ({ \
        __u32 reg_bit = offs % 8; \
        __u32 reg_num = offs / 8; \
        __u32 reg_val = readl(addr + int_cfg_addr[reg_num]); \
        reg_val &= (~(0xf << (reg_bit * 4))); \
        reg_val |= (mode << (reg_bit * 4)); \
        writel(reg_val, addr + int_cfg_addr[reg_num]); \
    })
    
    /* Enable GPIO interrupt for pin */
    #define SUNXI_UNMASK_GPIO_IRQ(addr, irq) ({ \
        __u32 reg_val = readl(addr + PIO_INT_CTRL_OFFSET); \
        reg_val |= (1 << irq); \
        writel(reg_val, addr + PIO_INT_CTRL_OFFSET); \
    })
    
    /* Disable GPIO interrupt for pin */
    #define SUNXI_MASK_GPIO_IRQ(addr, irq) ({ \
        __u32 reg_val = readl(addr + PIO_INT_CTRL_OFFSET); \
        reg_val &= ~(1 << irq); \
        writel(reg_val, addr + PIO_INT_CTRL_OFFSET); \
    })
    
    /* Set GPIO pin mode (input, output, etc)            */
    /* GPIO port has 4 cfg 32bit registers (8 pins each) */
    /* First port cfg register addr = port_num * 0x24    */
    #define SUNXI_SET_GPIO_MODE(addr, port, pin, mode) ({ \
        __u32 reg_val = 0; \
        __u32 pin_idx = pin >> 3; \
        void *raddr = addr + (((port)-1)*0x24 + ((pin_idx)<<2) + 0x00); \
        reg_val = readl(raddr); \
        reg_val &= ~(0x07 << (((pin - (pin_idx<<3))<<2))); \
        reg_val |= mode << (((pin - (pin_idx<<3))<<2)); \
        writel(reg_val, raddr); \
    })
    
    static script_gpio_set_t info;
    static unsigned key_handler;
    static struct class *key_class;
    static struct device *key_device;
    static unsigned int key_major;
    
    static void *__iomem gpio_addr = NULL;
    
    static int key_open(struct inode *inode, struct file *filp);
    static ssize_t key_write (struct file *filp, const char __user *buf, size_t len, loff_t *off);
    static int key_close(struct inode *inode, struct file *filp);
    
    struct file_operations key_operations = {
        .owner   = THIS_MODULE,
        .open    = key_open,
        .write   = key_write,
        .release = key_close,
    };
    
    struct key_str{
        char *name;
        int val;
    };
    
    struct key_str *g_key_str={"my_key",2};
    
    static irqreturn_t key_irq_handler(int irq, void *dev_id)
    {
        int reg_val;
        //clear the IRQ_EINT22 interrupt pending
        reg_val = readl(gpio_addr + PIO_INT_STAT_OFFSET);
    
        printk("key irq Interrupt\r\n");
    
    #if 1
        if (reg_val & (1 << (IRQ_EINT22))) {
            printk("==IRQ_EINT22=\r\n");
            writel(reg_val & (1 << (IRQ_EINT22)),
                   gpio_addr + PIO_INT_STAT_OFFSET);
            
        } else {
            printk("Other Interrupt\r\n");
            return IRQ_NONE;
        }
    #endif
        return IRQ_HANDLED;
    }
    
    static int key_open(struct inode *inode, struct file *filp)
    {
        int err = 0;
        int key_test_enabled = 0;
        int ret = 0;
        
        err = script_parser_fetch("key_test_para", "key_test_enable", &key_test_enabled,
                        sizeof(key_test_enabled)/sizeof(int));
    
        if(!err){
            printk("---script.bin key get ok,value:%d----\n",key_test_enabled);
        }
        else
        {
            printk("---script.bin key get false----\n");    
            return -1;
        }
    
        err = script_parser_fetch("key_test_para", "key2",
                    (int *)&info,
                    sizeof(script_gpio_set_t));
        if (err) {
            printk("----script.bin get io error----\r\n");
            return -1;
        }
        /* reserve gpio for led */
        key_handler = gpio_request_ex("key_test_para", "key2");
        if (!key_handler) {
            printk("----script.bin can't requst handler----\r\n");
            return -1;
        }
    
    #if 0
        /*设置为输入,没有上下拉*/
        err = gpio_set_one_pin_io_status(key_handler,0,"key2");
        if (err) {
            printk("----set io input error----\r\n");
            return -1;
        }   
    #endif
    
        err = gpio_set_one_pin_pull(key_handler,1,"key2");
        if (err) {
            printk("----set io pull error----\r\n");
            return -1;
        }
        
        if (!gpio_addr) {
            gpio_addr = ioremap(PIO_BASE_ADDRESS, PIO_RANGE_SIZE);
        }
    
        if(!gpio_addr)
        {
            printk("-----address error-----\r\n");
        }
        
        err = request_irq(SW_INT_IRQNO_PIO, key_irq_handler,
                  IRQF_SHARED, "gpio_pin_2", g_key_str);
    
        if (err < 0) {
            printk(" request irq error:%d\n",err);
            return -1;
        }
    
        /*set the gpio register*/
        SUNXI_SET_GPIO_IRQ_TYPE(gpio_addr,IRQ_EINT22,POSITIVE_EDGE);    
        SUNXI_UNMASK_GPIO_IRQ(gpio_addr,IRQ_EINT22);
        SUNXI_SET_GPIO_MODE(gpio_addr,9,10,6);/*PI10 EINT22 settiings*/
    
        return 0;
    }
    
    static ssize_t key_write (struct file *filp, const char __user *buf, size_t len, loff_t *off)
    {
    
        return 0;
    }
    
    static int key_close(struct inode *inode, struct file *filp)
    {
        SUNXI_MASK_GPIO_IRQ(gpio_addr,IRQ_EINT22);
    
        free_irq(SW_INT_IRQNO_PIO, g_key_str);
    
        printk("----key close----\r\n");
    
    
        return 0;
    }
    
    static int __init key_init(void)
    {
        key_major = register_chrdev(0, "key_chrdev", &key_operations);
    
        key_class = class_create(THIS_MODULE, "key_class");
    
        if(!key_class){
            unregister_chrdev(key_major, "key_chrdev");
            printk("----key_chrdev error----\r\n");
            return -1;
        }
        key_device = device_create(key_class, NULL, MKDEV(key_major,0),
                              NULL, "key_device");
        if(!key_device){
            class_destroy(key_class);
            unregister_chrdev(key_major, "key_chrdev");
            printk("----key_device error----\r\n");
            return -1;
        }
    
        printk("----key init ok----\r\n");
        return 0;
    }
    
    static void __exit  key_exit(void)
    {
        if (gpio_addr) {
            iounmap(gpio_addr);
        }
    
        if (key_handler)
            gpio_release(key_handler, 1);
        
        device_destroy(key_class, MKDEV(key_major, 0));
        class_destroy(key_class);
        unregister_chrdev(key_major, "key_chrdev");
    
        printk("---driver exit---\r\n");
    }
    
    module_init(key_init);
    module_exit(key_exit);
    
    MODULE_DESCRIPTION("Driver for key");
    MODULE_AUTHOR("wit_yuan");
    MODULE_LICENSE("GPL");```
    
    测试程序为:
    

    include "stdio.h"

    include <sys/types.h>

    include <sys/stat.h>

    include <fcntl.h>

    int main(int argc,char *argv[])
    {
    int fd;
    int val;
    fd = open("/dev/key_device",O_RDWR);
    if(fd < 0){
    printf("---open file error----\r\n");
    return -1;
    }

    while(1);
    
    return 0;
    

    }

    也就是说,只需要打开一个文件即可。
    
    Makefile文件为:
    

    ifeq ($(KERNELRELEASE),)
    KERNEL_DIR=/home/wityuan/Downloads/MarsBoard-A20-Linux-SDK-V1.2/linux-sunxi
    PWD=$(shell pwd)

    modules:
    $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules
    arm-linux-gnueabihf-gcc -o key key.c

    modules_install:
    $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules_install
    clean:
    rm -rf *.ko *.o .tmp_versions .mod.c modules.order Module.symvers ..cmd
    else
    obj-m:=key.o
    endif

    
    测试结果为:
    

    root@marsboard:~# ./key_test
    ---script.bin key get ok,value:1----
    key irq Interrupt
    ==IRQ_EINT22=
    key irq Interrupt
    ==IRQ_EINT22=
    key irq Interrupt
    ==IRQ_EINT22=
    key irq Interrupt
    ==IRQ_EINT22=
    key irq Interrupt
    ==IRQ_EINT22=
    key irq Interrupt
    ==IRQ_EINT22=
    key irq Interrupt
    ==IRQ_EINT22=
    key irq Interrupt
    ==IRQ_EINT22=
    key irq Interrupt
    ==IRQ_EINT22=
    ^Ckey irq Interrupt
    Other Interrupt
    ----key close----

    root@marsboard:~#
    root@marsboard:~#

    
    ok,简单的测试程序,暂时就这样了。下面再去优化。
    
    
    ### 3.5 polling查询按键值
    使用查询按键值的程序代码如下:
    key.c驱动程序:
    

    include "linux/init.h"

    include <linux/kernel.h>

    include <linux/module.h>

    include <linux/leds.h>

    include <plat/sys_config.h>

    include <linux/major.h>

    include <linux/fs.h>

    include <linux/device.h>

    include <asm/io.h>

    include <asm/uaccess.h>

    include <linux/interrupt.h>

    include <linux/ioport.h>

    include <asm/irq.h>

    include <asm/io.h>

    include <mach/irqs.h>

    include <mach/system.h>

    include <asm/uaccess.h>

    include <mach/hardware.h>

    include <linux/gpio.h>

    /* EINT type PIO controller registers */

    define PIO_INT_CFG0_OFFSET 0x200

    define PIO_INT_CFG1_OFFSET 0x204

    define PIO_INT_CFG2_OFFSET 0x208

    define PIO_INT_CFG3_OFFSET 0x20c

    define PIO_INT_STAT_OFFSET (0x214)

    define PIO_INT_DATA_OFFSET (0x130)

    define IRQ_EINT22 22

    define IRQ_EINT23 23

    define PIO_BASE_ADDRESS SW_PA_PORTC_IO_BASE

    define PIO_RANGE_SIZE (0x400)

    define PIO_INT_CTRL_OFFSET (0x210)

    /* EINT type defines */

    define POSITIVE_EDGE 0x0

    define NEGATIVE_EDGE 0x1

    define HIGH_LEVEL 0x2

    define LOW_LEVEL 0x3

    define DOUBLE_EDGE 0x4

    static int int_cfg_addr[] = {PIO_INT_CFG0_OFFSET,
    PIO_INT_CFG1_OFFSET,
    PIO_INT_CFG2_OFFSET,
    PIO_INT_CFG3_OFFSET};

    /* Setup GPIO irq mode (FALLING, RISING, BOTH, etc */

    define SUNXI_SET_GPIO_IRQ_TYPE(addr, offs, mode) ({ \

    __u32 reg_bit = offs % 8; \
    __u32 reg_num = offs / 8; \
    __u32 reg_val = readl(addr + int_cfg_addr[reg_num]); \
    reg_val &= (~(0xf << (reg_bit * 4))); \
    reg_val |= (mode << (reg_bit * 4)); \
    writel(reg_val, addr + int_cfg_addr[reg_num]); \
    

    })

    /* Enable GPIO interrupt for pin */

    define SUNXI_UNMASK_GPIO_IRQ(addr, irq) ({ \

    __u32 reg_val = readl(addr + PIO_INT_CTRL_OFFSET); \
    reg_val |= (1 << irq); \
    writel(reg_val, addr + PIO_INT_CTRL_OFFSET); \
    

    })

    /* Disable GPIO interrupt for pin */

    define SUNXI_MASK_GPIO_IRQ(addr, irq) ({ \

    __u32 reg_val = readl(addr + PIO_INT_CTRL_OFFSET); \
    reg_val &= ~(1 << irq); \
    writel(reg_val, addr + PIO_INT_CTRL_OFFSET); \
    

    })

    /* Set GPIO pin mode (input, output, etc) /
    /
    GPIO port has 4 cfg 32bit registers (8 pins each) /
    /
    First port cfg register addr = port_num * 0x24 */

    define SUNXI_SET_GPIO_MODE(addr, port, pin, mode) ({ \

    __u32 reg_val = 0; \
    __u32 pin_idx = pin >> 3; \
    void *raddr = addr + (((port)-1)*0x24 + ((pin_idx)<<2) + 0x00); \
    reg_val = readl(raddr); \
    reg_val &= ~(0x07 << (((pin - (pin_idx<<3))<<2))); \
    reg_val |= mode << (((pin - (pin_idx<<3))<<2)); \
    writel(reg_val, raddr); \
    

    })

    static script_gpio_set_t info;
    static unsigned key_handler1;
    static unsigned key_handler2;

    static struct class *key_class;
    static struct device *key_device;
    static unsigned int key_major;

    static unsigned int key_value;

    static void *__iomem gpio_addr = NULL;

    static int key_open(struct inode *inode, struct file *filp);
    static ssize_t key_read (struct file *, char __user *, size_t, loff_t *);
    static ssize_t key_write (struct file *filp, const char __user *buf, size_t len, loff_t *off);
    static int key_close(struct inode *inode, struct file *filp);

    struct file_operations key_operations = {
    .owner = THIS_MODULE,
    .open = key_open,
    .read = key_read,
    .write = key_write,
    .release = key_close,
    };

    struct key_str{
    char *name;
    int val;
    };

    struct key_str g_key_str[2]={{"key1",0x1},{"key2",2}};

    static irqreturn_t key_irq_handler1(int irq, void *dev_id)
    {
    int err;
    int reg_val = 0;
    int ret_val = 0;

    struct key_str *key_t = (struct key_str *)dev_id;
    //clear the IRQ_EINT22 interrupt pending
    reg_val = readl(gpio_addr + PIO_INT_STAT_OFFSET);
    
    if (reg_val & (1 << (IRQ_EINT22))) {
        //printk("==IRQ_EINT22=\r\n");
        
        writel(reg_val & (1 << (IRQ_EINT22)),
           gpio_addr + PIO_INT_STAT_OFFSET);
    
        ret_val = readl(gpio_addr + PIO_INT_DATA_OFFSET);
        if(!(ret_val&(1<<10)))
        {
            //printk("key1 pressed \r\n");
            key_value |= key_t->val;
        }
        else
        {
            //printk("key1 released \r\n");
            key_value &= ~key_t->val;
        }   
    
        //printk("key%d irq Interrupt,%d \r\n",key_t->val,key_value);
    }   
    
    return IRQ_HANDLED;
    

    }

    static irqreturn_t key_irq_handler2(int irq, void *dev_id)
    {

    int reg_val;
    int ret_val;
    //clear the IRQ_EINT23 interrupt pending
    reg_val = readl(gpio_addr + PIO_INT_STAT_OFFSET);
    
    struct key_str *key_t = (struct key_str *)dev_id;
    //clear the IRQ_EINT22 interrupt pending
    reg_val = readl(gpio_addr + PIO_INT_STAT_OFFSET);
    

    if 1

    if (reg_val & (1 << (IRQ_EINT23))) {
        //printk("==IRQ_EINT23=\r\n");
        writel(reg_val & (1 << (IRQ_EINT23)),
               gpio_addr + PIO_INT_STAT_OFFSET);
        
        ret_val = readl(gpio_addr + PIO_INT_DATA_OFFSET);
        if(!(ret_val&(1<<11)))
        {
            //printk("key2 pressed \r\n");
            key_value |= key_t->val;
        }
        else
        {
            //printk("key2 released \r\n");
            key_value &= ~key_t->val;
        }   
        //printk("key%d irq Interrupt,%d \r\n",key_t->val,key_value);
    
    } 
    

    endif

    return IRQ_HANDLED;
    

    }

    static ssize_t key_read (struct file *file, char __user *buf, size_t len, loff_t *off)
    {
    unsigned int value = 0;
    value = copy_to_user(buf,&key_value,4);

    return value;
    

    }

    static int key_open(struct inode *inode, struct file *filp)
    {
    int err = 0;
    int key_test_enabled = 0;
    int ret = 0;

    err = script_parser_fetch("key_test_para", "key_test_enable", &key_test_enabled,
                    sizeof(key_test_enabled)/sizeof(int));
    
    if(!err){
        printk("---script.bin key get ok,value:%d----\n",key_test_enabled);
    }
    else
    {
        printk("---script.bin key get false----\n");    
        return -1;
    }
    
    err = script_parser_fetch("key_test_para", "key1",
                (int *)&info,
                sizeof(script_gpio_set_t));
    if (err) {
        printk("----script.bin get io error----\r\n");
        return -1;
    }
    
    err = script_parser_fetch("key_test_para", "key2",
                (int *)&info,
                sizeof(script_gpio_set_t));
    if (err) {
        printk("----script.bin get io error----\r\n");
        return -1;
    }
    
    
    
    /* reserve gpio for led */
    key_handler1 = gpio_request_ex("key_test_para", "key1");
    if (!key_handler1) {
        printk("----script.bin can't requst handler----\r\n");
        return -1;
    }
    
    
    /* reserve gpio for led */
    key_handler2 = gpio_request_ex("key_test_para", "key2");
    if (!key_handler2) {
        printk("----script.bin can't requst handler----\r\n");
        return -1;
    }
    

    if 1

    /*设置为输入,没有上下拉*/
    err = gpio_set_one_pin_io_status(key_handler1,0,"key1");
    if (err) {
        printk("----set io input 1 error----\r\n");
        return -1;
    }   
    err = gpio_set_one_pin_io_status(key_handler2,0,"key2");
    if (err) {
        printk("----set io input 2 error----\r\n");
        return -1;
    }   
    

    endif

    err = gpio_set_one_pin_pull(key_handler1,1,"key1");
    if (err) {
        printk("----set io pull error----\r\n");
        return -1;
    }
    
    err = gpio_set_one_pin_pull(key_handler2,1,"key2");
    if (err) {
        printk("----set io pull error----\r\n");
        return -1;
    }
    
    
    
    
    if (!gpio_addr) {
        gpio_addr = ioremap(PIO_BASE_ADDRESS, PIO_RANGE_SIZE);
    }
    
    if(!gpio_addr)
    {
        printk("-----address error-----\r\n");
    }
    
    err = request_irq(SW_INT_IRQNO_PIO, key_irq_handler1,
              IRQF_SHARED, "gpio_pin_1", &g_key_str[0]);
    
    if (err < 0) {
        printk(" request irq 1 error:%d\n",err);
        return -1;
    }
    
    err = request_irq(SW_INT_IRQNO_PIO, key_irq_handler2,
              IRQF_SHARED, "gpio_pin_2", &g_key_str[1]);
    
    if (err < 0) {
        printk(" request irq error:%d\n",err);
        return -1;
    }
    
    /*set the gpio 1 register*/
    SUNXI_SET_GPIO_IRQ_TYPE(gpio_addr,IRQ_EINT22,DOUBLE_EDGE);  
    SUNXI_UNMASK_GPIO_IRQ(gpio_addr,IRQ_EINT22);
    SUNXI_SET_GPIO_MODE(gpio_addr,9,10,6);/*PI10 EINT22 settiings*/
    
    /*set the gpio 2 register*/
    SUNXI_SET_GPIO_IRQ_TYPE(gpio_addr,IRQ_EINT23,DOUBLE_EDGE);  
    SUNXI_UNMASK_GPIO_IRQ(gpio_addr,IRQ_EINT23);
    SUNXI_SET_GPIO_MODE(gpio_addr,9,11,6);/*PI11 EINT23 settiings*/
    
    
    return 0;
    

    }

    static ssize_t key_write (struct file *filp, const char __user *buf, size_t len, loff_t *off)
    {

    return 0;
    

    }

    static int key_close(struct inode *inode, struct file *filp)
    {
    SUNXI_MASK_GPIO_IRQ(gpio_addr,IRQ_EINT22);
    SUNXI_MASK_GPIO_IRQ(gpio_addr,IRQ_EINT23);

    free_irq(SW_INT_IRQNO_PIO, &g_key_str[0]);
    free_irq(SW_INT_IRQNO_PIO, &g_key_str[1]);
    printk("----key close----\r\n");
    
    
    return 0;
    

    }

    static int __init key_init(void)
    {
    key_major = register_chrdev(0, "key_chrdev", &key_operations);

    key_class = class_create(THIS_MODULE, "key_class");
    
    if(!key_class){
        unregister_chrdev(key_major, "key_chrdev");
        printk("----key_chrdev error----\r\n");
        return -1;
    }
    key_device = device_create(key_class, NULL, MKDEV(key_major,0),
                          NULL, "key_device");
    if(!key_device){
        class_destroy(key_class);
        unregister_chrdev(key_major, "key_chrdev");
        printk("----key_device error----\r\n");
        return -1;
    }
    
    printk("----key init ok----\r\n");
    return 0;
    

    }

    static void __exit key_exit(void)
    {
    if (gpio_addr) {
    iounmap(gpio_addr);
    }

    if (key_handler1)
        gpio_release(key_handler1, 1);
    if (key_handler2)
        gpio_release(key_handler2, 1);  
    
    device_destroy(key_class, MKDEV(key_major, 0));
    class_destroy(key_class);
    unregister_chrdev(key_major, "key_chrdev");
    
    printk("---driver exit---\r\n");
    

    }

    module_init(key_init);
    module_exit(key_exit);

    MODULE_DESCRIPTION("Driver for key");
    MODULE_AUTHOR("wit_yuan");
    MODULE_LICENSE("GPL");

    
    Makefile程序:
    

    ifeq ($(KERNELRELEASE),)
    KERNEL_DIR=/home/wityuan/Downloads/MarsBoard-A20-Linux-SDK-V1.2/linux-sunxi
    PWD=$(shell pwd)

    modules:
    $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules
    arm-linux-gnueabihf-gcc -o key key.c

    modules_install:
    $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules_install
    clean:
    rm -rf *.ko *.o .tmp_versions .mod.c modules.order Module.symvers ..cmd
    else
    obj-m:=key.o

    endif

    
    key_test.c测试程序:
    

    include "stdio.h"

    include <sys/types.h>

    include <sys/stat.h>

    include <fcntl.h>

    int main(int argc,char *argv[])
    {
    int fd;
    int val;
    fd = open("/dev/key_device",O_RDWR);
    if(fd < 0){
    printf("---open file error----\r\n");
    return -1;
    }

    while(1)
    {
        read(fd,&val,1);
        if(val!=0)
            printf("val:%0x\r\n",val);
    }
    
    return 0;
    

    }

    
    使用top命令查询应用程序占用cpu资源:
    ![按键驱动程序资源占用](https://img.haomeiwen.com/i3549048/fb05a6115daedca8.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    所以,使用这种方式,在程序设计角度来说,明显是不合理的。所以,必须要进行改进。
    
    ### 3.6 使用休眠方式
    由于3.5的程序中,应用程序是一直在读取内核数据。这样的方式明显将整个系统的性能降低。而程序设计的整体思路是,只需要在内核有数据的时候,应用层读取就可以了。所以呢,可以使用这种方式,应用层读取数据,在内核没有数据需要返回的时候,内核可以让该进程异步阻塞,这样就不会占用整个系统的资源。
    
    这种技巧,使用的主要是内核提供的几个函数:
    > * wait_event_interruptible
    > * wake_up_interruptible
    > * DECLARE_WAIT_QUEUE_HEAD
    > * init_waitqueue_head
    
    关于这种操作方式,可以参考文件:
    \marsboard\marsboard-a20-linux-sdk-v1.2\linux-sunxi\drivers\staging\iio\adc\Ad7780.c
    
    我把程序贴在下面:
    key.c驱动程序如下:
    

    include "linux/init.h"

    include <linux/kernel.h>

    include <linux/module.h>

    include <linux/leds.h>

    include <plat/sys_config.h>

    include <linux/major.h>

    include <linux/fs.h>

    include <linux/device.h>

    include <asm/io.h>

    include <asm/uaccess.h>

    include <linux/interrupt.h>

    include <linux/ioport.h>

    include <asm/irq.h>

    include <asm/io.h>

    include <mach/irqs.h>

    include <mach/system.h>

    include <asm/uaccess.h>

    include <mach/hardware.h>

    include <linux/gpio.h>

    include <linux/sched.h>

    include <linux/wait.h>

    /* EINT type PIO controller registers */

    define PIO_INT_CFG0_OFFSET 0x200

    define PIO_INT_CFG1_OFFSET 0x204

    define PIO_INT_CFG2_OFFSET 0x208

    define PIO_INT_CFG3_OFFSET 0x20c

    define PIO_INT_STAT_OFFSET (0x214)

    define PIO_INT_DATA_OFFSET (0x130)

    define IRQ_EINT22 22

    define IRQ_EINT23 23

    define PIO_BASE_ADDRESS SW_PA_PORTC_IO_BASE

    define PIO_RANGE_SIZE (0x400)

    define PIO_INT_CTRL_OFFSET (0x210)

    /* EINT type defines */

    define POSITIVE_EDGE 0x0

    define NEGATIVE_EDGE 0x1

    define HIGH_LEVEL 0x2

    define LOW_LEVEL 0x3

    define DOUBLE_EDGE 0x4

    static wait_queue_head_t key_data_avail;
    static unsigned int key_done = 0;

    static int int_cfg_addr[] = {PIO_INT_CFG0_OFFSET,
    PIO_INT_CFG1_OFFSET,
    PIO_INT_CFG2_OFFSET,
    PIO_INT_CFG3_OFFSET};

    /* Setup GPIO irq mode (FALLING, RISING, BOTH, etc */

    define SUNXI_SET_GPIO_IRQ_TYPE(addr, offs, mode) ({ \

    __u32 reg_bit = offs % 8; \
    __u32 reg_num = offs / 8; \
    __u32 reg_val = readl(addr + int_cfg_addr[reg_num]); \
    reg_val &= (~(0xf << (reg_bit * 4))); \
    reg_val |= (mode << (reg_bit * 4)); \
    writel(reg_val, addr + int_cfg_addr[reg_num]); \
    

    })

    /* Enable GPIO interrupt for pin */

    define SUNXI_UNMASK_GPIO_IRQ(addr, irq) ({ \

    __u32 reg_val = readl(addr + PIO_INT_CTRL_OFFSET); \
    reg_val |= (1 << irq); \
    writel(reg_val, addr + PIO_INT_CTRL_OFFSET); \
    

    })

    /* Disable GPIO interrupt for pin */

    define SUNXI_MASK_GPIO_IRQ(addr, irq) ({ \

    __u32 reg_val = readl(addr + PIO_INT_CTRL_OFFSET); \
    reg_val &= ~(1 << irq); \
    writel(reg_val, addr + PIO_INT_CTRL_OFFSET); \
    

    })

    /* Set GPIO pin mode (input, output, etc) /
    /
    GPIO port has 4 cfg 32bit registers (8 pins each) /
    /
    First port cfg register addr = port_num * 0x24 */

    define SUNXI_SET_GPIO_MODE(addr, port, pin, mode) ({ \

    __u32 reg_val = 0; \
    __u32 pin_idx = pin >> 3; \
    void *raddr = addr + (((port)-1)*0x24 + ((pin_idx)<<2) + 0x00); \
    reg_val = readl(raddr); \
    reg_val &= ~(0x07 << (((pin - (pin_idx<<3))<<2))); \
    reg_val |= mode << (((pin - (pin_idx<<3))<<2)); \
    writel(reg_val, raddr); \
    

    })

    static script_gpio_set_t info;
    static unsigned key_handler1;
    static unsigned key_handler2;

    static struct class *key_class;
    static struct device *key_device;
    static unsigned int key_major;

    static unsigned int key_value;

    static void *__iomem gpio_addr = NULL;

    static int key_open(struct inode *inode, struct file *filp);
    static ssize_t key_read (struct file *, char __user *, size_t, loff_t *);
    static ssize_t key_write (struct file *filp, const char __user *buf, size_t len, loff_t *off);
    static int key_close(struct inode *inode, struct file *filp);

    struct file_operations key_operations = {
    .owner = THIS_MODULE,
    .open = key_open,
    .read = key_read,
    .write = key_write,
    .release = key_close,
    };

    struct key_str{
    char *name;
    int val;
    };

    struct key_str g_key_str[2]={{"key1",0x1},{"key2",2}};

    static irqreturn_t key_irq_handler1(int irq, void *dev_id)
    {
    int err;
    int reg_val = 0;
    int ret_val = 0;

    struct key_str *key_t = (struct key_str *)dev_id;
    //clear the IRQ_EINT22 interrupt pending
    reg_val = readl(gpio_addr + PIO_INT_STAT_OFFSET);
    
    if (reg_val & (1 << (IRQ_EINT22))) {
        //printk("==IRQ_EINT22=\r\n");
        
        writel(reg_val & (1 << (IRQ_EINT22)),
           gpio_addr + PIO_INT_STAT_OFFSET);
    
        ret_val = readl(gpio_addr + PIO_INT_DATA_OFFSET);
        if(!(ret_val&(1<<10)))
        {
            //printk("key1 pressed \r\n");
            key_value |= key_t->val;
        }
        else
        {
            //printk("key1 released \r\n");
            key_value &= ~key_t->val;
        }
    
        key_done = 1;
        wake_up_interruptible(&key_data_avail);
    
    
        //printk("key%d irq Interrupt,%d \r\n",key_t->val,key_value);
    }   
    
    
    return IRQ_HANDLED;
    

    }

    static irqreturn_t key_irq_handler2(int irq, void *dev_id)
    {

    int reg_val;
    int ret_val;
    //clear the IRQ_EINT23 interrupt pending
    reg_val = readl(gpio_addr + PIO_INT_STAT_OFFSET);
    
    struct key_str *key_t = (struct key_str *)dev_id;
    //clear the IRQ_EINT22 interrupt pending
    reg_val = readl(gpio_addr + PIO_INT_STAT_OFFSET);
    

    if 1

    if (reg_val & (1 << (IRQ_EINT23))) {
        //printk("==IRQ_EINT23=\r\n");
        writel(reg_val & (1 << (IRQ_EINT23)),
               gpio_addr + PIO_INT_STAT_OFFSET);
        
        ret_val = readl(gpio_addr + PIO_INT_DATA_OFFSET);
        if(!(ret_val&(1<<11)))
        {
            //printk("key2 pressed \r\n");
            key_value |= key_t->val;
        }
        else
        {
            //printk("key2 released \r\n");
            key_value &= ~key_t->val;
        }   
    
        key_done = 1;
        wake_up_interruptible(&key_data_avail);     
        //printk("key%d irq Interrupt,%d \r\n",key_t->val,key_value);
    
    } 
    

    endif

    return IRQ_HANDLED;
    

    }

    static ssize_t key_read (struct file *file, char __user *buf, size_t len, loff_t *off)
    {
    unsigned int value = 0;

    key_done = 0;
    wait_event_interruptible(key_data_avail,key_done);
    
    value = copy_to_user(buf,&key_value,4);
    
    
    return value;
    

    }

    static int key_open(struct inode *inode, struct file *filp)
    {
    int err = 0;
    int key_test_enabled = 0;
    int ret = 0;

    err = script_parser_fetch("key_test_para", "key_test_enable", &key_test_enabled,
                    sizeof(key_test_enabled)/sizeof(int));
    
    if(!err){
        printk("---script.bin key get ok,value:%d----\n",key_test_enabled);
    }
    else
    {
        printk("---script.bin key get false----\n");    
        return -1;
    }
    
    err = script_parser_fetch("key_test_para", "key1",
                (int *)&info,
                sizeof(script_gpio_set_t));
    if (err) {
        printk("----script.bin get io error----\r\n");
        return -1;
    }
    
    err = script_parser_fetch("key_test_para", "key2",
                (int *)&info,
                sizeof(script_gpio_set_t));
    if (err) {
        printk("----script.bin get io error----\r\n");
        return -1;
    }
    
    
    
    /* reserve gpio for led */
    key_handler1 = gpio_request_ex("key_test_para", "key1");
    if (!key_handler1) {
        printk("----script.bin can't requst handler----\r\n");
        return -1;
    }
    
    
    /* reserve gpio for led */
    key_handler2 = gpio_request_ex("key_test_para", "key2");
    if (!key_handler2) {
        printk("----script.bin can't requst handler----\r\n");
        return -1;
    }
    

    if 1

    /*设置为输入,没有上下拉*/
    err = gpio_set_one_pin_io_status(key_handler1,0,"key1");
    if (err) {
        printk("----set io input 1 error----\r\n");
        return -1;
    }   
    err = gpio_set_one_pin_io_status(key_handler2,0,"key2");
    if (err) {
        printk("----set io input 2 error----\r\n");
        return -1;
    }   
    

    endif

    err = gpio_set_one_pin_pull(key_handler1,1,"key1");
    if (err) {
        printk("----set io pull error----\r\n");
        return -1;
    }
    
    err = gpio_set_one_pin_pull(key_handler2,1,"key2");
    if (err) {
        printk("----set io pull error----\r\n");
        return -1;
    }
    
    
    
    
    if (!gpio_addr) {
        gpio_addr = ioremap(PIO_BASE_ADDRESS, PIO_RANGE_SIZE);
    }
    
    if(!gpio_addr)
    {
        printk("-----address error-----\r\n");
    }
    
    err = request_irq(SW_INT_IRQNO_PIO, key_irq_handler1,
              IRQF_SHARED, "gpio_pin_1", &g_key_str[0]);
    
    if (err < 0) {
        printk(" request irq 1 error:%d\n",err);
        return -1;
    }
    
    err = request_irq(SW_INT_IRQNO_PIO, key_irq_handler2,
              IRQF_SHARED, "gpio_pin_2", &g_key_str[1]);
    
    if (err < 0) {
        printk(" request irq error:%d\n",err);
        return -1;
    }
    
    /*set the gpio 1 register*/
    SUNXI_SET_GPIO_IRQ_TYPE(gpio_addr,IRQ_EINT22,DOUBLE_EDGE);  
    SUNXI_UNMASK_GPIO_IRQ(gpio_addr,IRQ_EINT22);
    SUNXI_SET_GPIO_MODE(gpio_addr,9,10,6);/*PI10 EINT22 settiings*/
    
    /*set the gpio 2 register*/
    SUNXI_SET_GPIO_IRQ_TYPE(gpio_addr,IRQ_EINT23,DOUBLE_EDGE);  
    SUNXI_UNMASK_GPIO_IRQ(gpio_addr,IRQ_EINT23);
    SUNXI_SET_GPIO_MODE(gpio_addr,9,11,6);/*PI11 EINT23 settiings*/
    
    
    return 0;
    

    }

    static ssize_t key_write (struct file *filp, const char __user *buf, size_t len, loff_t *off)
    {

    return 0;
    

    }

    static int key_close(struct inode *inode, struct file *filp)
    {
    SUNXI_MASK_GPIO_IRQ(gpio_addr,IRQ_EINT22);
    SUNXI_MASK_GPIO_IRQ(gpio_addr,IRQ_EINT23);

    free_irq(SW_INT_IRQNO_PIO, &g_key_str[0]);
    free_irq(SW_INT_IRQNO_PIO, &g_key_str[1]);
    printk("----key close----\r\n");
    
    
    return 0;
    

    }

    static int __init key_test_init(void)
    {
    key_major = register_chrdev(0, "key_chrdev", &key_operations);

    key_class = class_create(THIS_MODULE, "key_class");
    
    if(!key_class){
        unregister_chrdev(key_major, "key_chrdev");
        printk("----key_chrdev error----\r\n");
        return -1;
    }
    key_device = device_create(key_class, NULL, MKDEV(key_major,0),
                          NULL, "key_device");
    if(!key_device){
        class_destroy(key_class);
        unregister_chrdev(key_major, "key_chrdev");
        printk("----key_device error----\r\n");
        return -1;
    }
    
    printk("----key init ok----\r\n");
    
    init_waitqueue_head(&key_data_avail);
    return 0;
    

    }

    static void __exit key_test_exit(void)
    {
    if (gpio_addr) {
    iounmap(gpio_addr);
    }

    if (key_handler1)
        gpio_release(key_handler1, 1);
    if (key_handler2)
        gpio_release(key_handler2, 1);  
    
    device_destroy(key_class, MKDEV(key_major, 0));
    class_destroy(key_class);
    unregister_chrdev(key_major, "key_chrdev");
    
    printk("---driver exit---\r\n");
    

    }

    module_init(key_test_init);
    module_exit(key_test_exit);

    MODULE_DESCRIPTION("Driver for key");
    MODULE_AUTHOR("wit_yuan");
    MODULE_LICENSE("GPL");

    
    Makefile程序如下:
    

    ifeq ($(KERNELRELEASE),)
    KERNEL_DIR=/home/wityuan/Downloads/MarsBoard-A20-Linux-SDK-V1.2/linux-sunxi
    PWD=$(shell pwd)

    modules:
    $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules
    arm-linux-gnueabihf-gcc -o key key.c

    modules_install:
    $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules_install
    clean:
    rm -rf *.ko *.o .tmp_versions .mod.c modules.order Module.symvers ..cmd
    else
    obj-m:=key.o

    endif

    
    key_test.c测试程序如下:
    

    include "stdio.h"

    include <sys/types.h>

    include <sys/stat.h>

    include <fcntl.h>

    int main(int argc,char *argv[])
    {
    int fd;
    int val;
    fd = open("/dev/key_device",O_RDWR);
    if(fd < 0){
    printf("---open file error----\r\n");
    return -1;
    }

    while(1)
    {
        read(fd,&val,1);
    
        if(val!=0)
            printf("val:%0x\r\n",val);
    
    }
    
    return 0;
    

    }

    再使用top命令查询:
    ![按键程序基本不占用cpu资源](https://img.haomeiwen.com/i3549048/34240160c4c26f5e.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)
    
    
    
    

    相关文章

      网友评论

          本文标题:四 . 树莓派A20 GPIO中断程序编写(1基本处理)

          本文链接:https://www.haomeiwen.com/subject/eywfkxtx.html