wiringPi是树莓派读DHT11/DHT22最轻量方案,封装微秒级时序,需用wiringPi编号(如引脚7)、调用wiringPiSetup()、间隔≥2秒读取;注意其已停更,新项目建议libgpiod或I²C模块替代。

用 wiringPi 读 DHT11/DHT22(树莓派常见场景)
树莓派上直接用 C++ 读 DHT 系列传感器,wiringPi 是最轻量、最省事的选择——它封装了底层时序,不用自己硬啃微秒级脉冲。但注意:wiringPi 已停止维护,新项目建议改用 wiringPi2 或 libgpiod,不过对 DHT 这类单总线传感器,wiringPi 当前仍稳定可用。
常见错误是:接线正确但始终返回 0, 0 或 -1, -1,大概率是没调用 wiringPiSetup() 初始化,或 GPIO 编号用错(wiringPi 用的是 wiringPi 编号,不是 BCM 或物理引脚号)。
- 确认 DHT 数据线接到 wiringPi 编号为
7的引脚(对应 BCM_GPIO 4) - 编译时加
-lwiringPi,例如:g++ -o dht dht.cpp -lwiringPi - 读取函数典型调用:
dht11_read_data(7)(返回结构体,含humidity和temperature字段) - 每次读取后必须间隔至少 2 秒,否则传感器会拒绝响应
用 libgpiod + 自定义时序(现代 Linux 推荐路径)
libgpiod 是内核主线支持的 GPIO 库,不依赖 wiringPi,适合长期维护项目。但它不提供 DHT 解析逻辑,你得自己实现“拉低 20ms → 释放 40μs → 等待传感器响应”这类时序——关键难点在微秒级延时和边沿检测。
容易踩的坑:用 std::this_thread::sleep_for(std::chrono::microseconds(40)) 不够准,Linux 用户态调度无法保证精度;必须用 clock_gettime(CLOCK_MONOTONIC, &ts) 配合忙等待(spin-wait),并用 gpiod_line_request_input_flags() 开启边沿事件监听。
立即学习“C++免费学习笔记(深入)”;
- 优先使用
gpiod_chip_get_line(chip, offset)获取 line,而非硬编码 GPIO 编号 - 设置 line 为输入模式,并启用
GPIOD_LINE_REQUEST_FLAG_BIAS_PULL_UP(DHT 默认高电平) - 读取循环中,用
gpiod_line_event_wait()等待下降沿比轮询更可靠 - 实测发现:同一块 DHT22,在
wiringPi下读取成功率 98%,用纯libgpiod忙等待实现后掉到 ~85%,需加软件滤波(连续 3 次一致才采信)
通过 I²C 温湿度模块(如 SHT3x、BME280)
如果传感器本身带 I²C 接口(比如 SHT30、BME280),就完全避开单总线时序难题。C++ 只需调用 Linux 的 /dev/i2c- 设备节点,用 ioctl() 发送命令、读寄存器。
关键点不在代码复杂度,而在设备树配置和权限。常见现象是 open("/dev/i2c-1") 返回 -1,错误码 EACCES——说明没权限,不是驱动没加载。
- 确认 I²C 已启用:
ls /dev/i2c*有输出,且i2cdetect -y 1能扫出设备地址(如0x44) - 用户需加入
i2c组:sudo usermod -aG i2c $USER,然后重新登录 - 读 SHT30 温度示例:先写命令
0x2C06(周期性测量),再从寄存器0x00读 6 字节,校验 CRC 后解析高位 16bit 为温度原始值 - BME280 更复杂些,要先写配置寄存器
0xF2(湿度超采样)、0xF4(温度/压力超采样),再触发测量
跨平台方案:用串口转接板(如 ESP32 做采集端)
当目标平台不是树莓派(比如 x86_64 工控机、Mac),又不想折腾 GPIO 驱动,最稳的办法是让 ESP32 当传感器子节点:它用 Arduino SDK 轻松读 DHT/BME,再通过 UART 以固定格式(如 "T:23.5,H:45.2\n")发给主机。
C++ 主机端只需打开串口、设好波特率(如 115200)、按行解析。看似绕路,实则规避了所有硬件兼容性问题,且 ESP32 可远距离部署(加 RS485 模块),而树莓派 GPIO 引脚不能拉长线。
- Linux 下串口路径通常是
/dev/ttyUSB0或/dev/ttyACM0,用stty -F /dev/ttyUSB0 115200预置参数 - C++ 中用
open()+read()即可,别用std::ifstream——它默认带缓冲,会丢帧 - 务必加超时:
fd_set+select(),避免read()永久阻塞(ESP32 断连时) - 解析字符串时用
sscanf(buf, "T:%f,H:%f", &t, &h)比正则快得多,也足够安全
真正麻烦的从来不是“怎么读”,而是“怎么让读出来的数据可信”。传感器冷凝、电源纹波、信号线耦合干扰,都会让一次读数突变。与其花时间调时序,不如在应用层加滑动窗口均值、变化率阈值过滤——这些比底层驱动更影响最终效果。


















