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 V0 ~ 50 ℃±2 ℃20 ~ 90 %RH±5 %RH8 bit1 s成本低,性能一般,适合入门实验
DHT22 / AM2302单总线3.3 ~ 6 V-40 ~ 80 ℃±0.5 ℃0 ~ 100 %RH±2 ~ 5 %RH16 bit2 s精度高于 DHT11,但刷新率较低
AHT20I²C2.0 ~ 5.5 V-40 ~ 85 ℃±0.3 ℃0 ~ 100 %RH±2 %RH16 bit80 ms低功耗,小体积,高精度,替代 DHT 系列
SHT30I²C2.4 ~ 5.5 V-40 ~ 125 ℃±0.3 ℃0 ~ 100 %RH±2 %RH14 bit8 s瑞士 Sensirion 出品,稳定性高
SHT31I²C2.4 ~ 5.5 V-40 ~ 125 ℃±0.3 ℃0 ~ 100 %RH±2 %RH14 bit2 sSHT30 升级版,支持更快采样
Si7021I²C1.9 ~ 3.6 V-40 ~ 125 ℃±0.4 ℃0 ~ 100 %RH±3 %RH14 bit<10 ms美国 Silicon Labs 出品,超低功耗
DS3231 内部温度传感器I²C2.3 ~ 5.5 V-40 ~ 85 ℃±3 ℃10 bit~1 s用于晶振温度补偿,温度精度有限
STM32 内部温度传感器片内 ADC1.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初始化传感器0xE10x08 0x0040ms进入正常工作模式
2读取状态(可选)读取 1 字节状态寄存器
  • bit3 (CALIB) = 1 → 表示校准完成,初始化成功

  • bit7 (BUSY) = 0 → 表示传感器空闲

3软件复位(Soft Reset)0xBA20ms可选步骤,用于强制复位传感器
4发送测量命令0xAC0x33 0x0080ms启动一次温湿度测量
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 测量数据)

内部实现

  1. Start 信号:主机发送起始信号

  2. 发送从机地址 + 读标志 (DevAddr+R)

  3. 接收数据:从从机连续读取指定长度的数据

  4. 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 库函数的使用方法,同时也对高精度温湿度传感器的应用进行了实践说明,为学习和工作提供了参考。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/95369.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/95369.shtml
英文地址,请注明出处:http://en.pswp.cn/bicheng/95369.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

今日分享:C++ -- vector

&#x1f60e;【博客主页&#xff1a;你最爱的小傻瓜】&#x1f60e; &#x1f914;【本文内容&#xff1a;C vector &#x1f60d; 】&#x1f914; --------------------------------------------------------------------------------------------------------------------…

NAS Docker 安装N8N

NAS Docker 安装N8Ndocker 操作中文版使用 Docker Compose&#xff08;更易于管理&#xff09;创建一个 docker-compose.yml 文件&#xff0c;内容如下&#xff1a;yaml version: 3services:n8n:image: n8nio/n8n:latestcontainer_name: n8nrestart: unless-stoppedports:- &q…

Node.js汉字转拼音指南:pinyin-pro全解析

pinyin-pro 工具库简介核心功能&#xff1a;汉字转拼音、多音字处理、音调控制、格式定制等性能特点&#xff1a;高效、轻量级、支持多种拼音风格应用场景&#xff1a;搜索优化、数据排序、中文输入法等环境准备与安装Node.js npm 或 yarn 安装 pinyin-pronpm install pinyin-p…

UART-TCP双向桥接服务

UART-TCP双向桥接服务是一种将串口&#xff08;UART&#xff09;通信与TCP/IP网络通信相互转换的技术服务&#xff0c;其核心功能是实现两种不同协议之间的数据透明传输。1. 基本概念UART&#xff08;串口&#xff09;&#xff1a;硬件设备的传统通信接口&#xff0c;常见于嵌入…

江协科技STM32学习笔记补充之001。为什么C语言在对STM32编程过程中的二进制要用十六进制来进行读写。而不能直接用二进制来进行读写。

下面给你一个“为什么嵌入式 C&#xff08;如 STM32&#xff09;普遍用十六进制而不是二进制来读写寄存器/地址”的系统性分析。核心观点&#xff1a;十六进制是对底层位模式更高效、更可靠的“人类可读编码”&#xff0c;与硬件资料、编译器和调试器生态形成了标准化协同。1&a…

从 “对话” 到 “共创”:生成式 AI 如何重塑内容创作全流程,普通人也能掌握的高效工具指南

一、引言&#xff1a;内容创作的 “AI 范式转移”—— 从单向输出到双向共创​传统内容创作痛点&#xff1a;灵感枯竭、流程繁琐&#xff08;选题 - 调研 - 初稿 - 修改 - 定稿耗时久&#xff09;、专业门槛高&#xff08;如设计需掌握 PS、写作需深厚文字功底&#xff09;​生…

函数、数组与 grep + 正则表达式的 Linux Shell 编程进阶指南

文章目录1.函数相关2.数组相关3.正则表达式与grep根据你提供的内容&#xff0c;我整理了一份关于Shell脚本中函数、数组和正则表达式的简明参考&#xff1a; 1.函数相关 函数调用&#xff1a; 直接使用函数名调用&#xff1a;函数名 参数传递&#xff1a; 函数内接收参数&…

nginx-realip问题解决方案

nginx-realip问题解决方案一、配置真实ip解析二、日志中记录真实 IP三、在日志中验证一、配置真实ip解析 让backend server知道前端是谁来访问的&#xff0c;知道他们的ip地址 LB在转发数据包的时候&#xff0c;在http请求报文里增加一个字段&#xff0c;携带user的ip地址&am…

Kafka入门指南:从安装到集群部署

一、Kafka 基础与系统要求 1.1 核心概念 Broker&#xff1a;Kafka 服务器节点&#xff0c;负责存储消息和处理客户端请求 Topic&#xff1a;消息分类的逻辑容器&#xff0c;每条消息需指定发送到某个 Topic Partition&#xff1a;Topic 的物理分片&#xff0c;可分布式存储…

20250828在荣品RD-RK3588-MID开发板的Android13系统下适配Bainianxing的GPS模块BU-16M10

20250828在荣品RD-RK3588-MID开发板的Android13系统下适配Bainianxing的GPS模块BU-16M10 2025/8/29 9:50荣品RD-RK3588-MID开发板。适配GPS 38400bps 需要配置波特率吗&#xff1f;一般是 9600这边使用的泰斗 你要适配新的gps模块&#xff1f;规格书&#xff1a;Baud rate 3840…

对部分国家(地区)出口商品类章金额数据库

一、数据库简介【艾思产研数据平台】对部分国家(地区)出口商品类章金额数据库&#xff0c;收录了2015年02月 - 2025年5月的信息&#xff0c;共计49万余条数据&#xff0c;整理出7个常用字段内容。更新频率为月更。字段内容年月、类章、国家、国家id、所属分类、月出口商品类章金…

STM32——中断

总&#xff1a;STM32——学习总纲 一、什么是中断 1.1 作用与意义 1.2 STM32 GPIO 外部中断简图 二、NVIC 2.1 NVIC 基本概念 Nested vectored interrupt controller&#xff0c;嵌套向量中断控制器&#xff0c;属于内核&#xff08;M3、M4、M7&#xff09; 用不到很多的优先…

DVWA靶场通关笔记-Weak Session IDs (Impossible级别)

目录 一、Session ID 二、源码分析 1、index.php 2、impossible.php 三、Weak Session IDs安全级别对比 四、impossible防范方法分析 1、高随机性会话 ID 生成 2、严格的 Cookie 作用域限制 3、安全的传输与存储控制期 本系列为通过《DVWA靶场通关笔记》的Weak Sessio…

SyncBack 备份同步软件: 使用 FTPS、SFTP 和 HTTPS 安全加密传输文件

传输加密是使用安全连接在网络中传输数据&#xff08;例如文件&#xff09;的过程。TLS&#xff08;传输层安全&#xff09;、SSL&#xff08;安全套接字层&#xff09;、SSH&#xff08;安全套接字外壳&#xff09;、HTTPS&#xff08;基于 SSL/TLS 的超文本传输协议&#xff…

保健品跨境电商:如何筑牢产品质量与安全防线?

保健品跨境电商&#xff1a;如何筑牢产品质量与安全防线&#xff1f;在保健品跨境电商领域&#xff0c;“质量与安全”是消费者信任的基石&#xff0c;也是品牌长期发展的生命线。从海外工厂生产到国内消费者手中&#xff0c;产品需经历“跨国运输、清关核验、仓储配送”多环节…

手把手教你搭建 UDP 多人聊天室(附完整源码)

一、项目介绍 本文将分享一个基于 UDP 协议的简易多人聊天室项目&#xff0c;包含服务器端和客户端的完整实现。该聊天室支持多客户端同时连接&#xff0c;能实现消息群发、用户加入 / 退出通知等核心功能&#xff0c;适合作为网络编程入门实践案例。项目采用 C 语言开发…

Vue基础知识-使用监视属性watch和计算属性computed实现列表过滤+排序

一、完整源码<!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>Document</title><script src…

自动化运维-ansible中的管理机密

自动化运维-ansible中的管理机密 一、Ansible Vault 在自动化配置管理中&#xff0c;直接以纯文本形式存储密码、API密钥、证书等敏感信息是极大的安全漏洞。Ansible Vault 正是为了解决这一问题而设计的核心功能 Ansible Vault 是 Ansible 的一个核心功能&#xff0c;它允许用…

UFUNCTION C++ 的再次理解

一.UFUNCTION 格式和属性也比较像&#xff0c;两部分 函数说明符&#xff0c;和元数据说明符UFUNCTION不仅能 控制对蓝图公开&#xff0c;还能与 绑定委托&#xff0c;用户输入,网络回调功能相关联&#xff0c;而且还能创建自己控制带命令二.函数说明符控制 &#xff0c;函数在…

《论文阅读》从心到词:通过综合比喻语言和语义上下文信号产生同理心反应 2025 ACL findings

《论文阅读》从心到词:通过综合比喻语言和语义上下文信号产生同理心反应 2025 ACL findings 前言 创新点 形象语言 (Figurative Language) 语义上下文信号(Semantic Context Signals) 模型架构 情绪原因标注 形象语言元数据获取 共情回复生成 实验结果 总结 趋势 前言 亲…