STM32CubeMX + HAL 库:基于 I²C 通信的 AHT20 高精度温湿度测量实验
1 概述
1.1 实验目的
本实验基于 STM32CubeMX 与 HAL 库,借助硬件 I²C 接口实现对 AHT20 高精度温湿度传感器的测量与数据处理。实验内容涵盖 AHT20 的初始化流程、指令交互机制、测量数据的采集与物理量转换等关键环节。通过对实验驱动代码与测试结果的完整展示,读者不仅能够深入理解 STM32 硬件 I²C 总线的应用方法,还能掌握数字环境传感器的通信特性及工程集成方式,为智能硬件系统中的 环境监测、气象采集与物联网应用 提供实践参考与技术支撑。
1.2 温湿度传感器介绍
除常见的温湿度传感器外,部分器件也具备温度测量功能。例如,实时时钟芯片 DS3231 内部集成了一个温度传感器,用于实现晶振的温度补偿功能。虽然该传感器可以提供温度数据输出,但其设计主要目的是保证时钟的高精度运行,因此在实际应用中温度测量精度有限(典型精度约 ±3 ℃),不适合用于对环境温度有高精度要求的场景。
此外,STM32 单片机内部也集成了温度传感器,通常位于片上二极管或晶体管结构,通过测量 PN 结电压随温度变化的特性来获得温度信息。该传感器的主要用途是为 MCU 的内部自适应调节和过热保护提供参考,其测量误差通常在 ±5 ℃ 甚至更大,且需要经过标定才能获得较为可靠的数据。因此,STM32 内部温度传感器更适合作为片内温度监测或过热保护手段,而不适合用于精确的环境温度采集。
型号 | 通信接口 | 工作电压 | 温度范围 | 温度精度 | 湿度范围 | 湿度精度 | 分辨率 | 响应时间 | 特点 |
---|---|---|---|---|---|---|---|---|---|
DHT11 | 单总线 | 3.3 ~ 5 V | 0 ~ 50 ℃ | ±2 ℃ | 20 ~ 90 %RH | ±5 %RH | 8 bit | 1 s | 成本低,性能一般,适合入门实验 |
DHT22 / AM2302 | 单总线 | 3.3 ~ 6 V | -40 ~ 80 ℃ | ±0.5 ℃ | 0 ~ 100 %RH | ±2 ~ 5 %RH | 16 bit | 2 s | 精度高于 DHT11,但刷新率较低 |
AHT20 | I²C | 2.0 ~ 5.5 V | -40 ~ 85 ℃ | ±0.3 ℃ | 0 ~ 100 %RH | ±2 %RH | 16 bit | 80 ms | 低功耗,小体积,高精度,替代 DHT 系列 |
SHT30 | I²C | 2.4 ~ 5.5 V | -40 ~ 125 ℃ | ±0.3 ℃ | 0 ~ 100 %RH | ±2 %RH | 14 bit | 8 s | 瑞士 Sensirion 出品,稳定性高 |
SHT31 | I²C | 2.4 ~ 5.5 V | -40 ~ 125 ℃ | ±0.3 ℃ | 0 ~ 100 %RH | ±2 %RH | 14 bit | 2 s | SHT30 升级版,支持更快采样 |
Si7021 | I²C | 1.9 ~ 3.6 V | -40 ~ 125 ℃ | ±0.4 ℃ | 0 ~ 100 %RH | ±3 %RH | 14 bit | <10 ms | 美国 Silicon Labs 出品,超低功耗 |
DS3231 内部温度传感器 | I²C | 2.3 ~ 5.5 V | -40 ~ 85 ℃ | ±3 ℃ | — | — | 10 bit | ~1 s | 用于晶振温度补偿,温度精度有限 |
STM32 内部温度传感器 | 片内 ADC | 1.8 ~ 3.6 V | -40 ~ 125 ℃ | ±5 ℃(需校准) | — | — | 12 bit | — | 用于芯片过热保护,环境测量精度差 |
1.3 AHT20指标介绍
参数 | 指标数值 | 说明 |
---|---|---|
供电电压 (VDD) | 2.0 ~ 5.5 V | 典型值 3.3 V |
工作电流 | 0.4 mA(测量时典型值) | 休眠电流 < 0.5 μA |
通信接口 | I²C(标准模式/快速模式) | 最大速率 400 kHz |
测量分辨率 | 16 bit | 温度/湿度均为 16 位 ADC |
湿度测量范围 | 0 %RH ~ 100 %RH | 无凝露情况下 |
湿度测量精度 | ±2 %RH(25 ℃时典型值) | 20%RH ~ 80%RH 区间 |
湿度重复性 | ±0.1 %RH | |
温度测量范围 | -40 ℃ ~ +85 ℃ | |
温度测量精度 | ±0.3 ℃(25 ℃时典型值) | -20 ℃ ~ +60 ℃ 区间 |
温度重复性 | ±0.1 ℃ | |
测量时间 | 约 80 ms | 启动测量到输出数据 |
数据输出格式 | 20 bit 有效数据(温度/湿度各占 20 位) | 通过 I²C 读取 6 字节数据 |
封装形式 | SMD 6 引脚 | 小体积、贴片封装 |
注: 入门实验可使用 DHT11 或 DHT22 进行温湿度采集,二者通信兼容,DHT22 精度更高;实际工程或环境监测广泛使用 AHT20,高精度可靠;DS3231 与 STM32 内部温度传感器仅作辅助参考,不适合精确环境测量。
1.4 AHT20使用介绍
在 STM32 HAL 库中,AHT20 的 7 位 I²C 地址固定为 0x38
,左移 1 位得到 0x70
。无论读写操作,只需在 HAL 函数中传入 0x70
,HAL库会根据函数类型自动设置最低位(0=写,1=读)
步骤 | 目的 | I²C 命令 | 数据/参数 | 延时 | 备注 |
---|---|---|---|---|---|
1 | 初始化传感器 | 0xE1 | 0x08 0x00 | 40ms | 进入正常工作模式 |
2 | 读取状态(可选) | 读取 1 字节 | — | — | 状态寄存器
|
3 | 软件复位(Soft Reset) | 0xBA | 无 | 20ms | 可选步骤,用于强制复位传感器 |
4 | 发送测量命令 | 0xAC | 0x33 0x00 | 80ms | 启动一次温湿度测量 |
5 | 读取测量数据 | 读取 6 字节 | — | — | 前 20bit:湿度;后 20bit:温度,需要解析成浮点值 |
1.5 写命令
在 HAL 库中,有两个常用 I²C 函数发送数据:
写数据 (HAL_I2C_Mem_Write)
HAL_I2C_Mem_Write
场景:适用于存储型 I²C 设备(如 EEPROM)
功能:一次性写入内存地址和数据
特点:保证总线时序连续,EEPROM 或寄存器型芯片可以正确识别存储地址
注意事项:
不能分两次使用
HAL_I2C_Master_Transmit
原因:第一次发送存储地址后 Stop → 第二次发送数据时,EEPROM 会把第一个数据字节当作新的内存地址
正确做法:一次性发送
[存储地址 + 数据]
,或使用HAL_I2C_Mem_Write
内部实现:
Start 信号:主机发送起始信号
发送从机地址 + 写标志 (DevAddr+W)
发送存储地址 (MemAddress)
发送数据:从机接收要写入的字节
Stop 信号:结束总线通信
传输数据 (HAL_I2C_Master_Transmit)
HAL_I2C_Master_Transmit
场景:适用于命令型 I²C 设备(如 AHT20)
功能:发送命令及参数数据
特点:可先发送命令,再连续发送参数,效果等同于
HAL_I2C_Mem_Write
原因:HAL 库底层写操作就是“先发送地址/命令 → 再发送数据”,总线连续
内部实现:
Start 信号:主机发送起始信号
发送从机地址 + 写标志 (DevAddr+W)
发送命令字
发送参数数据(可选)
Stop 信号:结束总线通信
HAL_StatusTypeDef HAL_I2C_Mem_Write(I2C_HandleTypeDef *hi2c, // 指向 I2C 外设句柄,选择具体 I2C(如 &hi2c1)uint16_t DevAddress, // 从设备 I²C 地址(左移1位的8位地址),HAL 自动处理 R/W 位uint16_t MemAddress, // 从设备内部寄存器地址(要写入的寄存器)uint16_t MemAddSize, // 寄存器地址长度:I2C_MEMADD_SIZE_8BIT 或 I2C_MEMADD_SIZE_16BITuint8_t *pData, // 指向要写入的数据缓冲区指针uint16_t Size, // 要写入的数据长度(字节数)uint32_t Timeout // 超时时间(ms),超过返回错误
);
HAL_StatusTypeDef HAL_I2C_Master_Transmit(I2C_HandleTypeDef *hi2c, // I2C 外设句柄uint16_t DevAddress, // 从机地址(7 位或 10 位地址左移 + R/W 位)uint8_t *pData, // 待发送的数据缓冲区指针uint16_t Size, // 发送的数据长度(字节数)uint32_t Timeout // 超时时间(ms)
);
1.6 读数据
在 HAL 库中,有两个常用 I²C 函数接收数据:
读数据 (HAL_I2C_Mem_Read)
场景:适合带内部地址或寄存器的 I²C 设备
功能:先写从机内部寄存器地址,再读取数据
特点:通过写入寄存器地址 + Repeated Start + 读操作,保证时序连续,适用于带寄存器或内存地址的 I²C 设备(如 EEPROM)
内部实现:
Start 信号:主机发送起始信号
发送从机地址 + 写标志 (DevAddr+W)
发送寄存器/存储地址 (MemAddress)
Repeated Start 信号:连续启动,保持总线控制权
发送从机地址 + 读标志 (DevAddr+R)
接收数据:从从机读取指定长度的数据
Stop 信号:结束总线通信
说明:这种操作保证了时序连续,EEPROM 或寄存器型 I²C 芯片可以安全识别寄存器地址并返回正确数据。
接收数据 (HAL_I2C_Master_Receive)
场景:适合命令型设备直接返回数据或连续读取 I²C 总线数据
功能:直接从 I²C 从机接收指定长度的数据
特点:无需先写寄存器地址,数据读取连续,适用于不带内部寄存器地址的设备(如 AHT20 测量数据)
内部实现:
Start 信号:主机发送起始信号
发送从机地址 + 读标志 (DevAddr+R)
接收数据:从从机连续读取指定长度的数据
Stop 信号:结束总线通信
说明:因为没有写入寄存器地址的过程,所以 EEPROM 等需要先指定内存地址的芯片不能直接使用该函数读取数据。
HAL_StatusTypeDef HAL_I2C_Master_Receive(I2C_HandleTypeDef *hi2c, // 指向 I2C 外设句柄,选择具体 I2C(如 &hi2c1)uint16_t DevAddress, // 从设备 I²C 地址(左移1位的8位地址),HAL 自动处理 R/W 位uint8_t *pData, // 指向接收数据缓冲区的指针uint16_t Size, // 要接收的数据长度(字节数)uint32_t Timeout // 超时时间(ms),超过返回错误
);
HAL_StatusTypeDef HAL_I2C_Mem_Read(I2C_HandleTypeDef *hi2c, // I2C 外设句柄uint16_t DevAddress, // I2C 从机地址(7 位左移 + R/W)uint16_t MemAddress, // 内存寄存器地址 / 命令字uint16_t MemAddSize, // MemAddress 长度:I2C_MEMADD_SIZE_8BIT 或 I2C_MEMADD_SIZE_16BITuint8_t *pData, // 接收数据缓冲区指针uint16_t Size, // 要接收的数据长度(字节数)uint32_t Timeout // 超时时间(ms)
);
2. STM32CubeMx设置
2.1 SYS设置
2.2 RCC设置
2.3 IIC设置
2.4 USART设置
3. MDK keil设置
3.1 Target设置
3.2 工程目录添加
3.3 debug设置
3.4 工程文件添加
4. VSCode编码
4.1 ATH20.c
#include "ATH20.h"
#include "stm32f1xx_hal.h"
#include "stdio.h"
#include "string.h"/*** * @brief 初始化完成检测* @retval 1: 初始化完成, 0: 未完成*/
uint8_t ATH20_Read_Cal_Init_Enable(void)
{uint8_t status = 0;HAL_I2C_Master_Receive(&hi2c1, ATH20_SLAVE_ADDRESS, &status, 1, HAL_MAX_DELAY);// CALIB = 1if((status & 0x08) != 0)return 1;elsereturn 0;
}/*** @brief 测量完成检测* @retval 1: 测量完成, 0: 测量中*/
uint8_t ATH20_Read_Cal_Test_Enable(void)
{uint8_t status = 0;HAL_I2C_Master_Receive(&hi2c1, ATH20_SLAVE_ADDRESS, &status, 1, HAL_MAX_DELAY);// BUSY = 0 表示测量完成return ((status & 0x80) == 0) ? 1 : 0;
}/*** @brief 初始化 AHT20* @retval 0 成功,1 失败*/
uint8_t ATH20_Init(void)
{uint8_t cmd = INIT;uint8_t param[2] = {0x08, 0x00};uint8_t count = 0;// 初始化传感器 HAL_I2C_Mem_Write(&hi2c1, ATH20_SLAVE_ADDRESS, INIT, I2C_MEMADD_SIZE_8BIT, param, 2, HAL_MAX_DELAY);// HAL_I2C_Master_Transmit(&hi2c1, ATH20_SLAVE_ADDRESS, &cmd, 1, HAL_MAX_DELAY);//先发送命令字// HAL_I2C_Master_Transmit(&hi2c1, ATH20_SLAVE_ADDRESS, param, 2, HAL_MAX_DELAY);// 再发送参数HAL_Delay(40);// 等待校准完成while (!ATH20_Read_Cal_Init_Enable()){// 软件复位uint8_t reset = SoftReset;HAL_I2C_Master_Transmit(&hi2c1, ATH20_SLAVE_ADDRESS, &reset, 1, HAL_MAX_DELAY);HAL_Delay(20);// 再次初始化HAL_I2C_Mem_Write(&hi2c1, ATH20_SLAVE_ADDRESS, INIT, I2C_MEMADD_SIZE_8BIT, param, 2, HAL_MAX_DELAY);// HAL_I2C_Master_Transmit(&hi2c1, ATH20_SLAVE_ADDRESS, &cmd, 1, HAL_MAX_DELAY);// HAL_I2C_Master_Transmit(&hi2c1, ATH20_SLAVE_ADDRESS, param, 2, HAL_MAX_DELAY);HAL_Delay(40);if (++count >= 10){printf("AHT20 init failed after 10 attempts\r\n");return 0; // 初始化失败}}printf("AHT20 initialization successful\r\n");return 1; // 初始化成功
}/*** @brief 读取温湿度数据* @param temp: 温度指针 (单位 ℃)* @param humidity: 湿度指针 (单位 %)*/
void ATH20_Read_CTdata(float *temp, float *humidity)
{uint8_t cmd[2] = {0x33, 0x00}; // 测量命令参数uint8_t buf[6] = {0};// 发送测量命令HAL_I2C_Mem_Write(&hi2c1, ATH20_SLAVE_ADDRESS, StartTest, I2C_MEMADD_SIZE_8BIT, cmd, 2, HAL_MAX_DELAY);HAL_Delay(80);// 等待测量完成while(!ATH20_Read_Cal_Test_Enable()) {HAL_Delay(5); // 每 5ms 查询一次状态寄存器}// 测量完成后读取 6 字节数据if(HAL_I2C_Master_Receive(&hi2c1, ATH20_SLAVE_ADDRESS, buf, 6, HAL_MAX_DELAY) != HAL_OK){*temp = 0;*humidity = 0;return;}// 数据解析uint32_t raw_hum = ((uint32_t)(buf[1]) << 12) | ((uint32_t)(buf[2]) << 4) | ((buf[3] >> 4) & 0x0F);uint32_t raw_temp = (((uint32_t)(buf[3] & 0x0F)) << 16) | ((uint32_t)(buf[4]) << 8) | buf[5];*humidity = (float)raw_hum * 100.0f / 1048576.0f;*temp = (float)raw_temp * 200.0f / 1048576.0f - 50.0f;
}
4.2 ATH20.h
#ifndef __ATH20_H
#define __ATH20_H#include "stm32f1xx_hal.h"// I2C 句柄
extern I2C_HandleTypeDef hi2c1;#define ATH20_SLAVE_ADDRESS (0x38 << 1) // HAL 库使用 8 位地址,需要左移1
// AHT20 命令
#define INIT 0xE1 // 初始化
#define SoftReset 0xBA // 软件复位
#define StartTest 0xAC // 启动测量uint8_t ATH20_Init(void);
uint8_t ATH20_Read_Cal_Init_Enable(void);
uint8_t ATH20_Read_Cal_Test_Enable(void);
void ATH20_Read_CTdata(float *temp, float *humidity);#endif
4.3 usart.c
/* USER CODE BEGIN Header */
/********************************************************************************* @file usart.c* @brief This file provides code for the configuration* of the USART instances.******************************************************************************* @attention** Copyright (c) 2025 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usart.h"/* USER CODE BEGIN 0 *//* USER CODE END 0 */UART_HandleTypeDef huart1;/* USART1 init function */void MX_USART1_UART_Init(void)
{/* USER CODE BEGIN USART1_Init 0 *//* USER CODE END USART1_Init 0 *//* USER CODE BEGIN USART1_Init 1 *//* USER CODE END USART1_Init 1 */huart1.Instance = USART1;huart1.Init.BaudRate = 115200;huart1.Init.WordLength = UART_WORDLENGTH_8B;huart1.Init.StopBits = UART_STOPBITS_1;huart1.Init.Parity = UART_PARITY_NONE;huart1.Init.Mode = UART_MODE_TX_RX;huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;huart1.Init.OverSampling = UART_OVERSAMPLING_16;if (HAL_UART_Init(&huart1) != HAL_OK){Error_Handler();}/* USER CODE BEGIN USART1_Init 2 *//* USER CODE END USART1_Init 2 */}void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{GPIO_InitTypeDef GPIO_InitStruct = {0};if(uartHandle->Instance==USART1){/* USER CODE BEGIN USART1_MspInit 0 *//* USER CODE END USART1_MspInit 0 *//* USART1 clock enable */__HAL_RCC_USART1_CLK_ENABLE();__HAL_RCC_GPIOA_CLK_ENABLE();/**USART1 GPIO ConfigurationPA9 ------> USART1_TXPA10 ------> USART1_RX*/GPIO_InitStruct.Pin = GPIO_PIN_9;GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);GPIO_InitStruct.Pin = GPIO_PIN_10;GPIO_InitStruct.Mode = GPIO_MODE_INPUT;GPIO_InitStruct.Pull = GPIO_NOPULL;HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);/* USART1 interrupt Init */HAL_NVIC_SetPriority(USART1_IRQn, 4, 0);HAL_NVIC_EnableIRQ(USART1_IRQn);/* USER CODE BEGIN USART1_MspInit 1 *//* USER CODE END USART1_MspInit 1 */}
}void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{if(uartHandle->Instance==USART1){/* USER CODE BEGIN USART1_MspDeInit 0 *//* USER CODE END USART1_MspDeInit 0 *//* Peripheral clock disable */__HAL_RCC_USART1_CLK_DISABLE();/**USART1 GPIO ConfigurationPA9 ------> USART1_TXPA10 ------> USART1_RX*/HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);/* USART1 interrupt Deinit */HAL_NVIC_DisableIRQ(USART1_IRQn);/* USER CODE BEGIN USART1_MspDeInit 1 *//* USER CODE END USART1_MspDeInit 1 */}
}/* USER CODE BEGIN 1 */
int fputc(int ch, FILE * file){ //打印重定向HAL_UART_Transmit(&huart1,(uint8_t*)&ch,1,1000);return ch;
}
/* USER CODE END 1 */
4.4 usart.h
/* USER CODE BEGIN Header */
/********************************************************************************* @file usart.h* @brief This file contains all the function prototypes for* the usart.c file******************************************************************************* @attention** Copyright (c) 2025 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USART_H__
#define __USART_H__#ifdef __cplusplus
extern "C" {
#endif/* Includes ------------------------------------------------------------------*/
#include "main.h"/* USER CODE BEGIN Includes */
#include "stdio.h"
/* USER CODE END Includes */extern UART_HandleTypeDef huart1;/* USER CODE BEGIN Private defines *//* USER CODE END Private defines */void MX_USART1_UART_Init(void);/* USER CODE BEGIN Prototypes *//* USER CODE END Prototypes */#ifdef __cplusplus
}
#endif#endif /* __USART_H__ */
4.5 main.c
/* USER CODE BEGIN Header */
/********************************************************************************* @file : main.c* @brief : Main program body******************************************************************************* @attention** Copyright (c) 2025 STMicroelectronics.* All rights reserved.** This software is licensed under terms that can be found in the LICENSE file* in the root directory of this software component.* If no LICENSE file comes with this software, it is provided AS-IS.********************************************************************************/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "i2c.h"
#include "usart.h"
#include "gpio.h"/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "ATH20.h"
/* USER CODE END Includes *//* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD *//* USER CODE END PTD *//* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD *//* USER CODE END PD *//* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM *//* USER CODE END PM *//* Private variables ---------------------------------------------------------*//* USER CODE BEGIN PV */
float temper, humidity; //ATH20输出参数
/* USER CODE END PV *//* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP *//* USER CODE END PFP *//* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 *//* USER CODE END 0 *//*** @brief The application entry point.* @retval int*/
int main(void)
{/* USER CODE BEGIN 1 *//* USER CODE END 1 *//* MCU Configuration--------------------------------------------------------*//* Reset of all peripherals, Initializes the Flash interface and the Systick. */HAL_Init();/* USER CODE BEGIN Init *//* USER CODE END Init *//* Configure the system clock */SystemClock_Config();/* USER CODE BEGIN SysInit *//* USER CODE END SysInit *//* Initialize all configured peripherals */MX_GPIO_Init();MX_USART1_UART_Init();MX_I2C1_Init();/* USER CODE BEGIN 2 */if (ATH20_Init()){printf("AHT20 Init OK!\r\n");}else{printf("AHT20 Init Failed!\r\n");while (1);}/* USER CODE END 2 *//* Infinite loop *//* USER CODE BEGIN WHILE */while (1){/* USER CODE END WHILE *//* USER CODE BEGIN 3 */// 温湿度读取ATH20_Read_CTdata(&temper, &humidity);printf("Temp: %.2f C, Humidity: %.2f %%\r\n", temper, humidity);HAL_Delay(3000);}/* USER CODE END 3 */
}/*** @brief System Clock Configuration* @retval None*/
void SystemClock_Config(void)
{RCC_OscInitTypeDef RCC_OscInitStruct = {0};RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};/** Initializes the RCC Oscillators according to the specified parameters* in the RCC_OscInitTypeDef structure.*/RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;RCC_OscInitStruct.HSEState = RCC_HSE_ON;RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;RCC_OscInitStruct.HSIState = RCC_HSI_ON;RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK){Error_Handler();}/** Initializes the CPU, AHB and APB buses clocks*/RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK){Error_Handler();}
}/* USER CODE BEGIN 4 *//* USER CODE END 4 *//*** @brief This function is executed in case of error occurrence.* @retval None*/
void Error_Handler(void)
{/* USER CODE BEGIN Error_Handler_Debug *//* User can add his own implementation to report the HAL error return state */__disable_irq();while (1){}/* USER CODE END Error_Handler_Debug */
}#ifdef USE_FULL_ASSERT
/*** @brief Reports the name of the source file and the source line number* where the assert_param error has occurred.* @param file: pointer to the source file name* @param line: assert_param error line source number* @retval None*/
void assert_failed(uint8_t *file, uint32_t line)
{/* USER CODE BEGIN 6 *//* User can add his own implementation to report the file name and line number,ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) *//* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
5. 验证
通过对 AHT20 传感器吹气,可以明显观察到温度和湿度的上升,传感器响应非常灵敏。本实验采用 I²C 通信实现数据采集。与存储型 EEPROM(如 AT24C32)不同,AHT20 属于命令型设备,因此在使用 STM32 HAL 库时的函数调用方式有所区别。本实验不仅巩固了 I²C 通信的基本知识和 HAL 库函数的使用方法,同时也对高精度温湿度传感器的应用进行了实践说明,为学习和工作提供了参考。