历史上的今天

今天是:2025年10月14日(星期二)

正在发生

2022年10月14日 | mini2440 简单按键中断模式驱动程序

发布者:快乐航程 来源: csdn关键字:mini2440  按键  中断模式  驱动程序 手机看文章 扫描二维码
随时随地手机看文章

Makefile


KERN_DIR = /home/grh/kernel_source_code/linux-2.6.32.2

all : 

make -C $(KERN_DIR) M=`pwd` modules

arm-linux-gcc key_interrupt_app.c -o key_interrupt_app

clean :

make -C $(KERN_DIR) M=`pwd` modules clean

rm -rf modules.order

obj-m += key_interrupt.o

copy : 

cp key_interrupt.ko key_interrupt_app /nfs


驱动程序代码

#include

#include

#include

#include

#include

#include

#include

#include

#include gpio.h>

#include

#include

#include

#include

#include

#include

 

#define GRH_MODULE_NAME "key_interrupt"

 

static int major;

static struct class *key_interrupt_class;

static struct class_device *key_interrupt_device; 

static int key_value;

 

//wait_event_interruptible函数需要的两个变量

static DECLARE_WAIT_QUEUE_HEAD(grh_wait_interrupt); //休眠的进程队列头

static volatile int sleep_for_interrupt; //这个变量为0的时候read函数会休眠,中断里面将其置1,read函数末尾将其设置为0

 

 

 

//pin_desc是对每一个按键中断的描述,不仅仅可以是整数,也可以是更复杂到的字段,这里用简单的按键值就行了

int pin_desc[6] = {

1, 2, 3, 4, 5, 6

};

 

 

//中断处理函数

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

int *p;

p = dev_id;

 

//printk(KERN_EMERG"key pressed! key=%dn", *p);

key_value = *p;

 

//唤醒休眠的进程

sleep_for_interrupt = 1;

wake_up_interruptible(&grh_wait_interrupt);

 

return IRQ_HANDLED;

}

 

static void init_key(void){

//注册irq中断处理函数,将按键值和中断号绑定,所有清中断操作以及初始化中断相关寄存器的操作全部交给

//内核自动完成了,不再需要像裸机程序一样显式地对寄存器进行读写了,中断发生后会自动跳到grh_handle_key_eint

request_irq(IRQ_EINT8, grh_handle_key_eint, IRQ_TYPE_EDGE_BOTH, "key1", pin_desc);

request_irq(IRQ_EINT11, grh_handle_key_eint, IRQ_TYPE_EDGE_BOTH, "key2", pin_desc+1);

request_irq(IRQ_EINT13, grh_handle_key_eint, IRQ_TYPE_EDGE_BOTH, "key3", pin_desc+2);

request_irq(IRQ_EINT14, grh_handle_key_eint, IRQ_TYPE_EDGE_BOTH, "key4", pin_desc+3);

request_irq(IRQ_EINT15, grh_handle_key_eint, IRQ_TYPE_EDGE_BOTH, "key5", pin_desc+4);

request_irq(IRQ_EINT19, grh_handle_key_eint, IRQ_TYPE_EDGE_BOTH, "key6", pin_desc+5);

}

 

static int key_interrupt_open(struct inode *inode, struct file *file){

printk(KERN_EMERG"DRIVER: OPENn");

sleep_for_interrupt = 0;

init_key();

return 0;

}

 

static ssize_t key_interrupt_write(struct inode *inode, const char __user *buf, size_t count, loff_t *ppos){

printk(KERN_EMERG"DRIVER: WRITEn");

return 0;

}

 

static ssize_t key_interrupt_read(struct file *file, char __user *buf, size_t count, loff_t *ppos){

printk(KERN_EMERG"DRIVER: READn");

//根据sleep_for_interrupt的数值决定是否将驱动进程加进休眠队列grh_wait_interrupt中

wait_event_interruptible(grh_wait_interrupt, sleep_for_interrupt);

copy_to_user(buf, &key_value, 4);

 

//下一次进入read的时候继续休眠等待中断发生

sleep_for_interrupt = 0;

return 0;

}

 

int key_interrupt_release(struct inode *inode, struct file *file){

//注销中断

free_irq(IRQ_EINT8, pin_desc);

free_irq(IRQ_EINT11, pin_desc+1);

free_irq(IRQ_EINT13, pin_desc+2);

free_irq(IRQ_EINT14, pin_desc+3);

free_irq(IRQ_EINT15, pin_desc+4);

free_irq(IRQ_EINT19, pin_desc+5);

printk(KERN_EMERG"DRIVER: RELEASEn");

return 0;

}

 

 

static struct file_operations key_interrupt_fops = {

.owner = THIS_MODULE,

.open = key_interrupt_open,

.write = key_interrupt_write,

.read = key_interrupt_read,

.release = key_interrupt_release,

};

 

int key_interrupt_module_init(void){

printk(KERN_EMERG"INIT MODULE!n");

 

//register the driver with the device

major = register_chrdev(0, GRH_MODULE_NAME, &key_interrupt_fops);

 

//create my own device class

key_interrupt_class = class_create(THIS_MODULE, "key_interrupt_class");

//create my device of my own class

key_interrupt_device = device_create(key_interrupt_class, NULL, MKDEV(major,0), NULL, "key_interrupt_device");

 

return 0;

}

 

void key_interrupt_module_exit(void){

unregister_chrdev(major, GRH_MODULE_NAME);

device_unregister(key_interrupt_device);

class_destroy(key_interrupt_class);

printk(KERN_EMERG"EXIT MODULE!n");

}

 

module_init(key_interrupt_module_init);

module_exit(key_interrupt_module_exit);

 

MODULE_AUTHOR("GRH");

MODULE_VERSION("1.0");

MODULE_DESCRIPTION("KEY POLL DRIVER");

MODULE_LICENSE("GPL");



用户空间测试程序:

#include

#include

#include

#include

#include

#include

 

int main(void){

int fd;

int i, sum;

int key_value;

 

fd = open("/dev/key_interrupt_device", O_RDWR);

if(-1 == fd){

printf("open key device error!n");

return -1;

}

 

while(1){

read(fd, &key_value, 4);

printf("key pressed : %dn", key_value);

}

close(fd);

return 0;

}



按下按键之后的运行结果:

当没有按键按下的时候,测试程序进程在内核态处于休眠状态,这样比起轮询式的驱动而言,资源的消耗就小了太多了:



关键字:mini2440  按键  中断模式  驱动程序 引用地址:mini2440 简单按键中断模式驱动程序

上一篇:mini2440 make menuconfig 找不到Flash CFI支持的解决办法
下一篇:min2440 uart中断模式(非fifo模式)

推荐阅读

在前边我们使用汇编完成了一个流水灯实验: Tiny4412汇编流水灯代码,Tiny4412裸机LED操作但是,汇编语言可读性太差,在这一节我们用 C语言来实现了同样的功能,而以后的试验也尽量用 C语言实现。我们在编写上位机程序时,C语言程序执行的第一条指令,并不在main函数中。生成一个 C程序的可执行文件时,编译器通常会在我们的代码中加上几个被称为启动文...
在这里介绍一种定时程序,说明循环程序在PIC单片机上的应用。笔者仍以PIC16F84单片机为例建立其定时源程序清单。该定时器源程序只需改变一条指令的常数设置,即可使定时时间从分钟级到38小时的连续变化(4MHz晶振条件)。PIC16F84单片机的硬件电路,请见本报第32期实验编程器101实验板电路。在该实验板电路上,若读者改变晶振的频率(2MHz、1MHz、500kHz)...
与电池类似,超级电容器适用于重复储存电能。据外媒报道,格拉茨技术大学(Tu Graz)的研究人员提出一种特别安全的可持续性超级电容器。 (图片来源:techxplore)目前,锂离子电池技术的主要缺点在于缺乏安全性、可持续性和可回收性,以及原材料(例如钴)供应有限。在寻找替代电化学储能系统用于电动出行和存储可再生能源的过程中,将电池和电容器组合...
日本电产的驱动马达系统“E-Axle”200kW机型被采用于吉利汽车高端电动汽车品牌“Zeekr”的首款车型中  中国的知名造车企业——吉利控股已决定在其高端品牌“Zeekr”(极氪)所发布的新款电动汽车“ZEEKR 001”中采用日本电产(以下简称“本公司”)的驱动马达系统“E-Axle”的200kW机型“Ni200Ex”。 “ZEEKR 001”是一款基于吉利控股-极氪智能科技 ...

史海拾趣

小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

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

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

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