1. 本章学习目标
-
掌握SHT45温湿度传感器的硬件接线方法
-
理解SHT45特有的"命令式"通信机制
-
使用两种不同的Python方式读取SHT45的温度和湿度数据
-
掌握原始数据的解析和换算方法
2. SHT45传感器简介
SHT45是瑞士Sensirion公司出品的一款高精度数字温湿度传感器,属于SHT4x系列中的旗舰型号。其主要特性如下:
| 参数 | 规格 |
|---|---|
| 温度精度 | ±0.1 °C(0~75 °C) |
| 湿度精度 | ±1.0% RH(25~75% RH) |
| 供电电压 | 1.08 V ~ 3.6 V |
| I2C地址 | 0x44 |
| 工作温度范围 | -40°C ~ 125°C |
| 平均电流 | 0.4 μA |
💡 小知识:SHT45基于"电容式湿度传感+带隙温度传感"的双核心技术,内部集成了信号处理电路,可将物理量直接转换为数字信号通过I2C接口输出-。SHT40、SHT41、SHT45三款传感器的接线方式和代码完全通用,本教程可直接用于SHT40和SHT41。
3. 硬件接线
3.1 引脚连接对照表
将SHT45模块与树莓派进行连接,请按照下表操作:
| SHT45模块引脚 | 树莓派GPIO | 物理引脚号 |
|---|---|---|
| VCC | 3.3V | 引脚1 |
| GND | GND | 引脚6 |
| SDA | GPIO2 | 引脚3 |
| SCL | GPIO3 | 引脚5 |

3.2 接线注意事项
-
电源选择 :SHT45的供电电压范围为1.08V至3.6V,请连接至树莓派的3.3V引脚,切勿连接5V引脚,以免损坏传感器。
-
线路检查:完成接线后,请再次确认SDA接GPIO2、SCL接GPIO3,GND和VCC不要接反。
-
上拉电阻:树莓派的GPIO引脚内部已集成I2C上拉电阻,一般情况下无需外接上拉电阻。
4. 启用树莓派I2C接口
在进行Python编程之前,需要确保树莓派的I2C接口已正确启用,如未启用才考我树莓派学习笔记1。
4.1 安装I2C工具和Python库
重启后,打开终端,安装所需的工具和库:
python
# 更新软件包列表
sudo apt update
# 安装I2C工具和Python SMBus库
sudo apt install i2c-tools python3-smbus -y
📖 说明 :
i2c-tools提供了i2cdetect、i2cget等命令行调试工具;python3-smbus则提供了Python中操作I2C的底层接口-53。
4.2 验证设备识别
安装完成后,执行以下命令扫描I2C总线上的设备:
sudo i2cdetect -y 1
结果如图:

⚠️ 注意:SHT4x系列的I2C地址出厂时固定为0x44,无法更改-。如果扫描不到该地址,请重新检查接线。
5. 理解SHT45的通信方式
在编写Python代码之前,需要先理解SHT45独特的通信机制。这与传统的寄存器型I2C设备有很大不同。
5.1 SHT45没有寄存器地址
SHT45与传统的I2C设备(如EEPROM、PCF8591等)不同,它没有寄存器地址的概念。SHT45的通信是通过发送"命令码(Command Code)"来完成的,不同的命令码对应不同的操作-。
5.2 常用命令码
SHT45支持以下测量命令码-:
| 命令码(十六进制) | 功能说明 | 等待时间 |
|---|---|---|
| 0xFD | 高精度测量(推荐) | 约10 ms |
| 0xF6 | 中精度测量 | 约5 ms |
| 0xE0 | 低精度测量 | 约2 ms |
5.3 I2C通信时序
读取SHT45数据的完整通信流程如下:
步骤1: 主机发送START信号
步骤2: 主机发送设备地址0x44 + 写标志位(0x88)
步骤3: 主机发送命令码(如0xFD)
步骤4: 主机发送STOP信号
步骤5: 等待传感器完成测量(10~20毫秒)
步骤6: 主机发送START信号
步骤7: 主机发送设备地址0x44 + 读标志位(0x89)
步骤8: 从机返回6字节数据(温湿度各2字节+CRC各1字节)
步骤9: 主机发送STOP信号
💡 提示 :步骤3发送命令码时,需要注意SHT45没有寄存器地址,因此不能使用
write_byte_data()这类带寄存器地址的函数,而应使用write_byte()函数直接发送命令码。
6. 方法一:使用smbus2库手动读取
6.1 安装smbus2库
python
sudo apt install python3-smbus2
6.2 完整代码实现
创建Python脚本文件read_sht45.py,输入以下代码:
python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import smbus2
import time
# 配置常量
I2C_BUS = 1 # 树莓派I2C总线编号
SHT45_ADDRESS = 0x44 # SHT45的I2C设备地址
# SHT45命令码定义
CMD_MEASURE_HIGH_PRECISION = 0xFD # 高精度测量
CMD_MEASURE_MEDIUM_PRECISION = 0xF6 # 中精度测量
CMD_MEASURE_LOW_PRECISION = 0xE0 # 低精度测量
def crc8(data):
"""
计算SHT45使用的CRC-8校验值
多项式: x^8 + x^5 + x^4 + 1 (0x31)
初始值: 0xFF
"""
crc = 0xFF
for byte in data:
crc ^= byte
for _ in range(8):
if crc & 0x80:
crc = (crc << 1) ^ 0x31
else:
crc <<= 1
crc &= 0xFF
return crc
def read_sht45_data(bus, cmd=CMD_MEASURE_HIGH_PRECISION):
"""
从SHT45读取温湿度数据
参数:
bus: smbus2总线对象
cmd: 测量命令码(可选高/中/低精度)
返回:
(温度, 湿度) 元组,失败时返回(None, None)
"""
try:
# 步骤1: 发送测量命令(注意:SHT45没有寄存器地址,直接发送命令码)
bus.write_byte(SHT45_ADDRESS, cmd)
# 步骤2: 等待传感器完成测量
# 根据不同的命令码等待不同时间
if cmd == CMD_MEASURE_HIGH_PRECISION:
time.sleep(0.015) # 高精度约15ms
elif cmd == CMD_MEASURE_MEDIUM_PRECISION:
time.sleep(0.007) # 中精度约7ms
else:
time.sleep(0.003) # 低精度约3ms
# 步骤3: 读取6字节数据(温度2字节+CRC1字节+湿度2字节+CRC1字节)
# 注意:SHT45没有寄存器地址,所以第二个参数使用0x00作为占位符
data = bus.read_i2c_block_data(SHT45_ADDRESS, 0x00, 6)
# 数据格式: data[0]=温度高8位, data[1]=温度低8位, data[2]=温度CRC
# data[3]=湿度高8位, data[4]=湿度低8位, data[5]=湿度CRC
# 验证温度数据的CRC校验
temp_crc = crc8(data[0:2])
if temp_crc != data[2]:
print("温度数据CRC校验失败")
return None, None
# 验证湿度数据的CRC校验
hum_crc = crc8(data[3:5])
if hum_crc != data[5]:
print("湿度数据CRC校验失败")
return None, None
# 解析原始数值
temp_raw = (data[0] << 8) | data[1]
humidity_raw = (data[3] << 8) | data[4]
# 转换为实际物理值
# 温度转换公式: T = -45 + 175 * (temp_raw / 65535)
temperature = -45.0 + 175.0 * (temp_raw / 65535.0)
# 湿度转换公式: RH = -6 + 125 * (humidity_raw / 65535)
humidity = -6.0 + 125.0 * (humidity_raw / 65535.0)
# 湿度限制在0~100%范围内
humidity = max(0.0, min(100.0, humidity))
return temperature, humidity
except Exception as e:
print(f"读取数据失败: {e}")
return None, None
def main():
# 初始化I2C总线
bus = smbus2.SMBus(I2C_BUS)
print(f"SHT45温湿度传感器已初始化(地址: 0x{SHT45_ADDRESS:02X})")
print("开始读取数据...")
print("-" * 40)
try:
while True:
# 读取温湿度数据
temp, hum = read_sht45_data(bus, CMD_MEASURE_HIGH_PRECISION)
if temp is not None and hum is not None:
print(f"温度: {temp:.2f} °C | 相对湿度: {hum:.1f} %RH")
else:
print("读取数据失败,请检查传感器连接")
# 每隔1秒读取一次
time.sleep(1)
except KeyboardInterrupt:
print("\n程序已停止")
finally:
bus.close()
if __name__ == "__main__":
main()
6.3 代码逐行解析
导入模块
python
import smbus2 # 提供I2C通信功能
import time # 提供延时功能
定义常量
python
I2C_BUS = 1 # 树莓派I2C总线编号
SHT45_ADDRESS = 0x44 # SHT45的I2C设备地址
CMD_MEASURE_HIGH_PRECISION = 0xFD # 高精度测量命令
💡 注意:SHT45的命令码是直接通过I2C总线发送的,不需要像传统I2C设备那样指定寄存器地址-。
🔒 CRC-8校验函数
python
def crc8(data):
crc = 0xFF
for byte in data:
crc ^= byte
for _ in range(8):
if crc & 0x80:
crc = (crc << 1) ^ 0x31
else:
crc <<= 1
crc &= 0xFF
return crc
SHT45返回的6字节数据中包含两个CRC校验字节,分别校验温度数据和湿度数据的完整性。CRC多项式为x^8 + x^5 + x^4 + 1(0x31),初始值为0xFF。在数据解析时验证CRC可以确保通信过程中没有发生错误。
📖 数据读取与解析
python
# 步骤1: 发送测量命令
bus.write_byte(SHT45_ADDRESS, cmd)
# 步骤2: 等待测量完成
time.sleep(0.015)
# 步骤3: 读取6字节数据
data = bus.read_i2c_block_data(SHT45_ADDRESS, 0x00, 6)
⚠️ 关键点 :
read_i2c_block_data()的第二个参数是寄存器地址,由于SHT45没有寄存器,我们使用0x00作为占位符。实际通信时,该函数会先发送设备地址+写标志(准备读取),然后发送一个寄存器地址字节(0x00),最后再重新发送设备地址+读标志来读取数据。对于SHT45,中间的0x00字节会被传感器忽略。
📐 数据转换公式
python
# 温度转换: T = -45 + 175 * (原始值 / 65535)
temperature = -45.0 + 175.0 * (temp_raw / 65535.0)
# 湿度转换: RH = -6 + 125 * (原始值 / 65535)
humidity = -6.0 + 125.0 * (humidity_raw / 65535.0)
这是SHT4x系列传感器的标准转换公式,其中65535是16位无符号整数的最大值。
6.4 运行代码
在终端中执行:
python
python3 read_sht45.py
预期输出示例:
SHT45温湿度传感器已初始化(地址: 0x44)
开始读取数据...
----------------------------------------
温度: 24.56 °C | 相对湿度: 45.2 %RH
温度: 24.58 °C | 相对湿度: 45.3 %RH
温度: 24.55 °C | 相对湿度: 45.1 %RH
...
按Ctrl + C可停止程序。
7. 方法二:使用Adafruit CircuitPython库(推荐)
如果你希望代码更简洁,可以使用Adafruit官方提供的CircuitPython库,它将底层细节封装得更加完善。
7.1 安装Adafruit库
python
# 安装Adafruit Blinka(CircuitPython的Linux兼容层)
sudo pip3 install adafruit-blinka
# 安装SHT4x传感器库
sudo pip3 install adafruit-circuitpython-sht4x
7.2 简洁版代码
创建脚本read_sht45_simple.py:
python
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import time
import board
import adafruit_sht4x
# 初始化I2C总线
i2c = board.I2C() # 自动使用board.SCL和board.SDA
# 初始化SHT45传感器
sht = adafruit_sht4x.SHT4x(i2c)
print("SHT45传感器已初始化")
# 可选:设置测量模式
# sht.mode = adafruit_sht4x.Mode.NO_HEAT_HIGH # 高精度模式(默认)
while True:
# 读取温湿度数据
temperature, relative_humidity = sht.measurements
print(f"温度: {temperature:.2f} °C")
print(f"相对湿度: {relative_humidity:.1f} %RH")
print("")
time.sleep(1)
7.3 两种方法的对比
| 特性 | smbus2手动实现 | Adafruit库 |
|---|---|---|
| 代码复杂度 | 较高(需手动处理CRC和转换) | 极低(仅3行核心代码) |
| 可控性 | 完全可控,适合学习底层原理 | 底层细节已封装 |
| CRC校验 | 需要手动实现 | 库内部已处理 |
| 适用场景 | 教学演示、深度定制 | 项目开发、快速原型 |
💡 建议:如果你是初学者或希望快速完成项目开发,推荐使用方法二(Adafruit库);如果你是希望深入学习I2C通信原理,建议仔细研究第一种方法的实现细节。
8. 故障排查指南
8.1 扫描不到0x44地址
| 故障现象 | 可能原因 | 解决方法 |
|---|---|---|
i2cdetect输出全是-- |
I2C未启用 | 执行sudo raspi-config重新启用I2C |
| 扫描不到0x44 | 接线错误 | 检查SDA/SCL是否接反或接触不良 |
| 扫描不到0x44 | 供电问题 | 确认SHT45连接的是3.3V引脚,不是5V |
| 扫描到其他地址 | 地址冲突 | SHT45地址固定为0x44,若有冲突需更换设备 |
8.2 读取数据时返回错误
| 错误信息 | 可能原因 | 解决方法 |
|---|---|---|
[Errno 121] Remote I/O error |
通信超时 | 检查接线,增加等待时间 |
CRC校验失败 |
数据传输错误 | 检查是否有电磁干扰,缩短连线长度 |
| 温度值异常(如-45°C) | 未正确发送测量命令 | 确认使用的是write_byte()而非write_byte_data() |
| 湿度值为负数 | 数据解析错误 | 检查转换公式中的除数和乘数是否正确 |
8.3 数据读取不稳定的解决方法
-
增加等待时间 :将
time.sleep(0.015)适当增加至20~30毫秒 -
检查电源稳定性:使用树莓派自带的3.3V供电,避免与其他大功率设备共用
-
降低I2C速率 :某些SHT45模块对时钟频率敏感,可在
/boot/config.txt中添加dtparam=i2c_arm_baudrate=100000将速率降至100kHz
9. 本章小结
本章围绕SHT45温湿度传感器,详细介绍了树莓派通过I2C接口读取温湿度数据的完整流程。主要知识点包括:
-
SHT45硬件接线:VCC→3.3V、GND→GND、SDA→GPIO2、SCL→GPIO3
-
I2C接口启用 :通过
raspi-config配置和i2c-tools验证 -
SHT45通信机制:命令码式通信(无寄存器地址),先发命令再读数据
-
Python编程方法:
-
底层手动实现:使用
smbus2库,掌握CRC校验和数据转换 -
高层库实现:使用
Adafruit CircuitPython库,快速上手
-
-
数据转换公式:温度T = -45 + 175×(原始值/65535),湿度RH = -6 + 125×(原始值/65535)
如欲继续学习,可参考本书后续章节关于将温湿度数据写入数据库、搭建Web监控界面或结合机器学习进行环境预测等内容。