SHT30温湿度传感器STM32F4驱动实战:I2C读写与CRC校验
2026/9/3 19:54:40 网站建设 项目流程

简介:面向STM32嵌入式开发者的SHT30温湿度传感器驱动资源,演示如何通过模拟IIC在STM32F407上完成温湿度读取,适合需要掌握IIC时序、传感器寄存器配置的初学者和项目开发者。压缩包共3个文件,包含SHT30.c/H驱动源码与温湿度.pdf说明文档,整体仅858KB;其中C/H文件提供可直接移植的驱动接口,覆盖GPIO模拟SDA/SCL、启动/停止信号、读写地址与数据校验等关键环节,PDF则详细梳理SHT30的7位地址(0x44/0x45)、单次/周期测量模式配置及IIC完整通信步骤,便于对照理解。目前已有1595人学习下载。借助该资源可快速跑通模拟IIC通信流程,省去自行阅读数据手册和反复调试时序的精力,也能为后续接入其他IIC传感器提供清晰的代码范式与排错思路,尤其适合在环境监测、智能家居等场景中快速落地。 解压SHT30温湿度传感器+stm32f4.zip这个压缩包时,我心里大概有数,这又是一套STM32环境采集的常规工程。但把代码完整过了一遍后发现,这个工程包做得比想象中完整,从STM32F407的I2C初始化、SHT30的寄存器读写、CRC校验,到串口输出、Keil5烧录配置都有,不是那种只丢一个main.c的碎片工程。这个项目能解决的问题很直接:用一块Cortex-M4单片机稳定读取SHT30温湿度传感器数据,通过I2C总线把原始数据变成真正的温度湿度数值。整个过程不依赖现成模块库,代码逻辑完全可控,特别适合两类人——一是刚把STM32跑起来、想快速上手一个真实传感器的初学者,二是手里有项目需求、想把SHT30低成本集成进现有固件的老手。

1. 这个工程包到底做了什么

1.1 SHT30:环境采集里非常能打的选手

SHT30是瑞士Sensirion(盛思锐)出的数字温湿度传感器,和传统湿敏电阻方案最大的区别在于:它直接输出经过校准的数字信号,温度和湿度都是16bit精度,不需要自己做校准和多点标定。精度方面,温度典型值±0.3°C,湿度典型值±2%RH,做环境监测、气象站、冷链运输记录、温室大棚控制都绰绰有余。同时它的接口是I2C,最高支持1MHz快速模式+,单次测量命令一次读回6个字节:温度高字节、低字节、温度CRC、湿度高字节、低字节、湿度CRC,数据干净利落,很省心。

我在项目里横向对比过DHT11、AM2302和SHT30。DHT11胜在便宜、程序简单,但精度和一致性只能说“凑合能用”;AM2302某种程度上是DHT11的升级版,测量范围大一些,但时序敏感、每次读取必须严格按照起始信号来,稍不注意就超时。SHT30贵一点,但基本不用调,上电就能拿到稳定数据,长期漂移也小很多。如果是做量产产品,SHT30的性价比其实更高,省掉了大量后期标定和测试时间。

1.2 为什么主控选STM32F4而不选其他

这个工程包选择STM32F4,核心原因不外乎三点:性能充裕、外设丰富、生态成熟。STM32F407主频168MHz,跑I2C这种低速总线完全是杀鸡用牛刀,但正是这种性能冗余给后期扩展留了空间,比如同时挂EMMC存数据、用SPI1接磁编码器MT6701、再接一块LCD屏,CPU也不会卡顿。另外,STM32F4的I2C、SPI、USART、SDIO接口齐全,在一颗芯片上就能完成“传感器采集+数据存储+对外通信”的闭环。相比用51单片机或者F1系列,F4有更大的Flash和RAM,工程里即便加上FatFS文件系统、Modbus协议栈,资源也不会捉襟见肘。

对初学者来说,STM32F4还有一层优势:网上资料特别多。而且工程用Keil5开发,图形化界面配好烧录器之后,点一下Load就能下载程序,调试门槛比Linux板卡低得多。这套方案放在2025年来看依然是最稳妥的入门路线,不会被各种新架构带偏。

1.3 工程包的代码结构长什么样

解压之后,里面的文件路径大概是这样的:

SHT30_STM32F4/ ├── Core/ │ ├── Inc/ │ │ ├── main.h │ │ └── sht30.h │ └── Src/ │ ├── main.c │ └── sht30.c ├── Drivers/ │ ├── CMSIS/ │ └── STM32F4xx_HAL_Driver/ ├── MDK-ARM/ │ ├── Project.uvprojx │ └── ... └── Readme.txt

这个结构是从STM32CubeMX生成的工程模板改过来的,把SHT30驱动单独拆成sht30.c和sht30.h,和主业务逻辑解耦。好处很明显:以后换传感器,只要替换驱动文件,不用动main.c里的业务代码;代码给别人看,也是先看接口再看实现,理解成本低很多。

2. 硬件连接和电路设计里容易忽略的细节

2.1 引脚定义与I2C地址的坑

SHT30的接口很简单,常用引脚就5个:VDD、GND、SCL、SDA、ADDR。默认情况下ADDR接地,器件7位地址是0x44;如果ADDR接VDD,地址变成0x45。我第一次调这块芯片就栽在地址上——HAL库的I2C函数要求传的是8位地址,也就是说要对左移一位,写地址是0x88、读地址是0x89,很多人直接填0x44,结果总线一直NACK,查了整整半天。

STM32F4这边,常用的I2C1引脚是PB6(SCL)和PB7(SDA),I2C2是PB10/PB11,I2C3是PA8/PC9。选哪一路不影响驱动逻辑,但要注意引脚是否和其他外设冲突。这个工程用的是I2C1,接法如下表:

SHT30引脚STM32F4引脚说明
VDD3.3V供电
GNDGND
SCLPB6I2C1时钟线
SDAPB7I2C1数据线
ADDRGND默认地址0x44

2.2 上拉电阻和电源去耦

I2C总线是开漏结构,必须在SCL和SDA上接上拉电阻。很多人第一次画板子会漏掉这一步,然后发现I2C通信时好时坏。上拉电阻阻值取4.7kΩ比较保守,如果总线上设备多或者线比较长,可以降到2.2kΩ;反过来,如果I2C速率高、走线短,10kΩ也能工作。SHT30手册给出的范围是1kΩ到10kΩ,推荐从4.7kΩ起步。

还有一个容易被忽略的点:传感器供电纹波。SHT30在3.3V下工作,如果电源来自DC-DC模块且纹波偏大,湿度数据会出现随机跳动。最好在VDD和GND之间放一个100nF陶瓷电容,空间允许再加一个10μF钽电容,效果会稳很多。此外,SHT30这类传感器对VDD爬坡速度也有要求,上电太慢可能导致初始化失败,稳定供电是前提。

2.3 一块板子上挂多个I2C设备的地址规划

I2C总线天然支持多设备挂载,但SHT30的地址选择只有0x44和0x45两档,一个I2C总线上最多挂两颗。如果项目需要测多个点位的温湿度,就得用TCA9548A这类I2C多路复用器,把总线扩展成8路,每路再挂SHT30。这个工程虽然只验证了一颗传感器,但驱动代码里用了地址宏定义,换成0x45或者动态传地址都很方便。规划阶段就把地址位分配好,后面联调省太多事。

3. 驱动代码拆解:从I2C到温湿度数据

3.1 I2C底层用硬件还是软件模拟

SHT30本身只要求标准I2C时序,STM32F4的硬件I2C完全够用。用HAL库的话,几行代码就能完成一次读取,我建议新手直接上硬件I2C,省心且不占CPU。不过要提醒一句,STM32F4的硬件I2C偶尔会出现BUSY标志卡死的情况,这时候强制拉一下SCL,或者在初始化里调用__HAL_I22C_CLEAR_FLAG(&hi2c1, I2C_FLAG_BUSY)就能解掉。

如果习惯把I2C引脚换成任意GPIO,或者想彻底避开硬件I2C的时序问题,也可以自己写软件I2C。方式就是用两个普通GPIO模拟开漏输出,配合延时翻转电平。这种方案移植性最强,换个单片机只要改引脚定义就能跑。缺点是CPU占用高、抗干扰依赖软件延时准确性,所以量产代码我更推荐硬件I2C。

3.2 SHT30核心命令与读取流程

SHT30的命令分单次测量和周期测量两大类。单次测量适合“需要时才测一次”的场景,周期测量适合持续监控。工程里用的是单次测量,命令是0x2C 0x06,含义是高重复性、时钟延展模式。

读取流程四步走:

  1. 主机向0x88地址发送测量命令0x2C 0x06
  2. 等待芯片完成测量,高重复性模式下约15ms
  3. 主机从0x89地址读取6个字节
  4. 解析温度和湿度原始值,并做CRC校验

核心代码:

#define SHT30_ADDR_W 0x88 // I2C写地址 #define SHT30_ADDR_R 0x89 // I2C读地址 #define SHT30_CMD_MS_H 0x2C // 单次测量,高重复性 #define SHT30_CMD_MS_L 0x06 uint8_t sht30_read_data(float *temp, float *hum) { uint8_t buf[6]; uint8_t cmd[2] = {SHT30_CMD_MS_H, SHT30_CMD_MS_L}; // 发送测量命令 if (HAL_I2C_Master_Transmit(&hi2c1, SHT30_ADDR_W, cmd, 2, 100) != HAL_OK) return 1; HAL_Delay(20); // 等待测量完成,留点余量 // 读取6字节数据 if (HAL_I2C_Master_Receive(&hi2c1, SHT30_ADDR_R, buf, 6, 100) != HAL_OK) return 2; // 校验CRC if (SHT30_CRC8(&buf[0], 2) != buf[2] || SHT30_CRC8(&buf[3], 2) != buf[5]) return 3; // 转换温度、湿度 uint16_t rawT = (buf[0] << 8) | buf[1]; uint16_t rawH = (buf[3] << 8) | buf[4]; *temp = -45.0f + 175.0f * rawT / 65535.0f; *hum = 100.0f * rawH / 65535.0f; return 0; }

一个细节:测量完成前绝对不要发读命令,否则读出来的是上上次的旧数据。工程里用HAL_Delay(20)是简单粗暴但有效的方式;如果对时序有严格要求,可以改成读取前的SCL电平轮询,或者用SHT30的“测量后查询”模式,那个不需要延时就知道了测量状态。

3.3 CRC校验到底在防什么

SHT30返回的6个字节里,每个16bit数据后面都跟了1个8bit CRC,由芯片内部CRC-8引擎生成,多项式0x31,初始值0xFF。这个设计专门用来检测通信链路是否受干扰。I2C走线如果比较长,或者环境里有电机、开关电源之类的干扰源,数据线上会出现毛刺,收到的原始值可能发生位翻转。没有CRC校验时,一个反了的bit可能让温度从25°C跳到-15°C,后果很严重。

所以驱动里的CRC校验不是可选项,而是必选项。我见过很多工程把CRC验证注释掉,靠平均值滤波来兜底,这种方式在实验室里没问题,放到工业现场迟早翻车。CRC代码也不复杂,一个循环就写完:

uint8_t SHT30_CRC8(uint8_t *data, uint8_t len) { uint8_t crc = 0xFF; for (uint8_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; }

3.4 温湿度计算公式与精度取舍

SHT30的原始数据是16bit,范围0~65535,换算成物理量的公式非常固定:

  • 温度:T = -45 + 175 * rawT / 65535
  • 湿度:RH = 100 * rawH / 65535

这个公式直接来自芯片手册,套用就好。有一点要注意,湿度公式算出来是相对湿度(RH),和绝对湿度、露点温度不是一回事。如果要算露点,需要用Magnus公式结合温度和相对湿度近似计算。工程里只输出了温湿度,但代码里留了扩展位,加一个露点计算函数也就十来行。

在STM32F4上,用浮点运算计算温湿度毫无压力,因为F4带硬件单精度浮点单元FPU。如果换成Cortex-M0这类没有FPU的芯片,就要考虑把浮点换成定点数,比如温度用扩大100倍的整数表示,输出时再除100,能显著降低CPU开销。这种对精度的取舍,做嵌入式要时刻记在心里。

4. Keil5烧录STM32F4工程全流程

4.1 工程模板与文件组织

用Keil5打开工程后,左侧Project栏会看到Target下的分组:Application里是main.c和sht30.c,Drivers里是HAL库源码和CMSIS启动文件。工程用的是STM32F407VET6,启动文件startup_stm32f407xx.s不能选错,选成F103的启动文件,芯片直接跑不起来。系统时钟配置这里也要留意,F407默认25MHz外部晶振,如果用8MHz晶振,必须改PLL配置,否则串口波特率会偏差到没法用。

4.2 烧录前必须检查的5个设置

我把这个工程里烧录踩过的坑整理成5个检查点:

  1. 芯片型号:Options for Target -> Device,选择STMicroelectronics -> STM32F4 Series -> 对应型号。型号不匹配时,Flash烧录算法和内存地址映射都会出错。
  2. 宏定义:C/C++ -> Define,必须写USE_HAL_DRIVER,STM32F407xx。USE_HAL_DRIVER告诉HAL库启用,STM32F407xx告诉库你的具体型号,缺一个编译直接报一大堆未定义错误。
  3. 调试器选择:Debug -> Use -> ST-Link Debugger(或J-LINK),Settings里选择SWD模式,不建议用JTAG。SWD只占两根线,省出来的引脚能干别的。
  4. Flash烧录算法:Debug -> Settings -> Flash Download,确认Flash Size和实际芯片一致。报“No Algorithm”就是没选对Flash,要把STM32F4xx Flash添加进来。
  5. Reset and Run:Flash Download里务必勾选Reset and Run,这样程序烧完自动复位执行。没勾也没关系,手动按复位键就行,但调试效率会低不少。

配置完成后,Rebuild编译,再点Load下载。正常情况下Build Output窗口会显示“Application running”,板上的LED开始闪烁。

4.3 串口打印调试技巧

这个工程把温湿度数据通过USART1打印,波特率115200。用printf重定向时,需要重写fputc函数:

int fputc(int ch, FILE *f) { while (!(USART1->SR & USART_FLAG_TXE)); USART1->DR = (uint8_t)ch; return ch; }

打开串口助手后,把显示格式设为字符串模式,不然看到的全是乱码。输出数据尽量不要做太多格式化,字符串越长,MCU和串口助手两边的配合越容易出问题。我一般输出CSV格式,方便直接记录到Excel里画温湿度曲线:

26.32,48.51 26.31,48.49 26.31,48.50

这样用串口助手的“保存到文件”功能,就能低成本攒下一整天的温湿度数据,后续处理也方便。

5. 实测中的典型问题与排查记录

5.1 传感器无应答,读回全是0xFF

这是调试SHT30时最常遇到的问题。现象是HAL_I2C_Master_Transmit返回值错误,或者读到的6个字节全是0xFF。排查顺序一般是这样的:

  1. 先用万用表测VDD和GND有没有电,电压是不是3.3V。遇到过开发板USB口供电不足,电压掉到2.8V,传感器就是不回应。
  2. 再查SCL、SDA有没有接反。SHT30封装比较小,手工焊接时焊反很常见。
  3. 确认上拉电阻存在。用示波器看SCL/SDA,如果空闲电平不是高电平,多半是上拉电阻没接或没焊好。
  4. 最后查代码里的地址。前面强调过,HAL库要用0x88/0x89,而不是0x44/0x45。

5.2 温湿度数值跳变、漂移

如果CRC校验已经通过,但数据还是会偶尔跳一下,问题多半出在电源或布线上。经验是:先给传感器单独加100nF去耦电容,再把I2C导线从电机、继电器等干扰源旁挪开,最后在上层加一个简单滑动平均滤波,比如采5次取中间值。这些招数组合下来,数据基本就稳了。

另外,传感器在通电初期,湿度值会有一个“爬坡”过程,这不是芯片坏了,而是内部高分子感湿膜在重新平衡环境湿度。从上电到稳定一般需要几分钟,尤其是刚从干燥仓储环境拿出来时,不要一上电就急着拿数据去验收。

5.3 Keil5下载时连接失败

Keil5点击Load后提示“Cannot access target”,我把它整理成一个速查表:

现象可能原因处理办法
连接失败ST-Link驱动没装好重装STSW-LINK009驱动
连接失败SWDIO/SWCLK接线松检查杜邦线或PCB焊盘
连接失败芯片读保护被使能用STM32CubeProgrammer去除读保护
连接失败板子没供电确认VDD,检查调试器是否给板子供了电
下载后不运行Flash Download没勾Reset and Run勾上,或者手动复位

有一个情况要特别提醒:如果之前往芯片里烧过读保护代码,芯片会锁定SWD口,此时Keil完全连不上。解决方法是按住板子复位键,点击Download,在出现烧录进度前松开复位键,通常能救回来;救不回来就上STM32CubeProgrammer,用整片擦除恢复。

5.4 问题排查速查表

症状大概率原因先查什么
I2C读取返回HAL_ERROR地址错/上拉缺失/接线错地址、波形
读回字节全为0xFFSDA线没上拉/接线断开上拉、连线
数据偶尔跳变电源纹波/布线干扰去耦电容、走线
温湿度值离谱公式用错/原始数据错位CRC、公式
CRC校验一直失败I2C速率太快/软件I2C时序不对降速、延时长一点
温度正常湿度偏高传感器受潮或靠近热源烘干、隔离

6. 后续扩展:SHT30和EMMC、SPI外设的联动

6.1 用SDIO把温湿度存进EMMC

工程基础功能跑通后,一个很自然的扩展方向是把温湿度数据存进存储介质,做一个独立的环境记录仪。STM32F407的SDIO接口可以直接驱动eMMC芯片,因为eMMC的接口协议和MMC/SD是兼容的,通过SDIO总线就能访问内部的控制逻辑和NAND Flash。

不过用eMMC不能只接四根线就完事,有几个点必须处理:eMMC通常需要VCC和VCCQ两路电源,VCCQ电平看芯片是1.8V还是3.3V;板子上要保证完整的初始化时序,包括CMD0、CMD1、CMD2这些命令;软件层建议直接挂FatFS文件系统,让数据以文件形式保存,主机端读起来方便。如果不用文件系统,就得自己实现坏块管理和均衡磨损,工作量成倍增加。在工程里,可以每完成一次SHT30读取,就把温湿度记录追加到一个文本文件里,再配上RTC时间戳,一个冷链运输记录仪的原型就成了。

6.2 SPI1驱动MT6701磁编码器

另一个相关的热词是“stm32f4配置spi1驱动mt6701”。MT6701是一款磁编码器芯片,输出绝对角度,机器人关节和云台上经常用它做位置反馈。它支持SPI、ABZ、PWM多种接口,如果走SPI,挂到STM32F4的SPI1主机接口即可,SCK、MOSI、MISO、CS四根线,软件上按芯片手册配好时钟极性和相位,读一次就能拿到14位角度数据,0到16383对应360度。

这样组合下来,一个系统里既有SHT30做环境监测,又有MT6701做运动位置反馈,再加上EMMC做数据记录,本质上就是“环境感知+运动感知+数据存储”的完整方案。在需要长期无人值守的设备上,这种组合很常见。

6.3 扩展时要注意的资源冲突

扩展外设之前,先翻芯片数据手册,确认引脚有没有打架。比如SPI1如果用了PB3、PB4、PB5,而I2C1用了PB6、PB7,表面看不冲突,但JTAG的默认引脚正好也是PB3、PB4,要把调试

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询