企业网站建设方案书,怎么检测网站是否安全,网站标题怎么改,wordpress导航下拉菜单大图目录 一、Linux 中断简介
上半部与下半部
二、添加设备树
三、编写驱动
1、定义宏 2、编写一个key结构体
3、imx6uirq设备添加成员
编辑4、按键中断处理函数
5、按键初始化
6、在驱动入口添加初始化
7、 驱动出口函数 代码如下
四、利用定时器进行消抖处理
1、添…目录 一、Linux 中断简介
上半部与下半部
二、添加设备树
三、编写驱动
1、定义宏 2、编写一个key结构体
3、imx6uirq设备添加成员
编辑4、按键中断处理函数
5、按键初始化
6、在驱动入口添加初始化
7、 驱动出口函数 代码如下
四、利用定时器进行消抖处理
1、添加定时器 2、修改中断处理函数
3、添加定时器处理函数
4、在按键初始化函数最后添加初始化定时器 5、驱动出口函数添加删除定时器
五、编写测试app
1、添加原子操作
2、初始化原子变量
3、按下和释放操作
4、读函数操作
总体代码如下 一、Linux 中断简介
在 Linux 内核中要想使用某个中断是需要申请的使用完成以后就要释放掉相应的中断申请中断的时候需要设置中断处理函数还有设置使能中断与禁止
上半部与下半部
有些资料中也将上半部和下半部称为顶半部和底半部。
上半部上半部就是中断处理函数那些处理过程比较快不会占用很长时间的处理就可以放在上半部完成。 下半部如果中断处理过程比较耗时那么就将这些比较耗时的代码提出来交给下半部去执行这样中断处理函数就会快进快出。 至于哪些代码属于上半部哪些代码属于下半部并没有明确的规定如果要处理的内容不希望被其他中断打断、处理的任务对时间敏感或处理的任务与硬件有关那么可以放到上半部其余以外的其他任务优先考虑放到下半部
二、添加设备树
打开原理图找到KEY 可以看到KEY0是接到UART1 CTS上
打开参考手册找到IOMUXC_SW_MUX_CTL_PAD_UART1_CTS_B 看到是可以复用为GPIO1_IO18的
根据之前key驱动实验编写的key节点添加 184-185两行 184行 指定父中断也就是中断控制器因为key复用为GPIO1_IO18所以为gpio1
185行设置中断源指定中断号触发方式。因为复用GPIO1_IO18所以为18 IRQ_TYPE_EDGE_BOTH 定义在文件 include/linux/irq.h 中 IRQ_TYPE_EDGE_BOTH 表示上升沿和下降沿同时有效相当于KEY0 按下和释放都会触发中断
添加完成之后编译设备树用此设备树启动
三、编写驱动
导入模板修改makefile 1、定义宏 2、编写一个key结构体 irq_desc为中断描述符这里是key所以用irq_keydesc
3、imx6uirq设备添加成员
在imx6uirq设备中使用用数组的形式主要是方便添加多个按键
4、按键中断处理函数
实现key结构体中的按键中断处理函数 71行中断处理函数格式如下
irqreturn_t (*irq_handler_t) (int, void *) 第一个参数是要中断处理函数要相应的中断号。第二个参数是一个指向 void 的指针也就是个通用指针用于区分共享中断的不同设备也可以指向设备数据结构。中断处理函数的返回值为 irqreturn_t 类型。
73行dev_id指向dev的设备也就是imx6uirq
74行获取gpio的值
5、按键初始化 88行通过路径查找设备树节点
93-94行通过循环来进行获取关于节点属性
100-103行通过循环初始化名字数组sprintf()用来作格式化的输出申请使用gpio
109行设置gpio输出
111行和113行作用一样都是获取中断号前者只能利用gpio获取后者利用通过属性索引获取
116行设置key0的中断处理函数
117行设置key0的按键值
120行在 Linux 内核中要想使用某个中断是需要申请的 request_irq 函数用于申请中断request_irq函数可能会导致睡眠因此不能在中断上下文或者其他禁止睡眠的代码段中使用 request_irq 函数。 request_irq 函数会激活(使能)中断所以不需要我们手动去使能中断 request_irq 函数原型如下 int request_irq(unsigned int irq irq_handler_t handler unsigned long flags const char * name void * dev) irq要申请中断的中断号。 handler中断处理函数当中断发生以后就会执行此中断处理函数。 flags中断标志可以在文件 include/linux/interrupt.h 里面查看所有的中断标志。这里使用上升沿和下降沿触发
name中断名字设置以后可以在/proc/interrupts 文件中看到对应的中断名字。 dev 如果将 flags 设置为 IRQF_SHARED 的话 dev 用来区分不同的中断一般情况下将dev 设置为设备结构体 dev 会传递给中断处理函数 irq_handler_t 的第二个参数。 返回值 0 中断申请成功其他负值 中断申请失败如果返回-EBUSY 的话表示中断已经 被申请了
6、在驱动入口添加初始化 7、 驱动出口函数 代码如下
#include linux/module.h
#include linux/kernel.h
#include linux/init.h
#include linux/fs.h
#include linux/uaccess.h
#include linux/io.h
#include linux/cdev.h
#include linux/device.h
#include linux/of.h
#include linux/of_address.h
#include linux/of_irq.h
#include linux/slab.h
#include linux/of_address.h
#include linux/of_gpio.h
#include linux/atomic.h
#include linux/timer.h
#include linux/jiffies.h
#include linux/string.h
#include linux/irq.h
#include linux/interrupt.h#define IMX6UIRQ_CNT 1
#define IMX6UIRQ_NAME imx6uirq
#define KEY_NUM 1 /* 按键数量 */
#define KEY0VALUE 0X01 /* KEY0按键值 */
#define INVAKEY 0XFF /* 无效的按键值 *//*key结构体*/
struct irq_keydesc{int gpio; /*io编号*/int irqnum; /*中断号*/unsigned char value; /*键值*/char name[10]; /*名字*/irqreturn_t(*handler) (int ,void *); /*中断处理函数*/
};struct imx6uirq_dev{dev_t devid;int major;int minor;struct cdev cdev;struct class *class;struct device *device;struct device_node *nd;struct irq_keydesc irqkey[KEY_NUM];
}imx6uirq;
static int imx6uirq_open(struct inode *inode, struct file *filp){filp-private_data imx6uirq;return 0;
}
static ssize_t imx6uirq_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{return 0;
}
static ssize_t imx6uirq_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{return 0;
}
static int imx6uirq_release(struct inode *inode, struct file *filp){return 0;
}static const struct file_operations imx6uirq_fops {.owner THIS_MODULE,.open imx6uirq_open,.read imx6uirq_read,.write imx6uirq_write,.release imx6uirq_release,
};
/*按键中段处理函数*/
static irqreturn_t key0_handler(int irq,void *dev_id){int value 0;struct imx6uirq_dev * dev dev_id;value gpio_get_value(dev-irqkey[0].gpio);if(value 0){/*按下*/printk(KEY0 push\r\n);}else if(value 1){/*释放*/printk(KEY0 release\r\n);}return IRQ_HANDLED;
}
/*按鍵初始化*/
static int keyio_init(struct imx6uirq_dev *dev){int i,ret 0 ;/*按鍵初始化*/dev-nd of_find_node_by_path(/key);if(dev-nd NULL){ret -EINVAL;goto fail_nd;}for(i0;iKEY_NUM;i){dev-irqkey[i].gpio of_get_named_gpio(dev-nd,key-gpios,i);if(dev-irqkey[i].gpio 0){ret -EINVAL;goto fail_gpio;}}for(i0;iKEY_NUM;i){memset(dev-irqkey[i].name,0,sizeof(dev-irqkey[i].name));sprintf(dev-irqkey[i].name,KEY%d,i);ret gpio_request(dev-irqkey[i].gpio , dev-irqkey[i].name);if(ret){ret -EBUSY;printk(IO %d cant request\r\n,dev-irqkey[i].gpio);goto fail_request;}gpio_direction_input(dev-irqkey[i].gpio);/*获取中断号*/dev-irqkey[i].irqnum gpio_to_irq(dev-irqkey[i].gpio);
#if 0dev-irqkey[i].irqnum irq_of_parse_and_map(dev-nd,i);#endif}dev-irqkey[0].handler key0_handler;dev-irqkey[0].value KEY0VALUE;/*按键中断初始化*/for(i0;iKEY_NUM;i){ret request_irq(dev-irqkey[i].irqnum,dev-irqkey[i].handler,IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING,dev-irqkey[i].name,imx6uirq);if(ret){printk(irq %d request failed!\r\n,dev-irqkey[i].irqnum);goto fail_irq;}}return 0;
fail_irq:for(i0;iKEY_NUM;i){gpio_free(dev-irqkey[i].gpio);}
fail_request:
fail_gpio:
fail_nd:return ret;
}static int __init imx6uirq_init(void){int ret 0;imx6uirq.major 0;if(imx6uirq.major){imx6uirq.devid MKDEV(imx6uirq.major,0);ret register_chrdev_region(imx6uirq.devid,IMX6UIRQ_CNT,IMX6UIRQ_NAME);if(ret 0){goto fail_devid;}}else{ret alloc_chrdev_region(imx6uirq.devid,0,IMX6UIRQ_CNT,IMX6UIRQ_NAME);if(ret 0){goto fail_devid;}imx6uirq.major MAJOR(imx6uirq.devid);imx6uirq.minor MINOR(imx6uirq.devid);printk(imx6uirq major %d, minor %d\r\n, imx6uirq.major, imx6uirq.minor);}imx6uirq.cdev.owner THIS_MODULE;cdev_init(imx6uirq.cdev, imx6uirq_fops);ret cdev_add(imx6uirq.cdev,imx6uirq.devid,IMX6UIRQ_CNT);if(ret){goto fail_cdevadd;}imx6uirq.class class_create(THIS_MODULE,IMX6UIRQ_NAME);if(IS_ERR(imx6uirq.class)){ret PTR_ERR(imx6uirq.class);goto fail_class;}imx6uirq.device device_create(imx6uirq.class,NULL,imx6uirq.devid,NULL,IMX6UIRQ_NAME);if(IS_ERR(imx6uirq.device)){ret PTR_ERR(imx6uirq.device);goto fail_device;}/*初始化IO*/ret keyio_init(imx6uirq);if(ret 0){goto fail_keyinit;}return 0;
fail_keyinit:device_destroy(imx6uirq.class,IMX6UIRQ_CNT);
fail_device:class_destroy(imx6uirq.class);
fail_class:cdev_del(imx6uirq.cdev);
fail_cdevadd:unregister_chrdev_region(imx6uirq.devid,IMX6UIRQ_CNT);
fail_devid:return ret;
}
static void __exit imx6uirq_exit(void){int i0;/*释放中断*/for(i0;iKEY_NUM;i){free_irq(imx6uirq.irqkey[i].irqnum,imx6uirq);}/*释放IO*/for(i0;iKEY_NUM;i){gpio_free(imx6uirq.irqkey[i].gpio);}device_destroy(imx6uirq.class,imx6uirq.devid);class_destroy(imx6uirq.class);cdev_del(imx6uirq.cdev);unregister_chrdev_region(imx6uirq.devid,IMX6UIRQ_CNT);printk(imx6uirq_exit\r\n);
}module_init(imx6uirq_init);
module_exit(imx6uirq_exit);MODULE_LICENSE(GPL);
MODULE_AUTHOR(ba che kai qi lai);
编译到开发板上按下按键0就会打印相关内容释放也会注意此处没做消抖
四、利用定时器进行消抖处理
1、添加定时器 2、修改中断处理函数 在进入到中断处理后定时器处理函数会周期延时20毫秒作消抖处理
3、添加定时器处理函数 消抖后判断是否按下按键
4、在按键初始化函数最后添加初始化定时器 5、驱动出口函数添加删除定时器 加载驱动进行测试之后按键按下和释放都会相对准确在按下和释放速度过快就会打印相同信息的情况
五、编写测试app
1、添加原子操作 2、初始化原子变量 3、按下和释放操作 4、读函数操作 总体代码如下
驱动
#include linux/module.h
#include linux/kernel.h
#include linux/init.h
#include linux/fs.h
#include linux/uaccess.h
#include linux/io.h
#include linux/cdev.h
#include linux/device.h
#include linux/of.h
#include linux/of_address.h
#include linux/of_irq.h
#include linux/slab.h
#include linux/of_address.h
#include linux/of_gpio.h
#include linux/atomic.h
#include linux/timer.h
#include linux/jiffies.h
#include linux/string.h
#include linux/irq.h
#include linux/interrupt.h#define IMX6UIRQ_CNT 1
#define IMX6UIRQ_NAME imx6uirq
#define KEY_NUM 1 /* 按键数量 */
#define KEY0VALUE 0X01 /* KEY0按键值 */
#define INVAKEY 0XFF /* 无效的按键值 *//*key结构体*/
struct irq_keydesc{int gpio; /*io编号*/int irqnum; /*中断号*/unsigned char value; /*键值*/char name[10]; /*名字*/irqreturn_t(*handler) (int ,void *); /*中断处理函数*/
};struct imx6uirq_dev{dev_t devid;int major;int minor;struct cdev cdev;struct class *class;struct device *device;struct device_node *nd;struct irq_keydesc irqkey[KEY_NUM];struct timer_list timer;atomic_t keyvalue;atomic_t releasekey;
}imx6uirq;
static int imx6uirq_open(struct inode *inode, struct file *filp){filp-private_data imx6uirq;return 0;
}
static ssize_t imx6uirq_read(struct file *filp, char __user *buf, size_t cnt, loff_t *offt)
{int ret 0;unsigned char keyvalue;unsigned char releasekey;struct imx6uirq_dev *dev filp-private_data;keyvalue atomic_read(dev-keyvalue);releasekey atomic_read(dev-releasekey);if(releasekey){/*有效按键*/if(keyvalue 0x80){keyvalue ~0x80;ret__copy_to_user(buf,keyvalue,sizeof(keyvalue));}else{goto data_error;}atomic_set(dev-releasekey,0);/*按下标志清零*/}else{goto data_error;}return ret;
data_error:return -EINVAL;
}
static ssize_t imx6uirq_write(struct file *filp, const char __user *buf, size_t cnt, loff_t *offt)
{return 0;
}
static int imx6uirq_release(struct inode *inode, struct file *filp){return 0;
}static const struct file_operations imx6uirq_fops {.owner THIS_MODULE,.open imx6uirq_open,.read imx6uirq_read,.write imx6uirq_write,.release imx6uirq_release,
};
/*按键中断处理函数*/
static irqreturn_t key0_handler(int irq,void *dev_id){struct imx6uirq_dev * dev dev_id;dev-timer.data (volatile unsigned long)dev_id;mod_timer(dev-timer,jiffies msecs_to_jiffies(20));/*10ms*/return IRQ_HANDLED;
}
/*定时器处理函数*/
static void timer_func(unsigned long arg){int value 0;struct imx6uirq_dev *dev (struct imx6uirq_dev *)arg;value gpio_get_value(dev-irqkey[0].gpio);if(value 0){/*按下*/atomic_set(dev-keyvalue,dev-irqkey[0].value);}else if(value 1){/*释放*/atomic_set(dev-keyvalue,0x80 | (dev-irqkey[0].value));atomic_set(dev-releasekey,1);}}
/*按鍵初始化*/
static int keyio_init(struct imx6uirq_dev *dev){int i,ret 0 ;/*按鍵初始化*/dev-nd of_find_node_by_path(/key);if(dev-nd NULL){ret -EINVAL;goto fail_nd;}for(i0;iKEY_NUM;i){dev-irqkey[i].gpio of_get_named_gpio(dev-nd,key-gpios,i);if(dev-irqkey[i].gpio 0){ret -EINVAL;goto fail_gpio;}}for(i0;iKEY_NUM;i){memset(dev-irqkey[i].name,0,sizeof(dev-irqkey[i].name));sprintf(dev-irqkey[i].name,KEY%d,i);ret gpio_request(dev-irqkey[i].gpio , dev-irqkey[i].name);if(ret){ret -EBUSY;printk(IO %d cant request\r\n,dev-irqkey[i].gpio);goto fail_request;}gpio_direction_input(dev-irqkey[i].gpio);/*获取中断号*/dev-irqkey[i].irqnum gpio_to_irq(dev-irqkey[i].gpio);
#if 0dev-irqkey[i].irqnum irq_of_parse_and_map(dev-nd,i);#endif}dev-irqkey[0].handler key0_handler;dev-irqkey[0].value KEY0VALUE;/*按键中断初始化*/for(i0;iKEY_NUM;i){ret request_irq(dev-irqkey[i].irqnum,dev-irqkey[i].handler,IRQ_TYPE_EDGE_FALLING | IRQ_TYPE_EDGE_RISING,dev-irqkey[i].name,imx6uirq);if(ret){printk(irq %d request failed!\r\n,dev-irqkey[i].irqnum);goto fail_irq;}}/*初始化定时器*/init_timer(imx6uirq.timer);imx6uirq.timer.function timer_func;return 0;
fail_irq:for(i0;iKEY_NUM;i){gpio_free(dev-irqkey[i].gpio);}
fail_request:
fail_gpio:
fail_nd:return ret;
}static int __init imx6uirq_init(void){int ret 0;imx6uirq.major 0;if(imx6uirq.major){imx6uirq.devid MKDEV(imx6uirq.major,0);ret register_chrdev_region(imx6uirq.devid,IMX6UIRQ_CNT,IMX6UIRQ_NAME);if(ret 0){goto fail_devid;}}else{ret alloc_chrdev_region(imx6uirq.devid,0,IMX6UIRQ_CNT,IMX6UIRQ_NAME);if(ret 0){goto fail_devid;}imx6uirq.major MAJOR(imx6uirq.devid);imx6uirq.minor MINOR(imx6uirq.devid);printk(imx6uirq major %d, minor %d\r\n, imx6uirq.major, imx6uirq.minor);}imx6uirq.cdev.owner THIS_MODULE;cdev_init(imx6uirq.cdev, imx6uirq_fops);ret cdev_add(imx6uirq.cdev,imx6uirq.devid,IMX6UIRQ_CNT);if(ret){goto fail_cdevadd;}imx6uirq.class class_create(THIS_MODULE,IMX6UIRQ_NAME);if(IS_ERR(imx6uirq.class)){ret PTR_ERR(imx6uirq.class);goto fail_class;}imx6uirq.device device_create(imx6uirq.class,NULL,imx6uirq.devid,NULL,IMX6UIRQ_NAME);if(IS_ERR(imx6uirq.device)){ret PTR_ERR(imx6uirq.device);goto fail_device;}/*初始化IO*/ret keyio_init(imx6uirq);if(ret 0){goto fail_keyinit;}/*初始化原子变量*/atomic_set(imx6uirq.keyvalue,INVAKEY);atomic_set(imx6uirq.releasekey,0);return 0;
fail_keyinit:device_destroy(imx6uirq.class,IMX6UIRQ_CNT);
fail_device:class_destroy(imx6uirq.class);
fail_class:cdev_del(imx6uirq.cdev);
fail_cdevadd:unregister_chrdev_region(imx6uirq.devid,IMX6UIRQ_CNT);
fail_devid:return ret;
}
static void __exit imx6uirq_exit(void){int i0;/*释放中断*/for(i0;iKEY_NUM;i){free_irq(imx6uirq.irqkey[i].irqnum,imx6uirq);}/*释放IO*/for(i0;iKEY_NUM;i){gpio_free(imx6uirq.irqkey[i].gpio);}del_timer_sync(imx6uirq.timer);device_destroy(imx6uirq.class,imx6uirq.devid);class_destroy(imx6uirq.class);cdev_del(imx6uirq.cdev);unregister_chrdev_region(imx6uirq.devid,IMX6UIRQ_CNT);printk(imx6uirq_exit\r\n);
}module_init(imx6uirq_init);
module_exit(imx6uirq_exit);MODULE_LICENSE(GPL);
MODULE_AUTHOR(ba che kai qi lai);
APP
#include sys/types.h
#include sys/stat.h
#include fcntl.h
#include stdio.h
#include unistd.h
#include stdlib.h
#include string.h
#include sys/ioctl.h#define CLOSE_CMD _IO(0XEF ,1) /*关闭命令*/
#define OPEN_CMD _IO(0XEF,2) /*打开命令*/
#define SETPERIOD_CMD _IO(0XEF,3) /*设置周期*/int main(int argc, char *argv[])
{int fd,ret;char *filename;unsigned char data;/*判断命令行输入参数是否正确*/if(argc ! 2){printf(error usage!\r\n);return -1;}/*用指针指向文件*/filename argv[1];/*打开文件*/fd open(filename , O_RDWR);if(fd 0){printf(file open failed\r\n,filename);return -1;}/*循环读取*/while(1){ret read(fd,data,sizeof(data));if(ret0){}else{if(data)printf( key vaule %d\r\n,data);}}/*关闭文件*/close(fd);return 0;
}