第3章 温度传感器(SHT30):I2C协议详解、寄存器配置与实战选型
各位同学,今天我们来啃一块硬骨头——SHT30。说实话,我在做温室项目之前,一直觉得温度传感器嘛,能读数就行。直到有一次,客户要求精度±0.3℃,响应时间还要快,我才发现DS18B20在某些场景下真的力不从心。嗯,SHT30就是这时候走进我的视野的。
3.1 I2C协议,咱们聊点实在的
I2C协议,说白了就是两根线干大事。SDA(数据线)和SCL(时钟线),挂一堆设备上去,每个设备有个唯一地址。SHT30的I2C地址是0x44(ADDR引脚接GND)或0x45(接VDD)。我个人习惯默认用0x44,省事。
I2C的通信流程其实就三步:
- 起始信号:SCL高电平时,SDA从高拉低
- 数据传输:每8位数据后跟一个ACK应答位
- 停止信号:SCL高电平时,SDA从低拉高
你想想看,这跟串口UART完全不是一个路子。UART是异步的,你得约定好波特率;I2C是同步的,时钟由主机控制。我在项目中遇到过一个问题:两个从机地址冲突了,结果数据全乱套。后来我养成了习惯——上电先扫描一遍总线,确认所有设备都在。
核心要点:I2C通信时,主机负责产生时钟,从机只能拉低SCL做时钟拉伸(Clock Stretching)。SHT30支持时钟拉伸,但实测中很少用到,除非你跑在400kHz高速模式下。
3.2 SHT30寄存器配置,别被手册吓到
SHT30的寄存器不多,但每个位都有讲究。我刚开始看数据手册时,那叫一个头大。后来发现,其实你只需要关注几个关键寄存器:
| 寄存器地址 | 名称 | 功能 |
|---|---|---|
| 0xE0 | 状态寄存器 | 读取状态、复位、加热器控制 |
| 0x2C | 测量命令(高精度) | 启动单次测量,重复性高 |
| 0x24 | 测量命令(低功耗) | 启动单次测量,省电模式 |
| 0x20 | 周期采集模式 | 设置自动连续采集 |
配置寄存器时,我习惯用这样的代码模板:
// SHT30 单次测量(高精度模式)
uint8_t cmd[2] = {0x2C, 0x06};
HAL_I2C_Master_Transmit(&hi2c1, 0x44 << 1, cmd, 2, 100);
HAL_Delay(15); // 等待测量完成
uint8_t buf[6];
HAL_I2C_Master_Receive(&hi2c1, 0x44 << 1, buf, 6, 100);
// 解析温度:buf[0]是高字节,buf[1]是低字节
uint16_t raw_temp = (buf[0] << 8) | buf[1];
float temperature = -45.0 + 175.0 * raw_temp / 65535.0;
小技巧:SHT30的CRC校验是可选的,但我建议你加上。我曾经因为没做CRC校验,读到了一组全是0xFF的数据,差点以为是传感器坏了。其实只是总线干扰了一下。
3.3 单次采集 vs 周期采集,怎么选?
这个问题,说白了就是「你要省电还是省事」。
- 单次采集模式:发一次命令,读一次数据。适合电池供电的场景。我做过一个无线温湿度节点,用单次模式+深度睡眠,两节AA电池撑了半年。
- 周期采集模式:设置好采样频率(0.5Hz、1Hz、2Hz、4Hz、10Hz),传感器自己干活。你只需要定时去读数据寄存器就行。适合需要连续监控的温室大棚。
周期采集模式的配置代码:
// 设置周期采集模式,2Hz,高重复性
uint8_t cmd[2] = {0x20, 0x32};
HAL_I2C_Master_Transmit(&hi2c1, 0x44 << 1, cmd, 2, 100);
// 之后每隔500ms读取一次数据
uint8_t buf[6];
HAL_I2C_Master_Receive(&hi2c1, 0x44 << 1, buf, 6, 100);
注意:周期模式下,如果你长时间不去读数据,传感器内部缓冲区会被覆盖。我建议用定时器中断,每500ms读一次,别用delay死等。
3.4 加热器功能,你可能用得上
SHT30内部有个小加热器,功率大约15mW。你可能会问:「温度传感器还带加热?这不是自己干扰自己吗?」
嗯,这个功能不是用来加热环境的,而是用来除湿的。我在南方做项目时,梅雨季节湿度经常飙到95%以上,传感器内部结露,读数直接飘了。这时候打开加热器,烤个几秒钟,水汽就散了。
加热器控制代码:
// 开启加热器
uint8_t cmd[2] = {0x30, 0x6D};
HAL_I2C_Master_Transmit(&hi2c1, 0x44 << 1, cmd, 2, 100);
// 等待2秒后关闭
HAL_Delay(2000);
cmd[0] = 0x30; cmd[1] = 0x66;
HAL_I2C_Master_Transmit(&hi2c1, 0x44 << 1, cmd, 2, 100);
避坑指南:加热器开启后,温度读数会偏高2-3℃。我曾经没注意这个,调试时发现温度一直比隔壁DS18B20高,查了半天才发现是加热器没关。所以,加热完记得关掉,并且等几秒让传感器冷却再读数。
3.5 SHT30 vs DS18B20,到底选哪个?
这个问题我经常被问到。说实话,没有绝对的谁好谁坏,关键看场景。我整理了一个对比表:
| 对比项 | SHT30 | DS18B20 |
|---|---|---|
| 接口 | I2C(两根线) | 单总线(一根线) |
| 精度 | ±0.3℃(典型) | ±0.5℃(典型) |
| 湿度测量 | 支持(±2%RH) | 不支持 |
| 分辨率 | 16位 | 9~12位可配置 |
| 最大速率 | 400kHz(I2C高速) | 约15kbps(单总线) |
| 多设备组网 | 地址固定(2个可选) | 64位ROM,可挂多个 |
| 成本 | 约8-12元 | 约3-5元 |
我的选型建议是这样的:
- 选SHT30:需要高精度、需要湿度数据、I2C总线有空余引脚。温室环境监测,我首选SHT30。
- 选DS18B20:成本敏感、只需要温度、需要长距离布线(单总线可以传50米以上)。工业现场布线不方便时,DS18B20是神器。
我记得有一次做温室项目,甲方要求每个大棚装20个温度点。如果用SHT30,I2C地址只有两个,得加多路复用器,麻烦。最后用了DS18B20,一根线串了20个传感器,省时省力。但如果你要测湿度,那就只能上SHT30了。
总结一下:SHT30是「精度派」,DS18B20是「实用派」。温室环境监测,我建议主控用SHT30(温湿度一体),关键点用DS18B20做冗余备份。两者互补,效果最好。
好了,这一章的内容就到这儿。下一章我们聊聊光照传感器,那个更有意思——BH1750和TSL2561,又是一场好戏。