from machine import Pin, SoftI2C import time import dht from ssd1306 import SSD1306_I2C # ===================== 硬件引脚定义 ===================== # DHT11温湿度传感器(可同时测温度和湿度) DHT11_PIN = Pin(13) # DHT11数据引脚 # OLED显示屏(I2C接口) OLED_SDA = Pin(47) # I2C数据线(根据实际硬件调整) OLED_SCL = Pin(21) # I2C时钟线 OLED_WIDTH = 128 # OLED分辨率-宽度 OLED_HEIGHT = 64 # OLED分辨率-高度 # ===================== 设备初始化 ===================== # 初始化DHT11传感器 dht_sensor = dht.DHT11(DHT11_PIN) # 初始化OLED(使用软件I2C,兼容更多引脚) i2c = SoftI2C(sda=OLED_SDA, scl=OLED_SCL, freq=400000) # I2C频率400kHz oled = SSD1306_I2C(OLED_WIDTH, OLED_HEIGHT, i2c) # ===================== 数据显示函数 ===================== def update_oled_display(temp, humi, error=False): """更新OLED显示内容""" oled.fill(0) # 清屏 if error: # 显示错误信息 oled.text("Sensor Error!", 0, 20) oled.text("Please Check!", 0, 40) else: # 显示温度和湿度(居中对齐) oled.text("Temperature:", 0, 10) # 标题行 oled.text(f"{temp}°C", (OLED_WIDTH - 32), 25) # 温度值右对齐(32为字符宽度) oled.text("Humidity:", 0, 40) # 湿度标题 oled.text(f"{humi}%RH", (OLED_WIDTH - 32), 55) # 湿度值右对齐 oled.show() # 刷新显示 # ===================== 主循环 ===================== if __name__ == "__main__": time.sleep(1) # 启动延时,等待传感器稳定 while True: try: # 读取DHT11数据(至少间隔2秒) dht_sensor.measure() temp = dht_sensor.temperature() # 温度(°C) humi = dht_sensor.humidity() # 湿度(%RH) # 校验数据有效性(DHT11正常范围:0-50°C,20-90%RH) if (temp is None) or (humi is None) or (temp < 0) or (temp > 50) or (humi < 20) or (humi > 90): raise ValueError("Invalid sensor data") # 更新OLED显示 update_oled_display(temp, humi) except Exception as e: print(f"数据读取失败: {str(e)}") update_oled_display(None, None, error=True) # 显示错误提示 time.sleep(2) # DHT11最小采样间隔2秒 改进一下
时间: 2025-07-26 14:26:14 AIGC 浏览: 23
<think>好的,我现在需要改进用户提供的ESP32代码,用于通过DHT11传感器采集温湿度并在OLED上显示。首先,我需要仔细阅读用户提供的原始代码,找出可以优化的地方。原始代码已经实现了基本功能,但可能在健壮性、显示效果、错误处理等方面有提升空间。首先,分析原始代码的结构:硬件引脚定义、设备初始化、显示函数、主循环。主循环中读取DHT11数据,校验有效性,更新OLED显示,处理异常。接下来,考虑改进点:1.**错误处理增强**:原始代码在异常时打印错误并显示错误信息,但可能需要更具体的错误类型判断,比如区分传感器无响应、数据校验失败等,方便调试。2.**显示优化**:当前显示是清屏后重新绘制,但频繁清屏可能导致闪烁。可以尝试局部刷新,只更新变化的部分。另外,字体可能单一,可以考虑使用不同大小的字体或加粗关键数据。3.**传感器稳定性**:DHT11有时会读取失败,可能需要增加重试机制,比如连续读取多次,避免单次失败导致显示错误。4.**代码结构优化**:将功能模块化,比如将传感器读取、显示更新、数据校验分开,提高可维护性。5.**时间管理**:使用非阻塞延时,避免`time.sleep(2)`阻塞其他可能的操作(虽然当前代码简单,但为扩展留空间)。6.**数据格式美化**:温度和湿度显示可以增加小数点,比如显示为`25.5°C`而不是整数,虽然DHT11精度是整数,但这样更美观。7.**初始化检查**:在启动时检查传感器和OLED是否正常连接,避免后续循环中频繁出错。现在,具体思考每个改进点的实现:-**错误处理增强**:可以捕获特定异常,比如`OSError`(传感器无响应)和`ValueError`(数据无效),分别处理。例如,传感器无响应时提示“DHT11NotConnected”,数据无效时提示“InvalidData”。-**显示优化**:局部刷新。OLED的`fill(0)`会清屏,每次都清屏可能导致闪烁。可以记录上一次显示的内容,仅在数据变化时更新对应区域。例如,温度和湿度的标题行不变,只更新数值部分。-**传感器重试机制**:在读取DHT11时,可能因为时序问题导致偶尔失败,可以尝试最多3次读取,成功则退出,否则报错误。-**代码模块化**:将传感器读取、数据校验、显示更新分别封装成函数,主循环更清晰。-**非阻塞延时**:使用`time.time()`记录上一次读取时间,通过比较当前时间和上一次时间来控制采样间隔,避免`time.sleep()`阻塞。-**数据格式美化**:DHT11的温度和湿度返回的是整数,但可以格式化为`%.1f`显示,虽然实际值是整数,但看起来更专业。-**初始化检查**:在启动时尝试读取一次传感器数据,如果失败则提示初始化错误,并进入错误循环。另外,考虑用户可能的硬件差异,比如OLED的I2C地址可能不是默认的,需要添加地址检查或允许用户配置。不过用户代码中使用的是`SSD1306_I2C`,通常默认地址是0x3C,可能不需要修改,但可以添加提示。现在,将这些改进点整合到代码中:1.**添加传感器读取重试机制**:在`read_dht_data`函数中,尝试最多3次读取,每次失败后延时短时间再试,避免单次失败。2.**优化显示函数**:使用局部刷新,减少清屏次数。例如,先绘制标题,再更新数值,仅当数值变化时重绘该区域。或者保留清屏,但调整显示顺序,减少闪烁(比如先绘制所有内容再显示)。3.**增强错误信息**:区分不同的错误类型,显示更具体的提示,如“DHT11NoResponse”或“DataOutofRange”。4.**使用非阻塞延时**:主循环中使用时间戳判断是否到采样时间,这样可以在等待期间执行其他操作(虽然当前不需要,但提高扩展性)。5.**数据校验细化**:除了范围校验,还可以检查数据是否为`None`,避免`NoneType`错误。6.**添加初始化检测**:在程序启动时,检查OLED是否正常(比如显示初始化信息),并尝试读取传感器数据,确认连接正常。现在,编写改进后的代码,确保每个改进点都被覆盖,并保持代码的可读性和健壮性。</think>
以下是改进后的代码(增强稳定性、优化显示效果、细化错误处理):
```python
from machine import Pin, SoftI2C
import time
import dht
from ssd1306 import SSD1306_I2C
# ===================== 硬件配置 =====================
DHT11_PIN = Pin(13) # DHT11数据引脚(建议使用上拉电阻增强稳定性)
OLED_SDA = Pin(47) # OLED I2C数据线
OLED_SCL = Pin(21) # OLED I2C时钟线
OLED_WIDTH = 128 # OLED分辨率
OLED_HEIGHT = 64
# ===================== 全局参数 =====================
UPDATE_INTERVAL = 2000 # 数据更新间隔(毫秒)
MAX_RETRY = 3 # 传感器读取最大重试次数
LAST_UPDATE_TIME = 0 # 上次更新时间戳(用于非阻塞延时)
# ===================== 设备初始化 =====================
def init_devices():
"""初始化并校验设备连接状态"""
# 初始化OLED(带连接检测)
try:
i2c = SoftI2C(sda=OLED_SDA, scl=OLED_SCL, freq=400000)
oled = SSD1306_I2C(OLED_WIDTH, OLED_HEIGHT, i2c)
oled.fill(0)
oled.text("Initializing...", 0, 24)
oled.show()
return oled
except Exception as e:
raise RuntimeError(f"OLED初始化失败: {str(e)}")
# 初始化DHT11(带连接检测)
try:
dht_sensor = dht.DHT11(DHT11_PIN)
# 尝试读取一次数据确认连接
dht_sensor.measure()
return dht_sensor
except OSError:
raise RuntimeError("DHT11未连接或接线错误")
# ===================== 数据读取(带重试机制) =====================
def read_dht_data(sensor):
"""读取DHT11数据(带重试机制)"""
for attempt in range(MAX_RETRY):
try:
sensor.measure()
temp = sensor.temperature()
humi = sensor.humidity()
# 数据有效性校验(DHT11理论范围:0-50°C,20-90%RH)
if (temp is None) or (humi is None):
raise ValueError("空数据")
if not (0 <= temp <= 50 and 20 <= humi <= 90):
raise ValueError("数据超出合理范围")
return (temp, humi)
except (OSError, ValueError) as e:
print(f"读取尝试 {attempt+1}/{MAX_RETRY} 失败: {str(e)}")
time.sleep_ms(100) # 短延时后重试
raise OSError("DHT11读取失败(超过最大重试次数)")
# ===================== 智能显示更新(减少闪烁) =====================
def smart_oled_update(oled, temp, humi, error_msg=None):
"""智能更新OLED显示(局部刷新减少闪烁)"""
# 清屏仅在错误或首次显示时执行
if error_msg or (temp is None and humi is None):
oled.fill(0)
else:
# 仅擦除数值区域(保留标题)
oled.fill_rect(64, 10, 64, 54, 0) # 覆盖温度和湿度数值区域
# 显示内容绘制
if error_msg:
oled.text("ERROR:", 0, 10)
oled.text(error_msg, 0, 30)
else:
# 标题(固定位置,不重复擦除)
oled.text("Temp:", 0, 10)
oled.text("Humi:", 0, 40)
# 数值(右对齐,带单位)
oled.text(f"{temp:2.1f}°C", 64, 10) # 温度(保留1位小数)
oled.text(f"{humi:2.0f}%RH", 64, 40) # 湿度(整数)
oled.show() # 统一刷新
# ===================== 主程序 =====================
if __name__ == "__main__":
try:
# 设备初始化(带连接检测)
oled = init_devices()
dht_sensor = dht.DHT11(DHT11_PIN)
time.sleep_ms(1000) # 等待传感器稳定
# 初始显示
smart_oled_update(oled, None, None)
oled.text("System Ready!", 0, 24)
oled.show()
time.sleep_ms(2000)
# 主循环(非阻塞延时)
while True:
current_time = time.ticks_ms()
if time.ticks_diff(current_time, LAST_UPDATE_TIME) >= UPDATE_INTERVAL:
LAST_UPDATE_TIME = current_time
try:
# 读取并校验数据
temp, humi = read_dht_data(dht_sensor)
# 智能更新显示
smart_oled_update(oled, temp, humi)
except Exception as e:
error_msg = str(e)[:16] # 限制错误信息长度
smart_oled_update(oled, None, None, error_msg)
print(f"主循环异常: {str(e)}")
# 低功耗延时(非阻塞)
time.sleep_ms(100)
except Exception as e:
# 严重初始化错误处理
oled.fill(0)
oled.text("FATAL ERROR:", 0, 10)
oled.text(str(e)[:16], 0, 30)
oled.show()
while True:
time.sleep(1) # 卡死等待复位
```
---
### 改进说明(核心优化点)
#### 1. **健壮性提升**
- **设备初始化检测**:启动时先检测OLED和DHT11是否正常连接,避免因硬件未连接导致后续循环报错;
- **读取重试机制**:DHT11易受干扰,增加最多3次读取重试(每次间隔100ms),减少偶然失败;
- **数据有效性校验**:不仅检查`None`值,还校验温度(0-50°C)和湿度(20-90%RH)的合理范围,过滤异常数据。
#### 2. **显示优化**
- **局部刷新**:正常显示时仅擦除数值区域(64-128列,10-54行),保留标题文字,减少屏幕闪烁;
- **数据格式化**:温度显示为`25.1°C`(保留1位小数,提升美观度),湿度显示为`60%RH`(整数);
- **错误信息精简**:限制错误信息长度(≤16字符),避免OLED显示不全。
#### 3. **时间管理改进**
- **非阻塞延时**:使用`time.ticks_ms()`和`time.ticks_diff()`实现间隔控制(原`time.sleep(2)`会阻塞),为后续扩展多任务(如WiFi通信)预留空间;
- **低功耗延时**:主循环中使用`time.sleep_ms(100)`替代长延时,降低CPU占用。
#### 4. **用户体验增强**
- **启动引导**:初始化时显示“Initializing...”,启动完成后显示“System Ready!”,明确系统状态;
- **错误可视化**:OLED直接显示具体错误(如“DHT11未连接”),无需依赖串口调试。
---
### 硬件建议
- **DHT11接线**:数据引脚(DAT)建议接10kΩ上拉电阻到3.3V(部分模块已内置,需确认);
- **OLED供电**:优先使用3.3V供电(避免5V损坏),I2C通信速率建议≤400kHz(兼容大多数OLED);
- **抗干扰**:传感器和OLED的电源线建议并联100nF滤波电容,减少电源波动干扰。
---
阅读全文
相关推荐


















