3 changed files with 1272 additions and 1054 deletions
File diff suppressed because it is too large
@ -0,0 +1,218 @@ |
|||||
|
/*
|
||||
|
* Copyright (c) 2025, Your Name |
||||
|
* |
||||
|
* SPDX-License-Identifier: Apache-2.0 |
||||
|
* |
||||
|
* Change Logs: |
||||
|
* Date Author Notes |
||||
|
* 2025-12-27 Developer First version for AHT20 on RT-Thread |
||||
|
*/ |
||||
|
|
||||
|
#include <rtthread.h> |
||||
|
#include <rtdevice.h> |
||||
|
#include <board.h> |
||||
|
|
||||
|
#define DBG_TAG "sensor.aht20" |
||||
|
#define DBG_LVL DBG_LOG |
||||
|
#include <rtdbg.h> |
||||
|
|
||||
|
/* AHT20 I2C 地址 */ |
||||
|
#define AHT20_I2C_ADDR 0x38 |
||||
|
/* 使用的 I2C 总线设备名 */ |
||||
|
#define AHT20_I2C_BUS_NAME "i2c2" // 根据你的板子修改,如 "i2c2"
|
||||
|
|
||||
|
static struct rt_i2c_bus_device *i2c_bus = RT_NULL; |
||||
|
|
||||
|
/**
|
||||
|
* 向 AHT20 发送命令 |
||||
|
*/ |
||||
|
static rt_err_t aht20_send_cmd(rt_uint8_t cmd, const rt_uint8_t *data, rt_size_t len) |
||||
|
{ |
||||
|
rt_uint8_t buf[3] = {cmd}; |
||||
|
if (len > 0) |
||||
|
{ |
||||
|
rt_memcpy(&buf[1], data, len); |
||||
|
} |
||||
|
|
||||
|
struct rt_i2c_msg msgs[1] = { |
||||
|
{ |
||||
|
.addr = AHT20_I2C_ADDR, |
||||
|
.flags = RT_I2C_WR, |
||||
|
.buf = buf, |
||||
|
.len = 1 + len, |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
if (rt_i2c_transfer(i2c_bus, msgs, 1) != 1) |
||||
|
{ |
||||
|
LOG_E("I2C send command 0x%02X failed.", cmd); |
||||
|
return -RT_ERROR; |
||||
|
} |
||||
|
return RT_EOK; |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* 从 AHT20 读取数据 |
||||
|
*/ |
||||
|
static rt_err_t aht20_read_data(rt_uint8_t *buf, rt_size_t len) |
||||
|
{ |
||||
|
struct rt_i2c_msg msgs[1] = { |
||||
|
{ |
||||
|
.addr = AHT20_I2C_ADDR, |
||||
|
.flags = RT_I2C_RD, |
||||
|
.buf = buf, |
||||
|
.len = len, |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
if (rt_i2c_transfer(i2c_bus, msgs, 1) != 1) |
||||
|
{ |
||||
|
LOG_E("I2C read data failed."); |
||||
|
return -RT_ERROR; |
||||
|
} |
||||
|
return RT_EOK; |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* 初始化 AHT20 |
||||
|
*/ |
||||
|
static rt_err_t aht20_init_sensor(void) |
||||
|
{ |
||||
|
rt_uint8_t status = 0; |
||||
|
rt_uint8_t cmd_data[2] = {0x08, 0x00}; |
||||
|
|
||||
|
/* 发送初始化命令 */ |
||||
|
if (aht20_send_cmd(0xBE, cmd_data, 2) != RT_EOK) |
||||
|
{ |
||||
|
LOG_E("Failed to send init command."); |
||||
|
return -RT_ERROR; |
||||
|
} |
||||
|
|
||||
|
rt_thread_mdelay(20); // 等待初始化完成
|
||||
|
|
||||
|
/* 读取状态字节(可选) */ |
||||
|
if (aht20_read_data(&status, 1) == RT_EOK) |
||||
|
{ |
||||
|
LOG_D("AHT20 status: 0x%02X", status); |
||||
|
} |
||||
|
|
||||
|
return RT_EOK; |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* 触发一次温湿度测量 |
||||
|
*/ |
||||
|
static rt_err_t aht20_trigger_measure(void) |
||||
|
{ |
||||
|
rt_uint8_t cmd[2] = {0x33, 0x00}; |
||||
|
return aht20_send_cmd(0xAC, cmd, 2); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* 读取原始温湿度数据(6 字节) |
||||
|
*/ |
||||
|
static rt_err_t aht20_fetch_raw(rt_uint8_t raw[6]) |
||||
|
{ |
||||
|
return aht20_read_data(raw, 6); |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* 解析原始数据为温度(0.1°C)和湿度(0.1%RH) |
||||
|
*/ |
||||
|
static void aht20_parse_data(const rt_uint8_t raw[6], rt_int32_t *temp, rt_int32_t *humi) |
||||
|
{ |
||||
|
rt_uint32_t humi_raw = ((rt_uint32_t)raw[1] << 12) | ((rt_uint32_t)raw[2] << 4) | (raw[3] >> 4); |
||||
|
rt_uint32_t temp_raw = ((rt_uint32_t)raw[3] & 0x0F) << 16 | ((rt_uint32_t)raw[4] << 8) | raw[5]; |
||||
|
|
||||
|
*humi = (rt_int32_t)((humi_raw * 1000) / (1 << 20)); // 转换为 0.1%RH
|
||||
|
*temp = (rt_int32_t)((temp_raw * 2000) / (1 << 20) - 500); // 转换为 0.1°C(公式:T = (raw / 2^20) * 200 - 50)
|
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* AHT20 读取线程 |
||||
|
*/ |
||||
|
static void aht20_thread_entry(void *parameter) |
||||
|
{ |
||||
|
rt_uint8_t raw_data[6]; |
||||
|
rt_int32_t temperature, humidity; |
||||
|
|
||||
|
while (1) |
||||
|
{ |
||||
|
if (aht20_trigger_measure() != RT_EOK) |
||||
|
{ |
||||
|
LOG_E("Trigger measurement failed."); |
||||
|
rt_thread_mdelay(2000); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
rt_thread_mdelay(80); // AHT20 典型转换时间 75ms
|
||||
|
|
||||
|
if (aht20_fetch_raw(raw_data) != RT_EOK) |
||||
|
{ |
||||
|
LOG_E("Fetch raw data failed."); |
||||
|
rt_thread_mdelay(2000); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
/* 检查忙标志(bit7 of raw_data[0] 应为 0)*/ |
||||
|
if (raw_data[0] & 0x80) |
||||
|
{ |
||||
|
LOG_W("AHT20 is busy, retrying..."); |
||||
|
rt_thread_mdelay(100); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
aht20_parse_data(raw_data, &temperature, &humidity); |
||||
|
|
||||
|
LOG_I("Temp: %d.%dC, Humidity: %d.%dRH", |
||||
|
temperature / 10, temperature % 10, |
||||
|
humidity / 10, humidity % 10); |
||||
|
|
||||
|
rt_thread_mdelay(5000); // 每 2 秒读取一次
|
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/**
|
||||
|
* AHT20 驱动初始化函数 |
||||
|
*/ |
||||
|
static int rt_hw_aht20_init(void) |
||||
|
{ |
||||
|
i2c_bus = rt_i2c_bus_device_find(AHT20_I2C_BUS_NAME); |
||||
|
if (i2c_bus == RT_NULL) |
||||
|
{ |
||||
|
LOG_E("Failed to find I2C bus: %s", AHT20_I2C_BUS_NAME); |
||||
|
return -RT_ENOSYS; |
||||
|
} |
||||
|
|
||||
|
LOG_I("Found I2C bus: %s", AHT20_I2C_BUS_NAME); |
||||
|
|
||||
|
if (aht20_init_sensor() != RT_EOK) |
||||
|
{ |
||||
|
LOG_E("AHT20 sensor initialization failed!"); |
||||
|
return -RT_ERROR; |
||||
|
} |
||||
|
|
||||
|
LOG_I("AHT20 initialized successfully."); |
||||
|
|
||||
|
/* 创建读取线程 */ |
||||
|
rt_thread_t tid = rt_thread_create("ahtX0", |
||||
|
aht20_thread_entry, |
||||
|
RT_NULL, |
||||
|
512, |
||||
|
RT_THREAD_PRIORITY_MAX - 2, |
||||
|
10); |
||||
|
if (tid != RT_NULL) |
||||
|
{ |
||||
|
rt_thread_startup(tid); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
LOG_E("Failed to create AHT20 thread."); |
||||
|
return -RT_ERROR; |
||||
|
} |
||||
|
|
||||
|
return RT_EOK; |
||||
|
} |
||||
|
|
||||
|
/* 自动初始化 */ |
||||
|
INIT_APP_EXPORT(rt_hw_aht20_init); |
||||
Loading…
Reference in new issue