AHT10简介和应用电路分析
AHT20传感器是奥松电子推出的一款湿温度传感器, 在之前的文章中我曾经出了一篇使用树莓派PICO驱动, 链接已经附加上了,大家感兴趣的话可以看一下. 而AHT20传感器的驱动实际上和AHT10的相差不多. 而我们选择使用AHT20传感器的目的是为了让大家熟悉ESP-IDF框架中较为新的 driver/i2cmaster.h 库的使用.AHT20传感器
我在其他的应用电路中有看到过, 在VDD间串联了一个330欧姆的电阻, 实际上这个电阻对电路的影响非常大. 在我3.3V的电路中大概有2V的压降,从而造成了传感器不工作的情况. 对于官方的典型应用电路, 如果你的开发板工作电压是在3.3V, 千万不要加这个电阻. 其推荐应用电路如下所示.
在实际的使用中发现两个上拉电阻和Cap的滤波电容对实际的电路影响不大, 去掉了也并不会在很大程度上影响到I2C通讯. 如果开发板上干扰较多的话,建议严格按照上述的原理图.
ESP-IDF的I2C驱动
ESP-IDF一共具有三个I2C驱动的库, 它们分别是 i2c.h(遗留 I2C API 的头文件用于使用旧驱动程序的应用). i2c_master.h (提供标准通信模式下特定 API 的头文件(用于使用主机模式的新驱动程序的应用)) i2c_slave.h (提供标准通信模式下特定 API 的头文件(用于使从机模式的新驱动程序的应用)
需要注意的一点是旧版驱动程序和新版驱动程序不能混合使用, 所以如果大家使用ESP-IDF开发应用的时候如果不想手动编写驱动程序的话, 一定要注意头文件中的驱动版本.
对于Master设备的驱动初始化的时候一般只需要按照下面的代码即可完成I2C总线的初始化
i2c_master_bus_config_t i2c_mst_config = { .clk_source = I2C_CLK_SRC_DEFAULT, .i2c_port = TEST_I2C_PORT, .scl_io_num = I2C_MASTER_SCL_IO, .sda_io_num = I2C_MASTER_SDA_IO, .glitch_ignore_cnt = 7, .flags.enable_internal_pullup = true, }; i2c_master_bus_handle_t bus_handle; ESP_ERROR_CHECK(i2c_new_master_bus(&i2c_mst_config, &bus_handle));
上述的代码仅仅是对总线进行初始化. 如果想要对对应的I2C设备进行初始化的话,我们还需要创建设备句柄, 并且把它挂载到I2C总线上.
i2c_device_config_t dev_cfg = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, .device_address = 0x58, .scl_speed_hz = 100000, }; i2c_master_dev_handle_t dev_handle; ESP_ERROR_CHECK(i2c_master_bus_add_device(bus_handle, &dev_cfg, &dev_handle));
上述代码则是绑定了一个I2C设备, 其地址为0X58 通讯的频率为100000HZ. 之后对这个设备句柄进行了初始化. 之后我们便可以使用I2C驱动的i2c_master_transmit 和 i2c_master_receive 进行数据的收发.
AHT20的驱动
首先我们需要绑定当前的AHT20设备句柄到I2C master总线上
void aht20_init(void) { i2c_device_config_t dev_cfg = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, .device_address = AHT20_I2C_ADDRESS, .scl_speed_hz = 400000, }; esp_err_t ret = i2c_master_bus_add_device(i2c_bus_handle, &dev_cfg, &aht10_dev_handle); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to create I2C device handle: %d", ret); } ESP_LOGI(TAG, "Initializing AHT10..."); uint8_t init_cmd[3] = {AHT20_CMD_INIT, 0x08, 0x00}; i2c_master_transmit(aht10_dev_handle, init_cmd, 3, 1000 / portTICK_PERIOD_MS); vTaskDelay(40 / portTICK_PERIOD_MS); // Wait for 40ms }
上述代码完成了数据手册里的第一部分, 即上电初始化.
之后使用按照数据手册定义, 发送0XAC和对应的命令来触发传感器的测量.
如下代码所示
uint8_t status; uint8_t trigger_cmd[3] = {AHT20_CMD_TRIGGER, 0x33, 0x00}; uint8_t data[7] = {0}; // Send trigger command i2c_master_transmit(aht10_dev_handle, trigger_cmd, 3, 1000 / portTICK_PERIOD_MS);
湿温度的测量需要一定的时间,在我们触发测量操作之后应该等待测量完成
如下代码所示
vTaskDelay(80 / portTICK_PERIOD_MS); // Wait for 80ms // 检查是否测量完成 i2c_master_receive(aht10_dev_handle, &status, 1, 1000 / portTICK_PERIOD_MS); while (status & 0x80) // Bit[7] should be 0 { vTaskDelay(10 / portTICK_PERIOD_MS); i2c_master_receive(aht10_dev_handle, &status, 1, 1000 / portTICK_PERIOD_MS); }
接着,我们可以从I2C总线上读取数据, 并且进行计算出湿温度数据.
如下代码所示
// 读取7个bytes数据 i2c_master_receive(aht10_dev_handle, data, 7, 1000 / portTICK_PERIOD_MS); uint32_t raw_humidity = ((uint32_t)data[1] << 12) | ((uint32_t)data[2] << 4) | ((uint32_t)data[3] >> 4); uint32_t raw_temperature = (((uint32_t)data[3] & 0x0F) << 16) | ((uint32_t)data[4] << 8) | (uint32_t)data[5]; // 计算湿温度数据 *humidity = ((float)raw_humidity / 1048576.0) * 100.0; *temperature = ((float)raw_temperature / 1048576.0) * 200.0 - 50.0;
完整代码如下所示
头文件
#ifndef AHT20_H #define AHT20_H #include "driver/i2c_master.h" // AHT20 I2C address #define AHT20_I2C_ADDRESS 0x38 /* AHT20 命令 */ #define AHT20_CMD_INIT 0xBE /* 初始化命令 */ #define AHT20_CMD_TRIGGER 0xAC /* 软件复位命令*/ #define AHT20_CMD_SOFT_RESET 0xBA // Function prototypes void aht20_init(void); float aht20_read_temperature_and_humidity(float *humidity, float *temperature); void aht20_soft_reset(void); #endif // AHT20_H
源码文件
#include "aht20.h" #include "driver/i2c_master.h" #include <unistd.h> #include "freertos/FreeRTOS.h" #include "freertos/task.h" #include "esp_log.h" extern i2c_master_bus_handle_t i2c_bus_handle; i2c_master_dev_handle_t aht10_dev_handle; static const char *TAG = "AHT20"; void aht20_init(void) { i2c_device_config_t dev_cfg = { .dev_addr_length = I2C_ADDR_BIT_LEN_7, .device_address = AHT20_I2C_ADDRESS, .scl_speed_hz = 400000, }; esp_err_t ret = i2c_master_bus_add_device(i2c_bus_handle, &dev_cfg, &aht10_dev_handle); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to create I2C device handle: %d", ret); } ESP_LOGI(TAG, "Initializing AHT10..."); uint8_t init_cmd[3] = {AHT20_CMD_INIT, 0x08, 0x00}; i2c_master_transmit(aht10_dev_handle, init_cmd, 3, 1000 / portTICK_PERIOD_MS); vTaskDelay(40 / portTICK_PERIOD_MS); // Wait for 40ms } // Function to read temperature and humidity float aht20_read_temperature_and_humidity(float *humidity, float *temperature) { uint8_t status; uint8_t trigger_cmd[3] = {AHT20_CMD_TRIGGER, 0x33, 0x00}; uint8_t data[7] = {0}; // Send trigger command i2c_master_transmit(aht10_dev_handle, trigger_cmd, 3, 1000 / portTICK_PERIOD_MS); vTaskDelay(80 / portTICK_PERIOD_MS); // Wait for 80ms // Check if measurement is complete i2c_master_receive(aht10_dev_handle, &status, 1, 1000 / portTICK_PERIOD_MS); while (status & 0x80) // Bit[7] should be 0 { vTaskDelay(10 / portTICK_PERIOD_MS); i2c_master_receive(aht10_dev_handle, &status, 1, 1000 / portTICK_PERIOD_MS); } // Read data i2c_master_receive(aht10_dev_handle, data, 7, 1000 / portTICK_PERIOD_MS); uint32_t raw_humidity = ((uint32_t)data[1] << 12) | ((uint32_t)data[2] << 4) | ((uint32_t)data[3] >> 4); uint32_t raw_temperature = (((uint32_t)data[3] & 0x0F) << 16) | ((uint32_t)data[4] << 8) | (uint32_t)data[5]; *humidity = ((float)raw_humidity / 1048576.0) * 100.0; *temperature = ((float)raw_temperature / 1048576.0) * 200.0 - 50.0; return 0; }
控制台效果如下:
图片效果如下:
源码文件: