2. 温湿度传感器(SHT30):工作原理、I2C协议基础、SHT30寄存器配置、驱动代码实现与数据读取
好,咱们开始聊SHT30。这个传感器我用了好几年了,从早期的SHT10一路用过来,SHT30算是性价比非常均衡的一款。说实话,在消费级和工业级之间,它卡位卡得刚刚好。
2.1 SHT30的工作原理
SHT30是Sensirion公司出的数字温湿度传感器。它内部集成了一个电容式湿度传感元件和一个带隙温度传感元件,外加一个14位的ADC。嗯,这里要注意,它输出的已经是数字信号了,不需要你再去搞什么模拟量转换。
湿度测量范围是0%到100%RH,温度是-40°C到125°C。精度方面,典型值是±2%RH和±0.3°C。我在一个农业大棚项目里用过它,连续跑了两年,数据漂移很小,这点让我挺放心的。
它内部有个加热器,可以除冷凝水。不过我个人建议,除非你确定环境湿度极高,否则别开。加热器一开,温度读数会偏个几度,你得做补偿,挺麻烦的。
2.2 I2C协议基础
SHT30用的是I2C接口。I2C这玩意儿,说白了就是两根线:SCL(时钟线)和SDA(数据线)。所有设备都挂在这两根线上,靠地址来区分。
I2C的基本流程是这样的:
- 主机发一个起始信号
- 然后发7位设备地址+1位读写位
- 从机应答
- 然后开始传数据,每8位后跟一个应答位
- 最后主机发停止信号
SHT30的I2C地址是0x44(ADDR引脚接GND时)。如果你把ADDR接VDD,地址就变成0x45。我在一个项目里同时用了两个SHT30,一个接GND一个接VDD,这样一根I2C总线上就能挂两个传感器,省了一个I2C接口。
关键点:SHT30的I2C通信速率最高支持1MHz,但很多单片机默认是100kHz或400kHz。我建议先用400kHz,稳定了再往上调。我曾经在1MHz下遇到过通信不稳定,降回400kHz就一切正常了。
2.3 SHT30寄存器配置
SHT30的寄存器不多,但有几个关键的你需要知道。
| 寄存器/命令 | 代码 | 说明 |
|---|---|---|
| 测量命令(高重复性) | 0x2400 | 默认模式,精度最高 |
| 测量命令(中重复性) | 0x240B | 精度稍低,速度快 |
| 测量命令(低重复性) | 0x2416 | 速度最快,精度最低 |
| 读取状态寄存器 | 0xF32D | 检查传感器状态 |
| 软复位 | 0x30A2 | 复位传感器 |
我个人习惯用高重复性模式。虽然测量时间会长一点(约15ms),但数据更可靠。如果你做的是电池供电的设备,可以考虑用中重复性模式,省点电。
还有一个寄存器叫“加热器控制”,命令是0x306D。我前面说了,不建议轻易开它。我曾经在一个冷库项目里试过,开了加热器后温度读数直接跳了2°C,还得做软件补偿,得不偿失。
2.4 驱动代码实现
好,咱们直接上代码。这是基于STM32 HAL库写的,但逻辑是通用的,你移植到其他平台也很容易。
// SHT30驱动代码片段
#define SHT30_ADDR 0x44 << 1 // 左移1位,因为HAL库需要8位地址
#define SHT30_CMD_MEASURE 0x2400 // 高重复性测量命令
#define SHT30_CMD_RESET 0x30A2 // 软复位命令
// 发送测量命令
HAL_StatusTypeDef SHT30_SendMeasureCmd(void)
{
uint8_t cmd[2];
cmd[0] = (SHT30_CMD_MEASURE >> 8) & 0xFF;
cmd[1] = SHT30_CMD_MEASURE & 0xFF;
return HAL_I2C_Master_Transmit(&hi2c1, SHT30_ADDR, cmd, 2, 100);
}
// 读取温湿度数据
HAL_StatusTypeDef SHT30_ReadData(float *temp, float *hum)
{
uint8_t buf[6];
HAL_StatusTypeDef ret;
// 先发测量命令
ret = SHT30_SendMeasureCmd();
if (ret != HAL_OK) return ret;
// 等待测量完成,高重复性模式需要15ms
HAL_Delay(20);
// 读取6字节数据
ret = HAL_I2C_Master_Receive(&hi2c1, SHT30_ADDR, buf, 6, 100);
if (ret != HAL_OK) return ret;
// 校验CRC(这里简化了,实际项目中一定要做)
// 温度转换
uint16_t raw_temp = (buf[0] << 8) | buf[1];
*temp = -45.0f + 175.0f * (float)raw_temp / 65535.0f;
// 湿度转换
uint16_t raw_hum = (buf[3] << 8) | buf[4];
*hum = 100.0f * (float)raw_hum / 65535.0f;
return HAL_OK;
}
小技巧:代码里的CRC校验我故意省略了,但实际项目中千万别省。SHT30的数据包最后一位是CRC校验码,你不校验的话,万一通信受干扰,读出来的数据可能是错的。我曾经在一个电磁环境复杂的项目里吃过这个亏,数据偶尔跳变,加了CRC校验后才定位到是通信干扰。
2.5 数据读取与解析
数据读取其实就两步:发命令,等结果,读数据。但有几个细节你得注意。
第一,测量命令发完后,一定要等够时间。高重复性模式至少等15ms,中重复性等8ms,低重复性等3ms。别问我为什么知道,我曾经为了省那几毫秒,把延时改成5ms,结果读出来的数据全是0xFFFF。嗯,教训深刻。
第二,数据转换公式是固定的:
- 温度(°C) = -45 + 175 * (原始值 / 65535)
- 湿度(%RH) = 100 * (原始值 / 65535)
这个公式在SHT30的数据手册里有,别自己瞎改。我见过有人把温度公式里的175写成180,结果读出来的温度比实际高了2°C,排查了半天才发现是公式抄错了。
第三,如果你发现读出来的湿度超过100%或者温度超出范围,大概率是通信出了问题。先检查I2C地址对不对,再检查接线。我遇到过最奇葩的一次,是SDA线虚焊,时通时不通,读出来的数据一会儿正常一会儿乱跳。
注意事项:SHT30的供电电压是2.4V到5.5V,但如果你用3.3V供电,I2C的上拉电阻建议用4.7kΩ。用10kΩ的话,在400kHz速率下波形可能会变形。我习惯用4.7kΩ,兼容性最好。
好了,SHT30的内容就这些。说白了,它就是个用I2C通信的数字传感器,驱动写起来不复杂,但细节决定成败。你只要把时序搞对,把CRC加上,把延时给够,基本不会出问题。
下一章咱们聊气压传感器,那个比这个稍微复杂一点,但套路是一样的。