Skip to content

Instantly share code, notes, and snippets.

@lucky-rydar
Created September 1, 2023 19:19
Show Gist options
  • Save lucky-rydar/2f39c09dd095924b24e2a8db385e1176 to your computer and use it in GitHub Desktop.
Save lucky-rydar/2f39c09dd095924b24e2a8db385e1176 to your computer and use it in GitHub Desktop.
Driver for AHT10 on ESP32
#include <memory.h>
#include "aht10.h"
#define AHT10_ADDR 0x38
#define AHT10_INIT_CMD 0xE1
#define AHT10_MEASURE_CMD 0xAC
#define AHT10_SOFT_RESET_CMD 0xBA
#define AHT10_AFTER_MEASURE_DELAY 100
#define AHT10_READ_DATA_SIZE 6
#define TWO_IN_20 1048576
bool aht10_get_data(aht10_data_t* ret) {
aht10_measure_cmd();
vTaskDelay(AHT10_AFTER_MEASURE_DELAY / portTICK_PERIOD_MS);
esp_err_t err;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
err = i2c_master_start(cmd);
err = i2c_master_write_byte(cmd, (AHT10_ADDR << 1) | I2C_MASTER_READ, true);
uint8_t read_data[AHT10_READ_DATA_SIZE] = {0};
err = i2c_master_read(cmd, read_data, AHT10_READ_DATA_SIZE, I2C_MASTER_ACK);
err = i2c_master_stop(cmd);
err = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_PERIOD_MS);
if(err != ESP_OK) {
//ESP_LOGE("aht10", "get_data: i2c_master_cmd_begin failed\n");
return false;
}
i2c_cmd_link_delete(cmd);
//memcpy(&ret->status, read_data, 1);
ret->status.busy = aht10_is_busy(read_data[0]);
ret->status.mode = aht10_get_working_mode(read_data[0]);
ret->status.calibrated = aht10_is_calibrated(read_data[0]);
uint32_t humidity = 0;
uint32_t temperature = 0;
humidity = read_data[1];
humidity <<= 8;
humidity |= read_data[2];
humidity <<= 4;
humidity |= read_data[3] >> 4;
temperature = read_data[3] & 0x0F;
temperature <<= 8;
temperature |= read_data[4];
temperature <<= 8;
temperature |= read_data[5];
// convert to real values
ret->humidity = (float)humidity * 100 / TWO_IN_20;
ret->temperature = (float)temperature * 200 / TWO_IN_20 - 50;
return true;
}
void aht10_device_init() {
vTaskDelay(100 / portTICK_PERIOD_MS);
aht10_init_cmd();
}
bool aht10_is_device_connected() {
esp_err_t err;
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (AHT10_ADDR << 1) | I2C_MASTER_WRITE, true);
i2c_master_stop(cmd);
err = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_PERIOD_MS);
i2c_cmd_link_delete(cmd);
return err == ESP_OK;
}
void write_cmd(uint8_t device_cmd) {
i2c_cmd_handle_t cmd = i2c_cmd_link_create();
i2c_master_start(cmd);
i2c_master_write_byte(cmd, (AHT10_ADDR << 1) | I2C_MASTER_WRITE, true);
uint8_t data[3] = {device_cmd, 0x33, 0x00};
i2c_master_write(cmd, data, 3, true);
i2c_master_stop(cmd);
esp_err_t err = i2c_master_cmd_begin(I2C_NUM_0, cmd, 1000 / portTICK_PERIOD_MS);
if(err != ESP_OK) {
ESP_LOGE("aht10", "write_cmd: i2c_master_cmd_begin failed\n");
}
i2c_cmd_link_delete(cmd);
}
void aht10_init_cmd() {
write_cmd(AHT10_INIT_CMD);
}
void aht10_measure_cmd() {
write_cmd(AHT10_MEASURE_CMD);
}
void aht10_soft_reset_cmd() {
write_cmd(AHT10_SOFT_RESET_CMD);
}
bool aht10_is_busy(uint8_t status) {
return status & 0x80; // the 7th bit
}
bool aht10_is_calibrated(uint8_t status) {
return status & 0x08; // the 3rd bit
}
working_mode_t aht10_get_working_mode(uint8_t status) {
// 0011 0000 = 0x30
uint8_t mode = (status & 0x30); // 5th and 6th bits
if(mode == 0x00) {
return NOR;
} else if(mode & 0x10) {
return CYC;
} else if(mode & 0x20) {
return CMD;
} else {
return -1;
}
}
#ifndef AHT10_H
#define AHT10_H
#include "driver/i2c.h"
#include "esp_log.h"
typedef enum {
NOR = 0,
CYC = 1,
CMD = 2
} working_mode_t;
typedef struct __attribute__((__packed__)) {
struct {
bool busy;
working_mode_t mode;
bool calibrated;
} status;
float humidity;
float temperature;
} aht10_data_t;
bool aht10_get_data(aht10_data_t* ret);
bool aht10_is_device_connected();
void aht10_device_init();
void aht10_init_cmd();
void aht10_measure_cmd();
void aht10_soft_reset_cmd();
bool aht10_is_busy(uint8_t status);
bool aht10_is_calibrated(uint8_t status);
static const char working_mode_str[][16] = {
"Normal",
"Cycle",
"Command"
};
working_mode_t aht10_get_working_mode(uint8_t status);
#endif // AHT10_H
#include <stdio.h>
#include <memory.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/gpio.h"
#include "driver/i2c.h"
#include "aht10.h"
void init_i2c() {
i2c_config_t i2c_config = {
.mode = I2C_MODE_MASTER,
.sda_io_num = GPIO_NUM_21,
.scl_io_num = GPIO_NUM_22,
.sda_pullup_en = GPIO_PULLUP_ENABLE,
.scl_pullup_en = GPIO_PULLUP_ENABLE,
.master.clk_speed = 100000
};
i2c_param_config(I2C_NUM_0, &i2c_config);
i2c_driver_install(I2C_NUM_0, I2C_MODE_MASTER, 0, 0, 0);
}
void aht10_task(void* pvParameter) {
aht10_device_init();
while(1) {
aht10_data_t data;
if(aht10_get_data(&data)) {
// printf("busy: %d, mode %s, calibrated: %d\n",
// data.status.busy,
// working_mode_str[data.status.mode],
// data.status.calibrated);
printf("humidity: %f, temperature: %f\n",
data.humidity,
data.temperature);
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
}
}
void app_main(void)
{
init_i2c();
xTaskCreate(aht10_task, "aht10_task", 2048, NULL, 10, NULL);
while(1) {
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment