GD32/AT32双平台:AHT20温湿度传感器驱动详解(附完整代码)
·
GD32/AT32双平台:AHT20温湿度传感器驱动详解(附完整代码)
手把手教你用GD32E23x和AT32F403A驱动AHT20高精度温湿度传感器,含I2C协议详解、完整代码、双平台适配、编译验证,一次搞定。
一、硬件准备
传感器简介
AHT20 是 ASAIR(奥松电子)出品的高精度温湿度传感器,I2C 接口,内部集成 MEMS 传感芯片,体积小、精度高、响应快。广泛应用于暖通空调、除湿器、智能家电、医疗设备等场景。
| 参数 | 值 |
|---|---|
| 工作电压 | 2.2V ~ 5.5V |
| 温度范围 | -40°C ~ +85°C(精度 ±0.3°C) |
| 湿度范围 | 0% ~ 100% RH(精度 ±2% RH) |
| 采样周期 | ≥1 秒 |
| 通信接口 | I2C(地址 0x38) |
| I2C 速率 | 最高 400kHz(Fast Mode) |
引脚接线
| AHT20 | GD32E23x | AT32F403A |
|---|---|---|
| VCC | 3.3V | 3.3V |
| SCL | PB6 | PB6 |
| SDA | PB7 | PB7 |
| GND | GND | GND |
注意: SCL 和 SDA 线需外接 4.7kΩ 上拉电阻到 VCC(成品模块通常已集成)。
二、I2C 通信协议详解
AHT20 使用标准 I2C 协议,7-bit 设备地址 0x38。本文采用软件模拟 I2C(bit-bang),不依赖硬件 I2C 外设,更容易理解协议本质。
命令列表
| 命令 | 代码 | 参数 | 说明 |
|---|---|---|---|
| 软复位 | 0xBA | 无 | 复位传感器,等待 20ms |
| 初始化 | 0xBE | 0x08, 0x00 | 使能校准,等待 10ms |
| 触发测量 | 0xAC | 0x33, 0x00 | 启动测量,等待 ≥75ms |
测量流程
Step 1 → 初始化(仅上电一次)
主机 → AHT20: [0xBE, 0x08, 0x00]
等待 10ms
Step 2 → 触发测量
主机 → AHT20: [0xAC, 0x33, 0x00]
等待 ≥75ms
Step 3 → 读取数据
主机 ← AHT20: [Status, HumH, HumM, HumL+TempH, TempM, TempL]
共 6 字节
数据格式与物理量转换
6 字节数据格式:
Byte 0: 状态寄存器 (bit7=忙, bit6=正常, bit3=校准已使能)
Byte 1: 湿度 [19:12] (高 8 位)
Byte 2: 湿度 [11:4] (中 8 位)
Byte 3: 湿度 [3:0] (低 4 位) | 温度 [19:16] (高 4 位)
Byte 4: 温度 [15:8] (中 8 位)
Byte 5: 温度 [7:0] (低 8 位)
转换公式:
湿度(%RH) = 湿度原始值 / 2^20 × 100%
温度(°C) = 温度原始值 / 2^20 × 200 - 50
三、GD32E23x 驱动实现
软件 I2C 底层
/* aht20.c — 软件 I2C 驱动 */
#include "gd32e23x_reg.h"
/* 引脚: PB6=SCL, PB7=SDA */
#define I2C_SCL_H() GPIO_SET(GPIOB_BASE, 6)
#define I2C_SCL_L() GPIO_CLR(GPIOB_BASE, 6)
#define I2C_SDA_H() GPIO_SET(GPIOB_BASE, 7)
#define I2C_SDA_L() GPIO_CLR(GPIOB_BASE, 7)
#define I2C_SDA_READ() GPIO_READ(GPIOB_BASE, 7)
/* AHT20 地址:0x38 << 1 */
#define AHT20_ADDR_W 0x70
#define AHT20_ADDR_R 0x71
#define AHT20_CMD_TRIGGER 0xAC
#define AHT20_CMD_INIT 0xBE
#define AHT20_CMD_SOFT_RST 0xBA
#define I2C_HALF_DELAY() delay_1us(5) /* ~100kHz */
uint8_t aht20_i2c_start(void) {
I2C_SDA_H(); I2C_SCL_H(); I2C_HALF_DELAY();
I2C_SDA_L(); /* SDA↓ while SCL↑ = START */
I2C_HALF_DELAY(); I2C_SCL_L(); I2C_HALF_DELAY();
return 0;
}
void aht20_i2c_stop(void) {
I2C_SDA_L(); I2C_SCL_H(); I2C_HALF_DELAY();
I2C_SDA_H(); /* SDA↑ while SCL↑ = STOP */
I2C_HALF_DELAY();
}
uint8_t aht20_i2c_send_byte(uint8_t data) {
uint8_t i;
for (i = 0; i < 8; i++) {
if (data & 0x80) I2C_SDA_H(); else I2C_SDA_L();
data <<= 1;
I2C_HALF_DELAY(); I2C_SCL_H(); I2C_HALF_DELAY(); I2C_SCL_L();
}
I2C_SDA_INPUT(); I2C_HALF_DELAY(); I2C_SCL_H();
I2C_HALF_DELAY();
uint8_t ack = I2C_SDA_READ(); /* 0=ACK, 1=NACK */
I2C_SCL_L(); I2C_SDA_OUTPUT();
return ack;
}
uint8_t aht20_i2c_recv_byte(uint8_t ack) {
uint8_t i, data = 0;
I2C_SDA_INPUT();
for (i = 0; i < 8; i++) {
data <<= 1;
I2C_HALF_DELAY(); I2C_SCL_H(); I2C_HALF_DELAY();
if (I2C_SDA_READ()) data |= 1;
I2C_SCL_L();
}
I2C_SDA_OUTPUT();
if (ack) I2C_SDA_H(); else I2C_SDA_L();
I2C_HALF_DELAY(); I2C_SCL_H(); I2C_HALF_DELAY(); I2C_SCL_L();
return data;
}
AHT20 读写实现
uint8_t aht20_init(void) {
/* 软复位 */
aht20_i2c_start();
aht20_i2c_send_byte(AHT20_ADDR_W);
aht20_i2c_send_byte(AHT20_CMD_SOFT_RST);
aht20_i2c_send_byte(0x00); aht20_i2c_send_byte(0x00);
aht20_i2c_stop();
delay_ms(20);
/* 初始化校准 */
aht20_i2c_start();
aht20_i2c_send_byte(AHT20_ADDR_W);
aht20_i2c_send_byte(AHT20_CMD_INIT);
aht20_i2c_send_byte(0x08); aht20_i2c_send_byte(0x00);
aht20_i2c_stop();
delay_ms(10);
return 0;
}
uint8_t aht20_read_th(float *temperature, float *humidity) {
uint8_t buf[6];
/* 触发测量 */
aht20_i2c_start();
aht20_i2c_send_byte(AHT20_ADDR_W);
aht20_i2c_send_byte(AHT20_CMD_TRIGGER);
aht20_i2c_send_byte(0x33); aht20_i2c_send_byte(0x00);
aht20_i2c_stop();
delay_ms(80);
/* 读 6 字节 */
aht20_i2c_start();
aht20_i2c_send_byte(AHT20_ADDR_R);
for (int i = 0; i < 6; i++)
buf[i] = aht20_i2c_recv_byte(i >= 5 ? 1 : 0);
aht20_i2c_stop();
if (buf[0] & 0x80) return 2; /* 忙 */
uint32_t hum_raw = ((uint32_t)buf[1] << 12) | ((uint32_t)buf[2] << 4)
| ((uint32_t)buf[3] >> 4);
uint32_t temp_raw = ((uint32_t)(buf[3] & 0x0F) << 16)
| ((uint32_t)buf[4] << 8) | (uint32_t)buf[5];
*humidity = (float)hum_raw / 1048576.0f * 100.0f;
*temperature = (float)temp_raw / 1048576.0f * 200.0f - 50.0f;
return 0;
}
四、AT32F403A 适配
AT32 版本协议逻辑完全一致,仅以下差异:
| 项目 | GD32E23x | AT32F403A |
|---|---|---|
| 头文件 | gd32e23x_reg.h |
at32f403a_reg.h |
| GPIO 模式 | GPIO_SET_MODE(port, pin, GPIO_MODE_OUTPUT_PP) |
GPIO_CFG(port, pin, GPIO_MODE_OUTPUT) |
| 时钟使能 | RCU_AHBEN |
CRM_AHB1EN |
| 主频 | 72MHz | 216MHz |
| delay_1us 循环 | ×6 | ×18 |
完整 AT32 源码结构一致,主要是寄存器和宏定义替换。
五、编译与烧录验证
编译输出
# GD32
text data bss dec hex
6520 0 2056 8576 2180 AHT20_GD32.elf
# AT32
text data bss dec hex
4940 0 4 4944 1350 AHT20_AT32.elf
串口验证
烧录后打开串口助手(115200-8-N-1),每 1 秒输出一次:
[OK] Temp: 25.1 C, RH: 60.3 %
[OK] Temp: 25.2 C, RH: 60.1 %
[OK] Temp: 25.1 C, RH: 60.2 %
六、注意事项
- 上拉电阻: SCL 和 SDA 必须外接 4.7kΩ 上拉电阻(成品模块通常已集成)
- 采样间隔: AHT20 最小测量间隔 1 秒,建议 ≥1 秒
- 首次上电: 上电后等待 20ms 才能通信
- 时序适配: 软件 I2C 的 delay_1us 循环数需适配 MCU 主频——GD32@72MHz 和 AT32@216MHz 不同
- 精度优势: AHT20 出厂已校准,温度 ±0.3°C、湿度 ±2% RH,显著优于 DHT11
- 与 DHT11 对比: AHT20 用 I2C 接口替代单总线,时序容错性更好,通信更可靠
\n\n> 完整工程源码(含 Keil 工程文件)已整理完毕,详见博主主页。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)