文章目录
- 一、电路连接
- 二、设备树
- 三、驱动代码
一、电路连接
人体红外 – PF12
检测到人体时会产生一个上升沿
光电开关 – PE15
有遮挡物时会产生一个上升沿
火焰传感器 – PF5
有火焰时会产生一个上升沿
二、设备树
/{
//人体红外PF12
human{
compatible = "zyx,human";
interrupt-parent = <&gpiof>; //中断父节点是gpiof
interrupts = <12 0>; //第一个参数是中断控制器下标
};
//光电开关PE15
light{
compatible = "zyx,light";
interrupt-parent = <&gpioe>;
interrupts = <15 0>;
};
//火焰传感器PF5
fire{
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){ //成功返回结构体指针,失败返回NULL
pr_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");
实验现象:
当触发光电开关的中断时,就会打印提示信息