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

2
.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
.idea/

38
CMakeLists.txt Normal file
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.
# Bootstrap before call to project().
include("$ENV{ESPROOT}/esp-cmake/ESP8266.bootstrap.cmake")
cmake_minimum_required(VERSION 3.5)
project(esp_drv C)
set(CMAKE_C_STANDARD 99)
# The directory containing global user_congih.h header file.
set(ESP_USER_CONFIG_DIR "${CMAKE_CURRENT_LIST_DIR}/examples/include")
set(ESP_USER_CONFIG "${ESP_USER_CONFIG_DIR}/user_config.h")
set(ESP_CMAKE_FIND_DIR "${CMAKE_CURRENT_LIST_DIR}/cmake")
set(ESP_LIB_BIN_DIR "${CMAKE_CURRENT_LIST_DIR}/bin")
# Magic.
include("${ESP_CMAKE_DIR}/ESP8266.cmake")
# Main application.
# Must define esp_main executable target.
add_subdirectory(src)
add_subdirectory(examples)
set(CPACK_GENERATOR "TGZ")
include(CPack)

174
LICENSE Normal file
View File

@ -0,0 +1,174 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.

52
README.md Normal file
View File

@ -0,0 +1,52 @@
## ESP8266 drivers.
The collection of device drivers for ESP8266.
- [DS18B20](src/esp_ds18b20) OneWire temperature sensor.
- [DHT22 (AM2302)](src/esp_dht22) temperature and humidity sensor.
- [SHT21 (Si7020)](src/esp_sht21) temperature and humidity sensor.
## Build environment.
This library is part of my build system for ESP8266 based on CMake.
To compile / flash examples you will have to have the ESP development
environment setup as described at https://github.com/rzajac/esp-dev-env.
## Development environment installation.
There are two ways to install device drivers in the development environment:
```
$ wget -O - https://raw.githubusercontent.com/rzajac/esp-drv/master/install.sh | bash
```
or if you already cloned this repository you can do:
```
$ cd build
$ cmake ..
$ make
$ make install
```
## Examples.
- [DHT22 get temperature and humidity](examples/dht22_temp_hum)
- [DS18B20 get temperature](examples/ds18b20_temp)
- [Search for DS18B20](examples/ds18b20_search)
# Dependencies.
This library depends on:
- https://github.com/rzajac/esp-prot
to install dependency run:
```
$ wget -O - https://raw.githubusercontent.com/rzajac/esp-prot/master/install.sh | bash
```
## License.
[Apache License Version 2.0](LICENSE) unless stated otherwise.

2
build/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
*
!.gitignore

BIN
doc/dht22-pinout.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

BIN
doc/ds18b20.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
doc/sht21.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

19
examples/CMakeLists.txt Normal file
View File

@ -0,0 +1,19 @@
# 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(ds18b20_search)
add_subdirectory(ds18b20_temp)
add_subdirectory(dht22_temp_hum)
add_subdirectory(sht21_example)

View File

@ -0,0 +1,31 @@
# 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.
find_package(esp_sdo REQUIRED)
find_package(esp_util REQUIRED)
add_executable(dht22_temp_hum main.c ${ESP_USER_CONFIG})
target_include_directories(dht22_temp_hum PUBLIC
${ESP_USER_CONFIG_DIR}
${esp_sdo_INCLUDE_DIRS}
${esp_util_INCLUDE_DIRS})
target_link_libraries(dht22_temp_hum
${esp_sdo_LIBRARIES}
${esp_util_LIBRARIES}
esp_dht22)
esp_gen_exec_targets(dht22_temp_hum)

View File

@ -0,0 +1,12 @@
## DHT22 example.
Demonstrates how to get temperature and humidity from DHT22 sensor.
## Flashing
```
$ cd build
$ cmake ..
$ make dht22_temp_hum_flash
$ miniterm.py /dev/ttyUSB0 74880
```

View File

@ -0,0 +1,117 @@
/*
* 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 <user_interface.h>
#include <esp_gpio.h>
#include <esp_dht22.h>
#include <mem.h>
#include <esp_sdo.h>
os_timer_t timer;
/**
* Rise base to power of.
*
* From: http://bbs.espressif.com/viewtopic.php?t=246
*
* @param base The number.
* @param exp The exponent.
*
* @return Product.
*/
static int ICACHE_FLASH_ATTR
power(int base, int exp)
{
int result = 1;
while (exp) {
result *= base;
exp--;
}
return result;
}
/**
* Get string representation of float.
*
* From: http://bbs.espressif.com/viewtopic.php?t=246
*
* Warning: limited to 15 chars & non-reentrant.
* e.g., don't use more than once per os_printf call.
*
* @param num The float to convert to string.
* @param decimals The number of decimal places.
*
* @return The float string representation.
*/
static char *ICACHE_FLASH_ATTR
ftoa(float num, uint8_t decimals)
{
static char *buf[16];
int whole = (int) num;
int decimal = (int) ((num - whole) * power(10, decimals));
if (decimal < 0) {
// get rid of sign on decimal portion
decimal -= 2 * decimal;
}
char *pattern[10]; // setup printf pattern for decimal portion
os_sprintf((char *) pattern, "%%d.%%0%dd", decimals);
os_sprintf((char *) buf, (const char *) pattern, whole, decimal);
return (char *) buf;
}
void ICACHE_FLASH_ATTR
sys_init_done(void* arg)
{
esp_dht22_err err;
esp_dht22_dev *dev = esp_dht22_new_dev(GPIO2);
// Get temperature.
err = esp_dht22_get(dev);
if (err != ESP_DHT22_OK) {
os_free(dev);
os_printf("DHT22 error code: %d\n", err);
return;
}
os_printf("Temp: %s\n", ftoa(dev->temp, 2));
os_printf("Hum: %s\n", ftoa(dev->hum, 2));
os_printf("--------------------\n");
os_free(dev);
}
void ICACHE_FLASH_ATTR
user_init()
{
// No need for wifi for this example.
wifi_station_disconnect();
wifi_set_opmode_current(NULL_MODE);
//system_init_done_cb(sys_init_done);
stdout_init(BIT_RATE_74880);
// Initialize DHT22 on GPIO 2.
esp_dht22_init(GPIO2);
// Wait before running main code.
os_printf("Initialized.\n");
os_timer_disarm(&timer);
os_timer_setfn(&timer, sys_init_done, NULL);
os_timer_arm(&timer, 1500, true);
}

View File

@ -0,0 +1,37 @@
# 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.
find_package(esp_sdo REQUIRED)
find_package(esp_ow REQUIRED)
find_package(esp_eb REQUIRED)
find_package(esp_util REQUIRED)
add_executable(ds18b20_search main.c ${ESP_USER_CONFIG})
target_include_directories(ds18b20_search PUBLIC
${ESP_USER_CONFIG_DIR}
${esp_sdo_INCLUDE_DIRS}
${esp_ow_INCLUDE_DIRS}
${esp_eb_INCLUDE_DIRS}
${esp_util_INCLUDE_DIRS})
target_link_libraries(ds18b20_search
${esp_sdo_LIBRARIES}
${esp_ow_LIBRARIES}
${esp_eb_LIBRARIES}
${esp_util_LIBRARIES}
esp_ds18b20)
esp_gen_exec_targets(ds18b20_search)

View File

@ -0,0 +1,12 @@
## Find DS18b20 devices.
Demonstrates how to search OneWire bus for DS18b20.
## Flashing
```
$ cd build
$ cmake ..
$ make ds18b20_search_flash
$ miniterm.py /dev/ttyUSB0 74880
```

View File

@ -0,0 +1,55 @@
/*
* 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 <user_interface.h>
#include <osapi.h>
#include <esp_ds18b20.h>
#include <esp_gpio.h>
#include <esp_sdo.h>
// List of found devices on the OneWire bus.
static esp_ow_device *root = NULL;
static void ICACHE_FLASH_ATTR
sys_init_done()
{
esp_ow_err err;
if (esp_ds18b20_init(GPIO2) == false) {
os_printf("Error initializing DS18B20.\n");
return;
}
err = esp_ds18b20_search(GPIO2, false, &root);
if (err != ESP_OW_OK) {
os_printf("Search error: %d\n", err);
return;
}
// Log found devices to serial.
esp_ow_dump_found(root);
}
void ICACHE_FLASH_ATTR
user_init()
{
// No need for wifi for this examples.
wifi_station_disconnect();
wifi_set_opmode_current(NULL_MODE);
stdout_init(BIT_RATE_74880);
system_init_done_cb(sys_init_done);
}

View File

@ -0,0 +1,37 @@
# 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.
find_package(esp_sdo REQUIRED)
find_package(esp_ow REQUIRED)
find_package(esp_eb REQUIRED)
find_package(esp_util REQUIRED)
add_executable(ds18b20_temp main.c ${ESP_USER_CONFIG})
target_include_directories(ds18b20_temp PUBLIC
${ESP_USER_CONFIG_DIR}
${esp_sdo_INCLUDE_DIRS}
${esp_ow_INCLUDE_DIRS}
${esp_eb_INCLUDE_DIRS}
${esp_util_INCLUDE_DIRS})
target_link_libraries(ds18b20_temp
${esp_sdo_LIBRARIES}
${esp_ow_LIBRARIES}
${esp_eb_LIBRARIES}
${esp_util_LIBRARIES}
esp_ds18b20)
esp_gen_exec_targets(ds18b20_temp)

View File

@ -0,0 +1,12 @@
## Get temperature measured by DS18B20.
Demonstrates how to search OneWire bus for DS18b20.
## Flashing
```
$ cd build
$ cmake ..
$ make ds18b20_temp_flash
$ miniterm.py /dev/ttyUSB0 74880
```

View File

@ -0,0 +1,81 @@
/*
* 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 <user_interface.h>
#include <osapi.h>
#include <esp_ds18b20.h>
#include <esp_gpio.h>
#include <esp_eb.h>
#include <esp_sdo.h>
#include <esp_util.h>
// List of found devices on the OneWire bus.
static esp_ow_device *root = NULL;
// Handle temperature conversion callbacks.
static void ICACHE_FLASH_ATTR
temperature(const char *event, void *arg)
{
esp_ow_device *dev = arg;
esp_ds18b20_st *st = dev->custom;
if (st->last_temp == ESP_DS18B20_TEMP_ERR) {
os_printf("Temperature read error.\n");
} else {
os_printf("Temperature: %s\n", esp_util_ftoa(st->last_temp, 4));
}
}
static void ICACHE_FLASH_ATTR
sys_init_done()
{
esp_ow_err err;
if (esp_ds18b20_init(GPIO2) == false) {
os_printf("Error initializing DS18B20.\n");
return;
}
err = esp_ds18b20_search(GPIO2, false, &root);
if (err != ESP_OW_OK) {
os_printf("Search error: %d\n", err);
return;
}
if (root == NULL) {
os_printf("No devices found.\n");
}
// Callbacks will be called when conversion is finished.
esp_eb_attach(ESP_DS18B20_EV_TEMP_READY, temperature);
esp_eb_attach(ESP_DS18B20_EV_TEMP_ERROR, temperature);
// Get temperature from the first DS18B20 sensor.
esp_ds18b20_convert(root);
}
void ICACHE_FLASH_ATTR
user_init()
{
// No need for wifi for this examples.
wifi_station_disconnect();
wifi_set_opmode_current(NULL_MODE);
stdout_init(BIT_RATE_74880);
system_init_done_cb(sys_init_done);
}

View File

@ -0,0 +1 @@
// This is only here to make the API headers happy.

View File

@ -0,0 +1,34 @@
# 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.
find_package(esp_sdo REQUIRED)
find_package(esp_i2c REQUIRED)
find_package(esp_util REQUIRED)
add_executable(sht21_example main.c ${ESP_USER_CONFIG})
target_include_directories(sht21_example PUBLIC
${ESP_USER_CONFIG_DIR}
${esp_sdo_INCLUDE_DIRS}
${esp_i2c_INCLUDE_DIRS}
${esp_util_INCLUDE_DIRS})
target_link_libraries(sht21_example
${esp_sdo_LIBRARIES}
${esp_i2c_LIBRARIES}
${esp_util_LIBRARIES}
esp_sht21)
esp_gen_exec_targets(sht21_example)

View File

@ -0,0 +1,15 @@
## SHT21 example.
Demonstrates how to:
- get serial number,
- get firmware version,
- get humidity and temperature.
## Flashing
```
$ cd build
$ cmake ..
$ make sht21_example_flash
$ miniterm.py /dev/ttyUSB0 74880
```

View File

@ -0,0 +1,131 @@
/*
* 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 <esp_sdo.h>
#include <user_interface.h>
#include <osapi.h>
#define SCL GPIO0
#define SDA GPIO2
os_timer_t timer;
/**
* Rise base to power of.
*
* From: http://bbs.espressif.com/viewtopic.php?t=246
*
* @param base The number.
* @param exp The exponent.
*
* @return Product.
*/
static int ICACHE_FLASH_ATTR
power(int base, int exp)
{
int result = 1;
while (exp) {
result *= base;
exp--;
}
return result;
}
/**
* Get string representation of float.
*
* From: http://bbs.espressif.com/viewtopic.php?t=246
*
* Warning: limited to 15 chars & non-reentrant.
* e.g., don't use more than once per os_printf call.
*
* @param num The float to convert to string.
* @param decimals The number of decimal places.
*
* @return The float string representation.
*/
static char *ICACHE_FLASH_ATTR
ftoa(float num, uint8_t decimals)
{
static char *buf[16];
int whole = (int) num;
int decimal = (int) ((num - whole) * power(10, decimals));
if (decimal < 0) {
// get rid of sign on decimal portion
decimal -= 2 * decimal;
}
char *pattern[10]; // setup printf pattern for decimal portion
os_sprintf((char *) pattern, "%%d.%%0%dd", decimals);
os_sprintf((char *) buf, (const char *) pattern, whole, decimal);
return (char *) buf;
}
void ICACHE_FLASH_ATTR
run_sht21()
{
uint8_t rev;
float value;
uint8_t sn[8];
esp_i2c_err err;
err = esp_sht21_init(SCL, SDA);
if (err != ESP_I2C_OK) {
os_printf("SHT21 init error.\n");
return;
}
err = esp_sht21_get_sn(sn);
if (err != ESP_I2C_OK) os_printf("SHT21 sn error %d.\n", err);
os_printf("SHT21 SN: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\n",
sn[0], sn[1], sn[2], sn[3],
sn[4], sn[5], sn[6], sn[7]);
err = esp_sht21_get_rev(&rev);
if (err != ESP_I2C_OK) os_printf("SHT21 sn error %d.\n", err);
os_printf("Firmware rev: 0x%02X\n", rev);
err = esp_sht21_get_rh(&value);
if (err != ESP_I2C_OK) os_printf("Get RH error: %d\n", err);
os_printf("Humidity: %s%%\n", ftoa(value, 2));
err = esp_sht21_get_temp_last(&value);
if (err != ESP_I2C_OK) os_printf("Get TEMP error: %d\n", err);
os_printf("Temperature: %s deg. C\n", ftoa(value, 2));
}
void ICACHE_FLASH_ATTR
user_init()
{
// We don't need WiFi for this example.
wifi_station_disconnect();
wifi_set_opmode(NULL_MODE);
stdout_init(BIT_RATE_74880);
os_printf("Starting...\n");
os_timer_disarm(&timer);
os_timer_setfn(&timer, (os_timer_func_t *) run_sht21, NULL);
os_timer_arm(&timer, 1500, false);
}

63
install.sh Executable file
View File

@ -0,0 +1,63 @@
#!/usr/bin/env bash
# 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.
# ESP8266 library installation script.
#
# Installer expects that:
# - The ESPROOT environment variable set.
# - The esp-open-sdk is installed and compiled at ESPROOT/esp-open-sdk.
# The full GitHub URL to the library.
LIB_FULL_NAME="rzajac/esp-drv"
# No modifications below this comment unless you know what you're doing.
TMP_DIR=`mktemp -d`
LIB_REPO="https://github.com/${LIB_FULL_NAME}"
LIB_NAME=${LIB_FULL_NAME##*/}
CMAKE=`which cmake`
# Remove temporary directory.
function rm_tmp() {
echo "Removing ${TMP_DIR}"
rm -rf ${TMP_DIR}
}
# Check / set ESPROOT.
if [ "${ESPROOT}" == "" ]; then ESPROOT=$HOME/esproot; fi
if ! [ -d "${ESPROOT}" ]; then mkdir -p ${ESPROOT}; fi
echo "Using ${ESPROOT} as ESPROOT"
echo "Cloning ${LIB_REPO} to temporary directory ${TMP_DIR}."
git clone ${LIB_REPO} ${TMP_DIR}
if [ $? != 0 ]; then
echo "Error: Cloning ${LIB_REPO} failed!"
rm_tmp
exit 1
fi
echo "Installing library ${LIB_NAME} to ${ESPROOT}"
mkdir ${TMP_DIR}/auto-build
(cd ${TMP_DIR}/auto-build && ${CMAKE} .. && make install)
if [ $? != 0 ]; then
echo "Error: Installing library ${LIB_NAME} failed!"
rm_tmp
exit 1
fi
rm_tmp
exit 0

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