模块熟悉

第 16 课:温湿度传感器 DHT11

第一个要靠"协议"才肯开口的传感器——一根线,你一句我一句

我是吴老师。从这节课开始,传感器分成两拨了。

前面那几位——光敏、热敏、麦克风——你对付它们的方式都一样:给它电,然后读一个电压。 它不会跟你耍脾气,你什么时候读,它什么时候给。读数是多少,全看当时的物理量。

DHT11 不是这样的。

它是一颗数字传感器,里面自带一个小芯片。它不给你"一个电压",它给你一个已经算好的数——温度多少、湿度多少。但你想拿到这个数,得按它规定的规矩跟它说话

你说错一个字,它就装死,什么也不给你。

这是你第一次遇到"要谈条件"的传感器。 后面还有 OLED(I²C)、舵机(PWM),全都是"有规矩"的。所以这节课的重点不是接线,是理解"规矩"这件事本身

学完这节课你能干的事很实在:知道屋里到底几度、潮不潮。 第 33 课那个"桌面温度计",和第 37 课结课的智能温室,核心都是它。

一、先认识它:丝印是 + OUT

先看实物。你手上这颗模块,多半是个蓝色小板,上面戳着一个带格栅的白色方块——那个方格窗就是它"呼吸"的地方(湿度要从这里进去)。

丝印跟前面所有模块都不一样,认准这三个字:

板上丝印 意思 接到哪
+ 电源正 3.3V
OUT 数据线 一个 GPIO,我们接 GPIO4
电源负(地) GND

这里我要专门停一下。

你前面见过的模块,电源都印 VCC,地都印 GND这块板子上印的是 +

第一次拿到它的人经常在这儿犹豫:"这个 + 是不是 VCC?这个 是不是 GND?"

是的,就是。 + 就是正极, 就是负极。丝印是厂家随便印的,功能是芯片定死的——这句话第 4 课讲过,现在又碰到一次。

顺带说一句:市面上 DHT11 有三针的,也有四针的(多出来的那根是空的)。以你手上板子的丝印为准,别照着别人的图接。接反了不会立刻烧,但读数一定是错的——而且它可能看起来在正常工作,只是数字离谱。

接线:

DHT11 接到
+ 3.3V
GND
OUT GPIO4GPIO3~GPIO7 这一带都是安全脚)

为什么避开 GPIO2GPIO8GPIO9,第 4 课那张引脚表讲过——那三个是 strapping 脚,上电那一刻有特殊任务,接外设容易出怪事。不确定的时候就用 GPIO3~GPIO7

二、它跟前面几个不一样:这次得"按规矩说话"

先讲清楚差别在哪——前面那些是模拟信号,DHT11 是数字信号

光敏是什么样? 你想读就读。analogRead 一执行,它就把当前电压交出来。你俩之间没有"规矩",你说了算。

数字信号是只有高低两档的方波,模拟信号是连续起伏的曲线

DHT11 是什么样? 你直接去读它的引脚,只会读到一个一直在高电平发呆的信号,什么信息都没有。

想拿到数据,得走这么一套流程:

  1. 主控把线拉低一段时间——"喂,我要读数了"
  2. 松手,等它应答
  3. 它开始一位一位地吐:湿度、温度、校验码
  4. 主控把这些位拼成数字

这一套"什么时候拉低、等多久、怎么算 0 怎么算 1",就叫协议

一个很贴切的比方:对讲机。

DHT11 和主控之间只有一根线:主控先发问,DHT11 再回答,同一时刻只能有一方说话,这叫单总线

对讲机是一根线(一个频道),但规矩是"你一句、我一句"

  • 你按住说话,别人只能听
  • 你说完松手,对方才回话
  • 两个人同时按下去,谁都听不清,这一轮就废了

DHT11 跟主控之间就一根线,这根线既要发指令、又要收数据。所以只能轮流用——这就叫单总线(One-Wire)。

"单"是"只有一根"的意思。 好处是省引脚(就占一个 GPIO);代价是主控得等——它说完话,必须老老实实等着对方把数据吐完,中间不能干别的。

注意:这根线是双向的。 主控一会儿是输出(发问),一会儿得变成输入(听答案)。这就是为什么 DHT11 的代码看起来比光敏"复杂"——光敏那根线永远是输入,不用变。

三、为什么代码里必须"等一等"

现在讲你可能已经踩到的那个坑。

DHT11 里的"湿"和"温",不是随时都在那儿的。

它内部有个元件在感受湿度、感受温度,然后转换成一个数字这个转换要花时间——手册上给的采样间隔是至少 1 秒,一般的代码里我们干脆写 2 秒。

所以:你读得太快,它会直接给你一个"这次不算数"。

表现出来就是——温度打印出来是 nan(Not a Number,"不是个数"),或者湿度是 0,或者干脆卡住不动。

第一次碰到的人会这么想:"是不是模块坏了?"换个新的还是这样。"是不是线接错了?"重插三遍还是这样。"是不是代码抄错了?"对着屏幕看半小时。

都不是。你只是催得太紧了。

这就是为什么代码里那个 delay(2000) 不是"随便加的"。

第 6 课讲闪烁的时候我说过:delay 是给"人眼"用的。这里的 delay 不一样——它是给传感器的,是它要求的。 你少喂它这一口时间,它就交白卷。

还有个时机问题:刚上电那一两秒,它自己也还在稳定,这时候读出来的数别当真。等程序转完一两圈再看。

四、±2°C:一颗"够用但不精确"的传感器

厂家给的参数就这两行,记住它:

它测什么 范围 精度
温度 0~50°C ±2°C
湿度 20~90% ±5%

现在把"±2°C"翻译成人话:

它报 26 度,真实温度可能在 24 到 28 之间任何地方它不是"稍微有点误差",它是"差个一两度很正常"。

湿度更松——报 55%,真实可能 50% 也可能 60%。

我为什么要把这件事掰开讲? 因为这是学生最容易在这儿钻牛角尖的地方:

你拿它跟家里的温度计一对,差了 1.5 度。你会以为是自己的代码错了。

不是代码错了。

  • 换算公式是芯片内部算好的,你想错都错不了
  • 真的是读错了,它会给你 nan,不会给你一个"差一点点的数"
  • 差一两度,就是这颗传感器的正常表现

那它有什么用?用处大了。 因为你真正关心的事,根本不需要精确到 0.1 度:

  • 屋里热不热、闷不闷 → 完全够
  • 湿度是不是太高了、衣柜要不要除湿 → 完全够
  • 温室里是不是太干,该浇水了 → 完全够

它是一颗"够用但不精确"的传感器。 这个定位你得从一开始就认清楚,别给自己找不痛快。

想要精确的怎么办? 换 DHT22,或者更贵一点的 SHT30(能到 ±0.3°C)。但那不是这节课的事——你先用手上这颗把"协议"这件事弄懂,比换一颗贵的传感器值多了。

记住这个态度:拿到一个元件,先看它的手册参数,再决定"它能干什么"。不是先指望它什么都能干,然后怪它不行。

五、协议已经被"封装"好了

听到"协议""时序"这几个字,你可能心里一紧:是不是要自己一位一位地拉高拉低?

不用。

第 1 课讲图形化平台的时候我说过一句话:那些脏活,平台替你干了。

两条路线都是这样:图形化路线拖一个"温湿度"积木出来,它直接给你温度和湿度两个数;代码路线用第 2 课装好的库,两行代码读出来。

第 2 课装的那两个库——DHT sensor libraryAdafruit Unified Sensor——就是为今天准备的。当时我说"现在装好,省得上到这一课手忙脚乱",你还记得吧。

代码长这样:

C++
#include "DHT.h"

DHT dht(4, DHT11);            // 数据脚是 GPIO4,型号 DHT11

void setup() {
  Serial.begin(115200);
  dht.begin();
}

void loop() {
  float h = dht.readHumidity();       // 湿度,单位 %
  float t = dht.readTemperature();    // 温度,单位 °C

  Serial.print("温度 ");
  Serial.print(t);
  Serial.print(" °C    湿度 ");
  Serial.print(h);
  Serial.println(" %");

  delay(2000);                        // 别读太快,给它留转换的时间
}

看,跟读光敏的代码一样短。

但我要你记住一件事:"库替你干了"不等于"底下没发生事"。

刚才那个拉低、应答、一位一位吐数据的过程,在你调 readTemperature() 的那一瞬间,全都真实地发生了一遍——只不过它藏在那两行代码底下。

这就是"会用"和"懂"的区别。

只会用的人,读到 nan 的时候只能到处问;懂的人知道是"催太急了"或者"线松了",改一个数、按一下线就好了。

你不用会写那套时序——但你得知道它存在。 这是我在这节课唯一较真的地方。

六、动手:读出来,然后捂住它

第一步:接好线,先只打印。

按上面的表接:+3.3VGNDOUTGPIO4。烧进去,打开串口。

你应该看到两行数字在每两秒刷一次。

第二步:先做第 5 课那个动作——"先测,再猜"。

用万用表量 OUT 脚对 GND 的电压:空闲时大概 3.3V(它在发呆,线被拉着高);数据在传的那一瞬间,电压会来回跳。

万用表反应没那么快,多半只能看到它在 3.3V 附近晃。能看到"晃"就对了——那正是它在说话。想看清楚的,用示波器,那是后话。

第三步:重点来了——用手把它捂起来。 用你的手掌整个包住那个白色格栅,别漏风,等十几秒。

盯着串口看。温度会一点点往上爬——从 26 爬到 28、29、30,慢慢停住。 湿度也会变——而且往往比温度涨得更明显,因为它对"手心里的汗气"特别敏感。

拿开手,它会慢慢退回去。 这个"慢慢"跟第 12 课热敏的"慢慢"是同一回事——热量和水汽传进去需要时间,不是模块反应慢。

这一步有个隐藏价值: 你第一次能同时看到两个物理量在同一个传感器上变化,而且它们的变化节奏不一样。温度涨得慢、湿度的反应更快——这说明它们在测两件不同的事,不是同一个数换了个名字。

第四步:让它"看见"你的手就反应。

加一个判断,把它跟前面的课串起来:

C++
void loop() {
  float t = dht.readTemperature();       // 读温度

  if (t > 29) {                          // 比你自己定的线大吗
    Serial.println("有点热了");           // 这里换成点灯、响蜂鸣器都行
  }

  delay(2000);
}

看,还是那个闭环:传感器(读温度)→ 判断(比 29 大吗)→ 执行器(打印 / 亮灯)。

这个阈值 29 别抄我的——按第 11 课标定那套:先测你自己的室温,再定一条线。 手捂着能不能过这条线,才是这个实验成不成立的关键。

顺便说个实际问题:DHT11 捂在手心里,湿度经常一下就冲到 90% 以上。那多半是到量程上限了(它只保证 20~90%)。看到数字顶住了,别以为坏了——换个地方,比如放在湿毛巾旁边,再看看。

自测

单选题DHT11 跟光敏、热敏比,最本质的区别是什么?
单选题代码里去掉 delay(2000),让它一秒读几十次,会发生什么?
单选题你用它测出室温 27.5°C,家里的温度计显示 26°C,怎么办?
问答题为什么 DHT11 的 OUT 那根线,主控有时候要当输出、有时候要当输入?这跟"单总线"有什么关系?
拓展一根线,怎么区分"这一位是 0"和"这一位是 1"?它又没有第二根线可以对照。

这个问题课上不讲,留给你自己找答案——**问 AI 是最好的办法**。

提示:搜"DHT11 时序 高电平持续时间 26us 70us"。想一想:如果约定"高电平长一点算 1、短一点算 0",那主控要量的是什么?这跟第 15 课超声波量"高电平持续了多久"是不是有点像?

拓展为什么 DHT11 便宜,DHT22、SHT30 贵好几倍?贵在哪儿了?

这个问题课上不讲,留给你自己找答案——**问 AI 是最好的办法**。

提示:搜"DHT11 DHT22 SHT30 对比 精度 接口"。想一想:有的传感器用单总线,有的用 I²C(第 19 课会讲),接口方式会不会也影响价格和用法?

本节你要动手做的事

  • [ ] 接好三根线+3.3VGNDOUTGPIO4接之前先断电认丝印不是 VCC/GND
  • [ ] 跑通打印:串口里能看到温度和湿度两个数,每两秒刷一次
  • [ ] 用万用表量一次 OUT:空闲时是不是 3.3V 左右?确认它跟光敏那根 AO 的表现不一样
  • [ ] 用手捂住格栅,看着温度和湿度慢慢变化——记下你开始和结束的两个数
  • [ ] 故意把 delay(2000) 改成 delay(50),看会发生什么,记住 nan 长什么样
  • [ ] 定一条自己的温度阈值(用你测出来的室温,别抄我的 29),让它"热了就打印一句话"

这节课你做成的是一件挺不容易的事:你让一个传感器按规矩跟你说话了。

前面那几位传感器,你是偷看它们——读一下电压就走。DHT11 不一样,它是你把问题递过去,它把整理好的答案交回来。这个"问—答"的关系,是你第一次建立起来的。

我知道看到 nan 的时候你会烦。但那个 nan 是有信息量的——它在说"你催得太急了"。能听懂器件在抱怨什么,就是这门课最想教给你的本事。

下一节我们换个方向,让板子自己发出声音。那是个特别轻松愉快的小模块——而且它的用法跟 LED 一模一样。第 6 课我说过"学会点灯就学会一半的输出设备",下一节就是兑现的时候。