Initial commit

This commit is contained in:
Rafal Zajac
2017-11-12 22:49:10 +01:00
commit 74d0876c59
39 changed files with 2503 additions and 0 deletions

18
src/CMakeLists.txt Normal file
View File

@ -0,0 +1,18 @@
# Copyright 2017 Rafal Zajac <rzajac@gmail.com>.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
add_subdirectory(esp_ds18b20)
add_subdirectory(esp_dht22)
add_subdirectory(esp_sht21)

View File

@ -0,0 +1,32 @@
# Copyright 2017 Rafal Zajac <rzajac@gmail.com>.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
project(esp_dht22 C)
find_package(esp_gpio REQUIRED)
add_library(esp_dht22 STATIC
esp_dht22.c
include/esp_dht22.h)
target_include_directories(esp_dht22 PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
${esp_gpio_INCLUDE_DIRS}
${ESP_USER_CONFIG_DIR})
esp_gen_lib(esp_dht22
${ESP_CMAKE_FIND_DIR}
${esp_gpio_LIBRARIES})

View File

@ -0,0 +1,46 @@
# Copyright 2017 Rafal Zajac <rzajac@gmail.com>.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# Try to find esp_dht22
#
# Once done this will define:
#
# esp_dht22_FOUND - System found the library.
# esp_dht22_INCLUDE_DIR - The library include directory.
# esp_dht22_INCLUDE_DIRS - If library has dependencies this will be set
# to <lib_name>_INCLUDE_DIR [<dep1_name_INCLUDE_DIRS>, ...].
# esp_dht22_LIBRARY - The path to the library.
# esp_dht22_LIBRARIES - The dependencies to link to use the library.
# It will have a form of <lib_name>_LIBRARY [dep1_name_LIBRARIES, ...].
#
find_path(esp_dht22_INCLUDE_DIR esp_dht22.h)
find_library(esp_dht22_LIBRARY NAMES esp_dht22)
find_package(esp_gpio REQUIRED)
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(esp_dht22
DEFAULT_MSG
esp_dht22_LIBRARY
esp_dht22_INCLUDE_DIR)
set(esp_dht22_INCLUDE_DIRS
${esp_dht22_INCLUDE_DIR}
${esp_gpio_INCLUDE_DIRS})
set(esp_dht22_LIBRARIES
${esp_dht22_LIBRARY}
${esp_gpio_LIBRARIES})

13
src/esp_dht22/README.md Normal file
View File

@ -0,0 +1,13 @@
## DHT22 (AM2302) driver for ESP8266.
ESP8266 driver for very popular DHT22 (AM2302) temperature and humidity sensor.
![DHT22](../../doc/dht22-pinout.jpg)
Before you can get the temperature and humidity from DHT22 you have to call
`esp_dht22_init`. You need to call it only once unless you change the GPIO
pin setup somewhere else in your code.
See driver documentation in [esp_dht22.h](include/esp_dht22.h) header file
for more details.

178
src/esp_dht22/esp_dht22.c Normal file
View File

@ -0,0 +1,178 @@
/*
* Copyright 2017 Rafal Zajac <rzajac@gmail.com>.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
#include <esp_dht22.h>
#include <esp_gpio.h>
#include <mem.h>
#include <user_interface.h>
#define BUS_LOW(gpio_num) (GPIO_OUT_EN_S = (0x1 << (gpio_num)))
#define BUS_HIGH(gpio_num) (GPIO_OUT_EN_C = (0x1 << (gpio_num)))
#define BUS_RELEASE(gpio_num) (GPIO_OUT_EN_C = (0x1 << (gpio_num)))
#define BUS_READ(gpio_num) ((GPIO_IN & (0x1 << (gpio_num))) != 0)
/**
* Measure number of 10us slots the state was kept.
*
* The maximum wait time for GPIO to change state is 500us.
*
* @param gpio_num The GPIO number.
* @param exp_state The state.
*
* @return The number time slots.
*/
static uint8_t ICACHE_FLASH_ATTR
state_lenght(uint8_t gpio_num, bool exp_state)
{
uint8_t slot = 0;
while (BUS_READ(gpio_num) == exp_state) {
if (slot++ > 50) break;
os_delay_us(8);
}
return slot;
}
/**
* Calculate temperature.
*
* @param data The pointer to 5 bytes read from the bus.
*
* @return Temperature in Celsius.
*/
static float calc_temp(const uint8_t *data)
{
// Remove negative temp indicator bit.
float temp = data[2] & 0x7F;
temp *= 0x100;
temp += data[3];
temp /= 10;
if ((data[2] & 0x80) > 0) temp *= -1;
return temp;
}
void ICACHE_FLASH_ATTR
esp_dht22_init(uint8_t gpio_num)
{
esp_gpio_setup(gpio_num, GPIO_MODE_INPUT_PULLUP);
}
esp_dht22_dev *ICACHE_FLASH_ATTR
esp_dht22_new_dev(uint8_t gpio_num)
{
esp_dht22_dev *dev = os_zalloc(sizeof(esp_dht22_dev));
if (dev == NULL) return NULL;
dev->gpio_num = gpio_num;
return dev;
}
esp_dht22_err ICACHE_FLASH_ATTR
esp_dht22_get(esp_dht22_dev *device)
{
uint16_t cnt = 0;
// The humidity, temperature and parity data.
uint8_t *data;
// Current byte index in data (0-4).
int8_t data_byte_idx = 0;
// Current mask for data byte. We start with MSB.
uint8_t data_byte_mask = 0x80;
// The bit from the bus.
bool bit;
// Previous bit.
bool prev_bit = false;
// Number of high states.
uint8_t high_cnt = 0;
if (device == NULL) return ESP_DHT22_ERR_DEV_NULL;
data = os_zalloc(5);
if (data == NULL) return ESP_DHT22_ERR_MEM;
// Emmit start signal.
BUS_LOW(device->gpio_num);
os_delay_us(820);
// End start signal.
BUS_RELEASE(device->gpio_num);
os_delay_us(25);
// Entering time critical code.
ETS_GPIO_INTR_DISABLE();
// Device responds with 80us low followed by 80us high.
cnt = state_lenght(device->gpio_num, 0);
if (cnt < 8 || cnt > 10) {
ETS_GPIO_INTR_ENABLE();
return ESP_DHT22_ERR_BAD_RESP_SIGNAL;
}
cnt = state_lenght(device->gpio_num, 1);
if (cnt < 8 || cnt > 10) {
ETS_GPIO_INTR_ENABLE();
return ESP_DHT22_ERR_BAD_RESP_SIGNAL;
}
// Sample data bus for 40 bits.
//
// Device transmits
// - 0 as 50us low followed by 25us high (total 75us).
// - 1 as 50us low followed by 70us high (total 120us).
//
// Data is transmitted MSB first.
//
// This means 40 bits transfer takes between 3000us and 4800us.
// The code below samples the bus no more then 4800us (10us * 480).
// During that time we count falling edges and count number of
// high states seen since last falling edge. The number of seen
// high states tells us if this was o or 1.
do {
bit = BUS_READ(device->gpio_num);
if (bit) high_cnt++;
if (bit == false && prev_bit == true) {
if (high_cnt >= 6) data[data_byte_idx] |= data_byte_mask;
high_cnt = 0;
data_byte_mask >>= 1;
if (data_byte_mask == 0) {
data_byte_idx++;
data_byte_mask = 0x80;
}
}
prev_bit = bit;
cnt++;
os_delay_us(10);
} while (data_byte_idx < 5 && cnt <= 480);
ETS_GPIO_INTR_ENABLE();
device->last_measure = system_get_time();
if (((uint8_t) (data[0] + data[1] + data[2] + data[3])) != data[4]) {
return ESP_DHT22_ERR_PARITY;
}
device->temp = calc_temp(data);
device->hum = data[0] * 0x100;
device->hum += data[1];
device->hum /= 10;
//os_free(data);
return ESP_DHT22_OK;
}

View File

@ -0,0 +1,75 @@
/*
* Copyright 2017 Rafal Zajac <rzajac@gmail.com>.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
#ifndef ESP_DHT22_H
#define ESP_DHT22_H
#include <c_types.h>
// Structure representing DHT22 device.
typedef struct {
float hum; // Humidity.
float temp; // Temperature in Celsius.
uint8_t gpio_num; // The GPIO this device is connected to.
uint32_t last_measure; // Last measure time. Uses system_get_time().
} esp_dht22_dev;
// Error codes.
typedef enum {
ESP_DHT22_OK,
ESP_DHT22_ERR_MEM,
ESP_DHT22_ERR_DEV_NULL,
ESP_DHT22_ERR_BAD_RESP_SIGNAL,
ESP_DHT22_ERR_PARITY,
} esp_dht22_err;
// Espressif SDK missing includes.
void ets_isr_mask(unsigned intr);
void ets_isr_unmask(unsigned intr);
/**
* Initialize DHT22.
*
* @param gpio_num The GPIO number DHT22 is connected to.
*/
void ICACHE_FLASH_ATTR
esp_dht22_init(uint8_t gpio_num);
/**
* Get DHT22 structure.
*
* It's up to a caller to release the memory at some point.
*
* @param gpio_num The GPIO number connected to the data bus.
*
* @return Device.
*/
esp_dht22_dev *ICACHE_FLASH_ATTR
esp_dht22_new_dev(uint8_t gpio_num);
/**
* Get temperature and humidity.
*
* NOTE: You must keep calls to this function at least 2s apart.
*
* @param device The device structure to set values on.
*
* @return Error code.
*/
esp_dht22_err ICACHE_FLASH_ATTR
esp_dht22_get(esp_dht22_dev *device);
#endif //ESP_DHT22_H

View File

@ -0,0 +1,38 @@
# Copyright 2017 Rafal Zajac <rzajac@gmail.com>.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
project(esp_ds18b20 C)
find_package(esp_ow REQUIRED)
find_package(esp_eb REQUIRED)
find_package(esp_tim REQUIRED)
add_library(esp_ds18b20 STATIC
esp_ds18b20.c
include/esp_ds18b20.h)
target_include_directories(esp_ds18b20 PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
${esp_ow_INCLUDE_DIRS}
${esp_eb_INCLUDE_DIRS}
${esp_tim_INCLUDE_DIRS}
${ESP_USER_CONFIG_DIR})
esp_gen_lib(esp_ds18b20
${ESP_CMAKE_FIND_DIR}
${esp_ow_LIBRARIES}
${esp_eb_LIBRARIES}
${esp_tim_LIBRARIES})

View File

@ -0,0 +1,52 @@
# Copyright 2017 Rafal Zajac <rzajac@gmail.com>.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# Try to find esp_ds18b20
#
# Once done this will define:
#
# esp_ds18b20_FOUND - System found the library.
# esp_ds18b20_INCLUDE_DIR - The library include directory.
# esp_ds18b20_INCLUDE_DIRS - If library has dependencies this will be set
# to <lib_name>_INCLUDE_DIR [<dep1_name_INCLUDE_DIRS>, ...].
# esp_ds18b20_LIBRARY - The path to the library.
# esp_ds18b20_LIBRARIES - The dependencies to link to use the library.
# It will have a form of <lib_name>_LIBRARY [dep1_name_LIBRARIES, ...].
#
find_path(esp_ds18b20_INCLUDE_DIR esp_ds18b20.h)
find_library(esp_ds18b20_LIBRARY NAMES esp_ds18b20)
find_package(esp_ow REQUIRED)
find_package(esp_eb REQUIRED)
find_package(esp_tim REQUIRED)
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(esp_ds18b20
DEFAULT_MSG
esp_ds18b20_LIBRARY
esp_ds18b20_INCLUDE_DIR)
set(esp_ds18b20_INCLUDE_DIRS
${esp_ds18b20_INCLUDE_DIR}
${esp_ow_INCLUDE_DIRS}
${esp_eb_INCLUDE_DIRS}
${esp_tim_INCLUDE_DIRS})
set(esp_ds18b20_LIBRARIES
${esp_ds18b20_LIBRARY}
${esp_ow_LIBRARIES}
${esp_eb_LIBRARIES}
${esp_tim_LIBRARIES})

45
src/esp_ds18b20/README.md Normal file
View File

@ -0,0 +1,45 @@
## DS18B20 driver for ESP8266.
Full featured DS18B20 digital thermometer driver.
![DS18B20](../../doc/ds18b20.jpg)
Before you can get the temperature from DS18B20 you have to call
`esp_ds18b20_init`. You need to call it only once unless you change the GPIO
pin setup somewhere else in your code.
To find device(s) on the OneWire bus you can use `esp_ds18b20_search` which
will give you linked list of `esp_ow_device` devices.
It's up to the user to release memory allocated for the linked list with
library provided helper function `esp_ds18b20_free_list` when it's not needed
anymore.
Most of the operations with the DS18B20 library is based on passing pointers
to the `esp_ow_device` structure which has pointer to `esp_ds18b20_st`
status structure. The `esp_ds18b20_st` keeps track of last scratch pad read
the last temperature conversion.
```
esp_ow_device *device;
esp_ds18b20_st *st = device->custom;
```
If you already know the ROM address of your device you can use
`esp_ds18b20_new_dev`:
```
uint8_t rom[8] = {0x28, 0x1D, 0x39, 0x31, 0x2, 0x0, 0x0, 0xF0}
esp_ow_dev *device = esp_ds18b20_new_dev(rom);
```
With DS18B20 temperature measurement takes between 94 and 750ms depending
on resolution. You don't want to block the CPU for that long waiting for
example using some kind of delay. That's why library is using event bus
(esp_eb) to emmit events when the temperature conversion is ready to read.
Check [example program](../../examples/ds18b20_temp) to see how it should be
done.
See driver documentation in [esp_ds18b20.h](include/esp_ds18b20.h) header file
for more details.

View File

@ -0,0 +1,305 @@
/*
* Copyright 2017 Rafal Zajac <rzajac@gmail.com>.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
#include <esp_ds18b20.h>
#include <esp_tim.h>
#include <esp_eb.h>
#include <mem.h>
/**
* Decode temperature.
*
* @param sp The address for first scrachpad byte.
*
* @return The temperature.
*/
float ICACHE_FLASH_ATTR
decode_temp(const uint8_t *sp)
{
bool minus;
uint8_t integer = 0;
float decimal = 0;
// Get only bits responsible for temperature and sign.
int16_t temp = sp[0] | (sp[1] << 8);
minus = (temp & 0x8000) > 0;
// Detect negative number.
if (minus) {
temp = (int16_t) (~temp + 1); // 2's complement.
}
// Remove fraction.
integer = (uint8_t) (temp >> 4);
// take only 3 LSB form MSB.
integer |= ((temp >> 8) & 0x07) << 4;
// Calculate fraction accounting for resolution.
switch ((sp[4] & 0x60) >> 5) {
case ESP_DS18B20_RES_12:
decimal = (temp & 0x0F) * ((float) ESP_DS18B20_STEP_12);
break;
case ESP_DS18B20_RES_11:
decimal = ((temp >> 1) & 0x07) * ((float) ESP_DS18B20_STEP_11);
break;
case ESP_DS18B20_RES_10:
decimal = ((temp >> 2) & 0x03) * ((float) ESP_DS18B20_STEP_10);
break;
case ESP_DS18B20_RES_9:
decimal = ((temp >> 3) & 0x01) * ((float) ESP_DS18B20_STEP_9);
break;
default:
decimal = 0;
}
decimal = integer + decimal;
if (minus) decimal = 0 - decimal;
return decimal;
}
esp_ow_err ICACHE_FLASH_ATTR
esp_d18b20_read_sp(esp_ow_device *device)
{
uint8_t idx;
uint8_t crc = 0;
esp_ds18b20_st *st = device->custom;
if (esp_ow_reset(device->gpio_num) == false) {
st->retries = -1;
return ESP_OW_ERR_NO_DEV;
}
esp_ow_match_dev(device);
esp_ow_write(device->gpio_num, ESP_DS18B20_CMD_READ_SP);
esp_ow_read_bytes(device->gpio_num, st->sp, 9);
for (idx = 0; idx < 9; idx++) {
crc = esp_ow_crc8(crc, st->sp[idx]);
}
if (crc != 0) {
memset(st->sp, 0, 9);
return ESP_OW_ERR_BAD_CRC;
}
return ESP_OW_OK;
}
esp_ow_err ICACHE_FLASH_ATTR
esp_ds18b20_write_sp(esp_ow_device *device)
{
uint8_t *start;
esp_ds18b20_st *st = device->custom;
if (esp_ow_reset(device->gpio_num) == false) {
return ESP_OW_ERR_NO_DEV;
}
esp_ow_match_dev(device);
esp_ow_write(device->gpio_num, ESP_DS18B20_CMD_WRITE_SP);
// We transmit only 3 bytes (Th, Tl, cfg).
start = &st->sp[2];
esp_ow_write_bytes(device->gpio_num, start, 3);
return ESP_OW_OK;
}
esp_ow_err ICACHE_FLASH_ATTR
read_temp(esp_ow_device *device)
{
esp_ds18b20_st *st = device->custom;
esp_ow_err err = esp_d18b20_read_sp(device);
st->retries = -1;
if (err != ESP_OW_OK) return err;
st->last_temp = decode_temp(st->sp);
return ESP_OW_OK;
}
static void ICACHE_FLASH_ATTR
start_conversion(void *arg)
{
esp_tim_timer *timer = arg;
bool done = false;
esp_ow_device *dev = timer->payload;
esp_ds18b20_st *st = dev->custom;
uint32_t sample_count = 200;
st->retries++;
do {
if (esp_ow_read_bit(dev->gpio_num)) {
done = true;
break;
}
os_delay_us(5);
sample_count--;
} while (sample_count > 0);
if (done == true) {
if (read_temp(dev) != ESP_OW_OK) {
esp_eb_trigger(ESP_DS18B20_EV_TEMP_ERROR, dev);
} else {
esp_eb_trigger(ESP_DS18B20_EV_TEMP_READY, dev);
}
} else {
// The worst case from datasheet is 750ms when
// 12 bits of resolution is set.
// Each call to this function takes about 200*5us (1ms).
// If temperature is not available we call ourselves again
// after 10ms. That gives 11ms per call. 68 calls * 11ms = 748ms.
// This condition basically makes sure we are not
// calling ourselves forever.
if (st->retries > 68) {
st->retries = -1;
esp_eb_trigger(ESP_DS18B20_EV_TEMP_ERROR, dev);
} else {
// Try again.
esp_tim_continue(timer);
}
}
}
bool ICACHE_FLASH_ATTR
esp_ds18b20_init(uint8_t gpio_num)
{
esp_ow_init(gpio_num);
return true;
}
esp_ow_err ICACHE_FLASH_ATTR
esp_ds18b20_search(uint8_t gpio_num, bool in_alert, esp_ow_device **list)
{
esp_ow_device *curr;
esp_ow_cmd cmd = in_alert ? ESP_OW_CMD_SEARCH_ROM_ALERT : ESP_OW_CMD_SEARCH_ROM;
esp_ow_err err = esp_ow_search_family(gpio_num, cmd, ESP_DS18B20_FAMILY_CODE, list);
if (err != ESP_OW_OK) return err;
curr = *list;
while (curr) {
curr->custom = os_zalloc(sizeof(esp_ds18b20_st));
((esp_ds18b20_st *) curr->custom)->last_temp = ESP_DS18B20_TEMP_ERR;
((esp_ds18b20_st *) curr->custom)->retries = -1;
curr = curr->next;
}
return err;
}
esp_ow_device *ICACHE_FLASH_ATTR
esp_ds18b20_new_dev(uint8_t *rom)
{
esp_ow_device *device = os_zalloc(sizeof(esp_ow_device));
esp_ds18b20_st *st = os_zalloc(sizeof(esp_ds18b20_st));
os_memcpy(device->rom, rom, 8);
st->last_temp = ESP_DS18B20_TEMP_ERR;
st->retries = -1;
device->custom = st;
return device;
}
esp_ow_device *ICACHE_FLASH_ATTR
esp_ds18b20_get(uint8_t gpio_num)
{
return esp_ow_read_rom_dev(gpio_num);
}
esp_ow_err ICACHE_FLASH_ATTR
esp_ds18b20_get_alarm(esp_ow_device *dev, int8_t *low, int8_t *high)
{
esp_ds18b20_st *st = dev->custom;
esp_ow_err err = esp_d18b20_read_sp(dev);
if (err != ESP_OW_OK) return err;
*low = st->sp[3];
*high = st->sp[2];
return ESP_OW_OK;
}
esp_ow_err ICACHE_FLASH_ATTR
esp_ds18b20_set_alarm(esp_ow_device *dev, int8_t low, int8_t high)
{
esp_ds18b20_st *st = dev->custom;
esp_ow_err err = esp_d18b20_read_sp(dev);
if (err != ESP_OW_OK) return err;
st->sp[3] = low;
st->sp[2] = high;
return esp_ds18b20_write_sp(dev);
}
void ICACHE_FLASH_ATTR
esp_ds18b20_free_list(esp_ow_device *list)
{
esp_ow_free_device_list(list, true);
}
esp_ds18b20_err ICACHE_FLASH_ATTR
esp_ds18b20_convert(esp_ow_device *device)
{
esp_ds18b20_st *st = device->custom;
// We are already waiting for the conversion.
if (st->retries >= 0) return ESP_DS18B20_ERR_CONV_IN_PROG;
if (esp_ow_reset(device->gpio_num) == false) return ESP_DS18B20_NO_DEV;
// Send conversion command.
esp_ow_match_dev(device);
esp_ow_write(device->gpio_num, ESP_DS18B20_CMD_CONVERT);
if (esp_tim_start(start_conversion, device)) {
st->retries = 0;
}
return ESP_DS18B20_OK;
}
bool ICACHE_FLASH_ATTR
esp_ds18b20_has_parasite(uint8_t gpio_num)
{
bool has_parasite;
if (esp_ow_reset(gpio_num) == false) {
return false; // No devices.
}
esp_ow_write(gpio_num, ESP_OW_CMD_SKIP_ROM);
esp_ow_write(gpio_num, ESP_DS18B20_CMD_READ_PWR);
has_parasite = !esp_ow_read_bit(gpio_num);
return has_parasite;
}

View File

@ -0,0 +1,187 @@
/*
* Copyright 2017 Rafal Zajac <rzajac@gmail.com>.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
#ifndef ESP_DS18B20_H
#define ESP_DS18B20_H
#include <esp_ow.h>
#include <c_types.h>
// The DS18B20 family code from datasheet.
#define ESP_DS18B20_FAMILY_CODE 0x28
// The absolute zero temperature is returned as error.
#define ESP_DS18B20_TEMP_ERR (-273)
// Temperature conversion ready.
#define ESP_DS18B20_EV_TEMP_READY "ds18b20tReady"
// Temperature conversion error.
#define ESP_DS18B20_EV_TEMP_ERROR "ds18b20tError"
// Temperature resolutions.
#define ESP_DS18B20_RES_9 0x0
#define ESP_DS18B20_RES_10 0x1
#define ESP_DS18B20_RES_11 0x2
#define ESP_DS18B20_RES_12 0x3
// Temperature steps.
#define ESP_DS18B20_STEP_9 0.5
#define ESP_DS18B20_STEP_10 0.25
#define ESP_DS18B20_STEP_11 0.125
#define ESP_DS18B20_STEP_12 0.0625
// OneWire commands.
typedef enum {
ESP_DS18B20_CMD_READ_PWR = 0xB4,
ESP_DS18B20_CMD_CONVERT = 0x44,
ESP_DS18B20_CMD_READ_SP = 0xBE,
ESP_DS18B20_CMD_WRITE_SP = 0x4E,
} esp_ds18b20_cmd;
typedef enum {
ESP_DS18B20_OK,
ESP_DS18B20_NO_DEV,
ESP_DS18B20_ERR_CONV_IN_PROG, // Conversion in progress.
} esp_ds18b20_err;
// DS18B20 status.
typedef struct {
uint8_t sp[9];
int8_t retries; // Is greater then zero when conversion in progress.
float last_temp; // Last successful temperature read.
} esp_ds18b20_st;
/**
* Initialize OneWire bus where DS18B20 is.
*
* To use many OneWire buses you have to initialize all of them.
*
* @param gpio_num The GPIO where OneWire bus is connected.
*
* @return Returns true on success, false otherwise.
*/
bool ICACHE_FLASH_ATTR
esp_ds18b20_init(uint8_t gpio_num);
/**
* Find devices on OneWire bus.
*
* @param in_alert Find only devices in alert mode.
* @param list The list of found devices or NULL.
*
* @return OneWire error code.
*/
esp_ow_err ICACHE_FLASH_ATTR
esp_ds18b20_search(uint8_t gpio_num, bool in_alert, esp_ow_device **list);
/**
* Construct DS18B20 device.
*
* It's up to a caller to release the memory at some point.
*
* @param rom The pointer to 8 byte ROM address
*
* @return The device.
*/
esp_ow_device *ICACHE_FLASH_ATTR
esp_ds18b20_new_dev(uint8_t *rom);
/**
* Get the only device on the bus.
*
* Can be used only when there is only one device on the OneWire bus!
*
* @param gpio_num The GPIO where OneWire bus is connected.
*
* @return The OneWire device. On error ROM address has all zeros.
*/
esp_ow_device *ICACHE_FLASH_ATTR
esp_ds18b20_get(uint8_t gpio_num);
/**
* Get DS18B20 alarm thresholds.
*
* @param dev The device to get alarm thresholds for.
* @param low The low threshold in Celsius.
* @param high The high threshold in Celsius.
*
* @return OneWire error code.
*/
esp_ow_err ICACHE_FLASH_ATTR
esp_ds18b20_get_alarm(esp_ow_device *dev, int8_t *low, int8_t *high);
/**
* Set DS18B20 alarm thresholds.
*
* @param dev The device to get alarm thresholds for.
* @param low The low threshold in Celsius.
* @param high The high threshold in Celsius.
*
* @return OneWire error code.
*/
esp_ow_err ICACHE_FLASH_ATTR
esp_ds18b20_set_alarm(esp_ow_device *dev, int8_t low, int8_t high);
/**
* Read scrachpad.
*
* @param device The device to read scratchpad for.
*
* @return OneWire error code.
*/
esp_ow_err ICACHE_FLASH_ATTR
esp_d18b20_read_sp(esp_ow_device *device);
/**
* Write scratchpad to the device.
*
* @param device The device to write scratchpad to.
*
* @return OneWire error code.
*/
esp_ow_err ICACHE_FLASH_ATTR
esp_ds18b20_write_sp(esp_ow_device *device);
/**
* Free memory allocated by devices found on OneWire bus.
*
* @param list
*/
void ICACHE_FLASH_ATTR
esp_ds18b20_free_list(esp_ow_device *list);
/**
* Start temperature conversion.
*
* @param device The device to start conversion on.
*
* @return Error code.
*/
esp_ds18b20_err ICACHE_FLASH_ATTR
esp_ds18b20_convert(esp_ow_device *device);
/**
* Check if OneWire bus has device with parasite power supply.
*
* @param gpio_num The GPIO where OneWire bus is connected.
*
* @return Returns true if parasite present, false otherwise.
*/
bool ICACHE_FLASH_ATTR
esp_ds18b20_has_parasite(uint8_t gpio_num);
#endif //ESP_DS18B20_H

View File

@ -0,0 +1,33 @@
# Copyright 2017 Rafal Zajac <rzajac@gmail.com>.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
project(esp_sht21 C)
find_package(esp_i2c REQUIRED)
add_library(esp_sht21 STATIC
esp_sht21.c
include/esp_sht21.h)
target_include_directories(esp_sht21 PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
${esp_i2c_INCLUDE_DIRS}
${ESP_USER_CONFIG_DIR})
esp_gen_lib(esp_sht21
${ESP_CMAKE_FIND_DIR}
${esp_i2c_LIBRARIES}
${esp_tim_LIBRARIES})

View File

@ -0,0 +1,46 @@
# Copyright 2017 Rafal Zajac <rzajac@gmail.com>.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
# Try to find esp_sht21
#
# Once done this will define:
#
# esp_sht21_FOUND - System found the library.
# esp_sht21_INCLUDE_DIR - The library include directory.
# esp_sht21_INCLUDE_DIRS - If library has dependencies this will be set
# to <lib_name>_INCLUDE_DIR [<dep1_name_INCLUDE_DIRS>, ...].
# esp_sht21_LIBRARY - The path to the library.
# esp_sht21_LIBRARIES - The dependencies to link to use the library.
# It will have a form of <lib_name>_LIBRARY [dep1_name_LIBRARIES, ...].
#
find_path(esp_sht21_INCLUDE_DIR esp_sht21.h)
find_library(esp_sht21_LIBRARY NAMES esp_sht21)
find_package(esp_i2c REQUIRED)
include(FindPackageHandleStandardArgs)
FIND_PACKAGE_HANDLE_STANDARD_ARGS(esp_sht21
DEFAULT_MSG
esp_sht21_LIBRARY
esp_sht21_INCLUDE_DIR)
set(esp_sht21_INCLUDE_DIRS
${esp_sht21_INCLUDE_DIR}
${esp_i2c_INCLUDE_DIRS})
set(esp_sht21_LIBRARIES
${esp_sht21_LIBRARY}
${esp_i2c_LIBRARIES})

18
src/esp_sht21/README.md Normal file
View File

@ -0,0 +1,18 @@
## SHT21 driver for ESP8266.
SHT21 a.k.a Si7021 driver for ESP8266. Features:
![DS18B20](../../doc/sht21.jpg)
- Humidity and temperature measurements.
- Get/set humidity and temperature measurement resolution.
- Get SHT21 serial number.
- Get SHT21 firmware revision.
- Turn on on-board heater to drive off condensation.
Before you can start communicating with SHT21 you have to call
`esp_sht21_init`. You need to call it only once unless you change the GPIO
pins setup somewhere else in your code.
See driver documentation in [esp_sht21.h](include/esp_sht21.h) header file
for more details.

324
src/esp_sht21/esp_sht21.c Normal file
View File

@ -0,0 +1,324 @@
/*
* Copyright 2017 Rafal Zajac <rzajac@gmail.com>.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
#include <esp_sht21.h>
#include <osapi.h>
static uint8_t ICACHE_FLASH_ATTR
calc_crc(uint8_t init, const uint8_t *data, uint8_t len)
{
uint8_t idx;
uint8_t bit;
// Calculates 8 bit checksum with polynomial 0x131 (10011001).
for (idx = 0; idx < len; idx++) {
init ^= (data[idx]);
for (bit = 0; bit < 8; bit++) {
if (init & 0x80) init = (uint8_t) ((init << 1) ^ 0x131);
else init = (init << 1);
}
}
return init;
}
esp_i2c_err ICACHE_FLASH_ATTR
esp_sht21_init(uint8_t gpio_scl, uint8_t gpio_sda)
{
return esp_i2c_init(gpio_scl, gpio_sda);
}
static float ICACHE_FLASH_ATTR
calc_rh(const uint8_t *data)
{
float hu;
hu = (float) (125.0 / 65536.0);
hu = hu * (((data[0] << 8) | data[1]) & ~0x3);
return hu - 6;
}
static float ICACHE_FLASH_ATTR
calc_temp(const uint8_t *data)
{
float temp;
temp = (float) (175.72 / 65536.0);
temp = temp * (((data[0] << 8) | data[1]) & ~0x3);
return (float) (temp - 46.85);
}
esp_i2c_err ICACHE_FLASH_ATTR
esp_sht21_get_rh(float *humidity)
{
esp_i2c_err err;
uint8_t data[3];
*humidity = ESP_SHT21_BAD_RH;
err = esp_i2c_start_read(ESP_SHT21_ADDRESS, ESP_SHT21_RH_HM);
if (err != ESP_I2C_OK) return err;
err = esp_i2c_read_bytes(data, 3);
if (err != ESP_I2C_OK) return err;
err = esp_i2c_stop();
if (calc_crc(0x0, data, 2) == data[2]) {
*humidity = calc_rh(data);
} else if (err == ESP_I2C_OK) {
err = ESP_I2C_ERR_DATA_CORRUPTED;
}
return err;
}
/**
* Get temperature.
*
* @param temp The temperature.
* @param cmd The temperature command.
*
* @return The I2C error code.
*/
static esp_i2c_err ICACHE_FLASH_ATTR
get_temp(float *temp, uint8_t cmd)
{
esp_i2c_err err;
uint8_t data[3];
// When getting temperature from previous humidity measurement
// the CRC checksum is not available.
uint8_t data_len = (uint8_t) (cmd == ESP_SHT21_TEMP_HM ? 3 : 2);
*temp = ESP_SHT21_BAD_TEMP;
err = esp_i2c_start_read(ESP_SHT21_ADDRESS, cmd);
if (err != ESP_I2C_OK) return err;
err = esp_i2c_read_bytes(data, data_len);
if (err != ESP_I2C_OK) return err;
err = esp_i2c_stop();
if (data_len == 2 || calc_crc(0x0, data, 2) == data[2]) {
*temp = calc_temp(data);
} else if (err == ESP_I2C_OK) {
err = ESP_I2C_ERR_DATA_CORRUPTED;
}
return err;
}
esp_i2c_err ICACHE_FLASH_ATTR
esp_sht21_get_temp(float *temp)
{
return get_temp(temp, ESP_SHT21_TEMP_HM);
}
esp_i2c_err ICACHE_FLASH_ATTR
esp_sht21_get_temp_last(float *temp)
{
return get_temp(temp, ESP_SHT21_TEMP_LAST);
}
esp_i2c_err ICACHE_FLASH_ATTR
esp_sht21_get_sn(uint8_t *sn)
{
uint8_t idx;
esp_i2c_err err;
uint8_t sn_idx = 0;
uint8_t crc;
uint8_t cmd1[2] = {0xFA, 0x0F};
uint8_t cmd2[2] = {0xFC, 0xC9};
uint8_t data[14];
err = esp_i2c_start_read_write(ESP_I2C_ADDR_WRITE(ESP_SHT21_ADDRESS), true);
if (err != ESP_I2C_OK) return err;
err = esp_i2c_write_bytes(cmd1, 2);
if (err != ESP_I2C_OK) return err;
err = esp_i2c_start_read_write(ESP_I2C_ADDR_READ(ESP_SHT21_ADDRESS), true);
if (err != ESP_I2C_OK) return err;
err = esp_i2c_read_bytes(data, 8);
if (err != ESP_I2C_OK) return err;
err = esp_i2c_stop();
if (err != ESP_I2C_OK) return err;
err = esp_i2c_start_read_write(ESP_I2C_ADDR_WRITE(ESP_SHT21_ADDRESS), true);
if (err != ESP_I2C_OK) return err;
err = esp_i2c_write_bytes(cmd2, 2);
if (err != ESP_I2C_OK) return err;
err = esp_i2c_start_read_write(ESP_I2C_ADDR_READ(ESP_SHT21_ADDRESS), true);
if (err != ESP_I2C_OK) return err;
err = esp_i2c_read_bytes((data + 8), 6);
if (err != ESP_I2C_OK) return err;
err = esp_i2c_stop();
// Validate data.
crc = 0x0;
for (idx = 0; idx < 8; idx += 2) {
crc = calc_crc(crc, &data[idx], 1);
if (data[idx + 1] != crc) {
return ESP_I2C_ERR_DATA_CORRUPTED;
}
sn[sn_idx++] = data[idx];
}
crc = 0x0;
for (idx = 8; idx < 14; idx += 3) {
crc = calc_crc(crc, &data[idx], 2);
if (data[idx + 2] != crc) {
return ESP_I2C_ERR_DATA_CORRUPTED;
}
sn[sn_idx++] = data[idx];
sn[sn_idx++] = data[idx + 1];
}
return err;
}
esp_i2c_err ICACHE_FLASH_ATTR
esp_sht21_get_rev(uint8_t *rev)
{
esp_i2c_err err;
uint8_t cmd[2] = {0x84, 0xB8};
err = esp_i2c_start_read_write(ESP_I2C_ADDR_WRITE(ESP_SHT21_ADDRESS), true);
if (err != ESP_I2C_OK) return err;
err = esp_i2c_write_bytes(cmd, 2);
if (err != ESP_I2C_OK) return err;
err = esp_i2c_start_read_write(ESP_I2C_ADDR_READ(ESP_SHT21_ADDRESS), true);
if (err != ESP_I2C_OK) return err;
err = esp_i2c_read_bytes(rev, 1);
if (err != ESP_I2C_OK) return err;
return esp_i2c_stop();
}
static esp_i2c_err ICACHE_FLASH_ATTR
register_get(uint8_t address, uint8_t reg_adr, uint8_t *reg)
{
esp_i2c_err err;
// Read the register.
err = esp_i2c_start_read(address, reg_adr);
if (err != ESP_I2C_OK) return err;
err = esp_i2c_read_bytes(reg, 1);
if (err != ESP_I2C_OK) return err;
return esp_i2c_stop();
}
static esp_i2c_err ICACHE_FLASH_ATTR
register_set(uint8_t address, uint8_t reg_adr, uint8_t value)
{
esp_i2c_err err;
err = esp_i2c_start_write(address, reg_adr);
if (err != ESP_I2C_OK) return err;
err = esp_i2c_write_bytes(&value, 1);
if (err != ESP_I2C_OK) return err;
return esp_i2c_stop();
}
esp_i2c_err ICACHE_FLASH_ATTR
esp_sht21_res_get(uint8_t *res)
{
esp_i2c_err err;
uint8_t reg1 = 0;
err = register_get(ESP_SHT21_ADDRESS, ESP_SHT21_UR1_READ, &reg1);
if (err != ESP_I2C_OK) return err;
*res = (uint8_t) (((reg1 >> 6) & 0x2) | (reg1 & 0x1));
return ESP_I2C_OK;
}
esp_i2c_err ICACHE_FLASH_ATTR
esp_sht21_res_set(uint8_t res)
{
esp_i2c_err err;
uint8_t reg1 = 0;
err = register_get(ESP_SHT21_ADDRESS, ESP_SHT21_UR1_READ, &reg1);
if (err != ESP_I2C_OK) return err;
// Clear bits 7 and 0
reg1 = (uint8_t) (reg1 & 0x7E);
// Logical or after some bit manipulation.
reg1 |= ((((res & 0x3) != 0) << 7) | ((res & 0x1) != 0));
return register_set(ESP_SHT21_ADDRESS, ESP_SHT21_UR1_WRITE, reg1);
}
esp_i2c_err ICACHE_FLASH_ATTR
esp_sht21_heater_get(bool *on_off, uint8_t *level)
{
esp_i2c_err err;
uint8_t reg1 = 0;
uint8_t hcr = 0;
err = register_get(ESP_SHT21_ADDRESS, ESP_SHT21_UR1_READ, &reg1);
if (err != ESP_I2C_OK) return err;
err = register_get(ESP_SHT21_ADDRESS, ESP_SHT21_HCR_READ, &hcr);
if (err != ESP_I2C_OK) return err;
*on_off = (reg1 & 0x4) != 0;
*level = (uint8_t) (hcr & 0xF);
return ESP_I2C_OK;
}
esp_i2c_err ICACHE_FLASH_ATTR
esp_sht21_heater_set(bool on_off, uint8_t level)
{
esp_i2c_err err;
uint8_t reg1 = 0;
uint8_t hcr = 0;
// Read both registers.
err = register_get(ESP_SHT21_ADDRESS, ESP_SHT21_UR1_READ, &reg1);
if (err != ESP_I2C_OK) return err;
err = register_get(ESP_SHT21_ADDRESS, ESP_SHT21_HCR_READ, &hcr);
if (err != ESP_I2C_OK) return err;
// Write new values.
reg1 = (uint8_t) (reg1 & 0xFB);
reg1 = reg1 | (on_off << 2);
err = register_set(ESP_SHT21_ADDRESS, ESP_SHT21_UR1_WRITE, reg1);
if (err != ESP_I2C_OK) return err;
hcr = (uint8_t) ((hcr & 0xF0) | (level & 0x0F));
err = register_set(ESP_SHT21_ADDRESS, ESP_SHT21_HCR_WRITE, 0x0);
if (err != ESP_I2C_OK) return err;
return register_set(ESP_SHT21_ADDRESS, ESP_SHT21_HCR_WRITE, hcr);
}

View File

@ -0,0 +1,168 @@
/*
* Copyright 2017 Rafal Zajac <rzajac@gmail.com>.
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License. You may obtain
* a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
#ifndef ESP_SHT21_H
#define ESP_SHT21_H
#include <c_types.h>
#include <esp_i2c.h>
#define ESP_SHT21_ADDRESS 0x40
// Measure relative humidity. Hold Master Mode.
#define ESP_SHT21_RH_HM 0xE5
// Measure relative humidity. No Hold Master Mode.
#define ESP_SHT21_RH_NHM 0xF5
// Measure temperature. Hold Master Mode.
#define ESP_SHT21_TEMP_HM 0xE3
// Measure temperature. No Hold Master Mode.
#define ESP_SHT21_TEMP_NHM 0xF3
// Read temperature from previous RH measurement.
#define ESP_SHT21_TEMP_LAST 0xE0
// Read User Register 1.
#define ESP_SHT21_UR1_READ 0xE7
// Write User Register 1.
#define ESP_SHT21_UR1_WRITE 0xE6
// Read Heater Control Register
#define ESP_SHT21_HCR_READ 0x11
// Write Heater Control Register
#define ESP_SHT21_HCR_WRITE 0x51
// Invalid humidity.
#define ESP_SHT21_BAD_RH ((float)-1.00)
// Invalid temperature.
#define ESP_SHT21_BAD_TEMP ((float)-273)
// SHT21 humidity and temperature resolutions.
// RH: 12bit TEMP: 14bit
#define ESP_SHT21_RES3 0x0
// RH: 8bit TEMP: 12bit
#define ESP_SHT21_RES2 0x1
// RH: 10bit TEMP: 13bit
#define ESP_SHT21_RES1 0x2
// RH: 11bit TEMP: 11bit
#define ESP_SHT21_RES0 0x3
/**
* Initialize SHT21.
*
* @param gpio_scl The GPIO pin used for clock.
* @param gpio_sda The GPIO pin used for data.
*
* @return The I2C error code.
*/
esp_i2c_err ICACHE_FLASH_ATTR
esp_sht21_init(uint8_t gpio_scl, uint8_t gpio_sda);
/**
* Measure humidity.
*
* It takes approximately around 20ms to return the value.
*
* @return The I2C error code.
*/
esp_i2c_err ICACHE_FLASH_ATTR
esp_sht21_get_rh(float *humidity);
/**
* Measure temperature.
*
* This function slow. Faster method is to use esp_sht21_get_temp_last
* function which will return temperature value from previous
* humidity measurement.
*
* @param temp The measured temperature.
*
* @return The I2C error code.
*/
esp_i2c_err ICACHE_FLASH_ATTR
esp_sht21_get_temp(float *temp);
/**
* Get temperature from previous humidity measurement.
*
* This function is faster then esp_sht21_get_temp.
*
* @param temp The measured temperature.
*
* @return The I2C error code.
*/
esp_i2c_err ICACHE_FLASH_ATTR
esp_sht21_get_temp_last(float *temp);
/**
* Get 64 bit unique SHT21 serial number.
*
* @param sn The pointer to 8 byte array.
*
* @return The I2C error code.
*/
esp_i2c_err ICACHE_FLASH_ATTR
esp_sht21_get_sn(uint8_t *sn);
/**
* Get firmware revision.
*
* @param rev The revision to set.
*
* @return The I2C error code.
*/
esp_i2c_err ICACHE_FLASH_ATTR
esp_sht21_get_rev(uint8_t *rev);
/**
* Get humidity and temperature measurement resolution.
*
* @param res The measurement resolution. One of the ESP_SHT21_RES* defines.
*
* @return The I2C error code.
*/
esp_i2c_err ICACHE_FLASH_ATTR
esp_sht21_res_get(uint8_t *res);
/**
* Set SHT21 humidity and temperature measurement resolution.
*
* @param res The resolution. One of the ESP_SHT21_RES* defines.
*
* @return The I2C error code.
*/
esp_i2c_err ICACHE_FLASH_ATTR
esp_sht21_res_set(uint8_t res);
/**
* Get on-board heater status.
*
* @param on_off The on/off status.
* @param level The heater level value 0-15.
*
* @return The I2C error code.
*/
esp_i2c_err ICACHE_FLASH_ATTR
esp_sht21_heater_get(bool *on_off, uint8_t *level);
/**
* Set on-board heater status.
*
* @param on_off The on/off status.
* @param level The heater level value 0-15.
*
* @return The I2C error code.
*/
esp_i2c_err ICACHE_FLASH_ATTR
esp_sht21_heater_set(bool on_off, uint8_t level);
#endif //ESP_SHT21_H