前言:

近期在做个小项目是在dragonboard410c的平台上,其中需要使用到DHT11温湿度传感器模块来实时显示当前环境的温湿度,由此需要编写相应的设备驱动来给上层提供接口。

一、DHT11模块介绍

1.产品概述:

DHT11 数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。它应用专用的数字模块采集技术和温湿度传感技术,确保产品具有枀高的可靠性与卓越的长期稳定性。传感器包括一个电阻式感湿元件和一个 NTC 测温元件,并与一个高性能 8 位单片机相连接。

2.应用范围:

暖通空调、除湿器、测试及检测设备、消费品、汽车、自动控制、数据记录器、气象站、家电、湿度调节器、医疗、其他相关湿度检测控制。

3.产品参数:

◎相对湿度
  分 辨 率: 16Bit
  重 复 性: ±1%RH
  精 度: 25℃ ±5%RH
  互 换 性:可完全互换
  响应时间: 1/e(63%)25℃ 6s
  1m/s 空气 6s
  迟 滞: <±0.3%RH
  长期稳定性: <±0.5%RH/yr

◎温度
分 辨 率: 16Bit
重 复 性:±1℃
精 度: 25℃ ±2℃
响应时间: 1/e(63%) 10S

◎电气特性
供 电: DC 3.3~5.5V
供电电流:测量 0.3mA 待机 60μA
采样周期:次 大于 2 秒

◎引脚说明
1、 VDD 供电 3.3~5.5V DC
2、 DATA 串行数据,单总线
3、 NC 空脚
4、 GND 接地,电源负枀

4.串行通信说明

◎单总线说明
DHT11 器件采用简化的单总线通信。单总线即只有一根数据线,系统中的数据交换、控制均由单总线完成。设备(主机或从机)通过一个漏枀开路或三态端口连至该数据线,以允许设备在不发送数据时能够释放总线,而让其它设备使用总线;单总线通常要求外接一个约 5.1kΩ 的上拉电阻,这样,当总线闲置时,其状态为高电平。由于它们是主从结极,只有主机呼叫从机时,从机才能应答,因此主机访问器件都必须严格遵循单总线序列,如果出现序列混乱,器件将不响应主机。

◎单总线传送数据位定义
DATA 用于微处理器与 DHT11 之间的通讯和同步,采用单总线数据格式,一次传送 40 位数据,高位先出。
数据格式:8bit 湿度整数数据 + 8bit 湿度小数数据+8bit 温度整数数据 + 8bit 温度小数数据+8bit 校验位。
注:其中温湿度小数部分为 0。

◎校验位数据定义
“ 8bit 湿度整数数据 + 8bit 湿度小数数据+8bit 温度整数数据 + 8bit 温度小数数据” 8bit 校验位等于所得结果的末 8 位。

示例一:接收到的 40 位数据为:0011 0101 0000 0000 0001 1000 0000 0000 0100 1101
湿度高 8 位 湿度低 8 位 温度高 8 位 温度低 8 位 校验位
计算:0011 0101+0000 0000+0001 1000+0000 0000= 0100 1101
接收数据正确:
湿度: 0011 0101=35H=53%RH 温度: 0001 1000=18H=24℃

示例二:接收到的 40 位数据为:0011 0101 0000 0000 0001 1000 0000 0000 0100 1001
湿度高 8 位 湿度低 8 位 温度高 8 位 温度低 8 位 校验位
计算:0011 0101+0000 0000+0001 1000+0000 0000= 0100 1101
01001101 不等于 0100 1001
本次接收的数据不正确,放弃,重新接收数据。

◎数据时序图
用户主机(MCU)发送一次开始信号后,DHT11从低功耗模式转换到高速模式,待主机开始信号结束后, DHT11 发送响应信号,送出 40bit 的数据,并触发一次信采集。信号发送如图所示。

注:主机从 DHT11 读取的温湿度数据总是前一次的测量值,如两次测间隔时间很长,请连续读两次以第二次获得的值为实时温湿度值。

◎外设读取步骤
主机和从机之间的通信可通过如下几个步骤完成(外设(如微处理器)读取 DHT11 的数据的步骤)。
步骤一:
DHT11 上电后(DHT11 上电后要等待 1S 以越过不稳定状态在此期间不能发送任何指令),测试环境温湿度数据,并记录数据,同时 DHT11 的 DATA 数据线由上拉电阻拉高一直保持高电平;此时 DHT11 的DATA 引脚处于输入状态,时刻检测外部信号。

步骤二:
微处理器的 I/O 设置为输出同时输出低电平,且低电平保持时间不能小于 18ms,然后微处理器的 I/O设置为输入状态,由于上拉电阻,微处理器的 I/O 即 DHT11 的 DATA 数据线也随之变高,等待 DHT11 作出回答信号,发送信号如图所示:

步骤三:
DHT11 的 DATA 引脚检测到外部信号有低电平时,等待外部信号低电平结束,延迟后 DHT11 的 DATA引脚处于输出状态,输出 80 微秒的低电平作为应答信号,紧接着输出 80 微秒的高电平通知外设准备接收数据,微处理器的 I/O 此时处于输入状态,检测到 I/O 有低电平(DHT11 回应信号)后,等待 80 微秒的高电平后的数据接收,发送信号如图所示:

步骤四:
由 DHT11 的 DATA 引脚输出 40 位数据,微处理器根据 I/O 电平的变化接收 40 位数据,位数据“ 0”的格式为: 50 微秒的低电平和 26-28 微秒的高电平,位数据“ 1”的格式为: 50 微秒的低电平加 70微秒的高电平。位数据“ 0”、“ 1”格式信号如图所示:

结束信号:
DHT11 的 DATA 引脚输出 40 位数据后,继续输出低电平 50 微秒后转为输入状态,由于上拉电阻随之变为高电平。但 DHT11 内部重测环境温湿度数据,并记录数据,等待外部信号的到来。

5.模块接线说明

VCC 外接3.3V-5V
  GND 外接GND
  DATA 小板开关数字量输出接口接Dragonboard410c PIN27

二、DHT11驱动代码分析

1.kernel-debian-qcom-dragonboard410c-16.04/source_code/kernel-debian-qcom-dragonboard410c-16.04/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi

2.kernel-debian-qcom-dragonboard410c-16.04/source_code/kernel-debian-qcom-dragonboard410c-16.04/drivers/iio/humidity/dht11.c

/** DHT11/DHT22 bit banging GPIO driver** Copyright (c) Harald Geyer <harald@ccbib.org>** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.*/#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/device.h>
#include <linux/kernel.h>
#include <linux/printk.h>
#include <linux/slab.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/sysfs.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/wait.h>
#include <linux/bitops.h>
#include <linux/completion.h>
#include <linux/mutex.h>
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/of_gpio.h>
#include <linux/timekeeping.h>#include <linux/iio/iio.h>#define DRIVER_NAME "dht11"#define DHT11_DATA_VALID_TIME  2000000000  /* 2s in ns */#define DHT11_EDGES_PREAMBLE 2
#define DHT11_BITS_PER_READ 40
/** Note that when reading the sensor actually 84 edges are detected, but* since the last edge is not significant, we only store 83:*/
#define DHT11_EDGES_PER_READ (2 * DHT11_BITS_PER_READ + \DHT11_EDGES_PREAMBLE + 1)/* Data transmission timing (nano seconds) */
#define DHT11_START_TRANSMISSION    18  /* ms */
#define DHT11_SENSOR_RESPONSE   80000
#define DHT11_START_BIT     50000
#define DHT11_DATA_BIT_LOW  27000
#define DHT11_DATA_BIT_HIGH 70000struct dht11 {struct device            *dev;int                gpio;int                irq;struct completion       completion;/* The iio sysfs interface doesn't prevent concurrent reads: */struct mutex         lock;s64                timestamp;int               temperature;int             humidity;/* num_edges: -1 means "no transmission in progress" */int               num_edges;struct {s64 ts; int value; }  edges[DHT11_EDGES_PER_READ];
};static unsigned char dht11_decode_byte(int *timing, int threshold)
{unsigned char ret = 0;int i;for (i = 0; i < 8; ++i) {ret <<= 1;if (timing[i] >= threshold)++ret;}return ret;
}static int dht11_decode(struct dht11 *dht11, int offset, int timeres)
{int i, t, timing[DHT11_BITS_PER_READ], threshold;unsigned char temp_int, temp_dec, hum_int, hum_dec, checksum;threshold = DHT11_DATA_BIT_HIGH / timeres;if (DHT11_DATA_BIT_LOW / timeres + 1 >= threshold)pr_err("dht11: WARNING: decoding ambiguous\n");/* scale down with timeres and check validity */for (i = 0; i < DHT11_BITS_PER_READ; ++i) {t = dht11->edges[offset + 2 * i + 2].ts -dht11->edges[offset + 2 * i + 1].ts;if (!dht11->edges[offset + 2 * i + 1].value)return -EIO;  /* lost synchronisation */timing[i] = t / timeres;}hum_int = dht11_decode_byte(timing, threshold);hum_dec = dht11_decode_byte(&timing[8], threshold);temp_int = dht11_decode_byte(&timing[16], threshold);temp_dec = dht11_decode_byte(&timing[24], threshold);checksum = dht11_decode_byte(&timing[32], threshold);if (((hum_int + hum_dec + temp_int + temp_dec) & 0xff) != checksum)return -EIO;dht11->timestamp = ktime_get_real_ns();if (hum_int < 20) {  /* DHT22 */dht11->temperature = (((temp_int & 0x7f) << 8) + temp_dec) *((temp_int & 0x80) ? -100 : 100);dht11->humidity = ((hum_int << 8) + hum_dec) * 100;} else if (temp_dec == 0 && hum_dec == 0) {  /* DHT11 */dht11->temperature = temp_int * 1000;dht11->humidity = hum_int * 1000;} else {dev_err(dht11->dev,"Don't know how to decode data: %d %d %d %d\n",hum_int, hum_dec, temp_int, temp_dec);return -EIO;}return 0;
}/** IRQ handler called on GPIO edges*/
static irqreturn_t dht11_handle_irq(int irq, void *data)
{struct iio_dev *iio = data;struct dht11 *dht11 = iio_priv(iio);/* TODO: Consider making the handler safe for IRQ sharing */if (dht11->num_edges < DHT11_EDGES_PER_READ && dht11->num_edges >= 0) {dht11->edges[dht11->num_edges].ts = ktime_get_real_ns();dht11->edges[dht11->num_edges++].value =gpio_get_value(dht11->gpio);if (dht11->num_edges >= DHT11_EDGES_PER_READ)complete(&dht11->completion);}return IRQ_HANDLED;
}static int dht11_read_raw(struct iio_dev *iio_dev,const struct iio_chan_spec *chan,int *val, int *val2, long m)
{struct dht11 *dht11 = iio_priv(iio_dev);int ret, timeres;mutex_lock(&dht11->lock);if (dht11->timestamp + DHT11_DATA_VALID_TIME < ktime_get_real_ns()) {timeres = ktime_get_resolution_ns();if (DHT11_DATA_BIT_HIGH < 2 * timeres) {dev_err(dht11->dev, "timeresolution %dns too low\n",timeres);/* In theory a better clock could become available* at some point ... and there is no error code* that really fits better.*/ret = -EAGAIN;goto err;}reinit_completion(&dht11->completion);dht11->num_edges = 0;ret = gpio_direction_output(dht11->gpio, 0);if (ret)goto err;msleep(DHT11_START_TRANSMISSION);ret = gpio_direction_input(dht11->gpio);if (ret)goto err;ret = request_irq(dht11->irq, dht11_handle_irq,IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,iio_dev->name, iio_dev);if (ret)goto err;ret = wait_for_completion_killable_timeout(&dht11->completion,HZ);free_irq(dht11->irq, iio_dev);if (ret == 0 && dht11->num_edges < DHT11_EDGES_PER_READ - 1) {dev_err(&iio_dev->dev,"Only %d signal edges detected\n",dht11->num_edges);ret = -ETIMEDOUT;}if (ret < 0)goto err;ret = dht11_decode(dht11,dht11->num_edges == DHT11_EDGES_PER_READ ?DHT11_EDGES_PREAMBLE :DHT11_EDGES_PREAMBLE - 2,timeres);if (ret)goto err;}ret = IIO_VAL_INT;if (chan->type == IIO_TEMP)*val = dht11->temperature;else if (chan->type == IIO_HUMIDITYRELATIVE)*val = dht11->humidity;elseret = -EINVAL;
err:dht11->num_edges = -1;mutex_unlock(&dht11->lock);return ret;
}static const struct iio_info dht11_iio_info = {.driver_module     = THIS_MODULE,.read_raw        = dht11_read_raw,
};static const struct iio_chan_spec dht11_chan_spec[] = {{ .type = IIO_TEMP,.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), },{ .type = IIO_HUMIDITYRELATIVE,.info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED), }
};static const struct of_device_id dht11_dt_ids[] = {{ .compatible = "thundersoft,dht11", }, { }
};
MODULE_DEVICE_TABLE(of, dht11_dt_ids);static int dht11_probe(struct platform_device *pdev)
{struct device *dev = &pdev->dev;struct device_node *node = dev->of_node;struct dht11 *dht11;struct iio_dev *iio;int ret;iio = devm_iio_device_alloc(dev, sizeof(*dht11));if (!iio) {dev_err(dev, "Failed to allocate IIO device\n");return -ENOMEM;}dht11 = iio_priv(iio);dht11->dev = dev;ret = of_get_gpio(node, 0);if (ret < 0)return ret;dht11->gpio = ret;ret = devm_gpio_request_one(dev, dht11->gpio, GPIOF_IN, pdev->name);if (ret)return ret;dht11->irq = gpio_to_irq(dht11->gpio);if (dht11->irq < 0) {dev_err(dev, "GPIO %d has no interrupt\n", dht11->gpio);return -EINVAL;}dht11->timestamp = ktime_get_real_ns() - DHT11_DATA_VALID_TIME - 1;dht11->num_edges = -1;platform_set_drvdata(pdev, iio);init_completion(&dht11->completion);mutex_init(&dht11->lock);iio->name = pdev->name;iio->dev.parent = &pdev->dev;iio->info = &dht11_iio_info;iio->modes = INDIO_DIRECT_MODE;iio->channels = dht11_chan_spec;iio->num_channels = ARRAY_SIZE(dht11_chan_spec);return devm_iio_device_register(dev, iio);
}static struct platform_driver dht11_driver = {.driver = {.name   = DRIVER_NAME,.of_match_table = dht11_dt_ids,},.probe  = dht11_probe,
};module_platform_driver(dht11_driver);MODULE_AUTHOR("Harald Geyer <harald@ccbib.org>");
MODULE_DESCRIPTION("DHT11 humidity/temperature sensor driver");
MODULE_LICENSE("GPL v2");

基于dragonboard410c DHT11模块的驱动移植相关推荐

  1. 基于I.MX6UL平台的WIFI模块AP6214A 驱动移植

    基于I.MX6UL平台的WIFI模块AP6214A 驱动移植 IoT-6ULX简要介绍 IoT-6ULX,主要面向Internet Of Things应用,该产品集成了 ARM Cortex-A7 9 ...

  2. 基于MSM平台的振动器驱动移植

    前言: 振动器是Android智能手机操作系统中比较常见的功能之一,在实际应用中可以将来电显示设置为振动模式作为提醒.在Android系统中,通过振动系统米快可以实现俩点铃声和来电的振动功能..本篇b ...

  3. 嵌入式linux驱动开发之移远4G模块EC800驱动移植指南

    回顾下移远4G模块移植过程, 还是蛮简单的.一通百通,无论是其他4G模块都是一样的.这里记录下过程,分享给有需要的人.环境使用正点原子的imax6ul开发板,板子默认支持中兴和移远EC20的驱动,这里 ...

  4. WIFI模块RTL8723BU驱动移植

    这里写目录标题 1.硬件平台 2.移植步骤 1.硬件平台 正点原子imx6ull开发板,RTL8723BU模块,很多板载的就是这种,这个模块还有蓝牙功能.一般有USB接口的,sdio接口的,串口wif ...

  5. QCA7000/QCA7005基于全志V3S Linux系统驱动移植

    使用硬件: 荔枝派V3S Lichee Pi Zero with Dock QCA7000HomePlugGreen PHY模块 开发环境: Ubuntu18.04.6 LTS buildroot:2 ...

  6. Zynq-Linux移植学习笔记之46-光模块I2C驱动移植

    1.背景介绍 近期板卡上开始使用中航光电的光模块,查阅资料发现这些光模块都可以通过I2C来获取状态信息并进行开关控制,描述如下,其中需要特别注意的是所有光模块的读写I2C地址都是一样的,不可以挂在一根 ...

  7. 基于imx6的gt911触摸屏驱动移植

    参考:https://blog.csdn.net/zhuyuming/article/details/52652525?locationNum=3 实验平台:TQ_iMX6Q 其实在Linux内核官网 ...

  8. rtl8188eu无线网卡驱动移植

    基于3.14内核rtl8188eu驱动移植 时间:2016-01-08作者:华清远见 最近的项目上要用到3.14的内核,我们需要一个可以使用wifi连接外网的文件系统,我们的wifi模块使用的是rtl ...

  9. 基于MT6752/32平台 Android L版本驱动移植步骤

    基于MT6752/32平台 Android L版本驱动移植步骤 根据MK官网所述,在Android L 版本上Turnkey ABS 架构将会phase out,而Mediatek Turnkey架构 ...

最新文章

  1. Ubuntu 14.04下java开发环境的搭建--2--Eclipse的安装
  2. 地理投影展开(近似多边形体)
  3. python统计分析--3.线性回归四种算法
  4. HDU 1244 DP
  5. oracle中的存储过程教程,oracle 存储过程
  6. 伦敦帝国学院提出局部特征提取新模式D2D:先描述后检测
  7. 轻量级的Canvas类库zrender使用笔记 :简单自定义图件开发
  8. Oracle 20c 新特性:自动的区域图 - Automatic Zone Maps
  9. linux服务器管理公司用户,Linux服务器用户账号如何管理
  10. matlab | 与 || 的区别
  11. datagridview 纵向 横向 合并单元格_Excel横向(行)筛选技巧分享,别人3分钟,你只要10秒...
  12. 服务器不知道循环生成文件,Windows服务器下PowerShell命令往服务器共享文件夹进行文件拷贝、循环文件重命名...
  13. Swarm基于多主机容器网络-overlay networks 梳理
  14. (附源码)springboot自律健身房会员管理系统 毕业设计456466
  15. 批处理清空文件夹内所有txt文件的内容
  16. [JZOJ5424]【NOIP2017提高A组集训10.25】凤凰院凶真
  17. 舱机器人尾巴毛茸茸_『新奇玩意』毛茸茸的机器人不仅可撸,还会摇尾巴
  18. 【软件分析/静态程序分析学习笔记】3.数据流分析(Data Flow Analysis) (上):可达性分析(Reaching Definitions)
  19. 吵翻了!导师确认录取后却被学生放了鸽子,生气之余导师建了个“失信名单”挂到网上
  20. 【最近抖音上元宇宙虚拟项目七国争霸,直播互动游戏源码解析】

热门文章

  1. mysql 字段名和保留字冲突_关于mysql字段名和保留字冲突的问题
  2. python为啥叫蛇_python为什么被称为蟒蛇?
  3. Win7上装双系统,完美体验Win8
  4. 键盘按下去弹起来很慢_键盘反应速度慢怎么办 键盘反应速度慢解决方法
  5. Django(二)精美博客搭建(13)实现留言页面及留言功能
  6. aspx文件怎么用服务器打开,aspx文件怎么打开?
  7. 使用JavaScript写的操作系统和输入法程序,太强了!
  8. idea 不自动提示代码 @Autowired等不高亮显示
  9. ajax 导致 css 延迟_腾讯START云游戏《英雄联盟》的Mac 轻体验:延迟较高时会卡顿 - 游戏 - IT商业网...
  10. Huawei News 华为与TPCAST​​和Mediapro签署合作协议,共同开展5G AR / VR协作