Linux驱动---光电开关、火焰传感器、人体红外传感器

一、电路连接

人体红外 – 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");

实验现象:

当触发光电开关的中断时,就会打印提示信息
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值