news 2026/9/7 5:54:02

SHT3x温湿度传感器实战:从I2C通信到CRC校验的完整驱动指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
SHT3x温湿度传感器实战:从I2C通信到CRC校验的完整驱动指南

简介:SHT3x高精度温湿度传感器是盛思锐(Sensirion)推出的数字温湿度检测器件,采用CMOSens®技术,可同时输出温度与相对湿度。围绕该传感器整理的代码包面向嵌入式开发者、STM32用户及电子竞赛爱好者,可帮助快速完成驱动移植、数据解析与项目集成,适用于环境监测、智能家居、工业自动化等场景。压缩包共13个文件,以sht3x.c/h等C源码与头文件为核心,覆盖I²C接口配置、测量命令发送、原始数据读取及温湿度换算逻辑;同时包含Keil工程文件(uvproj/uvopt)、STM32启动汇编文件、Readme说明和PDF结构指南,文件类型覆盖源码、工程配置与文档,便于直接导入工程进行编译与调试,也适合按目录逐层学习。资源整体仅34KB,体积轻盈,目前已有995人学习。配套文档对初始化、单次/连续测量、数据解析和错误处理等关键环节做了梳理,能帮助开发者理解底层交互原理,并在实际项目中快速复用与二次开发。

1. 先说结论:为什么我最终选了SHT3x而不是DHT11

做环境监测类项目时,温湿度传感器几乎是绕不开的器件。市面上最常见的DHT11便宜、资料多、教程一搜一大把,但如果你做过几次正经的数据记录或者产品原型,大概率会碰到它的一些硬伤:精度一般、响应偏慢、时序要求苛刻,最难受的是不同批次之间一致性不太行,同一批买回来的几个模块读出来的数能差出两三度。

SHT3x是Sensirion家的数字温湿度传感器,典型精度能做到±2%RH和±0.2°C(SHT35甚至更高),I2C接口,自带CRC8校验,还支持周期测量、加热器等功能。对于需要稳定、精确数据的上位机应用,或者想在STM32、ESP32上快速集成的场景,SHT3x比DHT11省心得多。这篇文章就把我实际调SHT3x的完整思路、代码细节和踩坑记录整理出来,适合正在做嵌入式驱动、环境数据采集或想把手头DHT11项目升级一下的朋友参考。

有人可能担心SHT3x比DHT11贵,这确实是个现实问题。但换个角度想:如果项目要过计量、要长期运行、要远程上报数据,那传感器本身的成本差异远小于后期返工调试的代价。我自己是从DHT11一路用过来的,后来转SHT30之后基本没有再为温湿度数据的可靠性头疼过。

2. 硬件接口与通信协议:弄懂I2C上的这几个坑

2.1 引脚、I2C地址与上拉电阻的选型逻辑

SHT3x的标准封装是DFN-8,一共8个引脚,但实际用到的就4个:VDD、GND、SDA、SCL,外加一个可选的ADDR引脚用于修改I2C地址,还有几个不接的保留引脚。最关键的是把ADDR处理对,因为它的电平直接决定I2C地址:

ADDR引脚状态I2C 7位地址
接GND或悬空0x44
接VDD0x45

很多新手第一次调试时读不到数据,十有八九是地址搞错了。I2C总线允许挂多个SHT3x,就是靠ADDR引脚区分,一个系统里最多能挂两个。实际布线时SDA和SCL都需要接上拉电阻,常见取值4.7kΩ,但如果你用的是400kHz快速模式,建议换成2.2kΩ或3.3kΩ,否则上升沿太慢容易导致通信不稳定。我习惯在传感器模块上直接焊10kΩ上拉,然后MCU那边再开内部上拉,两个并联大约5kΩ左右,也够用。

供电方面SHT3x支持2.4V到5.5V,但需要注意的是,如果MCU的IO电平是3.3V,传感器也最好用3.3V供电,避免I2C电平不匹配。5V供电时接口电平会偏高,部分MCU的IO不一定承受得住。我见过有人用5V供电然后把SCL/SDA直接连到3.3V的ESP32,虽然短期内没烧,但长期可靠性确实是个隐患。

2.2 测量命令与时序:单次测量和周期测量怎么选

SHT3x的命令集分为两大块:单次测量模式和周期测量模式。单次测量模式适合按需读取的场景,比如低功耗设备每隔几秒醒来采一次数据;周期测量模式则适合持续监测,传感器会按设定频率自动测量并缓存结果,主机随时可以读取。

单次测量模式下的常用命令:

命令值说明
0x2C06高频(mps=10),重复性高
0x2C10中频(mps=10),重复性中
0x2C0D低频(mps=10),重复性低
0x2400低频(mps=1),重复性低

重复性会影响测量噪声和功耗,但不会显著影响精度。如果项目对响应速度要求不高、电池供电,优先选0x2400;如果数据波动较大、希望读数更平稳,就选0x2C06。注意这是所谓的“高频”不是测量速度更快,而是传感器内部采样平均次数更多,噪声更低。别被命名误导了。

周期测量模式常用的命令有0x2130(0.5 mps)、0x2132(1 mps)等,这里mps是每秒测量次数。周期模式的优点是主控不必每次发起测量命令,能省掉一部分通信时间,适合数据需要连续刷新的场景,但我个人在大多数项目里还是用单次模式,逻辑更简单,也不容易出状态机问题。

2.3 CRC8校验:不校验等于埋雷

I2C本身只保证数据帧的传输完整性,不保证内容正确。传感器测量值在传输过程中如果被干扰,读回来可能就是错的。SHT3x对每条测量数据都附带一个CRC8校验字节,这一点是它比很多国产传感器厚道的地方。但反过来说,很多人的代码里压根没写校验函数,等于没利用这个特性。

CRC8的算法是多项式0x31(x^8 + x^5 + x^4 + 1),初值0xFF,按位处理。实现并不复杂,几十行C代码就搞定。后面的代码示例里我会给出直接能用的实现,读者可以直接复制进工程。一定要在读完数据之后校验,校验失败就重读或者报错,而不是硬着头皮用错误数据。

还有一个细节:读温度后跟的CRC校验字节,对应的只是温度两个字节;读湿度后跟的CRC校验字节,对应的只是湿度两个字节。也就是说读6个字节:温高、温低、温CRC、湿高、湿低、湿CRC。别把顺序搞反了,我见过有人把第三字节当成湿度的,结果读数怎么算都不对。

3. 核心代码实现:从裸机I2C读到完整驱动

3.1 读取一帧数据的完整流程

SHT3x的读取流程其实非常清晰,就三步:发命令、等转换、读数据。转换时间跟重复性设置有关,高频模式下典型等待时间是7.5ms左右,中频是6.5ms,低频是4.5ms。工程上为了稳妥起见,我都会多留一点余量,比如发完命令后延时10ms再读。

读取流程示意图大致如下:

  1. 主机发送I2C起始条件
  2. 发送传感器地址+写位(0x88,即0x44左移一位)
  3. 发送两个字节的命令
  4. 主机发送停止条件
  5. 延时等待(建议10ms,保守一点15ms也可以)
  6. 主机发送起始条件
  7. 发送传感器地址+读位(0x89,即0x44左移一位加1)
  8. 连续读取6个字节,每读一个字节后主机回应ACK,读最后一个字节时应回NACK
  9. 主机发送停止条件
  10. 对温度、湿度数据分别做CRC校验
  11. 用公式计算物理值

3.2 关键代码片段:发送命令与读取数据

下面的代码是基于STM32标准库的HAL风格伪代码加实际可运行逻辑改写的,读者移植到其他平台时只需要替换底层的I2C收发函数即可。

#define SHT3X_ADDR_0 0x44 // ADDR接GND #define SHT3X_ADDR_1 0x45 // ADDR接VDD #define SHT3X_CMD_MEAS_H 0x2C06 // 单次测量:高频,重复性高 uint8_t crc8(const uint8_t *data, size_t len) { uint8_t crc = 0xFF; for (size_t i = 0; i < len; i++) { crc ^= data[i]; for (uint8_t bit = 0; bit < 8; bit++) { if (crc & 0x80) crc = (crc << 1) ^ 0x31; else crc <<= 1; } } return crc; }

实际上在每个项目里,还要细分出I2C起始/停止/读写字节函数。如果用的是HAL库,可以这样封装命令发送:

uint8_t sht3x_send_command(uint16_t cmd) { uint8_t buf[2]; buf[0] = (uint8_t)(cmd >> 8); buf[1] = (uint8_t)(cmd & 0xFF); // 如果使用HAL库 if (HAL_I2C_Master_Transmit(&hi2c1, SHT3X_ADDR_0 << 1, buf, 2, 100) != HAL_OK) return 1; return 0; }

发送命令时,8位地址是7位地址左移一位拼上读写位。0x44左移一位是0x88,0x45左移一位是0x8A,这个细节在HAL库的API里经常被忽略。

读取测量结果的函数:

typedef struct { float temperature; float humidity; } sht3x_data_t; uint8_t sht3x_read_data(sht3x_data_t *out) { uint8_t buf[6] = {0}; // 发测量命令 if (sht3x_send_command(SHT3X_CMD_MEAS_H)) return 1; // 等待转换完成 delay_ms(10); // 读取6字节数据:温度高、温度低、温度CRC、湿度高、湿度低、湿度CRC if (HAL_I2C_Master_Receive(&hi2c1, (SHT3X_ADDR_0 << 1) | 1, buf, 6, 100) != HAL_OK) return 2; // CRC校验 if (crc8(&buf[0], 2) != buf[2]) return 3; if (crc8(&buf[3], 2) != buf[5]) return 4; // 计算物理量 uint16_t raw_temp = ((uint16_t)buf[0] << 8) | buf[1]; uint16_t raw_humi = ((uint16_t)buf[3] << 8) | buf[4]; out->temperature = -45.0f + 175.0f * (float)raw_temp / 65535.0f; out->humidity = 100.0f * (float)raw_humi / 65535.0f; return 0; }

有个容易忽略的小问题:如果使用纯软件模拟I2C,那每一帧的起始和停止条件都要严格符合时序要求。SHT3x的最高I2C频率支持到1MHz,但用软件模拟时建议控制在100kHz到400kHz之间,频率太高容易因为GPIO翻转速度不足导致数据错误。实测下来,400kHz在大部分MCU上是极限了,再高就要用硬件I2C。

3.3 从裸数据到真实温湿度:公式背后的原理

SHT3x输出的原始数据是16位无符号整数,范围0到65535,对应不同的物理范围。官方公式:

  • 温度:T = -45 + 175 × raw / 65535
  • 湿度:RH = 100 × raw / 65535

从公式可以看出,温度原始值0对应-45°C,65535对应130°C。湿度原始值0对应0%,65535对应100%。精度上,16位ADC换算出来的分辨率为0.01°C和0.01%RH左右,远超传感器本身的精度指标,所以不用担心中间计算会产生额外误差。

浮点运算在PC端或带FPU的MCU上都不是问题,但如果你用的是老旧的8位单片机,比如STC89C52这种,浮点运算会拖慢速度。这种情况下可以先用整数计算把结果放大100倍存储,最后需要输出时再转字符串。个人经验是,SHT3x的实际应用场景基本是32位MCU,浮点不是瓶颈,别过度优化。

4. 常见问题排查与经验心得

4.1 问题速查表

症状可能原因解决方案
一直读不到设备,I2C返回超时地址错误确认ADDR引脚电平,核对0x44/0x45
读到的温湿度为0或固定值数据字节顺序弄反检查6字节的顺序:温高、温低、温CRC、湿高、湿低、湿CRC
读数有跳变或错误值缺少CRC校验加上CRC8校验,错误时重读
读数偏高传感器附近有发热器件远离功率电阻、LDO、MCU
湿度读数持续偏低传感器暴露在气流中或PCB受热加防风罩,优化布局
I2C偶尔死锁总线被拉低,从机卡在中间状态重启总线(将SCL翻转9次)或断电复位

4.2 我踩过的坑和容易忽略的细节

先说I2C总线的死锁问题。传感器在测量过程中如果主机强行发起通信,有时候从机内部状态机会卡住,把SDA线拉低不放。这个时候最有效的恢复方式是把SCL时钟翻转9次,让从机退出异常状态,然后发送一个STOP条件。我在代码里会加一个总线恢复函数,在主循环初始化时调用,能显著减少运行期故障。

第二个坑是转换时间。很多例程里写的延时是“至少7ms”,但实际上在低温或高湿环境下,传感器转换时间可能会有少量波动,保守起见延时10到15ms更稳。自己打样测试时,把延时缩到5ms,结果发现大约每几十次就有一次读回全FF或者CRC错误,恢复延时之后问题消失。传感器转换时间这类参数,规格书给的是典型值,量产阶段要考虑最坏情况。

第三个问题是自发热。SHT3x本身功耗很低,但如果你把它紧挨着LDO或者WIFI模组,那测出来的温度会明显偏高。我见过有人把传感器贴在STM32主控旁边,测出来的温度比环境温度高3°C以上。解决办法是传感器脚和主控之间留空气间隔,或者用FPC软排线引出来,让传感器处于远离热源的位置。这个细节尤其影响精密测量场景,比如粮食仓储、药品运输、实验室环境监测。

第四个是湿度传感器的老化与污染问题。SHT3x虽然比DHT11耐造,但长期暴露在有机溶剂、烟雾、高浓度粉尘环境中,湿度测量值会出现漂移。Sensirion官方建议在PCBA清洗后要让传感器在正常环境条件下通风恢复一段时间再进行标定。另外,传感器表面不要用手直接触摸,油脂会显著影响湿度响应,这一点在装配调试环节特别容易翻车,因为我们调试时常会用手拿板子对比读数。

4.3 周期测量与低功耗调优

如果设备靠电池供电,单次测量模式是首选——平时让传感器处于休眠状态,需要数据时唤醒发送命令,读完后立即进入空闲。SHT3x待机电流实测可以做到0.2μA左右,完全不影响电池寿命。而周期测量模式下,传感器会保持活跃状态,功耗虽然也不高,但对低功耗设备的整体续航还是会有影响。

另外,SHT3x内置的加热器功能建议慎用。它可以用来去除传感器表面的冷凝水,但加热期间温度读数会显著偏高,最多可以高出十几度。除非是做防凝露场景,否则别在正常测量流程里打开加热器。我在做室内空气质量监测时,环境湿度长期偏高导致传感器内部结露,读数一直稳定在99%RH,后来靠加热器工作了几秒钟才恢复,但加热后至少需要几十秒等待温度回稳,这时候记录的数据是要丢弃的。

5. 一些最终建议:哪种情况下SHT3x才是最优解

做了几个月的SHT3x驱动开发后,我最大的体会是:传感器的选型决定了项目的天花板,而代码质量决定了项目的地板。SHT3x用起来简单,几行代码就能读到数据,但要让它长期稳定、可靠地工作,还是得在I2C时序、CRC校验、硬件布局上多花心思。

如果你的项目满足以下任意一条,我强烈建议考虑SHT3x:

  • 温湿度数据需要用于判断逻辑,比如控制加热除湿设备、空凋联动
  • 数据需要远程传输,无法人工核对,比如大棚监控、冷链运输
  • 设备安装位置不方便二次维护,比如密封的配电柜、户外气象站
  • 同一批设备需要一致性好、可比的测量结果

如果只是做个课堂作业,或者对精度完全不敏感,DHT11也能用,但我还是建议你把SHT3x的驱动框架搭一遍。这个传感器虽然是I2C接口,但它的命令设计非常规范,把CRC校验、状态机处理、异常恢复这些基础功打扎实了,以后换其他I2C传感器也会顺手很多。再加上SHT3x的代码量并不大,作为学习硬件通信协议的入门案例,我觉得比单纯调一个DHT11的时序有意思多了。

最后再分享一个小习惯:代码里把I2C读写返回的错误码定义清楚并打印出来。刚开始调SHT3x时我偷懒,只要读不到就一直重试,屏幕上什么也不打印,结果一个问题查了一下午。后来把每一步返回的错误码细化,分成了设备未响应、命令发送失败、CRC校验失败、数据超范围四类,再配合逻辑分析仪看波形,基本十分钟就能定位问题所在。好的驱动不是写完就完事,它是给未来半年后的自己留的退路。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/7 5:52:19

Agent Skill开发实战:SKILL.md、scripts、references三件套全解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/7 5:52:17

OSGEarth实战:预编译3rdParty库配置与FeatureNode点判断

简介&#xff1a;在Visual Studio 2019环境下编译OSG 3.6.5与OSGEarth 2.10时&#xff0c;第三方依赖库往往是最大的拦路虎。这份预编译好的64位三方库压缩包专门面向此类开发者&#xff0c;已包含用于编译OSG 3.6.5和OSGEarth 2.10的第三方依赖组件&#xff0c;可直接用于CMak…

作者头像 李华
网站建设 2026/9/7 5:52:10

AMD Ryzen AI Max+ 395 部署 ComfyUI 完整实战:核显跑 AI 生图

我之前在一台AMD Ryzen AI Max 395的准系统主机上折腾了一周&#xff0c;把Ubuntu Server 24.04 ComfyUI跑通&#xff0c;中间踩了不少坑&#xff0c;也把一些关键参数摸清楚了。这台机器比较特殊&#xff0c;它不像普通台式机那样有独立显卡&#xff0c;而是把所有算力都塞进…

作者头像 李华
网站建设 2026/9/7 5:52:05

DLSS 5泄露揭秘:驱动改写游戏角色的AI渲染技术与驱动升级实战

最近几天我的私信和群里都在刷同一个话题&#xff1a;DLSS 5的泄露截图和驱动字符串。引爆点的说法很玄乎——显卡驱动开始改写游戏角色了。乍一看像标题党&#xff0c;但如果你长期关注过AI超分、帧生成和神经渲染&#xff0c;就会明白这个方向其实早就有伏笔。这篇文我会做三…

作者头像 李华
网站建设 2026/9/7 5:48:57

Java 21 企业级 AI Agent:受控智能体模式实现可靠可控安全

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华