STM32CubeMX + HAL 库:基于 I²C 通信的 AHT20 高精度温湿度测量实验

发布于:2025-09-02 ⋅ 阅读:(16) ⋅ 点赞:(0)

 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 字节 状态寄存器
  • bit3 (CALIB) = 1 → 表示校准完成,初始化成功

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

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_16BIT
    uint8_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_16BIT
    uint8_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 = 1
    if((status & 0x08) != 0)
        return 1;
    else
        return 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 Configuration
    PA9     ------> USART1_TX
    PA10     ------> 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 Configuration
    PA9     ------> USART1_TX
    PA10     ------> 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 库函数的使用方法,同时也对高精度温湿度传感器的应用进行了实践说明,为学习和工作提供了参考。


网站公告

今日签到

点亮在社区的每一天
去签到