s5pv210中断法控制LED灯
来源:互联网 发布:ios版cf手游刷枪软件 编辑:程序博客网 时间:2024/04/28 07:39
前面介绍过轮询的方法控制LED灯,这里将介绍如何使用按键产生中断的方法控制LED灯。
linux内核的中断需要使用request_irq函数来申请,并用free_irq来释放它,在此就不介绍它的原理,下面将直接讲如何使用它们来完成中断操作,首先查看request_irq的原型,如下:
1、static inline int __must_check request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags,const char *name, void *dev)
其中__must_check是提醒工程师在使用这个函数后最好检查其返回值,以确保申请中断成功,以下对各参数作介绍:
参数1:irq表示中断号,这个与芯片直接相关,不能随便定义,应该与硬件的中断号相对应;
参数2:代表一个函数指针,其实就是一个中断回调函数,当发生中断时会调用这个函数进行相应操作,它的原型为static irqreturn_t (*handler)(int irq, void *dev),其中irq对应到request_irq的参数1,代表执行的哪个中断号的中断,因为有些中断会共享同一个中断,如IO口的中断,*dev对应于request_irq的最后一个参数,用于传递 参数给 回调函数。
参数3:代表这个中断发生的标志,如IO口的中断有上升沿触发或下降沿触发等等
参数4:中断的名字,通过cat /proc/interrupts 查找
参数5:用于传递给中断回调函数的参数
2、void free_irq(unsigned int irq, void *dev_id)
释放中断,一般在结束时释放它irq对应于request_irq第一个参数,第二个对应于request_irq的最后一个参数。
首先让我们查看原理图按键部分
由原理图可知KEY1对应于XEINT0,则通过查芯片手册可知其对应的中断号为XIENT[0],其它按键同理可查,在以前的基础上改写驱动可得
#include <linux/module.h>#include <linux/kernel.h>#include <linux/fs.h>#include <linux/init.h>#include <linux/delay.h>#include <asm/uaccess.h>#include <linux/gpio.h> #include <asm/irq.h>#include <linux/sched.h> #include <linux/irq.h>#include <asm/io.h>#include <linux/device.h>#include <linux/interrupt.h>#include <linux/wait.h>#include <linux/cdev.h>typedef struct {struct cdev cdev;dev_t devno;struct class *leddrv_class;struct device*leddrv_class_dev;int irq;int major;unsigned long virt;}CharLedDrive;static CharLedDrive led_info;static volatile int press = 0; struct pin_desc{unsigned int pin;unsigned char key_val;};static unsigned char witch_key = 0;static struct pin_desc key_descs[8] ={ [0] = { .pin = S5PV210_GPH0(0), .key_val = 0x01, }, [1] = { .pin = S5PV210_GPH0(1), .key_val = 0x02, }, [2] = { .pin = S5PV210_GPH0(2), .key_val = 0x03, }, [3] = { .pin = S5PV210_GPH0(3), .key_val = 0x04, }, [4] = { .pin = S5PV210_GPH0(4), .key_val = 0x05, }, [5] = { .pin = S5PV210_GPH0(5), .key_val = 0x06, }, [6] = { .pin = S5PV210_GPH2(6), .key_val = 0x07, }, [7] = { .pin = S5PV210_GPH2(7), .key_val = 0x08, }, };volatile unsigned long *GPC0CON, *GPC0DAT;//用与存放两个个寄存器的地址volatile unsigned long *GPH0CON, *GPH0DAT;//按键static unsigned char KeyFlag;static void all_leds_off(void);static void led_config(void){volatile unsigned long phys;//用于存放虚拟地址和物理地址phys = 0xE0200060; led_info.virt =(unsigned long)ioremap(phys, 0xf00);GPC0CON = (unsigned long *)(led_info.virt + 0x00);//指定需要操作的三个寄存器的地址GPC0DAT = (unsigned long *)(led_info.virt + 0x04);GPH0CON = (unsigned long *)(led_info.virt + 0xc00-0x60); //keY1配置为输入GPH0DAT = (unsigned long *)(led_info.virt + 0xc00-0x60+0x04);*GPC0CON &= ~(0xFF << 12);*GPC0CON |= 0x11 << 12;// 配置GPC0_3和GPC0_4为输出*GPH0CON &= ~0x0F; //配置为输入all_leds_off();}static void led1_on(void){*GPC0DAT |= 1 << 3;*GPC0DAT &= ~(0x01 << 4);//printk("led1 light\n");}static void led2_on(void){*GPC0DAT |= 1 << 4;*GPC0DAT &= ~(0x01 << 3);//printk("led2 light\n");}static void all_leds_on(void){*GPC0DAT |= 1 << 3;// 点亮LED1*GPC0DAT |= 1 << 4;// 点亮LED2printk("all leds light\n");}static void all_leds_off(void){*GPC0DAT &= ~(0x3 << 3);// 熄灭LED1和LED2printk("all leds off\n");}static int led_drv_open(struct inode *inode, struct file *file){printk("led_drv_open\n");led_config();all_leds_off();return 0;}static irqreturn_t led_handler(int irq, void *devid){struct pin_desc * pindesc = (struct pin_desc *)devid;witch_key = pindesc->key_val;KeyFlag = !KeyFlag;printk("KERNEL:irq == %d witch_key= %d\n",irq,witch_key);return IRQ_RETVAL(IRQ_HANDLED); }static ssize_t led_drv_write(struct file *file, const char __user *buf, size_t count, loff_t * ppos){char val = 0;int ret = -1;ret = copy_from_user(&val, buf, count);if(ret){printk("write ret= %x\n",ret);}return count;}static ssize_t led_drv_read(struct file *file, char __user *buf, size_t count, loff_t *ppos){int ret = -1;unsigned char from[1]={0};if(KeyFlag){ led1_on();}else{led2_on();}from[0] = witch_key;if(witch_key>0){ret = copy_to_user(buf,from,sizeof(from));if(ret){ printk("copy to user failed\n");}witch_key = 0;}return 0;}static struct file_operations led_drv_fops = { .owner = THIS_MODULE, /* 这是一个宏,推向编译模块时自动创建的__this_module变量 */ .open = led_drv_open, .write=led_drv_write,.read= led_drv_read, };//static irqreturn_t led_handler(int irq, void *dev_id)static int led_drv_init(void){int ret = -1;int i;cdev_init(&led_info.cdev, &led_drv_fops); //led_info.major = register_chrdev(0, "led_drv", &led_drv_fops); // 注册, 告诉内核led_info.cdev.owner = THIS_MODULE; ret = alloc_chrdev_region(&led_info.devno, 0, 1, "led_drv"); if(ret){ printk(KERN_ERR "alloc char device region faild!\n"); return ret; } ret = cdev_add(&led_info.cdev, led_info.devno, 1); if(ret){ printk(KERN_ERR "add char device faild!\n"); goto cdev_add_error; } led_info.leddrv_class = class_create(THIS_MODULE, "led_class_drv");if(IS_ERR(led_info.leddrv_class)){ printk(KERN_ERR "function class_create excute error!\n"); goto led_class_error; } led_info.leddrv_class_dev = device_create(led_info.leddrv_class, NULL, led_info.devno, NULL, "led_drv"); /* /dev/xyz */if(IS_ERR(led_info.leddrv_class_dev)){ printk(KERN_ERR "function device_create excute error!\n"); goto led_device_error; } for(i=0;i<5;i++) {ret = request_irq(IRQ_EINT(i), &led_handler, IRQ_TYPE_EDGE_FALLING,"led_irq", &key_descs[i]);if(ret){printk(KERN_ERR"function request_irq(%d) excute error\n",i);goto led_request_irq_error;}}return 0;led_request_irq_error:device_unregister(led_info.leddrv_class_dev);led_device_error:class_destroy(led_info.leddrv_class); led_class_error:cdev_del(&led_info.cdev);cdev_add_error:unregister_chrdev_region(led_info.devno,1); return -ENODEV;}static void led_drv_exit(void){free_irq(IRQ_EINT(0), &key_descs[0]);free_irq(IRQ_EINT(1), &key_descs[1]);free_irq(IRQ_EINT(2), &key_descs[2]);free_irq(IRQ_EINT(3), &key_descs[3]);free_irq(IRQ_EINT(4), &key_descs[4]);printk("led_drv_exit ....excute ok\n");//all_leds_off();printk("led_drv_exit ....excute ok0\n");device_unregister(led_info.leddrv_class_dev);printk("led_drv_exit ....excute ok1\n");class_destroy(led_info.leddrv_class);printk("led_drv_exit ....excute ok2\n");cdev_del(&led_info.cdev); printk("led_drv_exit ....excute ok3\n");unregister_chrdev_region(led_info.devno, 1); printk("led_drv_exit ....excute ok4\n");iounmap((void *)led_info.virt); //撤销映射关系}module_init(led_drv_init);module_exit(led_drv_exit);MODULE_LICENSE("GPL");
测试程序如下:
#include<stdio.h>#include<stdlib.h>#include<sys/types.h>#include<sys/stat.h>#include<fcntl.h>#include <unistd.h>int main(int argc,char **argv){ int fd = -1; char val = 0; char buf[10]={0}; char temp= 0; char *s = malloc(100); unsigned char key[1]; fd = open("/dev/led_drv",O_RDWR); if(fd<0)printf("can't open \n");while(1){val++; if(read(fd,key,sizeof(key))>0){ temp = key[0]; if(temp) printf("pressed key is key[%x]\n",temp); temp = 0;}}free(s); return 0;}
- s5pv210中断法控制LED灯
- 中断-按键控制LED灯
- tiny 6410按键中断控制LED灯
- 6.0 外部中断控制LED灯
- 中断控制LED灯亮灭
- arm中断控制led
- mini2440 外部中断控制led
- 中断控制LED裸机程序
- S5PV210 Android LED灯驱动程序
- wince6.0 +S3C6410 中断处理例子(按键控制LED灯)+应用程序控制LED流水灯
- mini2440按键中断控制led灯遇到的问题
- TQ2440裸奔程序3-中断控制LED灯
- Tiny210 中断控制LED灯的亮和灭
- OK6410利用矢量中断通过按键控制LED灯
- tiny210(S5PV210)中断控制相关学习记录
- s5pv210 LED
- 用中断的方式都控制LED
- 中断——按键控制LED状态
- linux下配置mysql开机自启动
- 非NSResponder类捕捉按键消息[How to capture ESC key in a Cocoa application]
- 3.合唱队
- 多文件结构
- 【Web 前端】CSS样式
- s5pv210中断法控制LED灯
- Injured Queen Problem+uva+dp
- 环境配置-无障碍搜索外文资料
- 使用maven 一步步构建springmvc的工程
- $.extend和$.fn.extend的区别
- Windows下无法启动MYSQL服务”1067 进程意外终止”解决办法
- Why Tomcat removes application folder after you deleted the war
- PJSIP开发手册之传输层(六)
- 几种软件开发模型