160 lines
4.5 KiB
C
160 lines
4.5 KiB
C
#include "temp_humidity_monitor.h"
|
|
|
|
#include <stdint.h>
|
|
|
|
#include "driver/i2c_master.h"
|
|
#include "esp_check.h"
|
|
#include "esp_err.h"
|
|
#include "esp_log.h"
|
|
#include "freertos/FreeRTOS.h"
|
|
#include "freertos/portmacro.h"
|
|
#include "freertos/task.h"
|
|
|
|
static const char *TAG = "shtc3";
|
|
|
|
#define SHTC3_I2C_PORT I2C_NUM_0
|
|
#define SHTC3_I2C_SDA GPIO_NUM_13
|
|
#define SHTC3_I2C_SCL GPIO_NUM_14
|
|
#define SHTC3_I2C_ADDRESS 0x70
|
|
#define SHTC3_I2C_HZ 100000
|
|
#define SHTC3_WAKEUP_CMD 0x3517
|
|
#define SHTC3_SLEEP_CMD 0xB098
|
|
#define SHTC3_MEASURE_CMD 0x7866
|
|
|
|
static i2c_master_bus_handle_t s_i2c_bus;
|
|
static i2c_master_dev_handle_t s_shtc3_dev;
|
|
static portMUX_TYPE s_env_mux = portMUX_INITIALIZER_UNLOCKED;
|
|
static int s_latest_temperature_c10;
|
|
static int s_latest_humidity_percent;
|
|
static bool s_has_latest;
|
|
|
|
static uint8_t shtc3_crc(const uint8_t *data)
|
|
{
|
|
uint8_t crc = 0xFF;
|
|
|
|
for (int i = 0; i < 2; i++) {
|
|
crc ^= data[i];
|
|
for (int bit = 0; bit < 8; bit++) {
|
|
if ((crc & 0x80) != 0) {
|
|
crc = (uint8_t)((crc << 1) ^ 0x31);
|
|
} else {
|
|
crc <<= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return crc;
|
|
}
|
|
|
|
static esp_err_t shtc3_send_command(uint16_t command)
|
|
{
|
|
uint8_t data[2] = {
|
|
(uint8_t)(command >> 8),
|
|
(uint8_t)(command & 0xFF),
|
|
};
|
|
return i2c_master_transmit(s_shtc3_dev, data, sizeof(data), 1000);
|
|
}
|
|
|
|
static esp_err_t shtc3_read_once(int *temperature_c10, int *humidity_percent)
|
|
{
|
|
uint8_t data[6] = { 0 };
|
|
|
|
ESP_RETURN_ON_ERROR(shtc3_send_command(SHTC3_WAKEUP_CMD), TAG, "wake failed");
|
|
vTaskDelay(pdMS_TO_TICKS(2));
|
|
ESP_RETURN_ON_ERROR(shtc3_send_command(SHTC3_MEASURE_CMD), TAG, "measure failed");
|
|
vTaskDelay(pdMS_TO_TICKS(15));
|
|
ESP_RETURN_ON_ERROR(i2c_master_receive(s_shtc3_dev, data, sizeof(data), 1000), TAG, "read failed");
|
|
(void)shtc3_send_command(SHTC3_SLEEP_CMD);
|
|
|
|
if (shtc3_crc(&data[0]) != data[2] || shtc3_crc(&data[3]) != data[5]) {
|
|
return ESP_ERR_INVALID_CRC;
|
|
}
|
|
|
|
uint16_t raw_temp = ((uint16_t)data[0] << 8) | data[1];
|
|
uint16_t raw_humidity = ((uint16_t)data[3] << 8) | data[4];
|
|
*temperature_c10 = -450 + (int)((1750L * raw_temp + 32767) / 65535);
|
|
*humidity_percent = (int)((100L * raw_humidity + 32767) / 65535);
|
|
if (*humidity_percent < 0) {
|
|
*humidity_percent = 0;
|
|
} else if (*humidity_percent > 100) {
|
|
*humidity_percent = 100;
|
|
}
|
|
|
|
return ESP_OK;
|
|
}
|
|
|
|
static esp_err_t shtc3_init(void)
|
|
{
|
|
i2c_master_bus_config_t bus_config = {
|
|
.i2c_port = SHTC3_I2C_PORT,
|
|
.sda_io_num = SHTC3_I2C_SDA,
|
|
.scl_io_num = SHTC3_I2C_SCL,
|
|
.clk_source = I2C_CLK_SRC_DEFAULT,
|
|
.glitch_ignore_cnt = 7,
|
|
.flags.enable_internal_pullup = true,
|
|
};
|
|
ESP_RETURN_ON_ERROR(i2c_new_master_bus(&bus_config, &s_i2c_bus), TAG, "i2c bus init failed");
|
|
|
|
i2c_device_config_t device_config = {
|
|
.dev_addr_length = I2C_ADDR_BIT_LEN_7,
|
|
.device_address = SHTC3_I2C_ADDRESS,
|
|
.scl_speed_hz = SHTC3_I2C_HZ,
|
|
};
|
|
ESP_RETURN_ON_ERROR(i2c_master_bus_add_device(s_i2c_bus, &device_config, &s_shtc3_dev),
|
|
TAG,
|
|
"shtc3 device add failed");
|
|
return ESP_OK;
|
|
}
|
|
|
|
static void temp_humidity_task(void *arg)
|
|
{
|
|
(void)arg;
|
|
|
|
while (1) {
|
|
int temperature_c10 = 0;
|
|
int humidity_percent = 0;
|
|
esp_err_t ret = shtc3_read_once(&temperature_c10, &humidity_percent);
|
|
if (ret == ESP_OK) {
|
|
portENTER_CRITICAL(&s_env_mux);
|
|
s_latest_temperature_c10 = temperature_c10;
|
|
s_latest_humidity_percent = humidity_percent;
|
|
s_has_latest = true;
|
|
portEXIT_CRITICAL(&s_env_mux);
|
|
} else {
|
|
ESP_LOGW(TAG, "read disabled this round: %s", esp_err_to_name(ret));
|
|
}
|
|
|
|
vTaskDelay(pdMS_TO_TICKS(10000));
|
|
}
|
|
}
|
|
|
|
void temp_humidity_monitor_start(void)
|
|
{
|
|
esp_err_t ret = shtc3_init();
|
|
if (ret != ESP_OK) {
|
|
ESP_LOGW(TAG, "temperature/humidity monitor disabled: %s", esp_err_to_name(ret));
|
|
return;
|
|
}
|
|
|
|
xTaskCreate(temp_humidity_task, "shtc3", 4096, NULL, 2, NULL);
|
|
}
|
|
|
|
bool temp_humidity_monitor_take_latest(int *temperature_c10, int *humidity_percent)
|
|
{
|
|
if (temperature_c10 == NULL || humidity_percent == NULL) {
|
|
return false;
|
|
}
|
|
|
|
bool has_latest = false;
|
|
portENTER_CRITICAL(&s_env_mux);
|
|
if (s_has_latest) {
|
|
*temperature_c10 = s_latest_temperature_c10;
|
|
*humidity_percent = s_latest_humidity_percent;
|
|
s_has_latest = false;
|
|
has_latest = true;
|
|
}
|
|
portEXIT_CRITICAL(&s_env_mux);
|
|
|
|
return has_latest;
|
|
}
|