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的时序图去理解,再结合看这个代码,非常容易上手。