从零构建STM32F103与SHT31的I2C通信系统:硬件连接、软件配置与数据解析全指南
在物联网和智能硬件快速发展的今天,环境监测已成为众多项目的核心需求。温湿度传感器作为最基础的环境感知元件,其稳定可靠的驱动实现是嵌入式开发者必须掌握的技能。本文将带领初学者使用STM32F103系列单片机,通过I2C接口与高精度SHT31温湿度传感器建立通信,从硬件连接到软件实现,逐步构建完整的测量系统。
1. 硬件准备与电路连接
1.1 所需材料清单
- 主控芯片:STM32F103C8T6(正点原子Mini开发板)
- 传感器模块:SHT31-DIS温湿度传感器
- 连接线材:杜邦线若干(建议使用不同颜色区分信号)
- 开发环境:
- Keil MDK-ARM或STM32CubeIDE
- STM32CubeMX配置工具
- 串口调试助手(如Putty、SecureCRT)
1.2 引脚连接详解
SHT31传感器与STM32的硬件连接需要特别注意电平匹配和信号完整性。以下是标准连接方式:
| SHT31引脚 | STM32引脚 | 功能说明 |
|---|---|---|
| VCC | 3.3V | 电源正极 |
| GND | GND | 电源地 |
| SDA | PC11 | I2C数据线 |
| SCL | PC12 | I2C时钟线 |
提示:实际项目中,当通信距离超过20cm时,建议在SDA和SCL线上各串联一个100Ω电阻,并添加2.2KΩ上拉电阻至3.3V,以提高信号质量。
1.3 硬件连接常见问题排查
初次连接时,开发者常会遇到以下问题:
通信失败:
- 检查电源电压是否稳定(3.3V±5%)
- 确认SDA/SCL线序是否正确
- 测量上拉电阻是否正常工作
数据不稳定:
- 确保电源去耦电容(0.1μF)靠近传感器VCC引脚
- 检查杜邦线接触是否良好
- 避免与高频信号线平行走线
2. 开发环境配置与工程建立
2.1 STM32CubeMX基础配置
使用STM32CubeMX可以快速生成初始化代码,大幅降低开发难度:
// 在CubeMX中进行如下配置: 1. 选择正确的STM32F103C8T6型号 2. 启用I2C1外设(或I2C2,根据实际连接) 3. 配置PC11为I2C_SDA,PC12为I2C_SCL 4. 设置I2C时钟速度为标准模式(100kHz) 5. 启用USART1用于调试输出(115200bps) 6. 生成Keil或IDE项目代码2.2 关键外设初始化代码解析
生成的初始化代码中,需要特别关注以下几个部分:
// I2C初始化结构体示例 hi2c1.Instance = I2C1; hi2c1.Init.ClockSpeed = 100000; hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2; hi2c1.Init.OwnAddress1 = 0; hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT; hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE; hi2c1.Init.OwnAddress2 = 0; hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE; hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE; if (HAL_I2C_Init(&hi2c1) != HAL_OK) { Error_Handler(); }2.3 工程目录结构规划
合理的项目结构能提高代码可维护性:
├── Core │ ├── Inc │ └── Src ├── Drivers │ ├── STM32F1xx_HAL_Driver │ └── CMSIS ├── SHT31 │ ├── sht31.h │ └── sht31.c └── Middlewares3. SHT31驱动实现详解
3.1 传感器通信协议分析
SHT31采用标准I2C协议,但有几点特殊之处:
- 设备地址:0x44(7位地址)
- 测量命令:
- 高重复性测量:0x2C06
- 中重复性测量:0x2C0D
- 低重复性测量:0x2C10
- 数据格式:
- 温度:16位原始数据,需按公式转换
- 湿度:16位原始数据,需按公式转换
3.2 核心驱动函数实现
以下是完整的传感器驱动实现:
// sht31.h 头文件定义 #define SHT31_ADDR 0x44<<1 // 7位地址左移1位 typedef enum { SHT31_HIGH_REPEAT = 0x2C06, SHT31_MED_REPEAT = 0x2C0D, SHT31_LOW_REPEAT = 0x2C10 } SHT31_Repeatability; uint8_t SHT31_ReadTempHumid(float *temp, float *humid, SHT31_Repeatability rep);// sht31.c 驱动实现 uint8_t SHT31_ReadTempHumid(float *temp, float *humid, SHT31_Repeatability rep) { uint8_t cmd[2]; uint8_t data[6]; // 发送测量命令 cmd[0] = rep >> 8; // 命令高字节 cmd[1] = rep & 0xFF; // 命令低字节 if(HAL_I2C_Master_Transmit(&hi2c1, SHT31_ADDR, cmd, 2, HAL_MAX_DELAY) != HAL_OK) return 0; // 等待测量完成(根据重复性等级不同等待时间不同) uint16_t delay_ms = rep == SHT31_HIGH_REPEAT ? 15 : (rep == SHT31_MED_REPEAT ? 6 : 4); HAL_Delay(delay_ms); // 读取测量结果 if(HAL_I2C_Master_Receive(&hi2c1, SHT31_ADDR|0x01, data, 6, HAL_MAX_DELAY) != HAL_OK) return 0; // 数据校验(CRC校验可在此添加) // 数据转换 uint16_t temp_raw = (data[0] << 8) | data[1]; uint16_t humid_raw = (data[3] << 8) | data[4]; *temp = -45 + 175 * ((float)temp_raw / 65535.0); *humid = 100 * ((float)humid_raw / 65535.0); return 1; }3.3 数据转换与校验
SHT31提供的数据需要经过特定公式转换:
温度转换公式:
T(°C) = -45 + 175 × (temp_raw / 65535)湿度转换公式:
RH(%) = 100 × (humid_raw / 65535)注意:实际应用中应考虑添加CRC校验以提高数据可靠性,特别是环境干扰较大的场合。
4. 系统集成与性能优化
4.1 主程序逻辑实现
将驱动集成到主程序中,实现周期性测量:
// main.c #include "sht31.h" #include <stdio.h> float temperature, humidity; char msg[64]; int main(void) { HAL_Init(); SystemClock_Config(); MX_I2C1_Init(); MX_USART1_UART_Init(); while (1) { if(SHT31_ReadTempHumid(&temperature, &humidity, SHT31_HIGH_REPEAT)) { sprintf(msg, "Temperature: %.2f C, Humidity: %.2f %%\r\n", temperature, humidity); HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), HAL_MAX_DELAY); } else { HAL_UART_Transmit(&huart1, (uint8_t*)"Read failed!\r\n", 13, HAL_MAX_DELAY); } HAL_Delay(1000); } }4.2 通信可靠性增强措施
为提高I2C通信稳定性,可采取以下措施:
错误处理机制:
- 添加超时重试逻辑
- 实现通信失败后的硬件复位
信号质量优化:
- 缩短通信线长度
- 添加适当的终端匹配
- 在PCB设计时保持I2C走线远离高频信号
软件滤波:
- 实现滑动平均滤波
- 设置数据合理性检查
4.3 低功耗设计考虑
对于电池供电应用,可优化功耗:
间歇工作模式:
// 设置传感器进入低功耗模式 uint8_t sleep_cmd[] = {0xB0, 0x98}; HAL_I2C_Master_Transmit(&hi2c1, SHT31_ADDR, sleep_cmd, 2, HAL_MAX_DELAY); // 唤醒传感器 uint8_t wake_cmd[] = {0x35, 0x17}; HAL_I2C_Master_Transmit(&hi2c1, SHT31_ADDR, wake_cmd, 2, HAL_MAX_DELAY); HAL_Delay(1); // 等待传感器稳定降低采样频率:根据应用需求调整测量间隔
电源管理:不测量时切断传感器电源
5. 高级应用与扩展
5.1 多传感器组网
通过I2C地址引脚,可以连接多个SHT31传感器:
地址配置:
- ADDR接GND:0x44
- ADDR接VDD:0x45
轮询读取:
float temp[2], humid[2]; SHT31_ReadTempHumid(&temp[0], &humid[0], SHT31_HIGH_REPEAT, 0x44<<1); SHT31_ReadTempHumid(&temp[1], &humid[1], SHT31_HIGH_REPEAT, 0x45<<1);
5.2 与环境光传感器联合使用
典型的环境监测节点往往需要多种传感器:
// 同时读取温湿度和光照强度 float temperature, humidity, lux; void read_sensors() { SHT31_ReadTempHumid(&temperature, &humidity); BH1750_ReadLight(&lux); // 假设已实现光强传感器驱动 // 数据打包处理... }5.3 云端数据上传
将采集数据通过Wi-Fi或NB-IoT上传:
// 伪代码示例 void upload_to_cloud() { char json[128]; sprintf(json, "{\"temp\":%.1f,\"humid\":%.1f,\"time\":%lu}", temperature, humidity, HAL_GetTick()); // 通过AT指令发送数据 GSM_SendATCommand("AT+HTTPPOST=\"api.example.com\",\"application/json\""); GSM_SendData(json); }在实际项目中,我发现SHT31的响应速度和高精度使其特别适合需要快速环境反馈的应用场景。通过合理配置重复性模式和采样频率,可以在精度和功耗之间取得良好平衡。对于初次接触I2C通信的开发者,建议先用逻辑分析仪抓取通信波形,直观理解I2C协议的时序要求,这对调试复杂的传感器应用大有裨益。