mirror of
https://github.com/rzajac/esp-drv.git
synced 2025-07-26 14:11:05 +03:00
Initial commit
This commit is contained in:
18
src/CMakeLists.txt
Normal file
18
src/CMakeLists.txt
Normal 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)
|
32
src/esp_dht22/CMakeLists.txt
Normal file
32
src/esp_dht22/CMakeLists.txt
Normal 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})
|
46
src/esp_dht22/Findesp_dht22.cmake
Normal file
46
src/esp_dht22/Findesp_dht22.cmake
Normal 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
13
src/esp_dht22/README.md
Normal file
@ -0,0 +1,13 @@
|
||||
## DHT22 (AM2302) driver for ESP8266.
|
||||
|
||||
ESP8266 driver for very popular DHT22 (AM2302) temperature and humidity sensor.
|
||||
|
||||

|
||||
|
||||
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
178
src/esp_dht22/esp_dht22.c
Normal 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;
|
||||
}
|
||||
|
75
src/esp_dht22/include/esp_dht22.h
Normal file
75
src/esp_dht22/include/esp_dht22.h
Normal 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
|
38
src/esp_ds18b20/CMakeLists.txt
Normal file
38
src/esp_ds18b20/CMakeLists.txt
Normal 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})
|
52
src/esp_ds18b20/Findesp_ds18b20.cmake
Normal file
52
src/esp_ds18b20/Findesp_ds18b20.cmake
Normal 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
45
src/esp_ds18b20/README.md
Normal file
@ -0,0 +1,45 @@
|
||||
## DS18B20 driver for ESP8266.
|
||||
|
||||
Full featured DS18B20 digital thermometer driver.
|
||||
|
||||

|
||||
|
||||
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.
|
305
src/esp_ds18b20/esp_ds18b20.c
Normal file
305
src/esp_ds18b20/esp_ds18b20.c
Normal 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;
|
||||
}
|
187
src/esp_ds18b20/include/esp_ds18b20.h
Normal file
187
src/esp_ds18b20/include/esp_ds18b20.h
Normal 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
|
33
src/esp_sht21/CMakeLists.txt
Normal file
33
src/esp_sht21/CMakeLists.txt
Normal 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})
|
46
src/esp_sht21/Findesp_sht21.cmake
Normal file
46
src/esp_sht21/Findesp_sht21.cmake
Normal 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
18
src/esp_sht21/README.md
Normal file
@ -0,0 +1,18 @@
|
||||
## SHT21 driver for ESP8266.
|
||||
|
||||
SHT21 a.k.a Si7021 driver for ESP8266. Features:
|
||||
|
||||

|
||||
|
||||
- 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
324
src/esp_sht21/esp_sht21.c
Normal 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, ®1);
|
||||
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, ®1);
|
||||
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, ®1);
|
||||
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, ®1);
|
||||
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);
|
||||
}
|
168
src/esp_sht21/include/esp_sht21.h
Normal file
168
src/esp_sht21/include/esp_sht21.h
Normal 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
|
Reference in New Issue
Block a user