Driver for Sensirion SHT3x sensor added
This is a driver for Sensirion SHT3x temperature and humidity sensors connected via I2C. This commit is a rebasing and contains some interface changes based on the review from @ourairquality.
This commit is contained in:
parent
546cc47121
commit
803931f2e2
9 changed files with 1283 additions and 0 deletions
48
examples/sht3x/README.md
Normal file
48
examples/sht3x/README.md
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
# SHT3x Driver Examples
|
||||||
|
|
||||||
|
These examples references two addtional drivers [i2c](https://github.com/kanflo/esp-open-rtos-driver-i2c) and [sht3x](https://github.com/gschorcht/esp-open-rtos/extras/sht3x), which are provided in the `../../extras` folder.
|
||||||
|
|
||||||
|
If you plan to use one or both of this drivers in your own projects, please check the main development pages for updated versions or reported issues.
|
||||||
|
|
||||||
|
## Hardware setup
|
||||||
|
|
||||||
|
There are examples for only one sensor and examples for two sensors.
|
||||||
|
|
||||||
|
To run examples with **one sensor**, just use GPIO5 (SCL) and GPIO4 (SDA) to connect to the SHT3x sensor's I2C interface.
|
||||||
|
|
||||||
|
```
|
||||||
|
+------------------------+ +--------+
|
||||||
|
| ESP8266 Bus 0 | | SHT3x |
|
||||||
|
| GPIO 5 (SCL) >---- > SCL |
|
||||||
|
| GPIO 4 (SDA) ------- SDA |
|
||||||
|
| | +--------+
|
||||||
|
+------------------------+
|
||||||
|
```
|
||||||
|
|
||||||
|
If you want to run examples with **two sensors**, you could do this with only one bus and different I2C addresses or with two buses and the same or different I2C addresses. In later case, use GPIO14 (SCL) and GPIO12 (SDA) for the second bus to connect to the second SHT3x sensor's I2C interface.
|
||||||
|
|
||||||
|
```
|
||||||
|
+------------------------+ +----------+
|
||||||
|
| ESP8266 Bus 0 | | SHT3x_1 |
|
||||||
|
| GPIO 5 (SCL) >-----> SCL |
|
||||||
|
| GPIO 4 (SDA) ------- SDA |
|
||||||
|
| | +----------+
|
||||||
|
| Bus 1 | | SHT3x_2 |
|
||||||
|
| GPIO 14 (SCL) >-----> SCL |
|
||||||
|
| GPIO 12 (SDA) ------- SDA |
|
||||||
|
+------------------------+ +----------+
|
||||||
|
```
|
||||||
|
|
||||||
|
## Example description
|
||||||
|
|
||||||
|
Examples show how to use the driver in single shot as well as in periodic mode.
|
||||||
|
|
||||||
|
|
||||||
|
### _sht3x_one_sensor_
|
||||||
|
|
||||||
|
The simple example show how to use the driver with one SHT3x sensor. It demonstrates two different user task implementations, one in *single shot mode* and one in *periodic mode*. In addition, it shows both approaches for the implementation of waiting for measurement results, one as busy waiting and one as passive waiting using *vTaskDelay*.
|
||||||
|
|
||||||
|
### _sht3x_two_sensors_
|
||||||
|
|
||||||
|
This simple example shows how to use the driver for two sensors. As with the example _sht3x_one_sensor_, it uses two different user task implementations and waiting approaches, in this example one for each of the tasks.
|
||||||
|
|
||||||
3
examples/sht3x/sht3x_one_sensor/Makefile
Normal file
3
examples/sht3x/sht3x_one_sensor/Makefile
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
PROGRAM=SHT3x_One_Sensor
|
||||||
|
EXTRA_COMPONENTS = extras/i2c extras/sht3x
|
||||||
|
include ../../../common.mk
|
||||||
126
examples/sht3x/sht3x_one_sensor/sht3x_one_sensor.c
Normal file
126
examples/sht3x/sht3x_one_sensor/sht3x_one_sensor.c
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
/**
|
||||||
|
* Simple example with one SHT3x sensor.
|
||||||
|
*
|
||||||
|
* It shows two different user task implementations, one in *single shot mode*
|
||||||
|
* and one in *periodic mode*. In addition, it shows both approaches for the
|
||||||
|
* implementation of waiting for measurement results, one as busy waiting and
|
||||||
|
* one as passive waiting using *vTaskDelay*.
|
||||||
|
*
|
||||||
|
* The implementation that is used is defined by constant SINGLE_SHOT_MODE.
|
||||||
|
*
|
||||||
|
* Harware configuration:
|
||||||
|
*
|
||||||
|
* +------------------------+ +----------+
|
||||||
|
* | ESP8266 Bus 0 | | SHT3x |
|
||||||
|
* | GPIO 5 (SCL) ------> SCL |
|
||||||
|
* | GPIO 4 (SDA) ------- SDA |
|
||||||
|
* +------------------------+ +----------+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "espressif/esp_common.h"
|
||||||
|
#include "esp/uart.h"
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
|
||||||
|
// include SHT3x driver
|
||||||
|
#include "sht3x/sht3x.h"
|
||||||
|
|
||||||
|
// define I2C interfaces at which SHTx3 sensors are connected
|
||||||
|
#define I2C_BUS 0
|
||||||
|
#define I2C_SCL_PIN GPIO_ID_PIN((5))
|
||||||
|
#define I2C_SDA_PIN GPIO_ID_PIN((4))
|
||||||
|
|
||||||
|
static sht3x_sensor_t* sensor; // sensor device data structure
|
||||||
|
|
||||||
|
// #define SINGLE_SHOT_MODE
|
||||||
|
|
||||||
|
#ifdef SINGLE_SHOT_MODE
|
||||||
|
/*
|
||||||
|
* User task that triggers measurements of sensor every 5 seconds. Due to
|
||||||
|
* power efficiency reasons, it uses the SHT3x *single_shot* and *vTaskDelay*
|
||||||
|
* to wait for measurement results.
|
||||||
|
*/
|
||||||
|
void user_task (void *pvParameters)
|
||||||
|
{
|
||||||
|
sht3x_values_t values;
|
||||||
|
int32_t duration;
|
||||||
|
|
||||||
|
TickType_t last_wakeup = xTaskGetTickCount();
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
// trigger one measurement in single shot mode
|
||||||
|
duration = sht3x_start_measurement (sensor, single_shot);
|
||||||
|
|
||||||
|
// passive waiting until measurement results are available
|
||||||
|
if (duration > 0)
|
||||||
|
vTaskDelay (duration/portTICK_PERIOD_MS);
|
||||||
|
|
||||||
|
// retrieve the values and do something with them
|
||||||
|
if (sht3x_get_results (sensor, &values))
|
||||||
|
printf("%.3f SHT3x Sensor: %.2f °C, %.2f %%\n",
|
||||||
|
(double)sdk_system_get_time()*1e-3,
|
||||||
|
values.temperature, values.humidity);
|
||||||
|
|
||||||
|
// passive waiting until 5 seconds are over
|
||||||
|
vTaskDelayUntil(&last_wakeup, 5000 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else // PERIODIC MODE
|
||||||
|
/*
|
||||||
|
* User task that fetches latest measurement results of sensor every 2
|
||||||
|
* seconds. It starts the SHT3x in periodic mode with 1 measurements per
|
||||||
|
* second (*periodic_1mps*). It uses busy waiting for first measurement
|
||||||
|
* results.
|
||||||
|
*/
|
||||||
|
void user_task (void *pvParameters)
|
||||||
|
{
|
||||||
|
sht3x_values_t values;
|
||||||
|
|
||||||
|
// start periodic measurement mode
|
||||||
|
sht3x_start_measurement (sensor, periodic_1mps);
|
||||||
|
|
||||||
|
// busy waiting until measurement results are available
|
||||||
|
while (sht3x_is_measuring (sensor) > 0) ;
|
||||||
|
|
||||||
|
TickType_t last_wakeup = xTaskGetTickCount();
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
// retrieve the values and do something with them
|
||||||
|
if (sht3x_get_results (sensor, &values))
|
||||||
|
printf("%.3f SHT3x Sensor: %.2f °C, %.2f %%\n",
|
||||||
|
(double)sdk_system_get_time()*1e-3,
|
||||||
|
values.temperature, values.humidity);
|
||||||
|
|
||||||
|
// passive waiting until 2 seconds are over
|
||||||
|
vTaskDelayUntil(&last_wakeup, 2000 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void user_init(void)
|
||||||
|
{
|
||||||
|
// Please note: Return values are not considered in this example for
|
||||||
|
// readability reasons. All functions return boolean and set an error
|
||||||
|
// code that allows effective error handling.
|
||||||
|
|
||||||
|
// Set UART Parameter
|
||||||
|
uart_set_baud(0, 115200);
|
||||||
|
|
||||||
|
// Give the UART some time to settle
|
||||||
|
sdk_os_delay_us(500);
|
||||||
|
|
||||||
|
// Init I2C bus interfaces at which SHT3x sensors are connected
|
||||||
|
// (different busses are possible)
|
||||||
|
i2c_init(I2C_BUS, I2C_SCL_PIN, I2C_SDA_PIN, I2C_FREQ_100K);
|
||||||
|
|
||||||
|
// Create sensors
|
||||||
|
sensor = sht3x_init_sensor (I2C_BUS, SHT3x_ADDR_2);
|
||||||
|
|
||||||
|
// Create a user task that uses the sensor
|
||||||
|
xTaskCreate(user_task, "user_task", 256, NULL, 2, 0);
|
||||||
|
|
||||||
|
// That's it.
|
||||||
|
}
|
||||||
3
examples/sht3x/sht3x_two_sensors/Makefile
Normal file
3
examples/sht3x/sht3x_two_sensors/Makefile
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
PROGRAM=SHT3x_Two_Sensors
|
||||||
|
EXTRA_COMPONENTS = extras/i2c extras/sht3x
|
||||||
|
include ../../../common.mk
|
||||||
135
examples/sht3x/sht3x_two_sensors/sht3x_two_sensors.c
Normal file
135
examples/sht3x/sht3x_two_sensors/sht3x_two_sensors.c
Normal file
|
|
@ -0,0 +1,135 @@
|
||||||
|
/**
|
||||||
|
* Simple example with two SHT3x sensors.
|
||||||
|
*
|
||||||
|
* It shows two different user task implementations, one in *single shot mode*
|
||||||
|
* and one in *periodic mode*. In addition, it shows both approaches for the
|
||||||
|
* implementation of waiting for measurement results, one as busy waiting and
|
||||||
|
* one as passive waiting using *vTaskDelay*.
|
||||||
|
*
|
||||||
|
* Harware configuration:
|
||||||
|
*
|
||||||
|
* +------------------------+ +----------+
|
||||||
|
* | ESP8266 Bus 0 | | SHT3x_1 |
|
||||||
|
* | GPIO 5 (SCL) ------> SCL |
|
||||||
|
* | GPIO 4 (SDA) ------- SDA |
|
||||||
|
* | | +----------+
|
||||||
|
* | Bus 1 | | SHT3x_2 |
|
||||||
|
* | GPIO 14 (SCL) ------> SCL |
|
||||||
|
* | GPIO 12 (SDA) ------- SDA |
|
||||||
|
* +------------------------+ +----------+
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "espressif/esp_common.h"
|
||||||
|
#include "esp/uart.h"
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
|
||||||
|
// include SHT3x driver
|
||||||
|
|
||||||
|
#include "sht3x/sht3x.h"
|
||||||
|
|
||||||
|
// define I2C interfaces at which SHTx3 sensors are connected
|
||||||
|
|
||||||
|
#define I2C_1_BUS 0
|
||||||
|
#define I2C_1_SCL_PIN GPIO_ID_PIN((5))
|
||||||
|
#define I2C_1_SDA_PIN GPIO_ID_PIN((4))
|
||||||
|
|
||||||
|
#define I2C_2_BUS 1
|
||||||
|
#define I2C_2_SCL_PIN GPIO_ID_PIN((14))
|
||||||
|
#define I2C_2_SDA_PIN GPIO_ID_PIN((12))
|
||||||
|
|
||||||
|
static sht3x_sensor_t* sensor1;
|
||||||
|
static sht3x_sensor_t* sensor2;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* User task that triggers measurements of sensor1 every 5 seconds. Due to
|
||||||
|
* power efficiency reasons, it uses the SHT3x *single_shot* and *vTaskDelay*
|
||||||
|
* to wait for measurement results.
|
||||||
|
*/
|
||||||
|
void user_task_sensor1 (void *pvParameters)
|
||||||
|
{
|
||||||
|
sht3x_values_t values;
|
||||||
|
int32_t duration;
|
||||||
|
|
||||||
|
TickType_t last_wakeup = xTaskGetTickCount();
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
// trigger one measurement in single shot mode
|
||||||
|
duration = sht3x_start_measurement (sensor1, single_shot);
|
||||||
|
|
||||||
|
// passive waiting until measurement results are available
|
||||||
|
if (duration > 0)
|
||||||
|
vTaskDelay (duration/portTICK_PERIOD_MS);
|
||||||
|
|
||||||
|
// retrieve the values and do something with them
|
||||||
|
if (sht3x_get_results (sensor1, &values))
|
||||||
|
printf("%.3f SHT3x Sensor1: %.2f °C, %.2f %%\n",
|
||||||
|
(double)sdk_system_get_time()*1e-3,
|
||||||
|
values.temperature, values.humidity);
|
||||||
|
|
||||||
|
// passive waiting until 5 seconds are over
|
||||||
|
vTaskDelayUntil(&last_wakeup, 5000 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* User task that fetches latest measurement results of sensor2 every 2
|
||||||
|
* seconds. It starts the SHT3x in periodic mode with 10 measurements per
|
||||||
|
* second (*periodic_10mps*). It uses busy waiting for first measurement
|
||||||
|
* results.
|
||||||
|
*/
|
||||||
|
void user_task_sensor2 (void *pvParameters)
|
||||||
|
{
|
||||||
|
sht3x_values_t values;
|
||||||
|
|
||||||
|
// start periodic measurement mode
|
||||||
|
sht3x_start_measurement (sensor2, periodic_10mps);
|
||||||
|
|
||||||
|
// busy waiting until measurement results are available
|
||||||
|
while (sht3x_is_measuring (sensor2) > 0);
|
||||||
|
|
||||||
|
TickType_t last_wakeup = xTaskGetTickCount();
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
// retrieve the values and do something with them
|
||||||
|
if (sht3x_get_results (sensor2, &values))
|
||||||
|
printf("%.3f SHT3x Sensor2: %.2f °C, %.2f %%\n",
|
||||||
|
(double)sdk_system_get_time()*1e-3,
|
||||||
|
values.temperature, values.humidity);
|
||||||
|
|
||||||
|
// passive waiting until 2 seconds are over
|
||||||
|
vTaskDelayUntil(&last_wakeup, 2000 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void user_init(void)
|
||||||
|
{
|
||||||
|
// Please note: Return values are not considered in this example for
|
||||||
|
// readability reasons. All functions return boolean and set an error
|
||||||
|
// code that allows effective error handling.
|
||||||
|
|
||||||
|
// Set UART Parameter
|
||||||
|
uart_set_baud(0, 115200);
|
||||||
|
|
||||||
|
// Give the UART some time to settle
|
||||||
|
sdk_os_delay_us(500);
|
||||||
|
|
||||||
|
// Init I2C bus interfaces at which SHT3x sensors are connected
|
||||||
|
// (different busses are possible)
|
||||||
|
i2c_init(I2C_1_BUS, I2C_1_SCL_PIN, I2C_1_SDA_PIN, I2C_FREQ_100K);
|
||||||
|
i2c_init(I2C_2_BUS, I2C_2_SCL_PIN, I2C_2_SDA_PIN, I2C_FREQ_100K);
|
||||||
|
|
||||||
|
// Create sensors
|
||||||
|
sensor1 = sht3x_init_sensor (I2C_1_BUS, SHT3x_ADDR_2);
|
||||||
|
sensor2 = sht3x_init_sensor (I2C_2_BUS, SHT3x_ADDR_1);
|
||||||
|
|
||||||
|
// Create tasks that use the sensors
|
||||||
|
xTaskCreate(user_task_sensor1, "user_task_sensor1", 256, NULL, 2, 0);
|
||||||
|
xTaskCreate(user_task_sensor2, "user_task_sensor2", 256, NULL, 2, 0);
|
||||||
|
|
||||||
|
// That's it.
|
||||||
|
}
|
||||||
259
extras/sht3x/README.md
Normal file
259
extras/sht3x/README.md
Normal file
|
|
@ -0,0 +1,259 @@
|
||||||
|
# Driver for **SHT3x** digital **temperature and humidity sensor**
|
||||||
|
|
||||||
|
This driver is written for usage with the ESP8266 and FreeRTOS using the I2C interface driver. It supports multiple sensors connected to the same or different I2C interfaces.
|
||||||
|
|
||||||
|
## About the sensor
|
||||||
|
|
||||||
|
SHT3x is a digital temperature and humidity sensor that uses an I2C interface with up to 1 MHz communication speed. It can operate with **three levels of repeatability** (low, medium and high) and in two different modes, the **single shot data acquisition mode** (or short **single shot mode**) and the **periodic data acquisition mode** (or short **periodic mode**).
|
||||||
|
|
||||||
|
### Repeatability
|
||||||
|
|
||||||
|
Repeatability or test–retest reliability is the variation in measurement results taken by the sensor under the same conditions, and in a short period of time. It is a measure for the noise on the physical sensor output. The higher the repeatability the smaller are changes in the output subsequent measurements.
|
||||||
|
|
||||||
|
The repeatability settings influences the measurement duration as well as the power consumption of the sensor. The measurement takes 3 ms with low repeatability, 5 ms with medium repeatability and 13.5 ms with high repeatability. That is, the measurement produces a noticeable delay in execution.
|
||||||
|
|
||||||
|
While the sensor measures at the lowest repeatability, the average current consumption is 800 μA. That is, the higher the repeatability level, the longer the measurement takes and the higher the power consumption. The sensor consumes only 0.2 μA in standby mode.
|
||||||
|
|
||||||
|
### Single shot data acquisition mode
|
||||||
|
|
||||||
|
In this mode, a measurement command triggers the acquisition of **exactly one data pair**. Each data pair consists of temperature and humidity as 16-bit decimal values.
|
||||||
|
|
||||||
|
### Periodic data acquisition mode
|
||||||
|
|
||||||
|
In this mode, one issued measurement command yields a stream of data pairs. Each data pair again consists of temperature and humidity as 16-bit decimal values. As soon as the measurement command has been sent to the sensor, it performs measurements **periodically at a rate of 0.5, 1, 2, 4 or 10 measurements per second (mps)**. The data pairs can be read with a fetch command at the same rate.
|
||||||
|
|
||||||
|
As in the *single shot mode*, the repeatability setting affects both the measurement duration and the current consumption of the sensor, see above.
|
||||||
|
|
||||||
|
|
||||||
|
## How the driver works
|
||||||
|
|
||||||
|
The driver supports multiple SHT3x sensors at the same time. They can be connected with different addresses at the same I2C bus or with arbitrary addresses to different I2C buses. Each sensor has to be initialized at the beginning using function **_sht3x_init_sensor_**. Parameters are the I2C bus and address at which the sensor is connected.
|
||||||
|
|
||||||
|
### Measurement process
|
||||||
|
|
||||||
|
Once the sensor is initialized and tested, it can be used for measurements. In order to avoid blocking of user tasks during measurements due to their duration, the measurement process is splitted into the following steps:
|
||||||
|
|
||||||
|
1. Trigger the sensor to start the measurement either in *single shot mode* or in *periodic mode*.
|
||||||
|
|
||||||
|
2. Fetch the values from the sensor once in *single shot mode* or periodically in *periodic mode*
|
||||||
|
|
||||||
|
Between the first step and the second step, the sensor performs the measurement, which can take up to 30 ms. During that time the user task has to wait.
|
||||||
|
|
||||||
|
#### Single shot data acquisition mode
|
||||||
|
|
||||||
|
In the *single shot mode*, the user task has to execute both steps every time new sensor values are needed, including the waiting time. The advantage of this mode is that the sensor can switch between successive measurements into the sleep mode which is more power-efficient. However, using the *single shot mode* produces a delay of up to 30 ms for each measurement.
|
||||||
|
|
||||||
|
#### Periodic data acquisition mode
|
||||||
|
|
||||||
|
In the *periodic mode*, the sensor automatically performs periodic measurements. Once the sensor has been triggered to start periodic measurements, new measurement results become available every 100 ms, 250 ms, 500 ms, 1000 ms or 2000 ms. The user task has simply to fetch them. Of course, the rate of fetching new measurement results must be less than the rate used by the sensor. The only waiting time required in this mode is the time between the start of the periodic measurements and the time when the first measurement results become available.
|
||||||
|
|
||||||
|
As in the *single shot mode* the sensor switches to the sleep mode between successive measurements. Thus, the *periodic mode* becomes as power-efficient as the *single shot mode* when at least one measurement result per second is required by the user task. Only, if the user task requires new measurement results seldom, e.g. one measurement per minute, then the *single shot mode* is the better choice.
|
||||||
|
|
||||||
|
### Starting measurement
|
||||||
|
|
||||||
|
Measurements are started using function **_sht3x_start_measurement_**. The SHT3x data acquisition mode to be used is defined by a parameter. In both modes, the highest repeatability is used.
|
||||||
|
|
||||||
|
If the measurement could be started successfully, the function returns an estimated duration until the first measurement results become available. The user task can use this duration with function **_vTaskDelay_** to wait until the measurement results are available. Alternatively, function **_sht3x_is_running_** can be used to realize a busy waiting. This function returns the remaining duration until the measurement will be finished.
|
||||||
|
|
||||||
|
Please note: Since *vTaskDelay* can only handle delays as multiples of 10 ms, the duration obtained as return value from function *sht3x_start_measurement* is 30 ms for high repeatability and 20 ms for medium as well as low repeatability.
|
||||||
|
|
||||||
|
### Measured data
|
||||||
|
|
||||||
|
Once new measurement results are available, either function **_sht3x_get_raw_data_** or function **_sht3x_get_results_** can be used to fetch the results.
|
||||||
|
|
||||||
|
Function **__sht3x_get_raw_data_** fetches only the raw sensor data in 16-decimal format, checks the CRC checksums and stores them in an byte array of type **_sht3x_raw_data_t_**. The user task then can use them directly or to call function **_sht3x_compute_values_** to compute floating point sensor values from them.
|
||||||
|
|
||||||
|
Function **_sht3x_get_results_** combines function *sht3x_read_raw_data* and function
|
||||||
|
*sht3x_compute_valus_* to get the latest sensor values. This is the preferred approach to get sensor values by the user task.
|
||||||
|
|
||||||
|
In the **periodic mode**, the function *sht3x get_results* can be executed repeatedly without a new call of function *sht3_start_measurement* and without a new waiting time. However, the rate of the repeated call should be less than the half of the periodic measuring rate of the sensor.
|
||||||
|
|
||||||
|
## Error Handling
|
||||||
|
|
||||||
|
Most driver functions return a simple boolean value to indicate whether its execution was successful or an error happened. In later case, the member **_error_code_** of the sensor device data structure is set which indicates what error happened.
|
||||||
|
|
||||||
|
There are two different error levels that are ORed into one single *error_code*, errors in I2C communication and errors with the SHT3x sensor itself. To test for a certain error you can AND the *error_code* with one of the error masks, **_SHT3x_I2C_ERROR_MASK_** for I2C errors and **_SHT3x_DRV_ERROR_MASK_** for other errors and then test for a certain error code.
|
||||||
|
|
||||||
|
## Usage
|
||||||
|
|
||||||
|
Before using the SHT3x driver, function **_i2c_init_** needs to be called for each I2C interface to setup them.
|
||||||
|
|
||||||
|
```
|
||||||
|
#include "sht3x/sht3x.h"
|
||||||
|
...
|
||||||
|
#define I2C_BUS 0
|
||||||
|
#define I2C_SCL_PIN GPIO_ID_PIN((5))
|
||||||
|
#define I2C_SDA_PIN GPIO_ID_PIN((4))
|
||||||
|
|
||||||
|
...
|
||||||
|
i2c_init(I2C_BUS, I2C_SCL_PIN, I2C_SDA_PIN, I2C_FREQ_100K))
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
sht3x_init_driver();
|
||||||
|
```
|
||||||
|
|
||||||
|
Once I2C interfaces are initialized, function **_sht3x_init_sensor_** has to be called for each sensor to initialize the sensor and to check its availability as well as its error state. The parameters specify the I2C bus and address to which it is connected.
|
||||||
|
|
||||||
|
```
|
||||||
|
static sht3x_sensor_t* sensor; // pointer to sensor device data structure
|
||||||
|
...
|
||||||
|
sensor = sht3x_init_sensor (I2C_BUS, SHT3x_ADDR_2);
|
||||||
|
```
|
||||||
|
|
||||||
|
Function **_sht3x_init_sensor_** returns a pointer to the sensor device data structure or NULL in case of error.
|
||||||
|
|
||||||
|
Last, the user task that uses the sensor has to be created.
|
||||||
|
|
||||||
|
```
|
||||||
|
xTaskCreate(user_task, "user_task", 256, NULL, 2, 0);
|
||||||
|
```
|
||||||
|
|
||||||
|
The user task can use the sensor in two different ways, either in *periodic mode* or in *single shot mode*.
|
||||||
|
|
||||||
|
In *periodic mode* the user task calls function **_sht3x_start_measurement_** only once and fetches the measurement result in each cycle with function **_sht3x_get_results_** without any delay. In this mode the user task could look like the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
void user_task(void *pvParameters)
|
||||||
|
{
|
||||||
|
sht3x_values_t values;
|
||||||
|
int32_t duration;
|
||||||
|
|
||||||
|
duration = sht3x_start_measurement (sensor, periodic_1mps);
|
||||||
|
|
||||||
|
// busy waiting
|
||||||
|
// while (sht3x_is_measuring (sensor) > 0) ;
|
||||||
|
|
||||||
|
// suspend the task for waiting
|
||||||
|
if (duration > 0)
|
||||||
|
vTaskDelay (duration/portTICK_PERIOD_MS);
|
||||||
|
|
||||||
|
TickType_t last_wakeup = xTaskGetTickCount();
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
// retrieve the values and do something with them
|
||||||
|
if (sht3x_get_results (sensor, &values))
|
||||||
|
printf("%.3f SHT3x Sensor: %.2f °C, %.2f %%\n",
|
||||||
|
(double)sdk_system_get_time()*1e-3,
|
||||||
|
values.temperature, values.humidity);
|
||||||
|
|
||||||
|
// passive waiting until 2 seconds are over
|
||||||
|
vTaskDelayUntil(&last_wakeup, 2000 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
At the beginning of the task, the periodic measurement is started by function **_sht3x_start_measurement_** with a rate of 1 measurements per second. Using the duration returned from this function, the task is delayed using **_vTaskDelay_**. This is the duration until the first measurement results become available. The busy waiting alternative is shown in comments.
|
||||||
|
|
||||||
|
Inside the task loop, the measurement results are fetched periodically using function **_sht3x_get_results_** with a rate of once per second.
|
||||||
|
|
||||||
|
In the *single shot mode*, the measurement in each cycle consist of the three steps:
|
||||||
|
|
||||||
|
- start the measurement using function **sht3x_start_measurement_**
|
||||||
|
- waiting the measurement duration
|
||||||
|
- fetch the results using function **sht3x_get_results_**
|
||||||
|
|
||||||
|
Thus the user task could look like the following:
|
||||||
|
|
||||||
|
```
|
||||||
|
void user_task(void *pvParameters)
|
||||||
|
{
|
||||||
|
sht3x_values_t values;
|
||||||
|
int32_t duration;
|
||||||
|
|
||||||
|
TickType_t last_wakeup = xTaskGetTickCount();
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
// trigger one measurement in single shot mode
|
||||||
|
duration = sht3x_start_measurement (sensor, single_shot);
|
||||||
|
|
||||||
|
// busy waiting
|
||||||
|
// while (sht3x_is_measuring (sensor) > 0) ;
|
||||||
|
|
||||||
|
// passive waiting until measurement results are available
|
||||||
|
if (duration > 0)
|
||||||
|
vTaskDelay (duration/portTICK_PERIOD_MS);
|
||||||
|
|
||||||
|
// retrieve the values and do something with them
|
||||||
|
if (sht3x_get_results (sensor, &values))
|
||||||
|
printf("%.3f SHT3x Sensor: %.2f °C, %.2f %%\n",
|
||||||
|
(double)sdk_system_get_time()*1e-3,
|
||||||
|
values.temperature, values.humidity);
|
||||||
|
|
||||||
|
// passive waiting until 5 seconds are over
|
||||||
|
vTaskDelayUntil(&last_wakeup, 5000 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
In contrast to the *periodic mode*, the function **_sht3x_start_measurement_** is called inside the task loop to start the measurement in each cycle. The task is then also delayed every time.
|
||||||
|
|
||||||
|
## Full Example
|
||||||
|
|
||||||
|
```
|
||||||
|
#include "espressif/esp_common.h"
|
||||||
|
#include "esp/uart.h"
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
#include "task.h"
|
||||||
|
|
||||||
|
// include SHT3x driver
|
||||||
|
#include "sht3x/sht3x.h"
|
||||||
|
|
||||||
|
// define I2C interfaces at which SHTx3 sensors are connected
|
||||||
|
#define I2C_BUS 0
|
||||||
|
#define I2C_SCL_PIN GPIO_ID_PIN((5))
|
||||||
|
#define I2C_SDA_PIN GPIO_ID_PIN((4))
|
||||||
|
|
||||||
|
static sht3x_sensor_t* sensor; // sensor device data structure
|
||||||
|
|
||||||
|
void user_task (void *pvParameters)
|
||||||
|
{
|
||||||
|
sht3x_values_t values;
|
||||||
|
|
||||||
|
// start periodic measurement mode
|
||||||
|
sht3x_start_measurement (sensor, periodic_1mps);
|
||||||
|
|
||||||
|
// busy waiting until measurement results are available
|
||||||
|
while (sht3x_is_measuring (sensor) > 0) ;
|
||||||
|
|
||||||
|
TickType_t last_wakeup = xTaskGetTickCount();
|
||||||
|
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
// retrieve the values and do something with them
|
||||||
|
if (sht3x_get_results (sensor, &values))
|
||||||
|
printf("%.3f SHT3x Sensor: %.2f °C, %.2f %%\n",
|
||||||
|
(double)sdk_system_get_time()*1e-3,
|
||||||
|
values.temperature, values.humidity);
|
||||||
|
|
||||||
|
// passive waiting until 2 seconds are over
|
||||||
|
vTaskDelayUntil(&last_wakeup, 2000 / portTICK_PERIOD_MS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void user_init(void)
|
||||||
|
{
|
||||||
|
// Set UART Parameter
|
||||||
|
uart_set_baud(0, 115200);
|
||||||
|
|
||||||
|
// Give the UART some time to settle
|
||||||
|
sdk_os_delay_us(500);
|
||||||
|
|
||||||
|
// Init I2C bus interfaces at which SHT3x sensors are connected
|
||||||
|
// (different busses are possible)
|
||||||
|
i2c_init(I2C_BUS, I2C_SCL_PIN, I2C_SDA_PIN, I2C_FREQ_100K);
|
||||||
|
|
||||||
|
// Create sensors
|
||||||
|
sensor = sht3x_init_sensor (I2C_BUS, SHT3x_ADDR_2);
|
||||||
|
|
||||||
|
// Create a user task that uses the sensor
|
||||||
|
xTaskCreate(user_task, "user_task", 256, NULL, 2, 0);
|
||||||
|
|
||||||
|
// That's it.
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Further Examples
|
||||||
|
|
||||||
|
See also the examples in the examples directory [examples directory](../../examples/sht3x/README.md).
|
||||||
9
extras/sht3x/component.mk
Normal file
9
extras/sht3x/component.mk
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
# Component makefile for extras/sht3x
|
||||||
|
|
||||||
|
# expected anyone using SHT3x driver includes it as 'sht3x/sht3x.h'
|
||||||
|
INC_DIRS += $(sht3x_ROOT)..
|
||||||
|
|
||||||
|
# args for passing into compile rule generation
|
||||||
|
sht3x_SRC_DIR = $(sht3x_ROOT)
|
||||||
|
|
||||||
|
$(eval $(call component_compile_rules,sht3x))
|
||||||
442
extras/sht3x/sht3x.c
Normal file
442
extras/sht3x/sht3x.c
Normal file
|
|
@ -0,0 +1,442 @@
|
||||||
|
/*
|
||||||
|
* Driver for Sensirion SHT3x digital temperature and humidity sensor
|
||||||
|
* connected to I2C
|
||||||
|
*
|
||||||
|
* Part of esp-open-rtos
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* The BSD License (3-clause license)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017 Gunar Schorcht (https://github.com/gschorcht
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Driver for Sensirion SHT3x digital temperature and humity sensor
|
||||||
|
* connected to I2C
|
||||||
|
*
|
||||||
|
* Part of esp-open-rtos
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "sht3x.h"
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
|
||||||
|
#include "espressif/esp_common.h"
|
||||||
|
#include "espressif/sdk_private.h"
|
||||||
|
|
||||||
|
#define SHT3x_STATUS_CMD 0xF32D
|
||||||
|
#define SHT3x_CLEAR_STATUS_CMD 0x3041
|
||||||
|
#define SHT3x_RESET_CMD 0x30A2
|
||||||
|
#define SHT3x_FETCH_DATA_CMD 0xE000
|
||||||
|
#define SHT3x_HEATER_OFF_CMD 0x3066
|
||||||
|
|
||||||
|
uint16_t SHT3x_MEASURE_CMD[6][3] = { {0x2c06,0x2c0d,0x2c10}, // [SINGLE_SHOT][H,M,L]
|
||||||
|
{0x2032,0x2024,0x202f}, // [PERIODIC_05][H,M,L]
|
||||||
|
{0x2130,0x2126,0x212d}, // [PERIODIC_05][H,M,L]
|
||||||
|
{0x2236,0x2220,0x222b}, // [PERIODIC_05][H,M,L]
|
||||||
|
{0x2234,0x2322,0x2329}, // [PERIODIC_05][H,M,L]
|
||||||
|
{0x2737,0x2721,0x272a} }; // [PERIODIC_05][H,M,L]
|
||||||
|
|
||||||
|
int32_t SHT3x_MEASURE_DURATION[3] = {30,20,20}; // [High, Medium, Low]
|
||||||
|
|
||||||
|
#ifdef SHT3x_DEBUG
|
||||||
|
#define debug(s, f, ...) printf("%s %s: " s "\n", "SHT3x", f, ## __VA_ARGS__)
|
||||||
|
#define debug_dev(s, f, d, ...) printf("%s %s: bus %d, addr %02x - " s "\n", "SHT3x", f, d->bus, d->addr, ## __VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define debug(s, f, ...)
|
||||||
|
#define debug_dev(s, f, d, ...)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define error(s, f, ...) printf("%s %s: " s "\n", "SHT3x", f, ## __VA_ARGS__)
|
||||||
|
#define error_dev(s, f, d, ...) printf("%s %s: bus %d, addr %02x - " s "\n", "SHT3x", f, d->bus, d->addr, ## __VA_ARGS__)
|
||||||
|
|
||||||
|
/** Forward declaration of function for internal use */
|
||||||
|
|
||||||
|
static bool sht3x_send_command (sht3x_sensor_t*, uint16_t);
|
||||||
|
static bool sht3x_read_data (sht3x_sensor_t*, uint8_t*, uint32_t);
|
||||||
|
static bool sht3x_get_status (sht3x_sensor_t*, uint16_t*);
|
||||||
|
|
||||||
|
static uint8_t crc8 (uint8_t data[], int len);
|
||||||
|
|
||||||
|
/** ------------------------------------------------ */
|
||||||
|
|
||||||
|
bool sht3x_init_driver()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sht3x_sensor_t* sht3x_init_sensor(uint8_t bus, uint8_t addr)
|
||||||
|
{
|
||||||
|
sht3x_sensor_t* dev;
|
||||||
|
|
||||||
|
if ((dev = malloc (sizeof(sht3x_sensor_t))) == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
// init sensor data structure
|
||||||
|
dev->bus = bus;
|
||||||
|
dev->addr = addr;
|
||||||
|
dev->mode = single_shot;
|
||||||
|
dev->repeatability = high;
|
||||||
|
dev->meas_started = false;
|
||||||
|
dev->meas_start_time = 0;
|
||||||
|
|
||||||
|
dev->active = true;
|
||||||
|
|
||||||
|
uint16_t status;
|
||||||
|
|
||||||
|
// soft-reset including status check leads to i2c problems.
|
||||||
|
// if (!sht3x_reset (dev))
|
||||||
|
if (!sht3x_get_status (dev, & status))
|
||||||
|
{
|
||||||
|
error_dev ("could not reset or check the status of the sensor", __FUNCTION__, dev);
|
||||||
|
free(dev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// clear sensor status register
|
||||||
|
if (!sht3x_send_command(dev, SHT3x_CLEAR_STATUS_CMD))
|
||||||
|
{
|
||||||
|
error_dev ("could not clear sensor status", __FUNCTION__, dev);
|
||||||
|
free(dev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// check the again the status after clear status command
|
||||||
|
if (!sht3x_get_status(dev, &status))
|
||||||
|
{
|
||||||
|
error_dev ("could not get sensor status", __FUNCTION__, dev);
|
||||||
|
free(dev);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug_dev ("sensor initialized", __FUNCTION__, dev);
|
||||||
|
return dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int32_t sht3x_start_measurement (sht3x_sensor_t* dev, sht3x_mode_t mode)
|
||||||
|
{
|
||||||
|
if (!dev || !dev->active) return -1;
|
||||||
|
|
||||||
|
dev->error_code = SHT3x_OK;
|
||||||
|
|
||||||
|
// return remaining time when measurement is already running
|
||||||
|
if (dev->meas_started)
|
||||||
|
{
|
||||||
|
debug_dev ("measurement already started", __FUNCTION__, dev);
|
||||||
|
dev->error_code = SHT3x_MEAS_ALREADY_RUNNING;
|
||||||
|
return sht3x_is_measuring (dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->mode = mode;
|
||||||
|
|
||||||
|
// start measurement according to selected mode and return an duration estimate
|
||||||
|
if (sht3x_send_command(dev, SHT3x_MEASURE_CMD[dev->mode][dev->repeatability]))
|
||||||
|
{
|
||||||
|
dev->meas_start_time = sdk_system_get_time ();
|
||||||
|
dev->meas_started = true;
|
||||||
|
dev->meas_first = true;
|
||||||
|
return SHT3x_MEASURE_DURATION[dev->repeatability]; // in ms
|
||||||
|
}
|
||||||
|
|
||||||
|
dev->error_code |= SHT3x_SEND_MEAS_CMD_FAILED;
|
||||||
|
return -1; // on error
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// returns 0 when finished, -1 on error, remaining measurement time otherwise
|
||||||
|
int32_t sht3x_is_measuring (sht3x_sensor_t* dev)
|
||||||
|
{
|
||||||
|
if (!dev || !dev->active) return -1;
|
||||||
|
|
||||||
|
dev->error_code = SHT3x_OK;
|
||||||
|
|
||||||
|
if (!dev->meas_started)
|
||||||
|
{
|
||||||
|
error_dev ("measurement not started", __FUNCTION__, dev);
|
||||||
|
dev->error_code = SHT3x_MEAS_NOT_STARTED;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// computation is necessary in periodic mode only for first measurement
|
||||||
|
// in single shot mode every measurment is the first one
|
||||||
|
if (!dev->meas_first)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
uint32_t start_time = dev->meas_start_time ; // in us
|
||||||
|
uint32_t system_time = sdk_system_get_time(); // in us
|
||||||
|
uint32_t elapsed_time;
|
||||||
|
|
||||||
|
if (system_time < start_time)
|
||||||
|
// in case of timer overflow
|
||||||
|
elapsed_time = (UINT32_MAX - start_time + system_time) / 1000; // in ms
|
||||||
|
else
|
||||||
|
// normal case
|
||||||
|
elapsed_time = (system_time - start_time) / 1000; // in ms
|
||||||
|
|
||||||
|
if (elapsed_time >= SHT3x_MEASURE_DURATION[dev->repeatability])
|
||||||
|
return 0;
|
||||||
|
else
|
||||||
|
return SHT3x_MEASURE_DURATION[dev->repeatability] - elapsed_time;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool sht3x_get_raw_data(sht3x_sensor_t* dev, sht3x_raw_data_t raw_data)
|
||||||
|
{
|
||||||
|
if (!dev || !dev->active || !raw_data) return false;
|
||||||
|
|
||||||
|
dev->error_code = SHT3x_OK;
|
||||||
|
|
||||||
|
if (sht3x_is_measuring (dev) == -1)
|
||||||
|
{
|
||||||
|
error_dev ("measurement is still running", __FUNCTION__, dev);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dev->mode == single_shot &&
|
||||||
|
sht3x_read_data(dev, raw_data, sizeof(sht3x_raw_data_t)))
|
||||||
|
{
|
||||||
|
debug_dev ("single shot data available", __FUNCTION__, dev);
|
||||||
|
dev->meas_started = false;
|
||||||
|
}
|
||||||
|
else if (dev->mode != single_shot &&
|
||||||
|
sht3x_send_command(dev, SHT3x_FETCH_DATA_CMD) &&
|
||||||
|
sht3x_read_data(dev, raw_data, sizeof(sht3x_raw_data_t)))
|
||||||
|
{
|
||||||
|
debug_dev ("periodic data available", __FUNCTION__, dev);
|
||||||
|
dev->meas_first = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
error_dev ("read raw data failed", __FUNCTION__, dev);
|
||||||
|
dev->error_code |= SHT3x_READ_RAW_DATA_FAILED;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crc8(raw_data,2) != raw_data[2])
|
||||||
|
{
|
||||||
|
error_dev ("CRC check for temperature data failed", __FUNCTION__, dev);
|
||||||
|
dev->error_code |= SHT3x_WRONG_CRC_TEMPERATURE;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (crc8(raw_data+3,2) != raw_data[5])
|
||||||
|
{
|
||||||
|
error_dev ("CRC check for humidity data failed", __FUNCTION__, dev);
|
||||||
|
dev->error_code |= SHT3x_WRONG_CRC_HUMIDITY;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool sht3x_compute_values (sht3x_raw_data_t raw_data, sht3x_values_t* values)
|
||||||
|
{
|
||||||
|
if (!raw_data || !values) return false;
|
||||||
|
|
||||||
|
values->temperature = ((((raw_data[0] * 256.0) + raw_data[1]) * 175) / 65535.0) - 45;
|
||||||
|
values->humidity = ((((raw_data[3] * 256.0) + raw_data[4]) * 100) / 65535.0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool sht3x_get_results (sht3x_sensor_t* dev, sht3x_values_t* values)
|
||||||
|
{
|
||||||
|
if (!dev || !dev->active || !values) return false;
|
||||||
|
|
||||||
|
sht3x_raw_data_t raw_data;
|
||||||
|
|
||||||
|
if (!sht3x_get_raw_data (dev, raw_data))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return sht3x_compute_values (raw_data, values);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Functions for internal use only */
|
||||||
|
|
||||||
|
static bool sht3x_send_command(sht3x_sensor_t* dev, uint16_t cmd)
|
||||||
|
{
|
||||||
|
if (!dev || !dev->active) return false;
|
||||||
|
|
||||||
|
uint8_t data[2] = { cmd >> 8, cmd & 0xff };
|
||||||
|
|
||||||
|
debug_dev ("send command MSB=%02x LSB=%02x", __FUNCTION__, dev, data[0], data[1]);
|
||||||
|
|
||||||
|
int err;
|
||||||
|
int count = 10;
|
||||||
|
|
||||||
|
// in case i2c is busy, try to write up to ten times and 100 ms
|
||||||
|
// tested with a task that is disturbing by using i2c bus almost all the time
|
||||||
|
while ((err=i2c_slave_write(dev->bus, dev->addr, 0, data, 2)) == -EBUSY && count--)
|
||||||
|
vTaskDelay (10 / portTICK_PERIOD_MS);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
dev->error_code |= (err == -EBUSY) ? SHT3x_I2C_BUSY : SHT3x_I2C_SEND_CMD_FAILED;
|
||||||
|
error_dev ("i2c error %d on write command %02x", __FUNCTION__, dev, err, cmd);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool sht3x_read_data(sht3x_sensor_t* dev, uint8_t *data, uint32_t len)
|
||||||
|
{
|
||||||
|
if (!dev || !dev->active) return false;
|
||||||
|
|
||||||
|
int err;
|
||||||
|
int count = 10;
|
||||||
|
|
||||||
|
// in case i2c is busy, try to read up to ten times and 100 ms
|
||||||
|
while ((err=i2c_slave_read(dev->bus, dev->addr, 0, data, len)) == -EBUSY && count--)
|
||||||
|
vTaskDelay (10 / portTICK_PERIOD_MS);
|
||||||
|
|
||||||
|
if (err)
|
||||||
|
{
|
||||||
|
dev->error_code |= (err == -EBUSY) ? SHT3x_I2C_BUSY : SHT3x_I2C_READ_FAILED;
|
||||||
|
error_dev ("error %d on read %d byte", __FUNCTION__, dev, err, len);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
# ifdef SHT3x_DEBUG
|
||||||
|
printf("SHT3x %s: bus %d, addr %02x - read following bytes: ",
|
||||||
|
__FUNCTION__, dev->bus, dev->addr);
|
||||||
|
for (int i=0; i < len; i++)
|
||||||
|
printf("%02x ", data[i]);
|
||||||
|
printf("\n");
|
||||||
|
# endif
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
static bool sht3x_reset (sht3x_sensor_t* dev)
|
||||||
|
{
|
||||||
|
if (!dev || !dev->active) return false;
|
||||||
|
|
||||||
|
debug_dev ("soft-reset triggered", __FUNCTION__, dev);
|
||||||
|
|
||||||
|
dev->error_code = SHT3x_OK;
|
||||||
|
|
||||||
|
// send reset command
|
||||||
|
if (!sht3x_send_command(dev, SHT3x_RESET_CMD))
|
||||||
|
{
|
||||||
|
dev->error_code |= SHT3x_SEND_RESET_CMD_FAILED;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// wait for small amount of time needed (according to datasheet 0.5ms)
|
||||||
|
vTaskDelay (20 / portTICK_PERIOD_MS);
|
||||||
|
|
||||||
|
uint16_t status;
|
||||||
|
|
||||||
|
// check the status after reset
|
||||||
|
if (!sht3x_get_status(dev, &status))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
static bool sht3x_get_status (sht3x_sensor_t* dev, uint16_t* status)
|
||||||
|
{
|
||||||
|
if (!dev || !dev->active || !status) return false;
|
||||||
|
|
||||||
|
dev->error_code = SHT3x_OK;
|
||||||
|
|
||||||
|
uint8_t data[3];
|
||||||
|
|
||||||
|
if (!sht3x_send_command(dev, SHT3x_STATUS_CMD) || !sht3x_read_data(dev, data, 3))
|
||||||
|
{
|
||||||
|
dev->error_code |= SHT3x_STATUS_CMD_FAILED;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*status = data[0] << 8 | data[1];
|
||||||
|
debug_dev ("status=%02x", __FUNCTION__, dev, *status);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static uint8_t* crc8_table; // lookup table with precomputed crc values
|
||||||
|
static bool crc8_first_time = true; // indicator whether table has still to be created
|
||||||
|
|
||||||
|
static void generate_crc8_table()
|
||||||
|
{
|
||||||
|
const uint8_t g_polynom = 0x31;
|
||||||
|
|
||||||
|
for (int i=0; i < 256; i++)
|
||||||
|
{
|
||||||
|
uint8_t value = (uint8_t)i;
|
||||||
|
for (uint8_t bit = 0; bit < 8; bit++)
|
||||||
|
{
|
||||||
|
bool xor = value & 0x80;
|
||||||
|
value = value << 1;
|
||||||
|
value = xor ? value ^ g_polynom : value;
|
||||||
|
}
|
||||||
|
crc8_table[i] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static uint8_t crc8 (uint8_t data[], int len)
|
||||||
|
{
|
||||||
|
// generate crc lookup table first time it is called
|
||||||
|
if (crc8_first_time)
|
||||||
|
{
|
||||||
|
crc8_first_time = false;
|
||||||
|
crc8_table = malloc(256);
|
||||||
|
generate_crc8_table ();
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialization value
|
||||||
|
uint8_t crc = 0xff;
|
||||||
|
|
||||||
|
// iterate over all bytes
|
||||||
|
for (int i=0; i < len; i++)
|
||||||
|
{
|
||||||
|
uint8_t b = data[i];
|
||||||
|
uint8_t data = (uint8_t)(b ^ crc);
|
||||||
|
crc = (uint8_t)(crc8_table[data]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return crc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
258
extras/sht3x/sht3x.h
Normal file
258
extras/sht3x/sht3x.h
Normal file
|
|
@ -0,0 +1,258 @@
|
||||||
|
/*
|
||||||
|
* Driver for Sensirion SHT3x digital temperature and humidity sensor
|
||||||
|
* connected to I2C
|
||||||
|
*
|
||||||
|
* Part of esp-open-rtos
|
||||||
|
*
|
||||||
|
* ----------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* The BSD License (3-clause license)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2017 Gunar Schorcht (https://github.com/gschorcht
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. Neither the name of the copyright holder nor the names of its
|
||||||
|
* contributors may be used to endorse or promote products derived from this
|
||||||
|
* software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef DRIVER_SHT3x_H_
|
||||||
|
#define DRIVER_SHT3x_H_
|
||||||
|
|
||||||
|
#include "stdint.h"
|
||||||
|
#include "stdbool.h"
|
||||||
|
|
||||||
|
#include "FreeRTOS.h"
|
||||||
|
|
||||||
|
#include "i2c/i2c.h"
|
||||||
|
|
||||||
|
// Uncomment to enable debug output
|
||||||
|
// #define SHT3x_DEBUG
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// definition of possible I2C slave addresses
|
||||||
|
#define SHT3x_ADDR_1 0x44 // ADDR pin connected to GND/VSS (default)
|
||||||
|
#define SHT3x_ADDR_2 0x45 // ADDR pin connected to VDD
|
||||||
|
|
||||||
|
// definition of error codes
|
||||||
|
#define SHT3x_OK 0
|
||||||
|
|
||||||
|
#define SHT3x_I2C_ERROR_MASK 0x000f
|
||||||
|
#define SHT3x_DRV_ERROR_MASK 0xfff0
|
||||||
|
|
||||||
|
// error codes for I2C interface ORed with SHT3x error codes
|
||||||
|
#define SHT3x_I2C_READ_FAILED 1
|
||||||
|
#define SHT3x_I2C_SEND_CMD_FAILED 2
|
||||||
|
#define SHT3x_I2C_BUSY 3
|
||||||
|
|
||||||
|
// SHT3x driver error codes OR ed with error codes for I2C interface
|
||||||
|
#define SHT3x_MEAS_NOT_STARTED (1 << 8)
|
||||||
|
#define SHT3x_MEAS_ALREADY_RUNNING (2 << 8)
|
||||||
|
#define SHT3x_MEAS_STILL_RUNNING (3 << 8)
|
||||||
|
#define SHT3x_READ_RAW_DATA_FAILED (4 << 8)
|
||||||
|
|
||||||
|
#define SHT3x_SEND_MEAS_CMD_FAILED (5 << 8)
|
||||||
|
#define SHT3x_SEND_RESET_CMD_FAILED (6 << 8)
|
||||||
|
#define SHT3x_STATUS_CMD_FAILED (7 << 8)
|
||||||
|
|
||||||
|
#define SHT3x_WRONG_CRC_TEMPERATURE (8 << 8)
|
||||||
|
#define SHT3x_WRONG_CRC_HUMIDITY (9 << 8)
|
||||||
|
|
||||||
|
#define SHT3x_RAW_DATA_SIZE 6
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief raw data type
|
||||||
|
*/
|
||||||
|
typedef uint8_t sht3x_raw_data_t [SHT3x_RAW_DATA_SIZE];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief sensor values type
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
float temperature; // temperature in degree Celcius
|
||||||
|
float humidity; // humidity in percent
|
||||||
|
} sht3x_values_t;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief possible measurement modes
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
single_shot = 0, // one single measurement
|
||||||
|
periodic_05mps, // periodic with 0.5 measurements per second (mps)
|
||||||
|
periodic_1mps, // periodic with 1 measurements per second (mps)
|
||||||
|
periodic_2mps, // periodic with 2 measurements per second (mps)
|
||||||
|
periodic_4mps, // periodic with 4 measurements per second (mps)
|
||||||
|
periodic_10mps // periodic with 10 measurements per second (mps)
|
||||||
|
} sht3x_mode_t;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief possible repeatability modes
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
high = 0,
|
||||||
|
medium,
|
||||||
|
low
|
||||||
|
} sht3x_repeat_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief SHT3x sensor device data structure type
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
|
||||||
|
bool active; // indicates whether sensor is active
|
||||||
|
|
||||||
|
uint32_t error_code; //
|
||||||
|
|
||||||
|
uint8_t bus; // I2C bus at which sensor is connected
|
||||||
|
uint8_t addr; // I2C slave address of the sensor
|
||||||
|
|
||||||
|
sht3x_mode_t mode; // used measurement mode
|
||||||
|
sht3x_repeat_t repeatability; // used repeatability
|
||||||
|
|
||||||
|
bool meas_started; // indicates whether measurement started
|
||||||
|
uint32_t meas_start_time; // measurement start time in microseconds
|
||||||
|
bool meas_first; // first measurement in periodic mode
|
||||||
|
|
||||||
|
} sht3x_sensor_t;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Initialize a SHT3x sensor
|
||||||
|
*
|
||||||
|
* The function creates a data structure describing the sensor device,
|
||||||
|
* initializes, probes for the device, and configures the device that is
|
||||||
|
* connected at the specified I2C bus with the given slave address.
|
||||||
|
*
|
||||||
|
* @param bus I2C bus at which sensor is connected
|
||||||
|
* @param addr I2C slave address of the sensor
|
||||||
|
* @return pointer to sensor data structure, or NULL on error
|
||||||
|
*/
|
||||||
|
sht3x_sensor_t* sht3x_init_sensor (uint8_t bus, uint8_t addr);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Start single shot or periodic measurements
|
||||||
|
*
|
||||||
|
* The function starts the measurement either in *single shot mode*
|
||||||
|
* (exactly one measurement) or *periodic mode* (periodic measurements).
|
||||||
|
*
|
||||||
|
* In the *single shot mode*, this function has to be called for each
|
||||||
|
* measurement. The measurement duration returned by the function has to be
|
||||||
|
* waited every time before the results can be fetched.
|
||||||
|
*
|
||||||
|
* In the *periodic mode*, this function has to be called only once. Also the
|
||||||
|
* measurement duration must be waited only once until the first results are
|
||||||
|
* available. After this first measurement, the sensor then automatically
|
||||||
|
* performs all subsequent measurements. The rate of periodic measurements can
|
||||||
|
* be 10, 4, 2, 1 or 0.5 measurements per second (mps). The user task can
|
||||||
|
* fetch the results with the half or less rate. The rate of the periodic
|
||||||
|
* measurements is defined by the parameter *mode*.
|
||||||
|
*
|
||||||
|
* On success, the function returns an estimated measurement duration. This
|
||||||
|
* defines the duration needed by the sensor before first results become
|
||||||
|
* available. The user task has to wait this time before it can fetch the
|
||||||
|
* results using function *sht3x_get_results* or *sht3x_get_raw_data*.
|
||||||
|
*
|
||||||
|
* @param dev pointer to sensor device data structure
|
||||||
|
* @param mode measurement mode, see type *sht3x_mode_t*
|
||||||
|
* @return true on success, false on error
|
||||||
|
*/
|
||||||
|
int32_t sht3x_start_measurement (sht3x_sensor_t* dev, sht3x_mode_t mode);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Check whether measurement is still running
|
||||||
|
*
|
||||||
|
* The function can be used to test whether a measurement has been started
|
||||||
|
* at all and how long it still takes before measurement results become
|
||||||
|
* available. The return value can be
|
||||||
|
*
|
||||||
|
* >0 in case the measurement is is still running,
|
||||||
|
* 0 in case the measurement has been already finished, or
|
||||||
|
* <0 in case of error.
|
||||||
|
*
|
||||||
|
* That is, a return value greater than 0 indicates that the measurement
|
||||||
|
* results are still not available and the user task has to wait that time.
|
||||||
|
*
|
||||||
|
* @param dev pointer to sensor device data structure
|
||||||
|
* @return remaining measurement duration or -1 on error
|
||||||
|
*/
|
||||||
|
int32_t sht3x_is_measuring (sht3x_sensor_t* dev);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read the results from sensor as raw data
|
||||||
|
*
|
||||||
|
* The function read measurement results from the sensor, checks the CRC
|
||||||
|
* checksum and stores them in the byte array as following.
|
||||||
|
*
|
||||||
|
* data[0] = Temperature MSB
|
||||||
|
* data[1] = Temperature LSB
|
||||||
|
* data[2] = Temperature CRC
|
||||||
|
* data[3] = Pressure MSB
|
||||||
|
* data[4] = Pressure LSB
|
||||||
|
* data[2] = Pressure CRC
|
||||||
|
*
|
||||||
|
* In case that there are no new data that can be read, the function returns
|
||||||
|
* false.
|
||||||
|
*
|
||||||
|
* @param dev pointer to sensor device data structure
|
||||||
|
* @param raw_data byte array in which raw data are stored
|
||||||
|
* @return true on success, false on error
|
||||||
|
*/
|
||||||
|
bool sht3x_get_raw_data(sht3x_sensor_t* dev, sht3x_raw_data_t raw_data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Computes sensor values from raw data
|
||||||
|
*
|
||||||
|
* @param raw_data byte array that contains raw data
|
||||||
|
* @param values pointer to data structure in which results are stored
|
||||||
|
* @return true on success, false on error
|
||||||
|
*/
|
||||||
|
bool sht3x_compute_values (sht3x_raw_data_t raw_data,
|
||||||
|
sht3x_values_t* values);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the results of latest measurement
|
||||||
|
*
|
||||||
|
* The function combines function *sht3x_read_raw_data* and function
|
||||||
|
* *sht3x_compute_values* to get the latest measurement results.
|
||||||
|
*
|
||||||
|
* @param dev pointer to sensor device data structure
|
||||||
|
* @param values pointer to data structure in which results are stored
|
||||||
|
* @return true on success, false on error
|
||||||
|
*/
|
||||||
|
bool sht3x_get_results (sht3x_sensor_t* dev, sht3x_values_t* values);
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* DRIVER_SHT3x_H_ */
|
||||||
Loading…
Add table
Add a link
Reference in a new issue