arm驱动程序——按键程序1(韦东山的视频总结及针对linux-2.6.30)

本文介绍了一个基于Linux的按键中断驱动程序的设计与实现。该程序利用中断方式响应按键操作,并通过注册和释放中断来管理按键事件。文章提供了完整的源代码示例,展示了如何设置GPIO引脚为中断模式、注册中断处理函数以及读取按键状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

相关代码在资源中下载。

按键程序是以中断方式写的,至于中断的内核相关的知识看中断框架和注册一节,

所用到的函数和结构:

/*用来注册中断*/

/*irq:中断号,handler:中断处理函数,flags:中断触发方式,

 *name:中断名字,dev:用来传给中断函数的*/

static inline int __must_check
request_irq(unsigned int irq, irq_handler_t handler, 

            unsigned long flags,const char *name, void *dev)


/*用来释放住的request_irq*/
void free_irq(unsigned int irq, void *dev_id);

驱动程序:

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/irq.h>
#include <linux/device.h>
#include <linux/poll.h>
#include <linux/irq.h>
#include <linux/interrupt.h>
#include <asm/uaccess.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <mach/irqs.h>
/*不同的linux版本的头文件会有所不同*/
static int major;
static struct class  *second_key_class;
static struct device *second_key_device;
volatile unsigned long *GPFCON = NULL;
volatile unsigned long *GPFDAT = NULL;
static irqreturn_t buttons_irq(int irq,void *dev_id){

      printk("irq= %d \n",irq);
      return IRQ_HANDLED;
}
static int second_key_open(struct inode *inode, struct file *file)
{
     /*设置相应引脚设置成中断方式*/
      *GPFCON &= ~((3<<0)|(3<<2)|(3<<4)|(3<<8));
      *GPFCON |= (1<<1)|(1<<3)|(1<<5)|(1<<7);
     /*中断注册*/
      request_irq(IRQ_EINT1,buttons_irq,IRQ_TYPE_EDGE_BOTH,"s1",1);
      request_irq(IRQ_EINT4,buttons_irq,IRQ_TYPE_EDGE_BOTH,"s2",1);
      request_irq(IRQ_EINT2,buttons_irq,IRQ_TYPE_EDGE_BOTH,"s3",1);
      request_irq(IRQ_EINT0,buttons_irq,IRQ_TYPE_EDGE_BOTH,"s4",1);
      return 0;
}
static ssize_t second_key_read(struct file *file, char __user *user_buffer, 

                               size_t count, loff_t *ppos)
{
     unsigned long reval;
     int i;
     unsigned long key_val[4];
     /*读出引脚状态*/
     reval = *GPFDAT;
     if(count != sizeof(key_val))
         return -EINVAL;
     key_val[0] = (reval & (0x01<<0)) ? 1 : 0;
     key_val[1] = (reval & (0x01<<1)) ? 1 : 0;
     key_val[2] = (reval & (0x01<<2)) ? 1 : 0;
     key_val[3] = (reval & (0x01<<4)) ? 1 : 0;
     /*把内核的数据传到用户空间*/
     copy_to_user(user_buffer,key_val,4);
     return 4;
}
static int second_key_close(struct inode *inode, struct file *file)
{
     /*释放分配的request_irq*/
     free_irq(IRQ_EINT1,1);
     free_irq(IRQ_EINT4,1);
     free_irq(IRQ_EINT2,1);
     free_irq(IRQ_EINT0,1);
     return 0;
}
/*定义一个file_operations结构*/
static struct file_operations second_key_fops =
{
    .owner   = THIS_MODULE,
    .open    = second_key_open,
    .read    = second_key_read,
    .release = second_key_close,
};
/*入口函数*/
static int  second_key_init(void)
{
    /*注册*/
    major =register_chrdev(0,"second_key1",&second_key_fops);
    /*分配一个类*/
    second_key_class = class_create(THIS_MODULE,"second_key_class");
    /*类下面创建一个设备*/
    second_key_device = 
    device_create(second_key_class,NULL,MKDEV(major,0),NULL,"buttons");
    /*映射物理地址到虚拟地址*/
    GPFCON = (volatile unsigned long *)ioremap(0x56000050,16);
    GPFDAT = GPFCON + 1;
    return 0;
}
/*出口函数*/
static void second_key_exit(void)
{
    /*注销*/
    unregister_chrdev(major,"second_key1");
    /*从系统中注销设备*/
    device_unregister(second_key_device);
    /*销毁创建的类*/
    class_destroy(second_key_class);

    /*取消虚拟地址的映射*/
    iounmap(GPFCON);
}
/*修饰*/
module_init(second_key_init);
module_exit(second_key_exit);
MODULE_LICENSE("GPL");

下面测试:

1,加载到内核 insmod second_key1.ko

2,打开中断设备 exec 5</dev/buttons

3, 按下按键 终端出现中断号

4,关闭中断设备 exec 5<&-

exec 5</dev/buttons 是用shell打开文件

你可以用ps查看/bin/sh的进程号,然后用ls -l /proc/进程号/fd

可以看到lr -x    1 root     root            64 Apr 29 17:04 5 -> /dev/buttons



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值