08 - SHT20 温湿度应用
本章节介绍 Pico-G1 扩展板上的 SHT20 温湿度传感器应用示例 —— sht20_display。该应用演示了如何使用 I2C 接口读取 SHT20 传感器的温度和湿度数据,并在 TFT 屏幕上实时显示环境信息。这是学习 I2C 环境监测传感器的基础示例。
应用源码位于 SDK 目录 source/app/08_sht20_display/,提供了完整的 I2C 温湿度传感器读取实现。
1 应用概述
1.1 功能特性
- I2C 温湿度读取:通过 I2C 接口读取 SHT20 温湿度数据
- 环境监测:实时显示当前环境温度和湿度
- 高精度显示:支持 0.1°C 温度和 1% 湿度精度
- 多芯片兼容:支持 SHT20/SI7021/HTU21 等兼容芯片
1.2 技术参数
| 参数 | 值 |
|---|---|
I2C 接口 | I2C3(/dev/i2c-3) |
从地址 | 0x40 |
温度范围 | -40~125°C |
湿度范围 | 0~100% RH |
温度精度 | ±0.3°C |
湿度精度 | ±2% RH |
刷新频率 | 2秒(可配置) |
1.3 测试用例列表
| index | 名称 | 测试指令 | 预期现象(成功) | 失败可能原因 |
|---|---|---|---|---|
| 1 | 基础读数 | ./sht20_display | TFT显示温湿度值,控制台输出数据 | I2C连接失败、地址错误 |
| 2 | 温度变化 | 手温传感器 | 温度值上升2~5°C | 传感器响应慢、接触不良 |
| 3 | 湿度变化 | 向传感器哈气 | 湿度值上升10~20% | 传感器污染、湿度测量延迟 |
1.4 目录结构
source/app/08_sht20_display/
├── Makefile # 构建脚本
├── main.c # 主程序
├── sht20.c # SHT20 驱动实现
├── sht20.h # SHT20 驱动头文件
├── i2c_hal.c # I2C HAL 层实现
├── i2c_hal.h # I2C HAL 层头文件
├── spi_hal.c # SPI HAL 层实现
├── spi_hal.h # SPI HAL 层头文件
├── st7789.c # ST7789 驱动实现
├── st7789.h # ST7789 驱动头文件
├── font8x16.h # 8×16 ASCII 点阵字库
└── README.md # 说明文档2 硬件连接说明
2.1 引脚定义
| 信号 | 板上 GPIO | 控制器 / 节点 | 说明 |
|---|---|---|---|
| SCL | GPIO4_1 | I2C3 → /dev/i2c-3 | 与 OLED/MPU6050 共享 I2C3 总线 |
| SDA | GPIO4_2 | I2C3 → /dev/i2c-3 | 共享总线 |
| VCC | 3.3V | — | SHT20 供电 2.1~3.6V |
| GND | GND | — | 地线 |
2.2 硬件电路
SHT20 接线图:
Pico-G1 SHT20 Module
┌───────────┐ ┌──────────────┐
│ │ │ │
│ GPIO4_1 ──┼────── SCL ───┤ SCL │
│ │ │ │
│ GPIO4_2 ──┼────── SDA ───┤ SDA │
│ │ │ │
│ 3.3V ───┼─────────────┤ VCC │
│ │ │ │
│ GND ───┼─────────────┤ GND │
└───────────┘ └──────────────┘芯片兼容性
SHT20、SI7021、HTU21 三种芯片 I2C 地址和命令兼容,可以互换使用。
3 编译与部署
3.1 编译应用
export PATH=$PATH:<SDK>/tools/linux/toolchains/arm-gcc12.2.0-linux-uclibceabi/bin
cd <SDK>/source/app/08_sht20_display
make3.2 运行应用
scp sht20_display root@<板端IP>:/usr/bin/
ssh root@<板端IP> '/usr/bin/sht20_display'3.3 预期输出
控制台输出
/mnt # ./sht20_display
[sht20] pad 复用:I2C3(4_1/4_2) -> func2
[sht20] pad 0x100C0010 -> 0x00001002
[sht20] pad 0x100C0014 -> 0x00001002
[sht20] 初始化 SPI 屏(/dev/spidev2.0)...
[spi] pad 0x100C0028 -> 0x00001004
[spi] pad 0x100C002C -> 0x00001004
[spi] pad 0x100C0030 -> 0x00001000
[spi] pad 0x100C0020 -> 0x00001005
[spi] pad 0x100C001C -> 0x00001005
[spi] opening /dev/spidev2.0 ...
[spi] spidev opened, fd=3
[spi] spidev mode/bits/speed set (MODE3/8b/24MHz)
[spi] chardev request DC @ /dev/gpiochip4 line 5 ...
[spi] chardev request RES @ /dev/gpiochip4 line 4 ...
[spi] chardev request CS @ /dev/gpiochip5 line 1 ...
[spi] chardev-verify: DC=0(expect0) RES=1(expect1) CS=1(expect1) ==> OK(chardev 真驱动了引脚)
[spi] spi_hal_init done
[tft] init: SLPOUT
[tft] init: SLPOUT +120ms ok
[tft] init: config cmds ok
[tft] init: DISPON
[tft] init: DISPON ok
[tft] init: clear-flush start
[tft] flush #1 start
[tft] flush #1 done
[tft] init: clear-flush done
[sht20] 初始化 SHT20(/dev/i2c-3 addr 0x40)...
[sht20] @ /dev/i2c-3 addr 0x40 就绪 (user_reg=0x3A)
[sht20] 采集中,每 2s 刷新,Ctrl+C 退出。
[sht20] T=23.7 C RH=60.5 %TFT 屏幕显示

4 SHT20 温湿度原理
4.1 I2C 通信协议
SHT20 使用标准 I2C 协议进行通信:
- 从地址:0x40(写地址 0x80,读地址 0x81)
- 支持速度:标准模式(100kHz)和快速模式(400kHz)
- 数据格式:16位测量数据 + 8位 CRC 校验
4.2 温湿度测量命令
| 命令名称 | 命令代码 | 说明 |
|---|---|---|
| 温度保持 | 0xE3 | Hold Master 模式 |
| 温度非保持 | 0xF3 | No Hold Master 模式 |
| 湿度保持 | 0xE5 | Hold Master 模式 |
| 湿度非保持 | 0xF5 | No Hold Master 模式 |
4.3 数据转换公式
温度计算:
float sht20_convert_temperature(uint16_t raw_temp)
{
return -46.85f + 175.72f * (raw_temp / 65536.0f);
}湿度计算:
float sht20_convert_humidity(uint16_t raw_humi)
{
return -6.0f + 125.0f * (raw_humi / 65536.0f);
}5 关键编程要点
5.1 I2C 设备操作
打开 I2C 设备:
int i2c_open(const char *i2c_bus, uint8_t device_addr)
{
int fd = open(i2c_bus, O_RDWR);
if (fd < 0) return -1;
if (ioctl(fd, I2C_SLAVE, device_addr) < 0) {
close(fd);
return -1;
}
return fd;
}5.2 温湿度读取实现
读取温度数据:
float sht20_read_temperature(int i2c_fd)
{
uint8_t cmd = 0xE3; // 温度保持命令
uint8_t data[3];
i2c_write_byte(i2c_fd, SHT20_ADDR, &cmd, 1);
usleep(85000); // 等待测量完成
i2c_read_bytes(i2c_fd, SHT20_ADDR, data, 3);
uint16_t raw_temp = (data[0] << 8) | data[1];
return sht20_convert_temperature(raw_temp);
}读取湿度数据:
float sht20_read_humidity(int i2c_fd)
{
uint8_t cmd = 0xE5; // 湿度保持命令
uint8_t data[3];
i2c_write_byte(i2c_fd, SHT20_ADDR, &cmd, 1);
usleep(30000); // 等待测量完成
i2c_read_bytes(i2c_fd, SHT20_ADDR, data, 3);
uint16_t raw_humi = (data[0] << 8) | data[1];
return sht20_convert_humidity(raw_humi);
}5.3 CRC 校验
CRC8 校验算法:
bool sht20_check_crc(const uint8_t *data, uint8_t len, uint8_t checksum)
{
uint8_t crc = 0xFF;
for (uint8_t i = 0; i < len; i++) {
crc ^= data[i];
for (uint8_t bit = 8; bit > 0; bit--) {
if (crc & 0x80) {
crc = (crc << 1) ^ 0x131;
} else {
crc = crc << 1;
}
}
}
return (crc == checksum);
}6 常见问题排查
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
| 读数失败 | I2C 连接失败、地址错误 | 检查接线、确认地址 0x40、使用 i2cdetect -y 3 检查设备可见性 |
| 温度异常 | 传感器损坏、接触不良 | 重新连接传感器、更换传感器 |
| 湿度固定 | 校准问题、传感器污染 | 重新校准传感器、清洁传感器 |
| CRC 错误 | I2C 通信干扰、电气噪声 | 检查 I2C 上拉电阻、增加滤波电容 |
| 数值跳动 | 环境变化快、气流不稳定 | 稳定测量环境、使用数据滤波 |
测量建议
为获得最佳测量效果:
- 预热时间:传感器上电后预热 1~2 分钟再开始测量
- 测量位置:避免阳光直射、空调出风口、热源附近
- 定期校准:每6个月校准一次,使用标准温湿度源
7 进阶功能
7.1 数据滤波
滑动平均滤波:
#define FILTER_WINDOW 5
void sht20_filter_add(float temp, float humi)
{
static float temp_buf[FILTER_WINDOW] = {0};
static float humi_buf[FILTER_WINDOW] = {0};
static int index = 0;
temp_buf[index] = temp;
humi_buf[index] = humi;
index = (index + 1) % FILTER_WINDOW;
// 计算平均值
float temp_avg = 0, humi_avg = 0;
for (int i = 0; i < FILTER_WINDOW; i++) {
temp_avg += temp_buf[i];
humi_avg += humi_buf[i];
}
temp_avg /= FILTER_WINDOW;
humi_avg /= FILTER_WINDOW;
printf("[SHT20] 温度: %.1f°C 湿度: %.1f%% (滤波后)\n", temp_avg, humi_avg);
}7.2 温湿度报警
报警检测逻辑:
typedef struct {
float temp_warning_high; // 温度警告上限
float temp_warning_low; // 温度警告下限
float humi_warning_high; // 湿度警告上限
float humi_warning_low; // 湿度警告下限
} sht20_alarm_threshold_t;
sht20_alarm_threshold_t g_alarm_threshold = {
.temp_warning_high = 35.0f,
.temp_warning_low = 15.0f,
.humi_warning_high = 70.0f,
.humi_warning_low = 30.0f,
};
void sht20_check_alarm(float temp, float humi)
{
if (temp > g_alarm_threshold.temp_warning_high) {
printf("[SHT20] 温度过高警告: %.2f°C\n", temp);
}
if (temp < g_alarm_threshold.temp_warning_low) {
printf("[SHT20] 温度过低警告: %.2f°C\n", temp);
}
if (humi > g_alarm_threshold.humi_warning_high) {
printf("[SHT20] 湿度过高警告: %.2f%%\n", humi);
}
if (humi < g_alarm_threshold.humi_warning_low) {
printf("[SHT20] 湿度过低警告: %.2f%%\n", humi);
}
}