2、常见传感器原理:温度传感器(DS18B20)、湿度传感器(DHT11)、压力传感器(BMP280)、红外传感器(HC-SR501)
做物联网采集,传感器就是我们的「眼睛」和「耳朵」。
这一章,我挑四个最常用的传感器,跟你聊聊它们的脾气秉性。说白了,搞懂它们,你就能搞定市面上八成以上的环境采集需求。
2.1 温度传感器 DS18B20 —— 一根线搞定温度
DS18B20 这玩意儿,我用了快十年了。它最大的特点就是——省线。
你想想看,传统的模拟温度传感器,至少得三根线:电源、地、信号。DS18B20 呢?一根数据线就够了。它用的是 1-Wire 总线,数据线和电源线复用,甚至还能从数据线上「偷电」工作(寄生供电模式)。
- 测温范围:-55°C ~ +125°C
- 精度:±0.5°C(-10°C ~ +85°C 范围内)
- 分辨率:9~12 位可配置(默认 12 位,0.0625°C)
- 通信接口:1-Wire(单总线)
- 每个芯片有唯一 64 位 ROM 编码,支持多颗挂在同一总线上
我习惯用 12 位分辨率,虽然转换时间要 750ms,但精度够用。如果你对实时性要求高,可以降到 9 位,转换时间只有 93.75ms。
2.1.1 硬件连接
DS18B20 只有三个引脚:GND、DQ(数据)、VDD。标准接法很简单:
- VDD 接 3.3V 或 5V
- GND 接地
- DQ 接 MCU 的 GPIO,同时上拉一个 4.7kΩ 电阻到 VDD
2.1.2 通信时序
1-Wire 的时序其实挺讲究的。我刚开始调的时候,被它的时序坑过好几次。核心就三个动作:
- 复位脉冲: 主机拉低总线 480μs 以上,然后释放。DS18B20 会在 60μs 内拉低总线作为应答。
- 写时序: 写 0 拉低 60μs,写 1 拉低 1~15μs 然后释放。
- 读时序: 主机拉低 1~15μs 后释放,在 15μs 内采样总线电平。
// DS18B20 读取温度的核心代码片段
uint8_t ds18b20_reset(void) {
uint8_t presence;
GPIO_LOW(); // 拉低总线
delay_us(480); // 保持 480μs
GPIO_RELEASE(); // 释放总线
delay_us(60); // 等待 60μs
presence = GPIO_READ(); // 读取应答信号
delay_us(420); // 等待剩余时间
return presence; // 0 表示存在
}
float ds18b20_read_temperature(void) {
uint8_t temp_lsb, temp_msb;
int16_t raw_temp;
ds18b20_reset();
ds18b20_write_byte(0xCC); // 跳过 ROM 检测(单颗传感器)
ds18b20_write_byte(0x44); // 启动温度转换
delay_ms(750); // 等待转换完成(12 位分辨率)
ds18b20_reset();
ds18b20_write_byte(0xCC);
ds18b20_write_byte(0xBE); // 读取暂存器
temp_lsb = ds18b20_read_byte();
temp_msb = ds18b20_read_byte();
raw_temp = (temp_msb << 8) | temp_lsb;
return raw_temp * 0.0625; // 12 位分辨率下,每个 LSB 代表 0.0625°C
}
2.2 湿度传感器 DHT11 —— 便宜但够用
DHT11 是入门级湿度传感器的代表。说实话,它的精度一般,但胜在便宜、接口简单。一个项目如果对湿度要求不高,用 DHT11 准没错。
- 湿度测量范围:20% ~ 90% RH
- 湿度精度:±5% RH
- 温度测量范围:0°C ~ 50°C
- 温度精度:±2°C
- 采样周期:1 秒(两次读取间隔至少 1 秒)
- 通信接口:单总线(自定义协议,非 1-Wire)
2.2.1 通信协议
DHT11 的协议跟 DS18B20 不一样,它用的是自己的一套单总线协议。数据格式是 40 位:
- 8 位湿度整数部分 + 8 位湿度小数部分
- 8 位温度整数部分 + 8 位温度小数部分
- 8 位校验和
校验和的计算很简单:前四个字节相加,取低 8 位,等于校验和就对了。
// DHT11 读取数据流程
uint8_t dht11_read_data(uint8_t *humidity, uint8_t *temperature) {
uint8_t data[5] = {0};
// 主机发送起始信号
GPIO_LOW();
delay_ms(18); // 拉低至少 18ms
GPIO_HIGH();
delay_us(30); // 拉高 20~40μs
// 等待 DHT11 响应
if (GPIO_READ() == 0) { // DHT11 拉低总线
while (GPIO_READ() == 0); // 等待拉高
while (GPIO_READ() == 1); // 等待拉低(准备发送数据)
// 读取 40 位数据
for (int i = 0; i < 5; i++) {
for (int j = 0; j < 8; j++) {
while (GPIO_READ() == 0); // 等待数据开始
delay_us(40); // 在 40μs 时采样
if (GPIO_READ() == 1) {
data[i] |= (1 << (7 - j));
}
while (GPIO_READ() == 1); // 等待数据结束
}
}
// 校验
if ((data[0] + data[1] + data[2] + data[3]) == data[4]) {
*humidity = data[0];
*temperature = data[2];
return 1; // 成功
}
}
return 0; // 失败
}
2.3 压力传感器 BMP280 —— 气压与海拔的精确测量
BMP280 是博世出品的气压传感器,精度很高。我一般在做气象站或者无人机高度计的时候用它。它支持 I2C 和 SPI 两种接口,我习惯用 I2C,省引脚。
- 压力范围:300 ~ 1100 hPa
- 压力精度:±1 hPa(相对精度 ±0.12 hPa)
- 温度精度:±1.0°C
- 接口:I2C(地址 0x76 或 0x77)或 SPI
- 功耗:2.7μA(超低功耗模式)
2.3.1 校准参数
BMP280 出厂时,每个芯片都有独立的校准参数,存储在寄存器 0x88~0xA1 中。读取压力数据时,必须用这些参数做补偿计算。说白了,不校准的话,读出来的数据就是废的。
// BMP280 校准参数结构体
typedef struct {
uint16_t dig_T1;
int16_t dig_T2;
int16_t dig_T3;
uint16_t dig_P1;
int16_t dig_P2;
int16_t dig_P3;
int16_t dig_P4;
int16_t dig_P5;
int16_t dig_P6;
int16_t dig_P7;
int16_t dig_P8;
int16_t dig_P9;
} bmp280_calib_t;
// 温度补偿计算(返回 0.01°C 精度的温度值)
int32_t bmp280_compensate_temperature(int32_t adc_T, bmp280_calib_t *calib) {
int32_t var1, var2, T;
var1 = ((((adc_T >> 3) - ((int32_t)calib->dig_T1 << 1))) *
((int32_t)calib->dig_T2)) >> 11;
var2 = (((((adc_T >> 4) - ((int32_t)calib->dig_T1)) *
((adc_T >> 4) - ((int32_t)calib->dig_T1))) >> 12) *
((int32_t)calib->dig_T3)) >> 14;
t_fine = var1 + var2;
T = (t_fine * 5 + 128) >> 8;
return T; // 返回 0.01°C 精度的温度值
}
2.4 红外传感器 HC-SR501 —— 人体检测的经典方案
HC-SR501 是基于热释电红外(PIR)原理的人体感应模块。它检测的是人体发出的红外辐射(波长 8~14μm)。说白了,只要有人经过,它就能感应到。
- 检测距离:3~7 米(可调)
- 感应角度:< 120°(锥形区域)
- 工作电压:4.5~20V(常用 5V)
- 输出信号:高电平 3.3V,低电平 0V
- 延时时间:5~200 秒(可调)
- 封锁时间:2.5 秒(触发后锁定,防止重复触发)
2.4.1 硬件配置
HC-SR501 模块上有两个可调电位器:
- Sx(灵敏度): 调节检测距离,顺时针增大,逆时针减小
- Tx(延时): 调节输出高电平的持续时间,顺时针延长
还有一个跳线帽,用来选择触发模式:
- H(重复触发): 只要有人在感应区内,输出一直保持高电平
- L(单次触发): 检测到人后输出高电平,延时结束后自动恢复低电平
2.4.2 使用注意事项
HC-SR501 有几个坑,我踩过,你注意一下:
- 上电稳定时间: 模块上电后需要 30~60 秒的稳定时间,期间会误触发。我一般在上电后延时 60 秒再读取数据。
- 热源干扰: 空调出风口、暖气片、甚至阳光直射都会导致误触发。安装时避开这些热源。
- 检测盲区: 正对传感器方向移动,检测效果最好。如果人从侧面横向移动,灵敏度会下降。
// HC-SR501 读取示例(简单轮询)
#define PIR_PIN GPIO_PIN_5
void pir_init(void) {
gpio_set_mode(PIR_PIN, GPIO_INPUT);
delay_ms(60000); // 等待 60 秒稳定时间
}
uint8_t pir_detect_motion(void) {
return gpio_read(PIR_PIN); // 高电平表示检测到人
}
2.5 四种传感器对比总结
我把这四种传感器放在一起对比一下,方便你选型:
| 传感器 | 测量对象 | 接口类型 | 精度 | 典型应用 | 参考价格 |
|---|---|---|---|---|---|
| DS18B20 | 温度 | 1-Wire | ±0.5°C | 环境测温、工业监控 | 3~5 元 |
| DHT11 | 温湿度 | 单总线 | ±5% RH / ±2°C | 室内环境监测 | 2~4 元 |
| BMP280 | 气压/温度 | I2C/SPI | ±1 hPa / ±1°C | 气象站、高度计 | 5~8 元 |
| HC-SR501 | 人体红外 | 数字输出 | N/A | 人体感应、安防 | 3~5 元 |
2.6 知识体系图:传感器选型与通信概览
下面这张图,我把四种传感器的通信方式、数据流向和典型应用场景串起来了。你一看就明白:
嗯,四种传感器讲完了。每种都有自己的脾气,但摸透了之后,你会发现它们其实都很「听话」。选型的时候,记住一句话:没有最好的传感器,只有最合适的传感器。
公众号:蓝海资料掘金营,微信deep3321