(linux自学笔记)linux按键中断驱动

发布者:MagicalSerenade最新更新时间:2024-09-23 来源: cnblogs关键字:linux  按键  中断驱动 手机看文章 扫描二维码
随时随地手机看文章

通常开发板自带按键中断的驱动,中断已被注册至内核。重新编译linux内核去掉自带驱动才能使用自己编写的驱动。

linux中断程序可分解为顶半部与底半部机制。顶半部完成尽可能少的紧急功能,底半部可以被新的中断打断。

驱动程序


#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include gpio.h>

#include

#include

#include

#include

#include

#include

#include


#define DEVICE_NAME     'key_device'

#define DEVICE_MAJOR    240


void key_tasklet_func(void);


DECLARE_TASKLET(key_tasklet,key_tasklet_func,0);


struct key_irq_desc

{

    int irq;

    int pin;

    int pin_setting;

    int number;

    char *name;


};


static struct key_irq_desc key_irqs [] =

{

    {IRQ_EINT(0), S3C64XX_GPN(0) ,  S3C64XX_GPN0_EINT0 , 0, 'KEY0'},

    {IRQ_EINT(1), S3C64XX_GPN(1) ,  S3C64XX_GPN1_EINT1 , 1, 'KEY1'},

    {IRQ_EINT(2), S3C64XX_GPN(2) ,  S3C64XX_GPN2_EINT2 , 2, 'KEY2'},

    {IRQ_EINT(3), S3C64XX_GPN(3) ,  S3C64XX_GPN3_EINT3 , 3, 'KEY3'},

    {IRQ_EINT(4), S3C64XX_GPN(4) ,  S3C64XX_GPN4_EINT4 , 4, 'KEY4'},

    {IRQ_EINT(5), S3C64XX_GPN(5),   S3C64XX_GPN5_EINT5 , 5, 'KEY5'},

};

static volatile int key_values [] = {1, 1, 1, 1, 1, 1};


//初始化等待列对

static DECLARE_WAIT_QUEUE_HEAD(button_waitq);


static volatile int event_flag = 0;



static irqreturn_t buttons_interrupt(int irq, void *dev_id)

{

    struct key_irq_desc *dev_irqs = (struct key_irq_desc *)dev_id;

    int down;


    down = gpio_get_value(dev_irqs->pin);


    //按键发生了变化

    if (down != (key_values[dev_irqs->number] & 1))

    {

        // Changed


        key_values[dev_irqs->number] = 0 + down;


        event_flag = 1;

        //唤醒列对

        wake_up_interruptible(&button_waitq);

    }


    tasklet_schedule(&key_tasklet);


    return IRQ_RETVAL(IRQ_HANDLED);

}


void key_tasklet_func(void)

{

    printk('<0>=======task========n');

    printk('<0>task function test~n');

    printk('<0>===================n');

}


static int s3c6410_key_open(struct inode *inode, struct file *file)

{

    int i;

    int err = 0;


    //注册中断              结构体未注册完

    for (i = 0; i < sizeof(key_irqs)/sizeof(key_irqs[0]); i++)

    {

        if (key_irqs[i].irq < 0)

        {

            continue;

        }


        //                    中断号                 中断处理寒酸     中断处理属性

        err = request_irq(key_irqs[i].irq, buttons_interrupt, IRQ_TYPE_EDGE_BOTH,

                          key_irqs[i].name, (void *)&key_irqs[i]);

        if (err)

            break;

    }


    //如果注册中断过程中出错,则注销注册成功的中断

    if (err)

    {

        i--;

        for (; i >= 0; i--)

        {

            if (key_irqs[i].irq < 0)

            {

                continue;

            }

            disable_irq(key_irqs[i].irq);

            free_irq(key_irqs[i].irq, (void *)&key_irqs[i]);

        }

        return -EBUSY;

    }



    //显示一次主界面而已

    event_flag = 1;


    return 0;

}



static int s3c6410_keys_close(struct inode *inode, struct file *file)

{

    int i;

    //注销中断

    for (i = 0; i < sizeof(key_irqs)/sizeof(key_irqs[0]); i++)

    {

        if (key_irqs[i].irq < 0)

        {

            continue;

        }

        free_irq(key_irqs[i].irq, (void *)&key_irqs[i]);

    }


    return 0;

}



static int s3c6410_keys_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)

{

    unsigned long err;


    if (!event_flag)

    {

        //没有新按键事件处理,如果用户要求不阻塞就直接返回,否则阻塞在button_waitq队列上。

        if (filp->f_flags & O_NONBLOCK)

            return -EAGAIN;

        else

            wait_event_interruptible(button_waitq, event_flag);

    }


    event_flag = 0;


    err = copy_to_user(buff, (const void *)key_values, min(sizeof(key_values), count));


    return err ? -EFAULT : min(sizeof(key_values), count);

}




static struct file_operations key_device_fops =

{

    .owner      =   THIS_MODULE,

    .open       =   s3c6410_key_open,

    .release    =   s3c6410_keys_close,

    .read       =   s3c6410_keys_read,

};




static int __init key_device_init(void)

{

    int ret;

    printk ('<0>key initn');

    //注册字符设备

    ret = register_chrdev(DEVICE_MAJOR,DEVICE_NAME,&key_device_fops);

    if (ret <0)

    {

        printk ('<0>register %s char dev errorn','key');

        return -1;

    }

    printk ('<0>successn');

    return 0;

}


static void __exit key_device_exit(void)

{

    //注销设备

    unregister_chrdev(DEVICE_MAJOR,DEVICE_NAME);

    printk ('<0>module exitn');

}


module_init(key_device_init);

module_exit(key_device_exit);


MODULE_LICENSE('GPL');

MODULE_AUTHOR('hebaichuan');


测试程序,按6键退出死循环。


#include   

#include   

#include   

#include   

  

#define key_exit 5


int main(int argc, char **argv)  

{  

    int fd,ret,i,key_value[6];  

        

    fd = open('/dev/key_device',0);  

    if(fd<0) 

    {  

        printf('open devie errorn');  

        return -1;  

    }  

  

    while(1)

    {  

        ret = read(fd,key_value, sizeof(key_value));  

        if(ret<0) 

        {  

            printf('read errorn');  

            continue;  

        }  

        else if(!key_value[key_exit])

            exit(0);


        for(i=0;i<5;i++)

        {  

            if(key_value[i])

            {

                printf('KEY%d releasedn',(i+1),key_value[i]);

            }  

            else  

            {

                printf('KEY%d pressed n',(i+1),key_value[i]);  

            }    

        }    

        printf('----------------key event----------------n');  

    }  

    close(fd);  

    return 0;  

}  


运行结果:


关键字:linux  按键  中断驱动 引用地址:(linux自学笔记)linux按键中断驱动

上一篇:(ARM11 S3C6410) ARM11裸机初体验,GPIO寄存器
下一篇:(linux自学笔记)linux驱动并发控制、阻塞/非阻塞IO、异步通知

推荐阅读最新更新时间:2026-03-20 07:42

(linux自学笔记)linux按键中断驱动
通常开发板自带按键中断的驱动,中断已被注册至内核。重新编译linux内核去掉自带驱动才能使用自己编写的驱动。 linux中断程序可分解为顶半部与底半部机制。顶半部完成尽可能少的紧急功能,底半部可以被新的中断打断。 驱动程序 #include linux/module.h #include linux/kernel.h #include linux/fs.h #include linux/init.h #include linux/delay.h #include linux/poll.h #include linux/irq.h #include asm/irq.h #include linux/inter
[单片机]
(<font color='red'>linux</font>自学笔记)<font color='red'>linux</font><font color='red'>按键</font><font color='red'>中断</font><font color='red'>驱动</font>
Linux驱动按键驱动编写(中断方式)
1、查看原理图,确定需要控制的IO端口 打开原理图,确定需要控制的IO端口为GPF0、GPF2、GPG3、GPG11。可以看到它的中断号为IRQ_EINT0、IRQ_EINT2、IRQ_EINT11、IRQ_EINT19 2、查看芯片手册,确定IO端口的寄存器地址,可以看到因为用了两组GPIO端口,所以它的基地址分别为0x56000050、0x56000060。中断方式的寄存器基地址为0x56000088、0x5600008c、0x56000090 3、编写驱动代码,编写驱动代码的步骤如下: 1)、编写出口、入口函数。代码如下,具体说明参考Linux驱动之LED驱动编写 static int second_
[单片机]
<font color='red'>Linux</font><font color='red'>驱动</font>之<font color='red'>按键</font><font color='red'>驱动</font>编写(<font color='red'>中断</font>方式)
linux设备树-按键中断驱动
---------------------------------------------------------------------------------------------------------------------------- 内核版本:linux 5.2.8 根文件系统:busybox 1.25.0 u-boot:2016.05 ---------------------------------------------------------------------------------------------------------------------------- 回到顶部 一、修改设备树
[单片机]
Tiny 6410 按键中断驱动笔记
1. 先查看《Tiny6410SDK-1103 底板原理图》,找到按键部分:   从上图可知,当按键按下时,相当于接地,即低电平,从而产生一个由高电平到低电平的跳变。   Tiny6410的底板有8个按键: 2. 查看《Tiny6410-1170 CPU核心板原理图》,找到EINT0的连接图:   从上图可知:   EINT0 接 GPN0   EINT1 接 GPN1   EINT2 接 GPN2   ENIT3 接 GPN3   EINT4 接 GPN4   EINT5 接 GPN5   EINT19 接 GPL11   EINT20 接 GPL12 知识点: 由s3c6410外部触发的中断就是外部中断,
[单片机]
Tiny 6410 <font color='red'>按键</font><font color='red'>中断</font><font color='red'>驱动</font>笔记
【改进Poll定时查询】IMX257实现GPIO-IRQ中断按键获取键值驱动程序
按键驱动程序中,如果不使用read函数中使程序休眠的,而是还是使用查询方式的话,可以使用Poll函数,来控制一定时间内,如果有按键发生,则立即返回键值。 同时,poll也可以同时监控多个(比如说按键,鼠标,等)一旦发生事件则立即返回。 我们在linux查看帮助: 从帮助中的说明得知, poll, ppoll - wait for some event on a file descriptor poll就是监控某个设备的事件。 修改驱动程序 1.增加头文件 #include linux/poll.h 2.增加key_poll 方法 static unsigned key_poll(struct file *fil
[单片机]
【改进Poll定时查询】IMX257实现GPIO-IRQ<font color='red'>中断</font><font color='red'>按键</font>获取键值<font color='red'>驱动</font>程序
字符设备驱动程序按键驱动---中断方式
中断函数:包含#include linux/irq.h request_irq(irq,handle,irqflag,name,dev_id) { 1,分配一个irqaction结构体 2、把这个结构体放到irq_desc (action链表)中 3、设置引脚 4、使能中断 } free_irq(irq,dev_id) { 1、irqaciton出链 2、禁止中断 } ----------------------------------------------------------------------------------------------------------------------
[单片机]
8051/2 单片机基础 LED闪烁,蜂鸣器,数码管驱动,独立按键中断,定时中断,串口通信
从软件转硬件路总是很艰难,各种电路知识,3个多月了,现在总算是入门了。 AT 8051/2 1.驱动LED闪烁 2.驱动蜂鸣器进行响动 3.驱动共阳级,单数码管,0—9 变化(MPX1-CA) - 使用8排阻 + NPN三极管 4.驱动共阴级,但数码管,0-9 变化(MPX1-CC) - 使用芯片74HC245 + PNP三极管 5.独立按键,控制单片机,并点亮/熄灭LED 6.中断,控制点亮/熄灭LED - INT0 , INT1 7.定时中断,控制点亮/熄灭LED - T0 , T1 8.串口通信 电路图: C代码: /** * 8051 DEMO 1 * 1.驱动LED闪烁 * 2.驱动蜂鸣器进行响动 *
[单片机]
8051/2 单片机基础 LED闪烁,蜂鸣器,数码管<font color='red'>驱动</font>,独立<font color='red'>按键</font>,<font color='red'>中断</font>,定时<font color='red'>中断</font>,串口通信
linux驱动学习笔记---实现中断下半部以及驱动编写规范(七)
中断下半部: tasklet : struct tasklet_struct { struct tasklet_struct *next; unsigned long state; atomic_t count; void (*func)(unsigned long); //下半部要执行的代码 unsigned long data; // 传递给func的参数 }; 1, 初始化tasklet tasklet_init(struct tasklet_struct * t, void(* func)(unsigned long), unsigned long data) 2, 在中断上半部
[单片机]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved