3.关于ZYNQ的linux驱动实验-dht11温度传感器

1.实验要求

1)通过vivado软件配置好接收dht11数据的接收端口

PS通过EMIO接到PL端的外接引脚(这一步想必大家都会,选引脚时记得看接的电压是否为3.3V,否则引脚电压太小,获取的数据有错误)

2)将生成的hdf文件导入到linux下的petalinux工程下

source setting.sh
petalinux-config --get-hw-description ../pwm.sdk/
petalinux-build -c u-boot

需要注意的一点,导入hdf文件后,需要重新编译下u-boot,否则获得的设备数和比特流文件不对。

3)将pl.dtsi,pcw.dtsi,zynq-7000.dtsi和system-top.dts文件全部复制到内核源文件的设备树文件中。

cp pl.dtsi pcw.dtsi zynq-7000 system-top.dts /path/dts/

4)进入system-tops.dts文件中,将设备树文件改成如下所示

/*
 * CAUTION: This file is automatically generated by Xilinx.
 * Version:  
 * Today is: Tue Dec 12 13:54:46 2023
 */
#define GPIO_ACTIVE_HIGH  0
#define GPIO_ACTIVE_LOW   1

/dts-v1/;
#include "zynq-7000.dtsi"
#include "pl.dtsi"
#include "pcw.dtsi"
/ {
	model = "Alientek-ZYNQ Development Board";

	chosen {
		bootargs = "console=ttyPS0,115200 earlyprintk root=/dev/mmcblk0p2 rw rootwait";
		stdout-path = "serial0:115200n8";
	};
	aliases {
		ethernet0 = &gem0;
		serial0 = &uart0;
		spi0 = &qspi;
	};
	memory {
		device_type = "memory";
		reg = <0x0 0x40000000>;
	};
	dht11 {
		compatible = "alientek,dht11";

		dht11-gpio = <&gpio0 54 GPIO_ACTIVE_HIGH>;
	};


};
&gem0 {
		local-mac-address = [00 0a 35 00 1e 53];
};


&qspi {
 		 #address-cells = <1>;
		 #size-cells = <0>;
		 flash0: flash@0 {
			 compatible = "n25q512a","micron,m25p80";			 
			 reg = <0x0>;
		     #address-cells = <1>;
			 #size-cells = <1>;
			 spi-max-frequency = <50000000>;
			 partition@0x00000000 {
					  label = "boot";
					  reg = <0x00000000 0x00500000>;
 			 };
			 partition@0x00500000 {
					  label = "bootenv";
					  reg = <0x00500000 0x00020000>;
			 };
			 partition@0x00520000 {
					  label = "kernel";
					  reg = <0x00520000 0x00a80000>;
			 };
			 partition@0x00fa0000 {
					  label = "spare";
					  reg = <0x00fa0000 0x00000000>;
			};
		};
};

5) 设备树文件改好后编译成system-top.dtb文件,并将其和在petalinux工程中编译获得的比特流文件拷贝到SD中,打开开发板

6)硬件相关的设备配置好后,需要我们写驱动和测试App了

驱动代码

#include <linux/module.h>
#include <linux/of_gpio.h>
#include <linux/cdev.h>
#include <linux/uaccess.h>
#include <linux/platform_device.h>
#include <linux/delay.h>
#define  DHT11_NAME     "dht11io"
#define  DHT11_CNT       1

struct dht11_dev {
    dev_t devid;
    struct cdev cdev;
    struct class *class;
    struct device *device;
    int    dht11_gpio;
};
struct dht11_data {
    unsigned char hmod_data;
    unsigned char lmod_data;
    unsigned char htem_data;
    unsigned char ltem_data;
};
static struct dht11_dev dht11;
static struct dht11_data mtdata;

static void dht11_start(struct dht11_dev *dev){
    gpio_direction_output(dev->dht11_gpio,1);
    mdelay(30);
    gpio_set_value(dev->dht11_gpio,0);
    mdelay(20);
    gpio_set_value(dev->dht11_gpio,1);
    udelay(30);
    gpio_direction_input(dev->dht11_gpio);
    udelay(2);

}

static int dht11_reply(struct dht11_dev *dev){
    unsigned char rey = 0;
    while((gpio_get_value(dev->dht11_gpio) == 1) && rey < 100){
        rey++;
        udelay(1);
    }
    if(rey >= 100){
        return -1;
    }else{
        rey = 0;
    }
    while((gpio_get_value(dev->dht11_gpio) == 0) && rey < 100){
        rey++;
        udelay(1);
    }
    if(rey >= 100){
        return -1;
    }else{
        return 0;
    }
}

static int dht11_read_bit(struct dht11_dev *dev){
    unsigned char rey = 0;
    while((gpio_get_value(dev->dht11_gpio) == 1) && rey < 100){
        rey++;
        udelay(1);
    }
    rey = 0;
    while((gpio_get_value(dev->dht11_gpio) == 0) && rey < 100){
        rey++;
        udelay(1);
    }
    udelay(40);
    if(gpio_get_value(dev->dht11_gpio) == 1){
        return 1;
    }else{
        return 0;
    }
}
static unsigned char dht11_read_byte(struct dht11_dev *dev){
    unsigned char i,dat;
    dat = 0;
    for(i = 0;i < 8;i++){
        dat <<= 1;
        dat |= dht11_read_bit(dev);
    }
    return dat;
}
static int dht11_open(struct inode *inode,struct file *filp){
    filp->private_data = &dht11;
    return 0;
}

static ssize_t dht11_write(struct file *filp,const char __user *buf,size_t cnt,loff_t *offt){
    return 0;
}

static ssize_t dht11_read(struct file *filp,char __user *buf,size_t cnt,loff_t *offt){
    struct dht11_dev *dev = filp->private_data;
    u8 kernel_buf[5];
    int ret,i;
    dht11_start(dev);
    ret = dht11_reply(dev);
    if(ret < 0){
        return ret;
    }
    
    for(i = 0;i < 5;i++){
        kernel_buf[4 - i] = dht11_read_byte(dev);
    }

    if(kernel_buf[4] + kernel_buf[3] + kernel_buf[2] + kernel_buf[1] == kernel_buf[0]){
        mtdata.hmod_data = kernel_buf[4];
        mtdata.lmod_data = kernel_buf[3];
        mtdata.htem_data = kernel_buf[2];
        mtdata.ltem_data = kernel_buf[1];
    }
    pr_info("DHT11: kernel_buf = [%u, %u, %u, %u]\n",
           mtdata.hmod_data,mtdata.lmod_data,mtdata.htem_data,mtdata.ltem_data);
    ret = copy_to_user(buf,&mtdata,sizeof(struct dht11_data));
    if(ret){
        return ret;
    }    
}
static int dht11_release(struct inode *inode,struct file *filp){
    return 0;
}

static struct file_operations dht11_ops = {
    .owner   = THIS_MODULE,
    .open    = dht11_open,
    .write   = dht11_write,
    .read    = dht11_read,
    .release = dht11_release,
};

static int dht11_probe(struct platform_device *pdev){
     int ret;
    //获得gpio编号
    dht11.dht11_gpio = of_get_named_gpio(pdev->dev.of_node,"dht11-gpio",0);
    if(!gpio_is_valid(dht11.dht11_gpio)){
        printk(KERN_ERR"Gipo number id invalid!\r\n");
        return -EINVAL;
    }
    //向系统申请gpio
    ret = gpio_request(dht11.dht11_gpio,"DHT11");
    if(ret){
        printk(KERN_ERR"Gipo request failed!\r\n");
        return -EINVAL;
    }
     //设备号
    ret = alloc_chrdev_region(&dht11.devid,0,DHT11_CNT,DHT11_NAME);
    if(ret)
        goto out1;
    //cdev
    dht11.cdev.owner = THIS_MODULE;
    cdev_init(&dht11.cdev,&dht11_ops);
    ret = cdev_add(&dht11.cdev,dht11.devid,DHT11_CNT);
    if(ret)
        goto out2;
    //创建类
    dht11.class = class_create(THIS_MODULE,DHT11_NAME);
    if(IS_ERR(dht11.class)){
        ret = PTR_ERR(dht11.class);
        goto out3;
    }
    //创建设备
    dht11.device = device_create(dht11.class,&pdev->dev,dht11.devid,NULL,DHT11_NAME);
    if(IS_ERR(dht11.device)){
        ret = PTR_ERR(dht11.device);
        goto out4;
    }
    return 0;
    out4:
        class_destroy(dht11.class);

    out3:
        cdev_del(&dht11.cdev);

    out2:
        unregister_chrdev_region(dht11.devid,DHT11_CNT);
    
    out1:
        gpio_free(dht11.dht11_gpio);

        return ret;
}

static int dht11_remove(struct platform_device *pdev){
    //注销设备
    device_destroy(dht11.class,dht11.devid);

    //注销类
    class_destroy(dht11.class);

    //注销字符设备
    cdev_del(&dht11.cdev);

    //注销设备号
    unregister_chrdev_region(dht11.devid,DHT11_CNT);

    //释放gpio
    gpio_free(dht11.dht11_gpio);
}

//匹配列表
static const struct of_device_id dht11_of_match[] = {
    {.compatible = "alientek,dht11"},
    {/*Sentinel*/}
};


static struct platform_driver dht11_driver = {
    .driver = {
        .name               = "zynq-dht11",
        .of_match_table     = dht11_of_match,
    },
    .probe         = dht11_probe,
    .remove        = dht11_remove,
};

module_platform_driver(dht11_driver);

MODULE_AUTHOR("fusu");
MODULE_DESCRIPTION("DHT11");
MODULE_LICENSE("GPL");

测试App代码

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>

struct dht11_data {
    unsigned char hmod_data;
    unsigned char  lmod_data;
    unsigned char  htem_data;
    unsigned char  ltem_data;
};

int main(int argc,char *argv[])
{
    int fd,ret;
    struct dht11_data mddata;

    if(argc != 2)
    {
        printf("Usage:\n"
                "\t./ledApp /dev/led 1       @close LED\n"
                "\t./ledApp /dev/led 0       @open LED\n");
        return -1;
    }

    fd = open(argv[1],O_RDWR);

    if(fd < 0)
    {
        printf("file %s open failed!\r\n",argv[1]);
        return -1;
    }

    while(1){
        read(fd,&mddata,sizeof(struct dht11_data));
        printf("湿度:%u.%u,温度:%u.%u\n",mddata.hmod_data,mddata.lmod_data,mddata.htem_data,mddata.ltem_data);
        sleep(1);
    }
    close(fd);
    return 0;

}

实验结果

一点小建议:先去dht11的时序图去理解,再结合看这个代码,非常容易上手。

  • 7
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值