1. 项目缘起为什么用micro:bit做温湿度计最近在整理工作室的电子元件翻出来几块闲置的micro:bit开发板和几个DHT11温湿度传感器。看着它们我就在想能不能用最简单、最直观的方式把它们组合成一个能实时显示环境数据的“桌面小仪表”这个想法其实挺实用的比如放在书桌上监控一下工作环境的舒适度或者放在花盆旁边看看植物是否需要浇水。micro:bit本身自带LED点阵屏虽然分辨率不高但显示几个数字和简单图标绰绰有余正好省去了外接复杂显示屏的麻烦。而DHT11作为一款经典的数字温湿度复合传感器价格低廉、接口简单和micro:bit简直是绝配。市面上很多教程要么过于简单只讲接线和显示数字要么一下子跳到物联网上传数据对中间的核心原理和可能遇到的坑一笔带过。这次我想从一个有实际项目经验的开发者角度从头到尾、掰开揉碎地讲清楚如何用micro:bit和DHT11搭建一个稳定可靠的温湿度计。我们不仅要让它“跑起来”更要理解它“为什么能跑”以及当它“跑不动”的时候该怎么排查。你会发现即使是这样一个小项目也蕴含着数字传感器通信、电源管理、代码健壮性设计等多个嵌入式开发的核心知识点。2. 核心器件选型与工作原理深潜在动手之前我们必须先吃透手头的两个“主角”micro:bit主控板和DHT11传感器。理解它们的能力边界和工作原理是后续一切顺利的基础。2.1 BBC micro:bit不只是个玩具开发板很多人对micro:bit的第一印象是面向教育的图形化编程工具但实际上它的硬件配置对于此类传感器应用是绰绰有余的。其核心是一颗Nordic nRF51822芯片这是一款ARM Cortex-M0内核的蓝牙低功耗SoC。对我们这个项目而言需要关注以下几个关键特性GPIO通用输入输出引脚micro:bit边缘的金手指连接器提供了多个GPIO其中一些支持模拟输入、PWM输出等特殊功能。DHT11使用的是单总线数字协议我们只需要任意一个普通的数字IO口即可。但这里有一个细节micro:bit的IO口逻辑电平是3.3V而DHT11的工作电压范围是3.3V-5.5V。这意味着在供电上我们可以直接用micro:bit的3.3V输出给DHT11供电两者电平匹配无需电平转换电路。电源管理micro:bit可以通过USB供电也可以用外部电池盒供电。当使用电池供电时整机的功耗变得非常重要。nRF51822本身功耗极低而DHT11在测量间隙处于休眠模式功耗也很小。因此这个温湿度计完全可以做成一个便携的、电池续航时间很长的设备。板载资源5x5的LED点阵是我们天然的显示器。虽然小但通过滚动显示或分屏显示例如上半部分显示温度下半部分显示湿度完全可以清晰呈现数据。板载的A/B按钮可以作为功能切换键比如切换显示单位摄氏/华氏、查看历史最大值/最小值等。2.2 DHT11温湿度传感器单总线协议详解DHT11是一款含有已校准数字信号输出的温湿度复合传感器。它采用单总线数据格式进行通信这意味着只需要一根数据线加上电源和地线就能完成双向通信。这是它简单易用的原因也是初学者最容易出错的地方。电气连接DHT11有四个引脚从正面看网格面朝自己从左到右VCC电源正极3.3V-5.5V。我们接micro:bit的3.3V引脚。DATA单总线数据引脚。需要接一个上拉电阻通常4.7KΩ-10KΩ到VCC。这是关键很多模块已经内置了这个上拉电阻如果是单独的传感器元件你必须自己外接。NC空脚不连接。GND电源地。接micro:bit的GND。通信协议时序重点与难点 DHT11的通信过程由微处理器micro:bit发起传感器响应。一次完整的数据传输为40bit5字节格式为8bit湿度整数 8bit湿度小数 8bit温度整数 8bit温度小数 8bit校验和。通信步骤分解主机发送开始信号micro:bit将数据线引脚拉低至少18毫秒ms然后拉高20-40微秒µs随后释放总线设置为输入模式由上拉电阻拉高。这个“先拉低再拉高”的组合拳是告诉DHT11“我要读数据了你准备好。”从机响应信号DHT11检测到开始信号后会先将总线拉低80µs作为应答再拉高80µs表示它准备好了要发送数据。数据传输随后DHT11开始发送40bit数据。每一位数据都以一个50µs的低电平起始位开始随后的高电平持续时间决定了数据是0还是1‘0’ bit高电平持续约26-28µs。‘1’ bit高电平持续约70µs。 因此核心在于精确测量这个高电平的持续时间。在micro:bit这种级别的MCU上我们需要用微秒级的延时函数和引脚状态读取来实现。校验和校验和是前四个字节湿度整数、湿度小数、温度整数、温度小数相加后的低8位。接收完数据后必须计算校验和并与接收到的第五个字节比较如果不匹配说明本次通信数据有误应该丢弃。为什么读取数据常为0这是网络热词中“stm32f103c8t6读取dht11数据为0”问题的核心。通常有以下几个原因时序不满足开始信号或读取位数据的延时时间不精确特别是从机响应后的等待时间或位数据高电平的判断阈值设置不当。上拉电阻缺失总线处于浮空状态电平不稳定。电源问题传感器供电不足或电压不稳。确保VCC电压在范围内且电流足够DHT11工作电流约2.5mA。接线错误或接触不良这是最容易被忽略的硬件问题。代码逻辑错误例如没有正确释放总线、没有将引脚模式在输出和输入之间正确切换。3. 硬件连接与电路搭建实操理解了原理动手连接就很简单了。这里我提供两种连接方案一种使用带内置上拉电阻的DHT11模块最推荐另一种使用裸传感器。3.1 方案一使用集成模块推荐给初学者这是最省事、成功率最高的方法。市面上常见的蓝色DHT11模块通常已经集成了上拉电阻和电源滤波电容。所需材料BBC micro:bit 一块DHT11温湿度传感器模块蓝色板 一个公对母杜邦线 3根连接步骤将micro:bit的3.3V引脚用杜邦线连接到DHT11模块的VCC引脚。将micro:bit的GND引脚用杜邦线连接到DHT11模块的GND引脚。将micro:bit的任意一个数字IO口例如我选择P0用杜邦线连接到DHT11模块的DATA引脚。 这就完成了模块上的“板载上拉电阻”已经帮我们处理了最易错的一环。3.2 方案二使用裸传感器深入理解如果你想更底层地理解电路或者手头只有裸传感器可以按此方案操作。所需材料BBC micro:bit 一块DHT11传感器裸体 一个公对母杜邦线 4根4.7KΩ 或 10KΩ 电阻 一个用作上拉电阻面包板 一块方便连接连接步骤在面包板上将micro:bit的3.3V连接到电源正极轨GND连接到电源负极轨。将DHT11的VCC引脚连接到正极轨GND引脚连接到负极轨。将DHT11的DATA引脚连接到micro:bit的P0引脚。关键一步将一个4.7KΩ电阻的一端连接到正极轨3.3V另一端连接到DATA引脚所在的线上。这个电阻就是上拉电阻确保总线在空闲时保持高电平。 这种连接方式让你对整个单总线电路的构成一目了然。注意无论哪种方案接线务必牢固。接触不良是导致通信失败、数据乱跳的罪魁祸首之一。建议使用面包板或焊接避免杜邦线虚接。4. 软件实现从MakeCode图形化到Python代码解析编程环境我们选择微软的MakeCode for micro:bit在线编辑器。它支持图形化积木块和JavaScript代码对于进阶用户我们也可以切换到Python模式进行更底层的控制。我将分别讲解两种方式。4.1 使用MakeCode图形化编程快速上手MakeCode的扩展库生态非常丰富有社区贡献的DHT11驱动积木极大简化了操作。步骤打开 MakeCode for micro:bit 网站新建一个项目。点击“高级” - “扩展”在搜索框中输入“dht11”选择“dht11/dht22”这个扩展并添加。添加后左侧积木区会出现“DHT11”类别。主要会用到两个积木从引脚 P0 读取 DHT11 温湿度值这是一个命令积木执行一次读取操作。DHT11 温度(℃)和DHT11 湿度(%)这是两个报告积木用于获取最近一次成功读取的温度和湿度值。编写逻辑我们通常会在“无限循环”中每隔一段时间如2秒读取一次传感器然后将数据显示在LED屏上。由于屏幕小我们可以用“显示数字”积木轮流显示温度和湿度中间用暂停隔开。图形化代码示例逻辑当开机时 设置数字引脚 P0 为输入模式有些扩展库要求 无限循环 从引脚 P0 读取 DHT11 温湿度值 如果读取成功 则 显示字符串“T:” 显示数字 DHT11 温度(℃) 暂停 1000 毫秒 显示字符串“H:” 显示数字 DHT11 湿度(%) 暂停 1000 毫秒 否则 显示图标“X” 表示读取失败 暂停 2000 毫秒 等待下一次读取这种方式非常简单但封装度太高不利于我们理解底层通信和进行错误处理。4.2 使用MicroPython编程推荐进阶掌握核心我强烈建议使用Python模式来编写。micro:bit的MicroPython固件对硬件控制能力很强我们可以自己实现DHT11的驱动从而完全掌控通信过程。步骤在MakeCode编辑器中点击右上角齿轮图标选择“Python”切换到Python代码编辑器。我们将编写一个完整的、带错误处理和校验的DHT11驱动函数。核心代码解析与实现首先我们需要导入必要的模块并定义引脚和常量。from microbit import * import utime # 配置 DHT_PIN pin0 # 假设数据线接在P0接下来是核心的read_dht11函数。这个函数将返回一个元组(temperature, humidity)如果失败则返回(None, None)。def read_dht11(): # 1. 主机发送开始信号 DHT_PIN.write_digital(0) # 拉低总线 sleep_ms(18) # 保持低电平至少18ms DHT_PIN.write_digital(1) # 拉高总线 utime.sleep_us(20) # 保持高电平20-40us这里取20us # 2. 准备接收将引脚设置为输入由上拉电阻拉高 DHT_PIN.set_pull(DHT_PIN.PULL_UP) # 等待从机响应低电平 if wait_pin_state(0, 100) is False: # 100us内没等到低电平 return None, None # 等待从机响应高电平 if wait_pin_state(1, 100) is False: # 100us内没等到高电平 return None, None # 3. 接收40位数据 data [] for i in range(40): # 等待每个位开始的50us低电平结束 if wait_pin_state(0, 60) is False: return None, None # 测量高电平持续时间 t pulse_width_us(1, 100) # 测量高电平超时100us if t 0: # 超时 return None, None # 根据高电平时间判断是0还是1 data.append(1 if t 40 else 0) # 阈值取40us左右介于26-28和70之间 # 4. 解析数据字节 humidity_high bits_to_byte(data[0:8]) humidity_low bits_to_byte(data[8:16]) temp_high bits_to_byte(data[16:24]) temp_low bits_to_byte(data[24:32]) checksum bits_to_byte(data[32:40]) # 5. 校验 if (humidity_high humidity_low temp_high temp_low) 0xFF ! checksum: return None, None # DHT11湿度小数位常为0温度小数位也常为0 humidity humidity_high humidity_low / 10.0 temperature temp_high temp_low / 10.0 return temperature, humidity # 辅助函数1等待引脚达到指定状态带超时 def wait_pin_state(state, timeout_us): start utime.ticks_us() while DHT_PIN.read_digital() ! state: if utime.ticks_diff(utime.ticks_us(), start) timeout_us: return False return True # 辅助函数2测量引脚高电平脉冲宽度带超时 def pulse_width_us(state, timeout_us): start utime.ticks_us() while DHT_PIN.read_digital() state: if utime.ticks_diff(utime.ticks_us(), start) timeout_us: return -1 return utime.ticks_diff(utime.ticks_us(), start) # 辅助函数3将位列表转换为一个字节 def bits_to_byte(bits): byte 0 for bit in bits: byte (byte 1) | bit return byte主循环与显示逻辑while True: temp, humi read_dht11() if temp is not None and humi is not None: # 在LED屏上滚动显示信息更清晰 display.scroll(T:{:.1f}C.format(temp), delay80, waitFalse) sleep(500) display.scroll(H:{:.1f}%.format(humi), delay80) else: display.show(Image.SAD) # 读取失败显示哭脸 sleep(2000) # 每2秒读取一次这段代码完整实现了DHT11协议包含了超时判断和校验和验证健壮性远高于简单的图形化模块。你可以清晰地看到“开始信号”、“等待响应”、“逐位读取”、“数据解析”的完整流程。5. 深度调试与常见问题排查指南即使代码和接线都正确在实际操作中你仍可能遇到问题。下面是我总结的排查清单按照从易到难的顺序进行。5.1 现象LED屏无显示或一直显示错误图标如“X”或哭脸排查步骤检查电源用万用表测量DHT11的VCC和GND之间电压确保在3.2V-3.4V之间。micro:bit的USB口供电能力足够但劣质USB线可能导致电压跌落。检查接线这是最高频的问题。逐根捏紧杜邦线与micro:bit金手指和传感器引脚的连接处。强烈建议将杜邦线直接插在micro:bit的引脚上而不是通过扩展板以排除扩展板接触不良的可能。检查引脚定义确认代码中的DHT_PIN pin0与你实际连接的物理引脚P0一致。micro:bit的引脚编号印在板子背面。检查上拉电阻如果使用裸传感器确认4.7KΩ上拉电阻已正确连接在DATA线和3.3V之间。可以用万用表测量DATA引脚在空闲时的电压应该是稳定的3.3V左右如果电压很低或飘忽不定说明上拉电阻没接好或电阻值太大。5.2 现象能显示数据但数值固定为0、255或明显错误如湿度95%不变排查步骤校验和错误首先在代码中打印出接收到的5个原始字节和计算出的校验和。如果校验和不匹配说明数据传输过程受到干扰数据整体错误。这通常指向时序问题或电气干扰。时序问题这是“stm32f103c8t6读取dht11数据为0”类问题的核心。MicroPython的utime.sleep_us()和utime.ticks_us()函数精度有限且会被中断影响。可以尝试调整阈值在判断数据位0/1时代码中用的阈值是40µs。你可以尝试微调这个值比如调整到35µs或45µs看看数据是否恢复正常。增加延时在主机发送开始信号后释放总线并切换到输入模式后可以增加一个短暂的等待如utime.sleep_us(5)再开始检测从机响应。给传感器一个更稳定的准备时间。关闭中断在读取DHT11的整个关键时序期间可以尝试关闭全局中断但MicroPython标准库不直接支持操作复杂一般不推荐。传感器损坏或型号不符DHT11有几种封装确保你使用的是正品。用万用表测量传感器VCC和GND之间的电阻不应短路。尝试更换一个传感器测试。电源噪声在DHT11的VCC和GND之间并联一个100nF0.1uF的陶瓷电容可以非常有效地滤除电源线上的高频噪声这是提升通信稳定性的经典做法成本极低但效果显著。5.3 现象数据偶尔跳变或读取间隔必须很长排查步骤遵守传感器休息时间DHT11两次测量之间需要至少1秒的间隔。如果你在循环中频繁调用读取函数比如间隔小于1秒会导致读取失败或返回旧数据。确保主循环中的sleep(2000)或类似延时存在且不少于1000毫秒。电气干扰确保信号线DATA不要与电机、继电器等高功率器件线路平行走线。如果无法避免可以使用双绞线或屏蔽线。代码健壮性确保你的read_dht11函数在每次调用时都严格遵循“输出模式发起信号-输入模式接收数据”的引脚模式切换流程。残留的电平状态可能影响下一次通信。6. 功能扩展与项目优化思路一个基础的温湿度计已经完成了但我们可以让它变得更聪明、更有用。6.1 增加显示模式与用户交互利用micro:bit的A/B按钮我们可以增加更多功能模式切换按A键切换显示温度℃按B键切换显示湿度%长按A键切换温度单位℃/℉。数据显示优化由于LED屏小可以设计更紧凑的显示方式。例如用点阵绘制一个简易的温度计图标和湿度水滴图标配合数字。历史记录在内存中记录一段时间内的最高/最低温湿度并通过特定按钮组合如同时按下AB来显示。6.2 数据记录与离线分析虽然micro:bit本身存储空间有限但我们可以实现简单的数据记录。间隔记录每小时记录一次数据到micro:bit的“文件系统”中需要启用MicroPython的文件支持。数据导出通过USB连接电脑将记录的数据文件复制出来用Excel或Python进行图表分析观察一天内的温湿度变化趋势。6.3 阈值报警功能这是一个非常实用的功能。声光报警当温度超过30℃或湿度低于30%时让micro:bit板载的蜂鸣器通过引脚P0模拟需外接无源蜂鸣器发出警报声同时LED屏幕闪烁特定图案。代码实现在主循环中读取到数据后加入if判断语句触发music.play()和display.show()报警序列。6.4 迈向物联网进阶如果你想将数据上传到网络micro:bit也完全有能力。蓝牙传输利用micro:bit内置的蓝牙功能编写一个手机App例如用MIT App Inventor来接收并显示实时温湿度数据。外接Wi-Fi/射频模块通过串口连接ESP8266等Wi-Fi模块将数据发送到MQTT服务器如ThingsBoard、Home Assistant或云平台需注意网络访问合规性实现远程监控。这需要更复杂的硬件连接和编程但可玩性极高。通过这个从硬件原理到软件实现再到调试排错和功能扩展的完整流程你收获的不仅仅是一个能显示数字的小装置更是一套应对嵌入式传感器项目的通用方法论。下次当你遇到其他I2C、SPI传感器时你会发现思路是相通的理解协议、确保电气连接正确、编写稳健的驱动、处理异常情况。这个小巧的micro:bit温湿度计项目正是打开嵌入式世界大门的一把绝佳钥匙。