拓冰建站拓冰建站
首页 / 资讯中心 / 正文

STM32F4驱动STH20温湿度传感器:I2C通信与开发实战

简介这是一套面向嵌入式开发者的 STM32F4 与 STH20 温湿度传感器通信工程实例完整展示了从 GPIO 配置、I2C 总线驱动到传感器数据读取与处理的全过程适合需要学习传感器集成和底层驱动编写的入门及进阶人群。压缩包内共一百七十一个文件以 C 语言源文件和头文件为主同时包含 Keil 工程配置文件、编译生成的中间文件及说明文档整体大小仅三点一九兆字节结构清晰便于查阅。该资源已有一百二十九人学习可用于快速理解 STM32F4 的 I2C 通信机制及 STH20 的测量模式选择以及数据校验和异常处理思路。借助完整工程源码和现成配置模板读者可省去环境搭建与排错的精力直接基于现有框架进行二次开发大幅缩短温湿度采集项目的启动时间也能从中掌握嵌入式驱动开发的一般方法。1. 项目概述STH20是一个很有意思的传感器工程。这个项目标题看起来简单但背后涉及的知识点相当密集I2C通信协议、STM32F4的HAL库开发、传感器数据手册的解读、温湿度数据的换算与校准甚至还有低功耗场景下的睡眠唤醒设计。最近在做毕业设计和嵌入式课程设计的同学或者工作中需要用MCU读取环境数据的工程师这个工程都能作为一套很干净的参考模板。先说说这个项目解决的痛点。STH20是Sensirion推出的数字温湿度传感器输出经过标定的数字信号直接用I2C接口就能读取。和传统的模拟量传感器比如DHT11需要自己写时序、读湿度还要查表换算相比STH20的好处是精度高、功耗低、通信协议标准化一颗芯片就能同时拿到温度和湿度两个数据。但“用I2C读取传感器”这句话说起来容易真正上手时会遇到不少坑I2C地址有7位和8位之分读时序要先发命令再等数据数据手册里的相对湿度公式是线性的但要注意单位还有CRC校验可选可不选——这些细节如果没有提前弄清楚调个两三天都出不了正确数据。选择STM32F4作为主控也是经过考虑的。F4系列主频最高能跑到180MHz带FPU浮点运算单元处理温度和湿度的换算尤其是用浮点运算计算相对湿度时非常轻松。而且F4的I2C外设支持400kHz快速模式STH20最高也是400kHz双方能完美匹配。相比用51单片机或者ArduinoSTM32F4留给后续扩展的余地更大——比如再接个屏幕显示、加个ESP32做数据上传、或者挂在RTOS上做多任务调度都是现成的路子。这篇博文我会从硬件接线讲起一步步拆解I2C读时序给出可直接编译运行的HAL库代码最后把调试时遇到的几个典型问题和排查思路也一并整理出来。无论你是第一次用STM32还是之前用过其他温湿度传感器想迁移过来这套流程都可以直接沿着走一遍代码稍微改改就能复用到其他I2C传感器上。2. 硬件选型与整体设计思路2.1 为什么是STM32F4 STH20这个组合我在选择这套方案时核心考量无非三个字稳、准、省。稳是指系统运行的稳定性准是指传感器读数的准确性省是指整体成本和开发时间。STM32F4系列的定位是高性能嵌入式控制内部有足够的Flash和RAM跑复杂的应用逻辑同时I2C硬件外设做得比较完善支持多主多从、时钟延展、DMA传输等高级功能这对于STH20这类数字传感器来说特别友好。STH20这颗传感器值得多说两句。它内部集成了一个电容式湿度传感元件和一个带隙温度传感元件搭配一个14位的ADC能把模拟信号直接转换为数字量输出。相比老一代的SHT10/SHT11需要自己用GPIO模拟时序读取STH20的通信方式标准了很多——标准的I2C协议7位设备地址0x44支持时钟延展读湿度时芯片会拉低SCL直到测量完成。这意味着任何支持I2C的MCU都能轻松驱动它不需要和时序较劲。Sensirion还给这颗芯片做了分批次校准每颗芯片出厂前都校准过校准系数存储在芯片内部的OTP存储器里所以我们读到的数据就是已经标定过的精度方面有保障。这里要澄清一个容易混淆的点。市面上还有一颗STH20不对是SHT20这是Sensirion的另一颗经典传感器。SHT20和STH20在寄存器和时序上其实是兼容的区别主要在于精度等级和封装形式。如果手头拿到的是SHT20代码完全可以通用这一点我在后面会再提到。很多人容易把这两颗芯片搞混调试时对着数据手册找不出问题其实就是型号看岔了。2.2 硬件接线与电路设计STH20的封装是DFN-8体积非常小所以实际项目中一般是把传感器贴在小板上通过排针或杜邦线和主控板连接。如果在面包板上做实验建议买那种已经焊好排针的SHT20模块用起来会省心很多。模块通常有四个引脚VCC、GND、SCL、SDA部分模块会额外引出ADD地址选择引脚这个引脚接地时I2C地址是0x447位接VCC时地址变成0x45。接线方面核心原则是I2C总线必须上拉电阻。STM32F4内部虽然可以开启上拉但内部上拉的阻值一般在30kΩ~50kΩ对于400kHz的I2C通信来说阻值偏大会导致边沿变缓、波形畸变严重时通信直接失败。稳妥的做法是在SCL和SDA线上各自接一个4.7kΩ或10kΩ的上拉电阻到3.3V。如果用的是现成模块板上一般已经焊好了上拉电阻这时候就不需要重复接了。电源方面STH20支持2.1V到3.6V的工作电压和STM32F4的3.3V供电完全兼容。但要注意电源纹波对湿度测量精度的影响——湿敏电容对电源噪声比较敏感如果电源是从DC-DC模块直接出来的建议至少加一个10μF的钽电容和0.1μF的陶瓷电容做去耦。我在实际调试时发现电源波动过大的情况下湿度读数会出现几个百分点的跳动加了电容之后明显稳定很多。模块和主控之间用杜邦线连接时走线尽量短一些最好控制在10cm以内。I2C是开漏结构走线过长或者经过面包板的寄生电容过大波形会被拉变形尤其是400kHz模式。如果实在需要长距离走线可以把I2C速率降到100kHz标准模式能换来更好的稳定性。反正STH20的采样率本来就不高降低速率完全不影响体验。3. STH20核心细节解析与实操要点3.1 I2C通信协议与寄存器映射STH20和其他I2C传感器最大的不同在于通信机制。大部分I2C传感器比如BMP280是按寄存器地址读写的STH20不是——它采用的是“命令触发”模式。也就是说主机STM32F4先发送一个特定的命令字节告诉STH20要执行什么操作比如触发一次温度测量然后芯片开始内部转换转换完成后主机再读取2个字节的数据可选读第3个字节做CRC校验。STH20的主要命令码如下表所示命令命令码说明触发温度测量保持主机0xE3测量期间SCL被拉低完成后释放触发湿度测量保持主机0xE5同上用于湿度测量触发温度测量不保持主机0xF3测量期间主机可做其他事用轮询等待触发湿度测量不保持主机0xF5同上用于湿度测量写用户寄存器0xE6配置分辨率、加热、OTP读取等读用户寄存器0xE7读取当前寄存器值软复位0xFE复位芯片恢复默认设置“保持主机”模式hold master是STH20的一个特色功能。当主机发送0xE3或0xE5后STH20会拉低SCL线强迫主机等待芯片测量完成后释放SCL主机继续发送时钟脉冲读取数据。这种模式下主机代码比较简单——不需要自己计算等待时间只要按I2C读流程操作芯片会自己控制节奏。缺点也很明显测量期间SCL被占用如果总线上还挂了其他从设备它们也会被拖住。所以多传感器共用一个I2C总线时更推荐用“不保持主机”模式主机发送命令后自己去忙别的隔一段时间再回来读数据。默认分辨率是12位湿度、14位温度对绝大多数应用已经够用。如果追求更快的采样周期可以通过写用户寄存器把分辨率降到8位/11位但精度也会相应下降。我在项目里一般保持默认分辨率不动——湿度12位的测量时间约14.5ms温度14位约85ms这个速度对环境监测场景来说绰绰有余没必要牺牲精度换速度。3.2 温湿度数据换算算法拿到STH20返回的16位原始数据后需要经过一步换算才能变成我们熟悉的摄氏度和相对湿度百分比。这一步不复杂但经常有人搞错。Sensirion数据手册给出的公式是温度公式T -45 175 × (rawTemperature / 65535)湿度公式RH -6 125 × (rawHumidity / 65535)注意看STH20的原始数据范围是0到6553516位满量程所以raw值除以65535相当于把原始值归一化到0~1之间。温度范围对应-45℃到130℃手册标注的工作范围通常是-40℃到125℃但公式本身支持更宽的范围湿度范围对应-6%RH到119%RH同样正常工作范围是0%到100%但公式允许轻微超量程。这里埋了一个坑有些人把分母写成65536而不是65535。这个误差虽然很小0.0015%但在高精度测量场景下会产生不可忽略的偏差。一定要严格按照数据手册的公式来分母是65535不是65536也不是32768。还有一个更隐蔽的坑——有些参考代码里用int型变量做除法直接把小数部分截断掉了。温度还好湿度换算时如果直接用整数除读数会跳变得很厉害相邻两个读数可能差1%RH以上。正确的做法是用浮点运算或者至少用定点运算先乘后除避免精度丢失。实际项目中我会先把原始数据保存为uint16_t换算时转成float再用上面的公式代入。STM32F4带FPU处理浮点运算速度很快完全不用担心性能问题。换算后的数据如果要在串口或屏幕上显示可以用sprintf格式化为保留一位小数既清爽又够用。3.3 用户寄存器配置与低功耗设计STH20的用户寄存器地址是0xE6默认值为0x00。寄存器里各位的含义包括测量分辨率选择、OTP读取使能、加热器使能等。大多数情况下保持默认值即可但有两个场景需要修改一是开启加热器在结露环境下防止湿敏元件结露二是降低分辨率换取更快的测量速度。低功耗场景值得重点说。STH20在空闲状态下的电流非常低典型值只有0.3μA这在电池供电的物联网设备中很有优势。但要注意测量期间的电流会上升到约1mA如果每隔几秒就采一次数据平均功耗仍然可接受如果每秒采几次功耗就会明显上升。合理的做法是降低采样频率比如环境监测设备每30秒采一次采集完立刻进入睡眠模式这样电池能撑很久。STM32F4这边可以配合RTC闹钟定时唤醒唤醒后触发I2C读取读完继续睡。另外STH20的加热器heater功能需要特别留意。它原本是为了在湿度极高或结露环境下让传感器自恢复用的平时不要打开。如果误开了加热器你会看到温度读数凭空高了好几度湿度也会偏低看起来就像传感器坏了。我之前排查过一个“温湿度怎么都对不上”的问题最后发现是寄存器里的加热器位被误置了1。排查方法很简单执行软复位命令0xFE让芯片恢复默认状态读数马上就正常了。4. 实操过程与核心环节实现4.1 Keil5工程配置与STM32F4设备添加STM32F4的开发环境我推荐用Keil MDK上手快、调试方便、资料多。新版本Keil MDK一般自带F4系列的支持包但如果你用的是老版本或者安装时没有勾选F4系列器件库就可能出现“新建工程时找不到STM32F407ZGT6”这类问题。解决办法是打开Pack Installer在搜索框输入STM32F4找到对应系列的Device Family Pack并安装。这一步看似不起眼但卡住过不少人。新建工程的步骤我走了一遍整理成清单方便对照打开Keil5选择Project - New uVision Project给工程起名并选择保存路径。在Device页面搜索并选择STM32F407ZGT6或者其他F4型号按你手上的板子选。在弹出的Manage Run-Time Environment窗口中勾选CMSIS - CORE以及Device - Startup这是最基础的配置。接下来配置时钟。用STM32CubeMX生成初始化代码是最高效的方式——在CubeMX里选好芯片型号配置I2C外设为I2C1或I2C2速率设为400kHz或100kHz然后生成Keil工程。CubeMX会自动把HAL库、时钟树、GPIO初始化这些繁琐的底层配置全部搞定。我见过很多初学者喜欢手写寄存器配置精神可嘉但对项目开发来说效率太低了。用CubeMX生成HAL库工程代码清晰易懂出错的概率也小得多后续维护还方便。唯一的代价是HAL库生成的代码体积比寄存器操作要大一些但对STM32F4这种Flash以512KB起步的芯片来说完全不是问题。4.2 I2C驱动代码实现与要点解析核心驱动代码其实不复杂但这部分是最容易出现隐蔽bug的地方。下面给出一个可直接编译的完整示例基于STM32 HAL库使用“保持主机”模式读取温度。先定义一个用于存储STH20原始数据的结构体typedef struct { uint16_t raw_temperature; uint16_t raw_humidity; float temperature_c; // 摄氏温度 float humidity_rh; // 相对湿度百分比 } STH20_Data_t;然后是读取温度和湿度的函数。以读取温度为例#define STH20_ADDR (0x44 1) // 7位地址0x44左移一位8位地址是0x88 #define CMD_MEAS_TEMP_HOLD 0xE3 // 保持主机模式温度测量 #define CMD_MEAS_RH_HOLD 0xE5 // 保持主机模式湿度测量 uint8_t STH20_Read_Temperature(STH20_Data_t *data) { uint8_t rx_buffer[2] {0}; uint8_t cmd CMD_MEAS_TEMP_HOLD; // 发送温度测量命令随后读取2字节数据 if (HAL_I2C_Master_Transmit(hi2c1, STH20_ADDR, cmd, 1, 1000) ! HAL_OK) return 1; if (HAL_I2C_Master_Receive(hi2c1, STH20_ADDR, rx_buffer, 2, 1000) ! HAL_OK) return 2; // 组合原始数据高字节在前 style="width:16px;margin-left:4px;vertical-align:text-bottom;cursor:text;" />
分享:

看完干货,该让你的企业上线了

免费需求沟通 · 48 小时内出具建站方案 · 河南本地可上门