文章目录
- 一、电路连接
- 二、设备树
- 三、驱动代码
一、电路连接
人体红外 – PF12
检测到人体时会产生一个上升沿
光电开关 – PE15
有遮挡物时会产生一个上升沿
火焰传感器 – PF5
有火焰时会产生一个上升沿
二、设备树
/{ //人体红外PF12human{ compatible = "zyx,human";interrupt-parent = <&gpiof>; //中断父节点是gpiofinterrupts = <12 0>; //第一个参数是中断控制器下标};//光电开关PE15light{compatible = "zyx,light";interrupt-parent = <&gpioe>;interrupts = <15 0>;};//火焰传感器PF5fire{compatible = "zyx,fire";interrupt-parent = <&gpiof>;interrupts = <5 0>;};
};
三、驱动代码
以光电开关为例
使用了platform总线驱动
/***人体红外PF12* ***/
#include <linux/module.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/mod_devicetable.h>
#include <linux/of.h> //设备树文件相关头文件
#include <linux/of_gpio.h>
#include <linux/cdev.h>
#include <linux/interrupt.h>#define CNAME "light"
struct cdev *cdev_light;
struct class *class_light;
struct device *device_light;
int major = 0; //主设备号
int minor = 0;
dev_t devno_light;int irqno_light; //中断号/***中断处理函数***/
irqreturn_t light_irq_handler(int irqno, void *dev){printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return IRQ_HANDLED;
}/***字符设备***/
int light_open(struct inode *inode, struct file *file){printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;
}
int light_close (struct inode *inode, struct file *file){printk("%s:%s:%d\n",__FILE__,__func__,__LINE__);return 0;
}const struct file_operations lightfops = {.open = light_open,.release = light_close,
};int light_probe(struct platform_device *dev){int ret=0;/***注册字符设备驱动***///1. 分配对象cdev_light = cdev_alloc();if(NULL == cdev_light){ //成功返回结构体指针,失败返回NULLpr_err("cdev_alloc error");ret = -ENOMEM;goto err1;}//初始化对象:部分成员初始化cdev_init(cdev_light,&lightfops);//申请设备号:如果major为0,则动态申请,否则就静态指定if(major > 0){ //静态申请ret = register_chrdev_region(MKDEV(major,minor),1,CNAME);if (ret) {pr_err("register_chrdev_region error\n");goto err2;}}else if(major == 0){ //动态申请ret = alloc_chrdev_region(&devno_light,0,1,CNAME); if (ret) {pr_err("alloc_chrdev_region error\n");goto err2;}major=MAJOR(devno_light);minor=MINOR(devno_light);}//注册ret = cdev_add(cdev_light,MKDEV(major,minor),1); if (ret) {pr_err("cdev_add error\n");goto err3;}/***自动创建设备节点***/class_light=class_create(THIS_MODULE,CNAME);if(IS_ERR(class_light)){pr_err("class_create error");ret = PTR_ERR(class_light);goto err4;}device_light = device_create(class_light,NULL,MKDEV(major,minor),NULL,CNAME);if(IS_ERR(device_light)){pr_err("device_create error");ret = PTR_ERR(device_light);goto err5;}/***初始化中断***///获取软中断号irqno_light=platform_get_irq(dev,0);if(irqno_light < 0){pr_err("platform_get_irq error");ret = irqno_light;goto err6;}//3.注册中断号ret = request_irq(irqno_light,light_irq_handler,IRQF_TRIGGER_FALLING,"light_IRQ",NULL);if(ret){pr_err("request_irq error");goto err6;}return 0;
err6:device_destroy(class_light, MKDEV(major,minor));
err5:class_destroy(class_light);
err4:cdev_del(cdev_light);
err3:unregister_chrdev_region(MKDEV(major,minor),1);
err2:kfree(cdev_light);
err1:return ret;
}int light_remove(struct platform_device *dev){free_irq(irqno_light,NULL);device_destroy(class_light, MKDEV(major, minor));class_destroy(class_light);cdev_del(cdev_light);unregister_chrdev_region(MKDEV(major,minor),1);kfree(cdev_light);return 0;
}//设备树匹配
struct of_device_id light_of_match[]={{.compatible="zyx,light"},{},
};
struct platform_driver light_driver={.probe=light_probe,.remove=light_remove,.driver={.name="light_driver",.of_match_table=light_of_match,},
};module_platform_driver(light_driver);
MODULE_LICENSE("GPL");
实验现象:
当触发光电开关的中断时,就会打印提示信息