3.linux arm button驱动
2013-10-30 16:07
127 查看
继续学习,选择一个较为简单的使用了终端的的button驱动。
先来看看源码:
驱动的实现其实很简单,就是注册中断,然后在中断处理函数里面来做对每个键按下的处理。这里我们是记录按键的次数。在用户空间需要读的时候再传递出去。
驱动主要的还是需要熟悉硬件原理图,比如我的开发板,其原理图如下:
它其实是一个扫描式的按键,我们需要控制GPB6和7是扫描。我为了方便,直接把GPB6和7都设置为低,就两个按键当一个用。
这里我们把按键作为砸设备,所以使用misc_register去注册。其实也可以简单的注册为字符设备。
好,下面来看看测试程序:
运行后,当你按下一个键的时候就会打印出相应的信息。其实也可以联系前面写的led的驱动,编一个让button去控制led的程序。
如果需要实现扫描式的按键,就需要去注册一个时钟中断。然后再每个时钟中断里面去扫描,课参考/article/1885430.html
先来看看源码:
#include <linux/miscdevice.h> #include <linux/delay.h> #include <linux/irq.h> #include <mach/regs-gpio.h> #include <mach/hardware.h> #include <linux/kernel.h> #include <linux/module.h> #include <linux/init.h> #include <linux/mm.h> #include <linux/fs.h> #include <linux/types.h> #include <linux/delay.h> #include <linux/moduleparam.h> #include <linux/slab.h> #include <linux/errno.h> #include <linux/ioctl.h> #include <linux/cdev.h> #include <linux/string.h> #include <linux/list.h> #include <linux/pci.h> #include <asm/uaccess.h> #include <asm/atomic.h> #include <asm/unistd.h> #include <linux/sched.h> #include <linux/gpio.h> #include <linux/interrupt.h> #define DEVICE_NAME "button" struct button_irq_desc { int irq; unsigned long flags; char *name; }; /* 用来指定按键所用的外部中断引脚及中断触发方式, 名字 */ static struct button_irq_desc button_irqs [] = { {IRQ_EINT0, IRQF_TRIGGER_FALLING, "KEY1"}, {IRQ_EINT2, IRQF_TRIGGER_FALLING, "KEY2"}, {IRQ_EINT11, IRQF_TRIGGER_FALLING, "KEY3"}, {IRQ_EINT19, IRQF_TRIGGER_FALLING, "KEY4"}, }; static volatile int press_cnt [] = {0, 0, 0, 0}; static volatile int const press_no [] = {1, 2, 3, 4}; static DECLARE_WAIT_QUEUE_HEAD(button_waitq); static volatile int ev_press = 0; static irqreturn_t buttons_interrupt(int irq, void *dev_id) { volatile int *index= (volatile int *)dev_id; if(*index==1) press_cnt[0]+=1; else if(*index==2)press_cnt[1]+=1; else if(*index==3)press_cnt[2]+=1; else if(*index==4)press_cnt[3]+=1; else press_cnt[0]+=1; ev_press = 1; // 表示中断发生了 // wake_up_interruptible(&button_waitq); // 唤醒休眠的进程 // return IRQ_RETVAL(IRQ_HANDLED); } static int button_open(struct inode *inode, struct file *file) { int i=0; int err=0; printk(DEVICE_NAME " open\n"); /*我的开发板是扫描式的,暂时把两个按键当一个用吧。见后面的接线原理图*/ s3c2410_gpio_cfgpin(S3C2410_GPB6, S3C2410_GPB6_OUTP); s3c2410_gpio_cfgpin(S3C2410_GPB7, S3C2410_GPB7_OUTP); s3c2410_gpio_setpin(S3C2410_GPB6, 0); s3c2410_gpio_setpin(S3C2410_GPB7, 0); for (i = 0; i <sizeof(button_irqs)/sizeof(button_irqs[0]); i++)//button_irqs[i].flags { // 注册中断处理函数 err = request_irq(button_irqs[i].irq, buttons_interrupt, button_irqs[i].flags, button_irqs[i].name, (void *)&press_no[i]); //err = request_irq(IRQ_EINT4, buttons_interrupt, 2,"KEY1", NULL); if (err) break; } if (err) { // 释放已经注册的中断 printk(DEVICE_NAME " err\n"); i--; for (; i >= 0; i--) free_irq(button_irqs[i].irq, (void *)&press_cnt[i]); return -EBUSY; } printk(DEVICE_NAME " openok\n"); return 0; } static int button_read(struct file *filp, char __user *buff, size_t count, loff_t *offp) { unsigned long err; // 如果ev_press等于0,休眠 // wait_event_interruptible(button_waitq, ev_press); // 执行到这里时,ev_press等于1,将它清0 // if(ev_press) { ev_press = 0; // 将按键状态复制给用户,并清0 // err = copy_to_user(buff, (const void *)press_cnt, min(sizeof(press_cnt), count)); memset((void *)press_cnt, 0, sizeof(press_cnt)); return 0; } return 1; } static int button_close(struct inode *inode, struct file *file) { int i; printk (DEVICE_NAME " close\n"); for (i = 0; i < sizeof(button_irqs)/sizeof(button_irqs[0]); i++) { // 释放已经注册的中断 free_irq(button_irqs[i].irq, (void *)&press_no[i]); } return 0; } static struct file_operations dev_ops = { .owner = THIS_MODULE, .open = button_open, .read = button_read, .release = button_close, }; static struct miscdevice misc = { .minor = MISC_DYNAMIC_MINOR, .name = DEVICE_NAME, .fops = &dev_ops, }; static int __init led_init() { int ret; ret = misc_register(&misc); printk(DEVICE_NAME "initialized\n"); return ret; } static void __exit led_exit() { misc_deregister(&misc); } module_init(led_init); module_exit(led_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("");
驱动的实现其实很简单,就是注册中断,然后在中断处理函数里面来做对每个键按下的处理。这里我们是记录按键的次数。在用户空间需要读的时候再传递出去。
驱动主要的还是需要熟悉硬件原理图,比如我的开发板,其原理图如下:
它其实是一个扫描式的按键,我们需要控制GPB6和7是扫描。我为了方便,直接把GPB6和7都设置为低,就两个按键当一个用。
这里我们把按键作为砸设备,所以使用misc_register去注册。其实也可以简单的注册为字符设备。
好,下面来看看测试程序:
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/time.h> int main(int argc, char **argv) { int i=0; int ret=0; int fd=-1; int press_cnt[4]={0,0,0,0}; fd = open("/dev/button", 0); // 打开设备 if (fd < 0) { printf("Can't open /dev/keya\n"); return -1; } // 这是个无限循环,进程有可能在read函数中休眠,当有按键被按下时,它才返回 while (1) { // 读出按键被按下的次数 ret = read(fd, press_cnt, sizeof(press_cnt)); if (ret ==0) { for (i = 0; i < sizeof(press_cnt)/sizeof(press_cnt[0]); i++) { // 如果被按下的次数不为0,打印出来 if (press_cnt[i]) printf("K%d has been pressed %d times!\n", i+1, press_cnt[i]); } } } close(fd); return 0; }
运行后,当你按下一个键的时候就会打印出相应的信息。其实也可以联系前面写的led的驱动,编一个让button去控制led的程序。
如果需要实现扫描式的按键,就需要去注册一个时钟中断。然后再每个时钟中断里面去扫描,课参考/article/1885430.html
相关文章推荐
- linux 相关
- Linux中select poll和epoll的区别
- linux VLAN配置(vconfig)
- 开始我的linux(随学习进度更新)
- Linux之tar.gz、tar、bz2、zip等解压缩、压缩命令小结
- linux通知链相关
- google protobuf@centos
- linux环境变了设定
- linux 程序运行前后台切换
- Linux之软件安装命令
- SecureCRT连接linux 中文乱码解决
- Linux进程监控日志
- Linux CentOS 6.4安装Mysql数据库教程
- 如何解决源码包安装时的依赖性问题
- linux下IPTABLES设置详解
- centos6.4如何安装中文输入法?
- Linux连接时间的日志
- Linux学习拾遗
- Centos 6.* 升级python到2.7.*
- Linux的五个查找命令:find,locate,whereis,which,type