znlgis 博客

GIS开发与技术分享

第13章:温度与湿度传感器

本章深入讲解 DS18B20 单总线温度传感器和 DHT11/XHT11 温湿度传感器的工作原理、通信协议与数据解码。


13.1 DS18B20 温度传感器

13.1.1 传感器介绍

DS18B20 是一款数字温度传感器:

参数 数值
测温范围 -55°C ~ +125°C
精度 ±0.5°C(-10°C ~ +85°C)
分辨率 9-12 位可配置
通信方式 单总线(1-Wire)
供电方式 3.0V ~ 5.5V 或寄生供电

13.1.2 单总线协议原理

单总线(1-Wire)协议只需要一根数据线(加地线):

主机 ─────┬───── DS18B20
          │
        [4.7K]  上拉电阻
          │
         VCC

时序特点

  • 主机通过控制时序发送/接收数据
  • 数据位通过高低电平持续时间编码

13.1.3 通信时序

复位脉冲 (Reset Pulse):
主机: ──────────┐           ┌────────────
                └───────────┘
                    480μs+

存在脉冲 (Presence Pulse):
设备:           ──────┐     ┌──────────
                      └─────┘
                       60-240μs

写"0":
主机: ──────┐                 ┌────────
            └─────────────────┘
                 60-120μs

写"1":
主机: ──────┐     ┌───────────────────
            └─────┘
             1-15μs   45-105μs

读位:
主机: ──────┐  ┌──────────────────────
            └──┘
            1μs  ← 采样点 (15μs内)

13.1.4 ROM 命令

命令 代码 说明
搜索 ROM 0xF0 枚举所有设备
读 ROM 0x33 读取唯一 64 位 ROM
匹配 ROM 0x55 选择特定设备
跳过 ROM 0xCC 跳过寻址(单设备时)

13.1.5 功能命令

命令 代码 说明
温度转换 0x44 启动温度转换
读暂存器 0xBE 读取 9 字节暂存器

13.1.6 数据编码格式

DS18B20 返回 9 字节暂存器数据:

字节 0: 温度 LSB
字节 1: 温度 MSB
字节 2: 高温报警阈值
字节 3: 低温报警阈值
字节 4: 配置寄存器
字节 5-7: 保留
字节 8: CRC 校验

温度数据解码

# 12 位分辨率时:
# 温度 = (MSB << 8 | LSB) / 16

# 示例: 0x0191 = 401
# 温度 = 401 / 16 = 25.0625°C

# 负温度 (二进制补码):
# 0xFF5E = -162 (有符号)
# 温度 = -162 / 16 = -10.125°C

13.1.7 MicroPython 代码

'''
实验:DS18B20 温度读取
接线:数据线连接 GP3
'''
import machine
import onewire
import ds18x20
import time

# 初始化单总线
ds_pin = machine.Pin(3)
ds_sensor = ds18x20.DS18X20(onewire.OneWire(ds_pin))

# 扫描设备
roms = ds_sensor.scan()
print(f'发现 DS18B20 设备: {roms}')

if not roms:
    print("未找到传感器!")
else:
    while True:
        # 启动温度转换
        ds_sensor.convert_temp()
        time.sleep_ms(750)  # 12位分辨率需要 750ms
        
        # 读取所有传感器
        for rom in roms:
            temp = ds_sensor.read_temp(rom)
            rom_hex = ''.join(f'{b:02x}' for b in rom)
            print(f"ROM: {rom_hex}  温度: {temp:.2f}°C")
        
        time.sleep(1)

13.1.8 多传感器系统

'''
实验:多个 DS18B20 并联
'''
import machine
import onewire
import ds18x20
import time

ds_pin = machine.Pin(3)
ds_sensor = ds18x20.DS18X20(onewire.OneWire(ds_pin))

# 传感器 ROM 映射到位置名称
SENSOR_NAMES = {}

def discover_sensors():
    """发现并命名传感器"""
    roms = ds_sensor.scan()
    print(f"发现 {len(roms)} 个传感器")
    
    for i, rom in enumerate(roms):
        rom_hex = ''.join(f'{b:02x}' for b in rom)
        name = input(f"传感器 {rom_hex} 的名称: ")
        SENSOR_NAMES[rom_hex] = name
    
    return roms

def read_all_temperatures():
    """读取所有传感器温度"""
    ds_sensor.convert_temp()
    time.sleep_ms(750)
    
    results = {}
    for rom in ds_sensor.scan():
        rom_hex = ''.join(f'{b:02x}' for b in rom)
        name = SENSOR_NAMES.get(rom_hex, rom_hex)
        temp = ds_sensor.read_temp(rom)
        results[name] = temp
    
    return results

roms = discover_sensors()

while True:
    temps = read_all_temperatures()
    for name, temp in temps.items():
        print(f"{name}: {temp:.2f}°C")
    print("---")
    time.sleep(2)

13.2 DHT11/XHT11 温湿度传感器

13.2.1 传感器介绍

DHT11/XHT11 是低成本温湿度传感器:

参数 DHT11 DHT22
湿度范围 20-90% RH 0-100% RH
湿度精度 ±5% RH ±2% RH
温度范围 0-50°C -40~80°C
温度精度 ±2°C ±0.5°C
采样周期 ≥1秒 ≥2秒

13.2.2 单总线协议

DHT 使用自定义单总线协议(与 DS18B20 不同):

通信流程:
1. 主机发送起始信号 (拉低 18ms+)
2. 主机释放总线
3. DHT 响应 (拉低 80μs + 拉高 80μs)
4. DHT 发送 40 位数据

数据格式:
[湿度整数][湿度小数][温度整数][温度小数][校验和]
   8位       8位       8位       8位       8位

13.2.3 位时序编码

数据 "0":
DHT: ────┐     ┌─────────────
         └─────┘
         50μs   26-28μs

数据 "1":
DHT: ────┐     ┌───────────────
         └─────┘
         50μs     70μs

解码方法:测量高电平持续时间

  • < 40μs → 数据位 0
  • 40μs → 数据位 1

13.2.4 数据校验

# 校验和 = (湿度整数 + 湿度小数 + 温度整数 + 温度小数) & 0xFF
checksum = (data[0] + data[1] + data[2] + data[3]) & 0xFF
if checksum == data[4]:
    print("校验通过")

13.2.5 MicroPython 代码

'''
实验:DHT11/XHT11 温湿度读取
接线:数据线连接 GP19
'''
import machine
import dht
import time

# 初始化
pin = machine.Pin(19, machine.Pin.OUT, machine.Pin.PULL_DOWN)
sensor = dht.DHT11(pin)

while True:
    try:
        sensor.measure()
        temp = sensor.temperature()
        hum = sensor.humidity()
        print(f"温度: {temp}°C  湿度: {hum}%")
    except OSError as e:
        print(f"读取失败: {e}")
    
    time.sleep(1.5)  # DHT11 最小采样间隔 1 秒

13.2.6 带重试机制

'''
实验:DHT 传感器稳定读取
'''
import machine
import dht
import time

sensor = dht.DHT11(machine.Pin(19))

def read_dht_with_retry(max_retries=5):
    """带重试的读取"""
    for attempt in range(max_retries):
        try:
            sensor.measure()
            return sensor.temperature(), sensor.humidity()
        except OSError:
            time.sleep(0.5)
    
    return None, None

while True:
    temp, hum = read_dht_with_retry()
    
    if temp is not None:
        print(f"温度: {temp}°C  湿度: {hum}%")
    else:
        print("读取失败")
    
    time.sleep(2)

13.3 NTC 热敏电阻

13.3.1 工作原理

NTC(负温度系数)热敏电阻的阻值随温度升高而降低:

R(T) = R25 × exp[B × (1/T - 1/298.15)]

R25: 25°C 时的标称电阻(通常 10KΩ)
B: B 值常数(通常 3950K)
T: 绝对温度 (开尔文)

13.3.2 电路与计算

'''
实验:NTC 热敏电阻温度测量
'''
from machine import ADC
import math
import time

ntc = ADC(26)

# NTC 参数
R25 = 10000    # 25°C 时电阻
B = 3950       # B 值
R_REF = 10000  # 分压电阻
VCC = 3.3

def read_temperature():
    """读取 NTC 温度"""
    adc = ntc.read_u16()
    voltage = adc * VCC / 65535
    
    # 计算 NTC 阻值
    if voltage <= 0 or voltage >= VCC:
        return None
    
    r_ntc = R_REF * voltage / (VCC - voltage)
    
    # 计算温度 (Steinhart-Hart 简化公式)
    temp_k = 1 / (1/298.15 + math.log(r_ntc/R25) / B)
    temp_c = temp_k - 273.15
    
    return temp_c

while True:
    temp = read_temperature()
    if temp:
        print(f"温度: {temp:.1f}°C")
    time.sleep(1)

13.4 LM35 模拟温度传感器

13.4.1 传感器特性

LM35 是精密模拟温度传感器:

  • 输出电压与温度成线性关系
  • 灵敏度:10mV/°C
  • 范围:-55°C ~ +150°C

13.4.2 计算方法

'''
实验:LM35 温度读取
'''
from machine import ADC
import time

lm35 = ADC(26)

def read_lm35():
    """读取 LM35 温度"""
    adc = lm35.read_u16()
    voltage = adc * 3.3 / 65535
    
    # 温度 = 电压 / 0.01V/°C
    temp = voltage / 0.01
    return temp

while True:
    temp = read_lm35()
    print(f"温度: {temp:.1f}°C")
    time.sleep(1)

13.5 温湿度数据应用

13.5.1 舒适度指数

'''
实验:温湿度舒适度指数
'''
def comfort_index(temp, humidity):
    """计算舒适度指数"""
    # 热指数公式 (Heat Index)
    if temp < 27:
        return temp  # 温度不高时直接返回
    
    hi = (-42.379 + 
          2.04901523 * temp + 
          10.14333127 * humidity -
          0.22475541 * temp * humidity -
          6.83783e-3 * temp**2 -
          5.481717e-2 * humidity**2 +
          1.22874e-3 * temp**2 * humidity +
          8.5282e-4 * temp * humidity**2 -
          1.99e-6 * temp**2 * humidity**2)
    
    return hi

def comfort_level(temp, humidity):
    """判断舒适等级"""
    hi = comfort_index(temp, humidity)
    
    if hi < 27:
        return "舒适"
    elif hi < 32:
        return "略热"
    elif hi < 41:
        return "较热,注意补水"
    elif hi < 54:
        return "酷热,避免剧烈活动"
    else:
        return "极度危险"

13.5.2 露点温度

import math

def dew_point(temp, humidity):
    """计算露点温度"""
    a = 17.27
    b = 237.7
    
    alpha = ((a * temp) / (b + temp)) + math.log(humidity/100.0)
    dew = (b * alpha) / (a - alpha)
    
    return dew

# 使用
temp = 25
hum = 60
dp = dew_point(temp, hum)
print(f"露点温度: {dp:.1f}°C")

13.5.3 温控系统

'''
实验:简易温控系统
'''
from machine import Pin
import dht
import time

sensor = dht.DHT11(Pin(19))
heater = Pin(0, Pin.OUT)  # 加热器继电器
cooler = Pin(1, Pin.OUT)  # 制冷器继电器

TARGET_TEMP = 25
HYSTERESIS = 2

def control_temperature():
    """温度控制逻辑"""
    try:
        sensor.measure()
        temp = sensor.temperature()
        
        if temp < TARGET_TEMP - HYSTERESIS:
            heater.value(1)
            cooler.value(0)
            status = "加热中"
        elif temp > TARGET_TEMP + HYSTERESIS:
            heater.value(0)
            cooler.value(1)
            status = "制冷中"
        else:
            heater.value(0)
            cooler.value(0)
            status = "保持"
        
        print(f"温度: {temp}°C  目标: {TARGET_TEMP}°C  状态: {status}")
        
    except OSError:
        print("传感器读取失败")

while True:
    control_temperature()
    time.sleep(2)

13.6 本章小结

本章介绍了温度与湿度传感器:

  1. DS18B20
    • 单总线数字温度传感器
    • 12 位分辨率,精度 ±0.5°C
    • 支持多传感器并联
  2. DHT11/XHT11
    • 温湿度一体传感器
    • 40 位数据格式 + 校验和
    • 采样间隔 ≥1 秒
  3. 数据编码
    • DS18B20:16 位有符号,除以 16 得温度
    • DHT11:整数+小数,带校验
  4. 应用场景
    • 舒适度评估
    • 露点计算
    • 温控系统

下一章将学习气体检测传感器。