Merge pull request #9317 from maribu/sht1x

drivers/sht11: Major refactoring
This commit is contained in:
Alexandre Abadie 2018-06-27 10:10:39 +02:00 committed by GitHub
commit 6e6716a1a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 1996 additions and 708 deletions

View File

@ -1,5 +1,3 @@
MODULE = boards_common_msb-430
DIRS = drivers
include $(RIOTBASE)/Makefile.base

View File

@ -25,6 +25,3 @@ export DEBUGGER_FLAGS = --tui --ex="target remote localhost:2000" --ex "monitor
# export common msb-430 includes
export INCLUDES += -I$(RIOTBOARD)/common/msb-430/include
export INCLUDES += -I$(RIOTBOARD)/common/msb-430/drivers/include
USEMODULE += boards_common_msb-430-drivers

View File

@ -1,5 +0,0 @@
MODULE = boards_common_msb-430-drivers
include $(RIOTBOARD)/$(BOARD)/Makefile.include
include $(RIOTBASE)/Makefile.base

View File

@ -1,49 +0,0 @@
/*
* Copyright 2013, Freie Universitaet Berlin (FUB). All rights reserved.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#ifndef SHT11_BOARD_H
#define SHT11_BOARD_H
/**
* @ingroup boards_common_msb-430
* @{
*/
/**
* @file
* @brief SHT11 Device Driver Configuration For MSB-430 Platform
*
* @author Freie Universität Berlin, Computer Systems & Telematics, RIOT
*
*/
#include <msp430x16x.h>
#include "bitarithm.h"
#ifdef __cplusplus
extern "C" {
#endif
/* SCK = P3B5
* DATA = P3B4
*/
#define SHT11_SCK_LOW P3OUT &= ~(BIT5); /**< serial clock line low */
#define SHT11_SCK_HIGH P3OUT |= BIT5; /**< serial clock line high */
#define SHT11_DATA (P3IN & BIT5) /**< read serial I/O */
#define SHT11_DATA_LOW P3OUT &= ~(BIT5); /**< serial I/O line low */
#define SHT11_DATA_HIGH P3OUT |= BIT5; /**< serial I/O line high */
#define SHT11_DATA_IN P3DIR &= ~(BIT5); /**< serial I/O as input */
#define SHT11_DATA_OUT P3DIR |= BIT5; /**< serial I/O as output */
#define SHT11_INIT P3DIR |= BIT5; /* FIO1DIR |= BIT25; PINSEL3 &= ~(BIT14|BIT15 | BIT16|BIT17); */
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* SHT11_BOARD_H */

View File

@ -1,5 +1,3 @@
MODULE = boards_common_msba2
DIRS = drivers
include $(RIOTBASE)/Makefile.base

View File

@ -27,8 +27,5 @@ endif
export FFLAGS = $(PORT) $(HEXFILE)
INCLUDES += -I$(RIOTBOARD)/common/msba2/include
INCLUDES += -I$(RIOTBOARD)/common/msba2/drivers/include
export UNDEF += $(BINDIR)/cpu/startup.o
USEMODULE += boards_common_msba2-drivers

View File

@ -1,3 +0,0 @@
MODULE = boards_common_msba2-drivers
include $(RIOTBASE)/Makefile.base

View File

@ -1,56 +0,0 @@
/*
* Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#ifndef SHT11_BOARD_H
#define SHT11_BOARD_H
/**
* @ingroup boards_common_msba2
* @{
*/
/**
* @file
* @brief LPC2387 SHT11 Device Driver
*
* @author Freie Universität Berlin, Computer Systems & Telematics, FeuerWhere project
* @version $Revision$
*
* @note $Id$
*/
#include "cpu.h"
#include "board.h"
#ifdef __cplusplus
extern "C" {
#endif
/* serial clock line low */
#define SHT11_SCK_LOW FIO1CLR = BIT25;
/* serial clock line high */
#define SHT11_SCK_HIGH FIO1SET = BIT25;
/* read serial I/O */
#define SHT11_DATA ((FIO1PIN & BIT26) != 0)
/* serial I/O line low */
#define SHT11_DATA_LOW (FIO1CLR = BIT26);
/* serial I/O line high */
#define SHT11_DATA_HIGH (FIO1SET = BIT26);
/* serial I/O as input */
#define SHT11_DATA_IN (FIO1DIR &= ~BIT26)
/* serial I/O as output */
#define SHT11_DATA_OUT (FIO1DIR |= BIT26)
#define SHT11_INIT FIO1DIR |= BIT25; PINSEL3 &= ~(BIT14|BIT15 | BIT16|BIT17);
#ifdef __cplusplus
}
#endif
/** @} */
#endif /* SHT11_BOARD_H */

View File

@ -0,0 +1,3 @@
ifneq (,$(filter saul_default,$(USEMODULE)))
USEMODULE += sht11
endif

View File

@ -59,6 +59,14 @@ extern "C" {
#define MSP430_HAS_EXTERNAL_CRYSTAL 0
/** @} */
/**
* @name Configure on-board SHT11 device
* @{
*/
#define SHT1X_PARAM_CLK (GPIO_PIN(3, 5))
#define SHT1X_PARAM_DATA (GPIO_PIN(3, 4))
/** @} */
#ifdef __cplusplus
}
#endif

View File

@ -0,0 +1,3 @@
ifneq (,$(filter saul_default,$(USEMODULE)))
USEMODULE += sht11
endif

View File

@ -47,6 +47,14 @@ extern "C" {
#define MSP430_HAS_EXTERNAL_CRYSTAL 1
/** @} */
/**
* @name Configure on-board SHT11 device
* @{
*/
#define SHT1X_PARAM_CLK (GPIO_PIN(3, 5))
#define SHT1X_PARAM_DATA (GPIO_PIN(3, 4))
/** @} */
#ifdef __cplusplus
}
#endif

View File

@ -3,3 +3,7 @@ include $(RIOTBOARD)/common/msba2/Makefile.dep
ifneq (,$(filter netdev_default gnrc_netdev_default,$(USEMODULE)))
USEMODULE += cc110x
endif
ifneq (,$(filter saul_default,$(USEMODULE)))
USEMODULE += sht11
endif

View File

@ -307,7 +307,9 @@ ifneq (,$(filter servo,$(USEMODULE)))
FEATURES_REQUIRED += periph_pwm
endif
ifneq (,$(filter sht11,$(USEMODULE)))
ifneq (,$(filter sht1%,$(USEMODULE)))
USEMODULE += sht1x
FEATURES_REQUIRED += periph_gpio
USEMODULE += xtimer
endif

View File

@ -50,6 +50,10 @@ ifneq (,$(filter dht,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/dht/include
endif
ifneq (,$(filter sht1x,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/sht1x/include
endif
ifneq (,$(filter ds1307,$(USEMODULE)))
USEMODULE_INCLUDES += $(RIOTBASE)/drivers/ds1307/include
endif

View File

@ -1,108 +0,0 @@
/*
* Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup drivers_sht11 SHT11 Humidity and Temperature Sensor
* @ingroup drivers_sensors
* @brief Driver for Sensirion SHT11 Humidity and Temperature Sensor
* @{
*
* @file
* @brief SHT11 Device Driver
*
* @author Freie Universität Berlin, Computer Systems & Telematics
*/
#ifndef SHT11_H
#define SHT11_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
#define SHT11_NO_ACK (0) /**< don't ack read in `read_byte` */
#define SHT11_ACK (1) /**< do acknowledge read in `read_byte` */
/* adr command r/w */
#define SHT11_STATUS_REG_W (0x06) /**< will write to status register */
#define SHT11_STATUS_REG_R (0x07) /**< will read from status register */
#define SHT11_MEASURE_TEMP (0x03) /**< tell sensor to measure temperature */
#define SHT11_MEASURE_HUMI (0x05) /**< tell sensor to measure humidity */
#define SHT11_RESET (0x1E) /**< reset the sensor */
/** time to wait after toggling the data line */
#define SHT11_DATA_WAIT (1)
/** time to wait after toggling the clock line */
#define SHT11_CLK_WAIT (1)
/** set measurement timeout to 1 second */
#define SHT11_MEASURE_TIMEOUT (1000)
/**
* @brief sht11 measureable data
*/
typedef struct {
float temperature; /**< temperature value */
float relhum; /**< linear relative humidity */
float relhum_temp; /**< temperature compensated relative humidity */
} sht11_val_t;
/**
* @brief SHT11 modes that can be measured
*/
typedef enum {
TEMPERATURE = 1,
HUMIDITY = 2
} sht11_mode_t;
/**
* @brief Initialize SHT11 ports
*/
void sht11_init(void);
/**
* @brief Read sensor
*
* @param value The struct to be filled with measured values
* @param mode Specifies type of data to be read
*
* @return 1 on success, 0 otherwise
*
* Example:
* \code sht11_val sht11;
* sht11_read_sensor(&sht11, HUMIDITY|TEMPERATURE);
* printf("%-6.2f °C %5.2f %% %5.2f %%\n", sht11.temperature, sht11.relhum, sht11.relhum_temp); \endcode
*/
uint8_t sht11_read_sensor(sht11_val_t *value, sht11_mode_t mode);
/**
* @brief Write status register
*
* @param p_value The value to write
*
* @return 1 on success, 0 otherwise
*/
uint8_t sht11_write_status(uint8_t *p_value);
/**
* @brief Read status register with checksum
*
* @param p_value The read value
* @param p_checksum The received checksum
*
* return 1 on success, 0 otherwise
*/
uint8_t sht11_read_status(uint8_t *p_value, uint8_t *p_checksum);
#ifdef __cplusplus
}
#endif
#endif /* SHT11_H */
/** @} */

188
drivers/include/sht1x.h Normal file
View File

@ -0,0 +1,188 @@
/*
* Copyright 2009 Freie Universitaet Berlin (FUB)
* 2018 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @defgroup drivers_sht1x SHT10/SHT11/SHT15 Humidity and Temperature Sensor
* @ingroup drivers_sensors
* @brief Driver for Sensirion SHT10/SHT11/SHT15 Humidity and Temperature
Sensor
* @{
*
* @file
* @brief SHT10/SHT11/SHT15 Device Driver
*
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*/
#ifndef SHT1X_H
#define SHT1X_H
#include <stdint.h>
#include <periph/gpio.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Possible configuration (=status byte) values of the SHT10/11/15
*
* These values can be or'ed together to get the configuration.
*/
typedef enum {
/** Use 8/12 bit resolution instead of 12/14 bit for temp/hum */
SHT1X_CONF_LOW_RESOLUTION = 0x01,
/** Don't upload calibration data to register to safe 10 millisec */
SHT1X_CONF_SKIP_CALIBRATION = 0x02,
/** Waste 8mA at 5V to increase the sensor temperature up to 10°C */
SHT1X_CONF_ENABLE_HEATER = 0x04,
/** Skip the CRC check (and reading the CRC byte) to safe time */
SHT1X_CONF_SKIP_CRC = 0x08,
} sht1x_conf_t;
/**
* @brief Possible values for Vdd (measured temperature depends on it)
*/
typedef enum {
SHT1X_VDD_5_0V = 0,
SHT1X_VDD_4_0V = 1,
SHT1X_VDD_3_5V = 2,
SHT1X_VDD_3_0V = 3,
SHT1X_VDD_2_5V = 4,
} sht1x_vdd_t;
/**
* @brief SHT10/11/15 temperature humidity sensor
*/
typedef struct {
gpio_t clk; /**< GPIO connected to the clock pin of the SHT1X */
gpio_t data; /**< GPIO connected to the data pin of the SHT1X */
int16_t temp_off; /**< Offset to add to the measured temperature */
int16_t hum_off; /**< Offset to add to the measured humidity */
uint8_t conf; /**< Status byte (containing configuration) of the SHT1X */
uint8_t vdd; /**< Supply voltage of the SHT1X (as sht1x_vdd_t) */
} sht1x_dev_t;
/**
* @brief Parameters required to set up the SHT10/11/15 device driver
*/
typedef struct {
gpio_t clk; /**< GPIO connected to the clock pin of the SHT1X */
gpio_t data; /**< GPIO connected to the data pin of the SHT1X */
sht1x_vdd_t vdd; /**< The supply voltage of the SHT1X */
} sht1x_params_t;
/**
* @brief Initialize the SHT10/11/15 sensor
*
* @param dev SHT1X sensor to initialize
* @param params Information on how the SHT1X is connected to the board
*
* @retval 0 Success
* @retval -EIO IO failure (`gpio_init()` failed)
* @retval -EPROTO Sensor did not acknowledge reset command
*/
int sht1x_init(sht1x_dev_t *dev, const sht1x_params_t *params);
/**
* @brief Calculate the temperature from the raw input
* @note This internal function is exposed for unit tests
*
* @param dev Device from which the raw value was received
* @param raw The raw (unprocessed) temperature value
*
* @return The correct temperature in E-02 °C
* @retval INT16_MIN Passed `NULL` for parameter `dev` or `dev->vdd`
*/
int16_t sht1x_temperature(const sht1x_dev_t *dev, uint16_t raw);
/**
* @brief Calculate the relative humidity from the raw input
* @note This internal function is exposed for unit tests
*
* @param dev Device from which the raw value was received
* @param raw The raw (unprocessed) temperature value
* @param temp The temperature at which the humidity was measure in
* E-02 °C
*
* @return The correct temperature in E-02 %
* @retval -1 Passed `NULL` for parameter `dev`
*/
int16_t sht1x_humidity(const sht1x_dev_t *dev, uint16_t raw, int16_t temp);
/**
* @brief Read the current temperature
*
* @param dev SHT1X sensor to read
* @param temp Store the measured temperature in E-02 °C here
* @param hum Store the measured relative humidity in E-02 % here
*
* @retval 0 Success
* @retval -EIO IO failure (`gpio_init()` failed)
* @retval -EBADMSG CRC-8 checksum didn't match (--> Retry)
* @retval -EINVAL Passed `NULL` for dev or for both `temp` and `hum`
* @retval -EBADMSG CRC checksum didn't match
* @retval -ECANCELED Measurement timed out
* @retval -EPROTO Sensor did not acknowledge command
*
* For either `temp` or `hum` `NULL` can be passed, if only one value is of
* interest. Passing `NULL` for `hum` speeds up the communication, but
* passing `NULL` for `temp` does not. The temperature value is required to
* calculate the relative humidity from the raw input. So the temperature is
* measured in any case, it is just not returned if `temp` is `NULL`.
*/
int sht1x_read(const sht1x_dev_t *dev, int16_t *temp, int16_t *hum);
/**
* @brief Apply the given configuration (= status byte) to
*
* @param dev SHT1X device to configure
* @param conf Configuration to apply
*
* @retval 0 Configuration applied
* @retval -EINVAL Called with `dev == NULL`
* @retval -EIO I/O error (`gpio_init()` failed)
* @retval -EPROTO Sensor did not acknowledge command
* @retval -ECANCELED Sensor did not apply configuration
* @retval -EBADMSG CRC checksum error while verifying uploaded configuration
*/
int sht1x_configure(sht1x_dev_t *dev, sht1x_conf_t conf);
/**
* @brief Read the status byte of an SHT1X sensor
*
* @param dev SHT1X device to receive the status from
* @param status Store the received status byte here
*
* @retval 0 Configuration applied
* @retval -EINVAL Called with `dev == NULL`
* @retval -EIO I/O error (`gpio_init()` failed)
* @retval -EPROTO Sensor did not acknowledge command
* @retval -EBADMSG CRC checksum didn't match
*/
int sht1x_read_status(sht1x_dev_t *dev, uint8_t *status);
/**
* @brief Reset the sensor's configuration to default values
*
* @param dev SHT1X device to reset
*
* @retval 0 Reset successful
* @retval -EINVAL Called with `dev == NULL`
* @retval -EIO I/O error (`gpio_init()` failed)
* @retval -EPROTO Sensor did not acknowledge reset command
*/
int sht1x_reset(sht1x_dev_t *dev);
#ifdef __cplusplus
}
#endif
#endif /* SHT1X_H */
/** @} */

View File

@ -1,350 +0,0 @@
/*
* Copyright 2009, Freie Universitaet Berlin (FUB). All rights reserved.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_sht11
* @brief Driver for the Sensirion SHT11 humidity and temperature sensor
* @{
*
* @file
* @brief SHT11 Device Driver
*
* @version $Revision: 2396 $
*
* @note $Id: sht11.c 2396 2010-07-06 15:12:35Z ziegert $
* @}
*/
#include <stdio.h>
#include <stdint.h>
#include "xtimer.h"
#include "mutex.h"
#include "sht11.h"
#include "sht11-board.h"
#include "bitarithm.h"
float sht11_temperature_offset;
/**
* @brief Perform measurement
*
* @param p_value Measured value (14 or 12 bit -> 2 bytes)
* @param p_checksum Checksum of measurement
* @param mode The requestested measurement mode: temperature or humidity
*
* @return 1 on success, 0 otherwise
*/
static uint8_t measure(uint8_t *p_value, uint8_t *p_checksum, uint8_t mode);
/**
* @brief Write one byte
*
* @param value The value to write
*
* @return 1 for acknowledged write, 0 otherwise
*/
static uint8_t write_byte(uint8_t value);
/**
* @brief Read ony byte
*
* @param ack Set if the data read should be acknowledged
*
* @return The read byte
*/
static uint8_t read_byte(uint8_t ack);
/**
* @brief Communication reset
*/
static void connection_reset(void);
/**
* @brief Send start of transmision sequence
*/
static void transmission_start(void);
/**
* @brief Toggle the clock line
*/
static inline void clk_signal(void);
/* mutex for exclusive measurement operation */
mutex_t sht11_mutex = MUTEX_INIT;
/*---------------------------------------------------------------------------*/
static inline void clk_signal(void)
{
SHT11_SCK_HIGH;
xtimer_usleep(SHT11_CLK_WAIT);
SHT11_SCK_LOW;
xtimer_usleep(SHT11_CLK_WAIT);
}
/*---------------------------------------------------------------------------*/
static uint8_t write_byte(uint8_t value)
{
uint8_t i;
uint8_t ack;
SHT11_DATA_OUT;
/* send value bit by bit to sht11 */
for (i = 0; i < 8; i++) {
if (value & BIT7) {
SHT11_DATA_HIGH;
xtimer_usleep(SHT11_DATA_WAIT);
}
else {
SHT11_DATA_LOW;
xtimer_usleep(SHT11_DATA_WAIT);
}
/* trigger clock signal */
clk_signal();
/* shift value to write next bit */
value = value << 1;
}
/* wait for ack */
SHT11_DATA_IN;
xtimer_usleep(SHT11_CLK_WAIT);
ack = SHT11_DATA;
clk_signal();
return ack;
}
/*---------------------------------------------------------------------------*/
static uint8_t read_byte(uint8_t ack)
{
uint8_t i;
uint8_t value = 0;
SHT11_DATA_IN;
xtimer_usleep(SHT11_DATA_WAIT);
/* read value bit by bit */
for (i = 0; i < 8; i++) {
value = value << 1;
SHT11_SCK_HIGH;
xtimer_usleep(SHT11_CLK_WAIT);
if (SHT11_DATA) {
/* increase data by one when DATA is high */
value++;
}
SHT11_SCK_LOW;
xtimer_usleep(SHT11_CLK_WAIT);
}
/* send ack if necessary */
SHT11_DATA_OUT;
if (ack) {
SHT11_DATA_LOW;
xtimer_usleep(SHT11_DATA_WAIT);
}
else {
SHT11_DATA_HIGH;
xtimer_usleep(SHT11_DATA_WAIT);
}
clk_signal();
/* release data line */
SHT11_DATA_IN;
return value;
}
/*---------------------------------------------------------------------------*/
static void transmission_start(void)
{
/* _____ ________
DATA: |_______|
___ ___
SCK : ___| |___| |______
*/
SHT11_DATA_OUT;
/* set initial state */
SHT11_DATA_HIGH;
xtimer_usleep(SHT11_DATA_WAIT);
SHT11_SCK_LOW;
xtimer_usleep(SHT11_CLK_WAIT);
SHT11_SCK_HIGH;
xtimer_usleep(SHT11_CLK_WAIT);
SHT11_DATA_LOW;
xtimer_usleep(SHT11_DATA_WAIT);
SHT11_SCK_LOW;
xtimer_usleep(SHT11_CLK_WAIT);
SHT11_SCK_HIGH;
xtimer_usleep(SHT11_CLK_WAIT);
SHT11_DATA_HIGH;
xtimer_usleep(SHT11_DATA_WAIT);
SHT11_SCK_LOW;
xtimer_usleep(SHT11_CLK_WAIT);
}
/*---------------------------------------------------------------------------*/
static void connection_reset(void)
{
/* _____________________________________________________ ____
DATA: |_______|
_ _ _ _ _ _ _ _ _ ___ ___
SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______| |___| |__
*/
uint8_t i;
SHT11_DATA_HIGH;
xtimer_usleep(SHT11_DATA_WAIT);
SHT11_SCK_LOW;
xtimer_usleep(SHT11_CLK_WAIT);
for (i = 0; i < 9; i++) {
clk_signal();
}
transmission_start();
}
/*---------------------------------------------------------------------------*/
static uint8_t measure(uint8_t *p_value, uint8_t *p_checksum, uint8_t mode)
{
uint8_t error = 0;
uint8_t ack = 1;
uint16_t i;
transmission_start();
error = write_byte(mode);
xtimer_usleep(1000);
/* wait untile sensor has finished measurement or timeout */
for (i = 0; (i < SHT11_MEASURE_TIMEOUT) && (!error); i++) {
ack = SHT11_DATA;
if (!ack) {
break;
}
xtimer_usleep(1000);
}
error += ack;
/* read MSB */
*(p_value + 1) = read_byte(SHT11_ACK);
/* read LSB */
*(p_value) = read_byte(SHT11_ACK);
/* read checksum */
*p_checksum = read_byte(SHT11_NO_ACK);
return (!error);
}
/*---------------------------------------------------------------------------*/
void sht11_init(void)
{
sht11_temperature_offset = 0;
SHT11_INIT;
xtimer_usleep(11 * 1000);
}
/*---------------------------------------------------------------------------*/
uint8_t sht11_read_status(uint8_t *p_value, uint8_t *p_checksum)
{
uint8_t error = 0;
transmission_start();
error |= write_byte(SHT11_STATUS_REG_R);
*p_value = read_byte(SHT11_ACK);
*p_checksum = read_byte(SHT11_NO_ACK);
return (!error);
}
/*---------------------------------------------------------------------------*/
uint8_t sht11_write_status(uint8_t *p_value)
{
uint8_t error = 0;
transmission_start();
error += write_byte(SHT11_STATUS_REG_W);
error += write_byte(*p_value);
return (!error);
}
/*---------------------------------------------------------------------------*/
uint8_t sht11_read_sensor(sht11_val_t *value, sht11_mode_t mode)
{
uint8_t error = 0;
uint8_t checksum;
uint16_t humi_int, temp_int;
/* Temperature arithmetic where S0(T) is read value
* T = D1 + D2 * S0(T) */
const float D1 = -39.6;
const float D2 = 0.01;
/* Arithmetic for linear humdity where S0(RH) is read value
* HL = C1 + C2 * S0(RH) + C3 * SO(RH)^2 */
const float C1 = -4.0;
const float C2 = +0.0405;
const float C3 = -0.0000028;
/* Arithmetic for temperature compesated relative humdity
* HT = (T-25) * ( T1 + T2 * SO(RH) ) + HL */
const float T1 = +0.01;
const float T2 = +0.00008;
/* check for valid buffer */
if (value == NULL) {
return 0;
}
value->temperature = 0;
value->relhum = 0;
value->relhum_temp = 0;
mutex_lock(&sht11_mutex);
connection_reset();
/* measure humidity */
if (mode & HUMIDITY) {
error += (!measure((uint8_t *) &humi_int, &checksum, SHT11_MEASURE_HUMI));
}
/* measure temperature */
if (mode & TEMPERATURE) {
error += (!measure((uint8_t *) &temp_int, &checksum, SHT11_MEASURE_TEMP));
}
/* break on error */
if (error != 0) {
connection_reset();
mutex_unlock(&sht11_mutex);
return 0;
}
if (mode & TEMPERATURE) {
value->temperature = D1 + (D2 * ((float) temp_int)) + sht11_temperature_offset;
}
if (mode & HUMIDITY) {
value->relhum = C1 + (C2 * ((float) humi_int)) + (C3 * ((float) humi_int) * ((float) humi_int));
if (mode & TEMPERATURE) {
value->relhum_temp = (value->temperature - 25) * (T1 + (T2 * (float) humi_int)) + value->relhum;
}
}
mutex_unlock(&sht11_mutex);
return 1;
}

View File

@ -0,0 +1,72 @@
/*
* Copyright 2009 Freie Universitaet Berlin (FUB)
* 2018 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_sht1x
* @{
*
* @file
* @brief Internal defines required by the SHT10/SHT11/SHT15 driver
*
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*/
#ifndef SHT1X_DEFINES_H
#define SHT1X_DEFINES_H
#include <stdint.h>
#include <periph/gpio.h>
#include <mutex.h>
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Possible values to pass as `ack` parameter to `write_byte`
* @see write_byte
* @{
*/
#define SHT1X_NO_ACK (1) /**< don't ack read in `read_byte` */
#define SHT1X_ACK (0) /**< do acknowledge read in `read_byte` */
/** @} */
/**
* @name Commands that can be sent to the SHT1X driver
* @{
*/
#define SHT1X_STATUS_REG_W (0x06) /**< will write to status register */
#define SHT1X_STATUS_REG_R (0x07) /**< will read from status register */
#define SHT1X_MEASURE_TEMP (0x03) /**< tell sensor to measure temperature */
#define SHT1X_MEASURE_HUM (0x05) /**< tell sensor to measure humidity */
#define SHT1X_RESET (0x1E) /**< reset the sensor */
/** @} */
/**
* @name Timing parameters for the SHT10/SHT1X/SHT15
* @{
*/
#define SHT1X_HALF_CLOCK (1) /**< Half clock length in µsec */
#define SHT1X_MEASURE_TIMEOUT (1000) /**< Timeout for the SHT1x to complete
the measurement (in millisec) */
#define SHT1X_RESET_WAIT (11000) /**< Wait 11ms after soft reset */
/** @} */
#define SHT1X_CONF_MASK (0x07) /**< Bitmask to get writable bits of the
status byte */
#define SHT1X_SAUL_RETRIES (3) /**< How often reading the sensor should
be retried in case of communication
failures */
#ifdef __cplusplus
}
#endif
#endif /* SHT1X_DEFINES_H */
/** @} */

View File

@ -0,0 +1,93 @@
/*
* Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_sht1x
*
* @{
* @file
* @brief Default configuration for SHT10/SHT11/SHT15 devices
*
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*/
#ifndef SHT1X_PARAMS_H
#define SHT1X_PARAMS_H
#include "board.h"
#include "sht1x.h"
#include "saul_reg.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @name Set default configuration parameters for the SHT1X devices
* @{
*/
#ifndef SHT1X_PARAM_CLK
#define SHT1X_PARAM_CLK (GPIO_PIN(1, 25))
#endif
#ifndef SHT1X_PARAM_DATA
#define SHT1X_PARAM_DATA (GPIO_PIN(1, 26))
#endif
#ifndef SHT1X_PARAM_VDD
#define SHT1X_PARAM_VDD (SHT1X_VDD_3_5V)
#endif
#ifndef SHT1X_PARAMS
#define SHT1X_PARAMS { .clk = SHT1X_PARAM_CLK, \
.data = SHT1X_PARAM_DATA, \
.vdd = SHT1X_PARAM_VDD }
#endif
/**@}*/
/**
* @name Set default SAUL info text depending on used pseudo module
* @{
*/
#ifndef SHT1X_SAULINFO
#ifdef MODULE_SHT15
#define SHT1X_SAULINFO { .name = "SHT15 temperature" }, \
{ .name = "SHT15 humidity" }
#else
#ifdef MODULE_SHT10
#define SHT1X_SAULINFO { .name = "SHT10 temperature" }, \
{ .name = "SHT10 humidity" }
#else
/* SHT11 is the most commonly used, so use that as default */
#define SHT1X_SAULINFO { .name = "SHT11 temperature" }, \
{ .name = "SHT11 humidity" }
#endif /* MODULE_SHT10 */
#endif /* MODULE_SHT15 */
#endif /* SHT1X_SAULINFO */
/**@}*/
/**
* @brief Configure SHT1X devices
*/
static const sht1x_params_t sht1x_params[] =
{
SHT1X_PARAMS
};
/**
* @brief Allocate and configure entries to the SAUL registry
*/
static const saul_reg_info_t sht1x_saul_info[] =
{
SHT1X_SAULINFO
};
#ifdef __cplusplus
}
#endif
#endif /* SHT1X_PARAMS_H */
/** @} */

694
drivers/sht1x/sht1x.c Normal file
View File

@ -0,0 +1,694 @@
/*
* Copyright 2009 Freie Universitaet Berlin (FUB)
* 2018 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_sht1x
* @brief Driver for the Sensirion SHT10/SHT11/SHT15 humidity and
* temperature sensor
* @{
*
* @file
* @brief SHT10/SHT11/SHT15 Device Driver
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*
* @}
*/
#include <errno.h>
#include <stdint.h>
#include "xtimer.h"
#include "sht1x.h"
#include "sht1x_defines.h"
#include "bitarithm.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/**
* @brief Perform measurement
*
* @param dev SHT1X device to use
* @param value Measured value
* @param mode The requested measurement mode: temperature or humidity
*
* @retval 0 Success
* @retval -EIO I/O failure (`gpio_init()` failed)
* @retval -EBADMSG CRC-8 checksum didn't match
* @retval -EPROTO SHT1x did not acknowledge command
* @retval -ECANCELED Measurement timed out
*/
static int measure(const sht1x_dev_t *dev, uint16_t *value, uint8_t mode);
/**
* @brief Write one byte
*
* @param dev SHT1X device to send the byte to
* @param value The value to write
*
* @retval 1 Write was acknowledged
* @retval 0 Write was *NOT* acknowledged (communication failure)
* @retval -EIO I/O failure (`gpio_init()` failed)
*/
static int write_byte(const sht1x_dev_t *dev, uint8_t value);
/**
* @brief Read one byte
*
* @param dev SHT1X device to receive the byte from
* @param dest Store the received byte here
* @param ack `SHT1X_ACK` to acknowledge byte, `SHT1X_NO_ACK` otherwise
*
* @retval 0 Success
* @retval -EIO I/O failure (`gpio_init()` failed)
*/
static int read_byte(const sht1x_dev_t *dev, uint8_t *dest, int ack);
/**
* @brief Communication reset
*
* @param dev SHT1X device to reset the connection to
*
* @retval 0 Success
* @retval -EIO I/O failure (`gpio_init()` failed)
*/
static int connection_reset(const sht1x_dev_t *dev);
/**
* @brief Send start of transmission sequence
*
* @param dev SHT1X device to send the transmission start sequence to
*
* @retval 0 Success
* @retval -EIO I/O failure (`gpio_init()` failed)
*/
static int transmission_start(const sht1x_dev_t *dev);
/**
* @brief Toggle the clock line
*
* @param dev SHT1X device to send one clock signal to
*/
static inline void clk_signal(const sht1x_dev_t *dev);
/**
* @brief Calculate the initial value of the CRC-8 checksum
*
* @param status The current sensor status
*
* @return The initial value of the CRC-8 checksum
*/
static inline uint8_t crc_initial_value(uint8_t status);
/**
* @brief Reverse the order of bits in a byte (needed for CRC)
*
* @param value The byte to reverse the bits of
*
* @return The reversed input
*/
static inline uint8_t reverse_byte(uint8_t value);
/**
* @brief Look up table required for CRC-8 calculation
*
* Values taken from the Application Note PDF of Sensirion (December 2011)
*/
static const uint8_t crc_lookup_table[] = {
0x00, 0x31, 0x62, 0x53, 0xc4, 0xf5, 0xa6, 0x97,
0xb9, 0x88, 0xdb, 0xea, 0x7d, 0x4c, 0x1f, 0x2e,
0x43, 0x72, 0x21, 0x10, 0x87, 0xb6, 0xe5, 0xd4,
0xfa, 0xcb, 0x98, 0xa9, 0x3e, 0x0f, 0x5c, 0x6d,
0x86, 0xb7, 0xe4, 0xd5, 0x42, 0x73, 0x20, 0x11,
0x3f, 0x0e, 0x5d, 0x6c, 0xfb, 0xca, 0x99, 0xa8,
0xc5, 0xf4, 0xa7, 0x96, 0x01, 0x30, 0x63, 0x52,
0x7c, 0x4d, 0x1e, 0x2f, 0xb8, 0x89, 0xda, 0xeb,
0x3d, 0x0c, 0x5f, 0x6e, 0xf9, 0xc8, 0x9b, 0xaa,
0x84, 0xb5, 0xe6, 0xd7, 0x40, 0x71, 0x22, 0x13,
0x7e, 0x4f, 0x1c, 0x2d, 0xba, 0x8b, 0xd8, 0xe9,
0xc7, 0xf6, 0xa5, 0x94, 0x03, 0x32, 0x61, 0x50,
0xbb, 0x8a, 0xd9, 0xe8, 0x7f, 0x4e, 0x1d, 0x2c,
0x02, 0x33, 0x60, 0x51, 0xc6, 0xf7, 0xa4, 0x95,
0xf8, 0xc9, 0x9a, 0xab, 0x3c, 0x0d, 0x5e, 0x6f,
0x41, 0x70, 0x23, 0x12, 0x85, 0xb4, 0xe7, 0xd6,
0x7a, 0x4b, 0x18, 0x29, 0xbe, 0x8f, 0xdc, 0xed,
0xc3, 0xf2, 0xa1, 0x90, 0x07, 0x36, 0x65, 0x54,
0x39, 0x08, 0x5b, 0x6a, 0xfd, 0xcc, 0x9f, 0xae,
0x80, 0xb1, 0xe2, 0xd3, 0x44, 0x75, 0x26, 0x17,
0xfc, 0xcd, 0x9e, 0xaf, 0x38, 0x09, 0x5a, 0x6b,
0x45, 0x74, 0x27, 0x16, 0x81, 0xb0, 0xe3, 0xd2,
0xbf, 0x8e, 0xdd, 0xec, 0x7b, 0x4a, 0x19, 0x28,
0x06, 0x37, 0x64, 0x55, 0xc2, 0xf3, 0xa0, 0x91,
0x47, 0x76, 0x25, 0x14, 0x83, 0xb2, 0xe1, 0xd0,
0xfe, 0xcf, 0x9c, 0xad, 0x3a, 0x0b, 0x58, 0x69,
0x04, 0x35, 0x66, 0x57, 0xc0, 0xf1, 0xa2, 0x93,
0xbd, 0x8c, 0xdf, 0xee, 0x79, 0x48, 0x1b, 0x2a,
0xc1, 0xf0, 0xa3, 0x92, 0x05, 0x34, 0x67, 0x56,
0x78, 0x49, 0x1a, 0x2b, 0xbc, 0x8d, 0xde, 0xef,
0x82, 0xb3, 0xe0, 0xd1, 0x46, 0x77, 0x24, 0x15,
0x3b, 0x0a, 0x59, 0x68, 0xff, 0xce, 0x9d, 0xac,
};
/** @brief Lookuptable for d1 parameter depending on supply voltage */
static const int16_t sht1x_d1[] = { -4010, -3980, -3970, -3960, -3940 };
/*---------------------------------------------------------------------------*/
static inline void clk_signal(const sht1x_dev_t *dev)
{
gpio_set(dev->clk);
xtimer_usleep(SHT1X_HALF_CLOCK);
gpio_clear(dev->clk);
xtimer_usleep(SHT1X_HALF_CLOCK);
}
/*---------------------------------------------------------------------------*/
static int write_byte(const sht1x_dev_t *dev, uint8_t value)
{
int ack;
if (gpio_init(dev->data, GPIO_OUT) == -1) {
return -EIO;
}
/* send value bit by bit to sht1x */
for (int i = 0; i < 8; i++) {
if (value & BIT7) {
gpio_set(dev->data);
}
else {
gpio_clear(dev->data);
}
xtimer_usleep(SHT1X_HALF_CLOCK);
/* trigger clock signal */
clk_signal(dev);
/* shift value to write next bit */
value <<= 1;
}
/* wait for ack */
if (gpio_init(dev->data, GPIO_IN) == -1) {
return -EIO;
}
xtimer_usleep(SHT1X_HALF_CLOCK);
ack = gpio_read(dev->data);
clk_signal(dev);
return ack;
}
/*---------------------------------------------------------------------------*/
static int read_byte(const sht1x_dev_t *dev, uint8_t *dest, int ack)
{
uint8_t value = 0;
xtimer_usleep(SHT1X_HALF_CLOCK);
/* read value bit by bit */
for (int i = 0; i < 8; i++) {
value <<= 1;
gpio_set(dev->clk);
xtimer_usleep(SHT1X_HALF_CLOCK);
if (gpio_read(dev->data)) {
/* set bit when DATA is high */
value |= 0x01;
}
gpio_clear(dev->clk);
xtimer_usleep(SHT1X_HALF_CLOCK);
}
/* send ack if necessary */
if (gpio_init(dev->data, GPIO_OUT) == -1) {
return -EIO;
}
gpio_write(dev->data, ack);
xtimer_usleep(SHT1X_HALF_CLOCK);
clk_signal(dev);
/* release data line */
if (gpio_init(dev->data, GPIO_IN) == -1) {
return -EIO;
}
*dest = value;
return 0;
}
/*---------------------------------------------------------------------------*/
static int transmission_start(const sht1x_dev_t *dev)
{
/* _____ ________
DATA: |_______|
___ ___
SCK : ___| |___| |______
*/
if (gpio_init(dev->data, GPIO_OUT) == -1) {
return -EIO;
}
/* set initial state */
gpio_set(dev->data);
xtimer_usleep(SHT1X_HALF_CLOCK);
gpio_clear(dev->clk);
xtimer_usleep(SHT1X_HALF_CLOCK);
gpio_set(dev->clk);
xtimer_usleep(SHT1X_HALF_CLOCK);
gpio_clear(dev->data);
xtimer_usleep(SHT1X_HALF_CLOCK);
gpio_clear(dev->clk);
xtimer_usleep(SHT1X_HALF_CLOCK);
gpio_set(dev->clk);
xtimer_usleep(SHT1X_HALF_CLOCK);
gpio_set(dev->data);
xtimer_usleep(SHT1X_HALF_CLOCK);
gpio_clear(dev->clk);
xtimer_usleep(SHT1X_HALF_CLOCK);
if (gpio_init(dev->data, GPIO_IN) == -1) {
return -EIO;
}
return 0;
}
/*---------------------------------------------------------------------------*/
static int connection_reset(const sht1x_dev_t *dev)
{
/* _____________________________________________________ ____
DATA: |_______|
_ _ _ _ _ _ _ _ _ ___ ___
SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______| |___| |__
*/
if (gpio_init(dev->data, GPIO_OUT) == -1) {
return -EIO;
}
gpio_set(dev->data);
xtimer_usleep(SHT1X_HALF_CLOCK);
gpio_clear(dev->clk);
xtimer_usleep(SHT1X_HALF_CLOCK);
for (int i = 0; i < 9; i++) {
clk_signal(dev);
}
return transmission_start(dev);
}
/*---------------------------------------------------------------------------*/
static inline uint8_t crc_initial_value(uint8_t status)
{
status &= 0x07;
return (
((0x01 & status) << 7) |
((0x02 & status) << 5) |
((0x04 & status) << 3)
);
}
/*---------------------------------------------------------------------------*/
static inline uint8_t reverse_byte(uint8_t value)
{
uint8_t result = (value & 0x01) << 7;
result |= (value & 0x02) << 5;
result |= (value & 0x04) << 3;
result |= (value & 0x08) << 1;
result |= (value & 0x10) >> 1;
result |= (value & 0x20) >> 3;
result |= (value & 0x40) >> 5;
result |= (value & 0x80) >> 7;
return result;
}
/*---------------------------------------------------------------------------*/
static int measure(const sht1x_dev_t *dev, uint16_t *value, uint8_t mode)
{
uint8_t data[2] = { 0, 0 };
int retval;
retval = transmission_start(dev);
if (retval != 0) {
return retval;
}
switch (write_byte(dev, mode)) {
case -EIO:
return -EIO;
case 0:
break;
default:
case 1:
return -EPROTO;
}
/* wait until sensor has finished measurement or timeout */
{
int ack = 1;
for (int i = 0; ack != 0; i++) {
if (i > SHT1X_MEASURE_TIMEOUT) {
return -ECANCELED;
}
xtimer_usleep(1000);
ack = gpio_read(dev->data);
}
}
/* read MSB */
retval = read_byte(dev, &data[0], SHT1X_ACK);
if (retval != 0) {
return retval;
}
/* read LSB, send ACK only if CRC checking is enabled */
retval = (dev->conf & SHT1X_CONF_SKIP_CRC) ? SHT1X_NO_ACK : SHT1X_ACK;
retval = read_byte(dev, &data[1], retval);
if (retval != 0) {
return retval;
}
if (!(dev->conf & SHT1X_CONF_SKIP_CRC)) {
uint8_t crc;
uint8_t expected;
retval = read_byte(dev, &crc, SHT1X_NO_ACK);
if (retval != 0) {
return retval;
}
expected = crc_initial_value(dev->conf);
expected = crc_lookup_table[expected ^ mode];
expected = crc_lookup_table[expected ^ data[0]];
expected = crc_lookup_table[expected ^ data[1]];
expected = reverse_byte(expected);
if (expected != crc) {
DEBUG("[sht1x] CRC expected: 0x%02x, got: 0x%02x\n"
" CRC0: 0x%02x, CMD: 0x%02x, data: {0x%02x, 0x%02x}\n",
(int)expected, (int)crc,
(int)crc_initial_value(dev->conf), mode,
(int)data[0], (int)data[1]);
return -EBADMSG;
}
}
*value = (((uint16_t)data[0]) << 8) | (uint16_t)data[1];
return 0;
}
/*---------------------------------------------------------------------------*/
int sht1x_init(sht1x_dev_t *dev, const sht1x_params_t *params)
{
if (
!dev ||
!params ||
(((uint8_t)params->vdd) >= sizeof(sht1x_d1) / sizeof(sht1x_d1[0]))
) {
return -EINVAL;
}
dev->clk = params->clk;
dev->data = params->data;
if (gpio_init(dev->clk, GPIO_OUT) || gpio_init(dev->data, GPIO_IN)) {
return -EIO;
}
dev->temp_off = 0;
dev->hum_off = 0;
dev->conf = 0;
dev->vdd = (uint8_t)params->vdd;
return sht1x_reset(dev);
}
/*---------------------------------------------------------------------------*/
int16_t sht1x_temperature(const sht1x_dev_t *dev, uint16_t raw)
{
if (!dev || (dev->vdd >= sizeof(sht1x_d1) / sizeof(sht1x_d1[0]))) {
return INT16_MIN;
}
int16_t d1 = sht1x_d1[dev->vdd];
int16_t d2 = (dev->conf & SHT1X_CONF_LOW_RESOLUTION) ? 4 : 1;
return d1 + d2 * ((int16_t)raw);
}
/*---------------------------------------------------------------------------*/
int16_t sht1x_humidity(const sht1x_dev_t *dev, uint16_t raw, int16_t temp)
{
if (!dev) {
return -1;
}
static const int32_t c1 = -20468;
static const int32_t t1 = 1;
int32_t c2, c3, c4, t2;
if (dev->conf & SHT1X_CONF_LOW_RESOLUTION) {
c2 = 5872;
c3 = 494801;
c4 = 1000000;
t2 = 781;
}
else {
c2 = 367;
c3 = 791684;
c4 = 100000;
t2 = 12500;
}
/*
* Calculate linear humidity, but slightly different. Original formula:
*
* hum_lin = c1 + c2 * raw + c3 * (raw * raw)
*
* But we use:
*
* hum_lin = c1 + c2 * raw - (c4 * raw / c3') * (c4 * raw / c3')
*
* where: c3' = 1 / (sqrt(-c3) / c4)
*
* (This better fits for integer calculation)
*/
int32_t res = ((int32_t)raw * c4) / c3;
res = c1 + c2 * (int32_t)raw - (res * res);
/*
* Perform temperature compensation, again slightly different.
* Original formula:
*
* hum_true = (temp - 25) * (t1 + t2 * raw) + hum_lin
*
* But we use:
*
* hum_true = (temp - 25) * t1 + (temp - 25) * raw / t2') + hum_lin
*
* where t2' = 1/t2
*/
int32_t temp_diff = temp - 2500;
res = temp_diff * t1 + (temp_diff * (int32_t)raw * 100) / t2 + res;
return (int16_t)(res / 100);
}
/*---------------------------------------------------------------------------*/
int sht1x_read(const sht1x_dev_t *dev, int16_t *temp, int16_t *rel_hum)
{
uint16_t temp_raw;
int16_t t;
uint16_t hum_raw;
int retval;
if (
!dev ||
(dev->vdd >= sizeof(sht1x_d1) / sizeof(sht1x_d1[0])) ||
(!temp && !rel_hum)
) {
return -EINVAL;
}
retval = measure(dev, &temp_raw, SHT1X_MEASURE_TEMP);
if (retval != 0) {
connection_reset(dev);
return retval;
}
t = sht1x_temperature(dev, temp_raw) + dev->temp_off;
if (temp != NULL) {
*temp = t;
}
if (rel_hum != NULL) {
retval = measure(dev, &hum_raw, SHT1X_MEASURE_HUM);
if (retval != 0) {
connection_reset(dev);
return retval;
}
*rel_hum = sht1x_humidity(dev, hum_raw, t) + dev->hum_off;
}
return 0;
}
/*---------------------------------------------------------------------------*/
int sht1x_configure(sht1x_dev_t *dev, sht1x_conf_t conf)
{
if (!dev) {
return -EINVAL;
}
/* Apply config that is not stored on the sensor */
dev->conf &= SHT1X_CONF_MASK;
dev->conf |= conf & (~(SHT1X_CONF_MASK));
/* Send new status byte to sensor, if on-device config was changed */
if ((conf & SHT1X_CONF_MASK) != (dev->conf & SHT1X_CONF_MASK)) {
int retval = transmission_start(dev);
if (retval != 0) {
return retval;
}
switch (write_byte(dev, SHT1X_STATUS_REG_W)) {
case -EIO:
return -EIO;
case 0:
break;
default:
case 1:
return -EPROTO;
}
switch (write_byte(dev, conf & SHT1X_CONF_MASK)) {
case -EIO:
return -EIO;
case 0:
break;
default:
case 1:
return -EPROTO;
}
/* Read back uploaded configuration to verify that sensor applied it */
uint8_t status;
retval = sht1x_read_status(dev, &status);
if (retval != 0) {
return retval;
}
if (dev->conf != conf) {
/* Configuration was not applied by sensor */
return -ECANCELED;
}
}
return 0;
}
/*---------------------------------------------------------------------------*/
int sht1x_read_status(sht1x_dev_t *dev, uint8_t *status)
{
int retval;
if (!dev || !status) {
return -EINVAL;
}
retval = transmission_start(dev);
if (retval != 0) {
return retval;
}
switch (write_byte(dev, SHT1X_STATUS_REG_R)) {
case -EIO:
return -EIO;
case 0:
break;
default:
case 1:
return -EPROTO;
}
retval = read_byte(dev, status, SHT1X_ACK);
if (retval != 0) {
return retval;
}
{
uint8_t crc;
uint8_t expected;
/* read checksum */
retval = read_byte(dev, &crc, SHT1X_NO_ACK);
if (retval != 0) {
return retval;
}
expected = crc_initial_value(*status);
expected = crc_lookup_table[expected ^ SHT1X_STATUS_REG_R];
expected = crc_lookup_table[expected ^ *status];
expected = reverse_byte(expected);
if (expected != crc) {
DEBUG("[sht1x] CRC expected: 0x%02x, got: 0x%02x\n"
" CRC0: 0x%02x, CMD: 0x%02x, data: {0x%02x}\n",
(int)expected, (int)crc,
(int)crc_initial_value(*status), SHT1X_STATUS_REG_R,
(int)*status);
return -EBADMSG;
}
}
/* Extract config from status and store it after CRC check passed */
dev->conf &= ~(SHT1X_CONF_MASK);
dev->conf |= *status & SHT1X_CONF_MASK;
return 0;
}
/*---------------------------------------------------------------------------*/
int sht1x_reset(sht1x_dev_t *dev)
{
int retval;
if (!dev) {
return -EINVAL;
}
retval = transmission_start(dev);
if (retval != 0) {
return retval;
}
switch (write_byte(dev, SHT1X_RESET)) {
case -EIO:
return -EIO;
case 0:
break;
default:
case 1:
return -EPROTO;
}
dev->conf = 0;
xtimer_usleep(SHT1X_RESET_WAIT);
return 0;
}

View File

@ -0,0 +1,87 @@
/*
* Copyright 2018 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup drivers_sht1x
* @{
*
* @file
* @brief SAUL adaption for SHT10/SHT11/SHT15 devices
*
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*
* @}
*/
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include "phydat.h"
#include "saul.h"
#include "sht1x_defines.h"
#include "sht1x.h"
static int read(const sht1x_dev_t *dev, int16_t *temp, int16_t *hum)
{
for (int retries = 0; retries < SHT1X_SAUL_RETRIES; retries++) {
switch (sht1x_read(dev, temp, hum)) {
case 0:
return 0;
case -EBADMSG:
puts("[sht1x] CRC");
continue;
case -EPROTO:
puts("[sht1x] Sensor did not acknowledge measurement command");
continue;
case -ECANCELED:
puts("[sht1x] Measurement times out");
default:
/* Other failure, cannot recover so giving up */
return -1;
}
}
printf("[sht1x] Giving up after %i tries\n", SHT1X_SAUL_RETRIES);
return -1;
}
static int read_temp(const void *dev, phydat_t *res)
{
if (read(dev, &res->val[0], NULL) == 0) {
res->unit = UNIT_TEMP_C;
res->scale = -2;
return 1;
}
return -ECANCELED;
}
static int read_hum(const void *dev, phydat_t *res)
{
if (read(dev, NULL, &res->val[0]) == 0) {
res->unit = UNIT_PERCENT;
res->scale = -2;
return 1;
}
return -ECANCELED;
}
const saul_driver_t sht1x_saul_temp_driver = {
.read = read_temp,
.write = saul_notsup,
.type = SAUL_SENSE_TEMP
};
const saul_driver_t sht1x_saul_hum_driver = {
.read = read_hum,
.write = saul_notsup,
.type = SAUL_SENSE_HUM
};

View File

@ -95,6 +95,11 @@ PSEUDOMODULES += adc121c
PSEUDOMODULES += sx1272
PSEUDOMODULES += sx1276
# include variants of SHT1X drivers as pseudo modules
PSEUDOMODULES += sht10
PSEUDOMODULES += sht11
PSEUDOMODULES += sht15
# include variants of Si114x drivers as pseudo modules
PSEUDOMODULES += si1145
PSEUDOMODULES += si1146

View File

@ -20,10 +20,6 @@
#include "auto_init.h"
#ifdef MODULE_SHT11
#include "sht11.h"
#endif
#ifdef MODULE_MCI
#include "diskio.h"
#endif
@ -101,10 +97,6 @@ void auto_init(void)
DEBUG("Auto init xtimer module.\n");
xtimer_init();
#endif
#ifdef MODULE_SHT11
DEBUG("Auto init SHT11 module.\n");
sht11_init();
#endif
#ifdef MODULE_MCI
DEBUG("Auto init mci module.\n");
mci_initialize();
@ -275,6 +267,12 @@ void auto_init(void)
#endif
/* initialize sensors and actuators */
#ifdef MODULE_SHT1X
DEBUG("Auto init SHT1X module (SHT10/SHT11/SHT15 sensor driver).\n");
extern void auto_init_sht1x(void);
auto_init_sht1x();
#endif
#ifdef MODULE_AUTO_INIT_SAUL
DEBUG("auto_init SAUL\n");

View File

@ -0,0 +1,102 @@
/*
* Copyright 2018 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*
*/
/*
* @ingroup sys_auto_init
* @{
*
* @file
* @brief Auto initialization for SHT1X temperature/humidity sensors
*
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*
* @}
*/
#ifdef MODULE_SHT1X
#include "log.h"
#include "sht1x_params.h"
#include "sht1x.h"
#define ENABLE_DEBUG (0)
#include "debug.h"
/**
* @brief Define the number of configured sensors
*/
#define SHT1X_NUM (sizeof(sht1x_params) / sizeof(sht1x_params[0]))
/**
* @brief Allocate memory for the device descriptors
*/
sht1x_dev_t sht1x_devs[SHT1X_NUM];
#ifdef MODULE_AUTO_INIT_SAUL
/**
* @brief Memory for the SAUL registry entries
*/
static saul_reg_t saul_entries[SHT1X_NUM * 2];
/**
* @name Import SAUL endpoints
* @{
*/
extern const saul_driver_t sht1x_saul_temp_driver;
extern const saul_driver_t sht1x_saul_hum_driver;
/** @} */
#endif /* MODULE_AUTO_INIT_SAUL */
static void sht1x_error(unsigned int num, const char *reason)
{
LOG_ERROR("[auto_init] error initializing SHT10/SHT11/SHT15 sensor "
"#%u: %s\n", num, reason);
}
void auto_init_sht1x(void)
{
for (unsigned int i = 0; i < SHT1X_NUM; i++) {
DEBUG("[auto_init_sht1x] Initializing SHT1X sensor #%u\n", i);
switch (sht1x_init(&sht1x_devs[i], &sht1x_params[i])) {
case 0:
break;
case -EIO:
sht1x_error(i, "Failed to initialize GPIOs");
continue;
case -EINVAL:
sht1x_error(i, "Invalid configuration for VDD");
continue;
case -EPROTO:
sht1x_error(i, "Reset command not acknowledged");
continue;
default:
/* Should not happen, but better safe than sorry */
sht1x_error(i, "?");
continue;
}
#ifdef MODULE_AUTO_INIT_SAUL
saul_entries[(i * 2) ].dev = &(sht1x_devs[i]);
saul_entries[(i * 2) + 1].dev = &(sht1x_devs[i]);
saul_entries[(i * 2) ].name = sht1x_saul_info[(i * 2) ].name;
saul_entries[(i * 2) + 1].name = sht1x_saul_info[(i * 2) + 1].name;
saul_entries[(i * 2) ].driver = &sht1x_saul_temp_driver;
saul_entries[(i * 2) + 1].driver = &sht1x_saul_hum_driver;
saul_reg_add(&(saul_entries[(i * 2) ]));
saul_reg_add(&(saul_entries[(i * 2) + 1]));
#endif /* MODULE_AUTO_INIT_SAUL */
}
}
#else
typedef int dont_be_pedantic;
#endif /* MODULE_SHT1X */

View File

@ -8,8 +8,8 @@ endif
ifneq (,$(filter ps,$(USEMODULE)))
SRC += sc_ps.c
endif
ifneq (,$(filter sht11,$(USEMODULE)))
SRC += sc_sht11.c
ifneq (,$(filter sht1x,$(USEMODULE)))
SRC += sc_sht1x.c
endif
ifneq (,$(filter lpc2387,$(USEMODULE)))
SRC += sc_heap.c

View File

@ -1,112 +0,0 @@
/*
* Copyright (C) 2013 INRIA.
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_shell_commands
* @{
*
* @file
* @brief Provides shell commands to poll sht11 sensor
*
* @author Oliver Hahm <oliver.hahm@inria.fr>
*
* @}
*/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "sht11.h"
#ifdef MODULE_SHT11
extern float sht11_temperature_offset;
int _get_humidity_handler(int argc, char **argv)
{
(void) argc;
(void) argv;
uint8_t success;
sht11_val_t sht11_val;
success = sht11_read_sensor(&sht11_val, HUMIDITY | TEMPERATURE);
if (!success) {
printf("Error reading SHT11\n");
return 1;
}
else {
printf("Relative humidity: %5.2f%% / Temperature compensated humidity; %5.2f%%\n",
(double) sht11_val.relhum, (double) sht11_val.relhum_temp);
return 0;
}
}
int _get_temperature_handler(int argc, char **argv)
{
(void) argc;
(void) argv;
uint8_t success;
sht11_val_t sht11_val;
success = sht11_read_sensor(&sht11_val, TEMPERATURE);
if (!success) {
printf("Error reading SHT11\n");
return 1;
}
else {
printf("Temperature: %-6.2f°C\n", (double) sht11_val.temperature);
return 0;
}
}
int _get_weather_handler(int argc, char **argv)
{
(void) argc;
(void) argv;
uint8_t success;
sht11_val_t sht11_val;
success = sht11_read_sensor(&sht11_val, HUMIDITY | TEMPERATURE);
if (!success) {
printf("Error reading SHT11\n");
return 1;
}
else {
printf("Relative humidity: %5.2f%% / Temperature compensated humidity; %5.2f%% ",
(double) sht11_val.relhum, (double) sht11_val.relhum_temp);
printf("Temperature: %-6.2f°C\n", (double) sht11_val.temperature);
return 0;
}
}
int _set_offset_handler(int argc, char **argv)
{
if (argc != 2) {
printf("Usage: %s <OFFSET>\n", argv[0]);
return 1;
}
else {
sht11_temperature_offset = atoi(argv[1]);
printf("Temperature offset set to %f\n", (double) sht11_temperature_offset);
return 0;
}
}
#endif

View File

@ -0,0 +1,378 @@
/*
* Copyright (C) 2013 INRIA
* 2018 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup sys_shell_commands
* @{
*
* @file
* @brief Provides shell commands to access SHT10/SHT11/SHT15 sensors
*
* @author Oliver Hahm <oliver.hahm@inria.fr>
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*
* @}
*/
#ifdef MODULE_SHT1X
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "sht1x.h"
#include "sht1x_params.h"
#define SHT1X_NUM (sizeof(sht1x_params) / sizeof(sht1x_params[0]))
extern sht1x_dev_t sht1x_devs[SHT1X_NUM];
static sht1x_dev_t *get_dev(int argc, char **argv)
{
switch (argc) {
case 1:
return &sht1x_devs[0];
case 2:
{
int pos = atoi(argv[1]);
if ((pos < 0) || (pos >= (int)SHT1X_NUM)) {
printf("No SHT10/SHT11/SHT15 device with number %i\n", pos);
return NULL;
}
return &sht1x_devs[pos];
}
default:
break;
}
printf("Usage: %s [DEVICE_NUMBER]\n", argv[0]);
return NULL;
}
static void error_msg(const char *msg)
{
printf("[sht1x] Operation failed: %s\n", msg);
}
static int read_sensor(int16_t *temp, int16_t *hum, int argc, char **argv)
{
const sht1x_dev_t *dev = get_dev(argc, argv);
if (!dev) {
return -1;
}
switch (sht1x_read(dev, temp, hum)) {
case 0:
break;
case -EIO:
error_msg("gpio_init() failed");
return -1;
case -EBADMSG:
error_msg("CRC checksum error");
return -1;
case -ECANCELED:
error_msg("Measurement timed out");
return -1;
case -EPROTO:
error_msg("Sensor did not acknowledge command");
return -1;
default:
/* Should never happen, but better safe the sorry */
error_msg("Unknown error");
return -1;
}
return 0;
}
int _get_humidity_handler(int argc, char **argv)
{
int16_t hum;
if (read_sensor(NULL, &hum, argc, argv)) {
return -1;
}
printf("Relative humidity: %i.%02i%%\n", (int)hum / 100, (int)hum % 100);
return 0;
}
int _get_temperature_handler(int argc, char **argv)
{
int16_t temp;
if (read_sensor(&temp, NULL, argc, argv)) {
return -1;
}
printf("Temperature: %i.%02i°C\n", (int)temp / 100, (int)temp % 100);
return 0;
}
int _get_weather_handler(int argc, char **argv)
{
int16_t hum;
int16_t temp;
if (read_sensor(&temp, &hum, argc, argv)) {
return -1;
}
printf("Relative humidity: %i.%02i%%\n", (int)hum / 100, (int)hum % 100);
printf("Temperature: %i.%02i°C\n", (int)temp / 100, (int)temp % 100);
return 0;
}
static void print_config(const sht1x_dev_t *dev)
{
const char *vdds[] = { "5.0", "4.0", "3.5", "3.0", "2.5" };
printf("Sensor VDD = %s\n", vdds[dev->vdd]);
printf("Temperature offset [-t]: %i\n", (int)dev->temp_off);
printf("Humidity offset [-h]: %i\n", (int)dev->hum_off);
printf("Resolution [-r]: %s\n",
(dev->conf & SHT1X_CONF_LOW_RESOLUTION) ? "low" : "high");
printf("Skip calibration (faster reading) [-c]: %s\n",
(dev->conf & SHT1X_CONF_SKIP_CALIBRATION) ? "yes" : "no");
printf("Heater [-H]: %s\n",
(dev->conf & SHT1X_CONF_ENABLE_HEATER) ? "on" : "off");
printf("CRC checking [-C]: %s\n",
(dev->conf & SHT1X_CONF_SKIP_CRC) ? "off" : "on");
}
static void unknown_parameter(int index, char **argv)
{
printf("Unknown parameter \"%s\"\n"
"Usage: \"%s [PARAMS]\", run \"%s --help\" for help\n",
argv[index], argv[0], argv[0]);
}
static void missing_argument(int index, char **argv)
{
printf("Missing argument for parameter \"%s\"\n"
"Usage: \"%s [%s <ARG>][PARAMS]\", run \"%s --help\" for help\n",
argv[index], argv[0], argv[index], argv[0]);
}
static void invalid_argument(int index, char **argv, const char *valid)
{
printf("Invalid argument \"%s\" for parameter \"%s\"\n"
"Valid arguments are: \"%s\", run \"%s --help\" for help\n",
argv[index + 1], argv[index], valid, argv[0]);
}
int _sht_config_handler(int argc, char **argv)
{
uint8_t set_conf = 0;
uint8_t unset_conf = 0;
int16_t temp_off = INT16_MAX;
int16_t hum_off = INT16_MAX;
int dev_num = 0;
if ((argc == 2) && (strcmp("--help", argv[1]) == 0)) {
printf("Usage: \"%s [PARMS]\n"
"\n"
"Supported parameters:\n"
" -d <NUM>\n"
" Use SHT10/11/15 sensor number <NUM>. Default: 0\n"
"\n"
" -t <OFFSET>\n"
" Add <OFFSET> (in e-2°C) to all temperature measurements\n"
"\n"
" -h <OFFSET>\n"
" Add <OFFSET> (in e-2%%) to all humidity measurements\n"
"\n"
" -r l/h\n"
" Set resolution to low/high. Low resolution trades "
"presicion for speed\n"
"\n"
" -H y/n\n"
" Turns heater on/off. Can increase temperature by up to "
"10°C\n"
"\n"
" -C y/n\n"
" Turns on/off CRC checking. No checking trades robustness "
"for speed\n",
argv[0]);
return 0;
}
for (int i = 1; i < argc; i++) {
if ((argv[i][0] != '-') || (!argv[i][1]) || (argv[i][2])) {
unknown_parameter(i, argv);
return -1;
}
switch (argv[i][1]) {
case 'd':
if (++i >= argc) {
missing_argument(i - 1, argv);
return -1;
}
dev_num = atoi(argv[i]);
if ((dev_num < 0) || (dev_num >= (int)SHT1X_NUM)) {
printf("No SHT10/11/15 sensor with number %i\n", dev_num);
return -1;
}
break;
case 't':
if (++i >= argc) {
missing_argument(i - 1, argv);
return -1;
}
temp_off = (int16_t)atoi(argv[i]);
break;
case 'h':
if (++i >= argc) {
missing_argument(i - 1, argv);
return -1;
}
hum_off = (int16_t)atoi(argv[i]);
break;
case 'r':
if (++i >= argc) {
missing_argument(i - 1, argv);
return -1;
}
if ((!argv[i][0]) || (argv[i][1])) {
invalid_argument(i - 1, argv, "l, h");
return -1;
}
switch (argv[i][0]) {
case 'l':
set_conf |= SHT1X_CONF_LOW_RESOLUTION;
break;
case 'h':
unset_conf |= SHT1X_CONF_LOW_RESOLUTION;
break;
default:
invalid_argument(i - 1, argv, "l, h");
return -1;
}
break;
case 'c':
if (++i >= argc) {
missing_argument(i - 1, argv);
return -1;
}
if ((!argv[i][0]) || (argv[i][1])) {
invalid_argument(i - 1, argv, "y, n");
return -1;
}
switch (argv[i][0]) {
case 'y':
set_conf |= SHT1X_CONF_SKIP_CALIBRATION;
break;
case 'n':
unset_conf |= SHT1X_CONF_SKIP_CALIBRATION;
break;
default:
invalid_argument(i - 1, argv, "y, n");
return -1;
}
break;
case 'H':
if (++i >= argc) {
missing_argument(i - 1, argv);
return -1;
}
if ((!argv[i][0]) || (argv[i][1])) {
invalid_argument(i - 1, argv, "y, n");
return -1;
}
switch (argv[i][0]) {
case 'y':
set_conf |= SHT1X_CONF_ENABLE_HEATER;
break;
case 'n':
unset_conf |= SHT1X_CONF_ENABLE_HEATER;
break;
default:
invalid_argument(i - 1, argv, "y, n");
return -1;
}
break;
case 'C':
if (++i >= argc) {
missing_argument(i - 1, argv);
return -1;
}
if ((!argv[i][0]) || (argv[i][1])) {
invalid_argument(i - 1, argv, "y, n");
return -1;
}
switch (argv[i][0]) {
case 'y':
unset_conf |= SHT1X_CONF_SKIP_CRC;
break;
case 'n':
set_conf |= SHT1X_CONF_SKIP_CRC;
break;
default:
invalid_argument(i - 1, argv, "y, n");
return -1;
}
break;
default:
unknown_parameter(i, argv);
return -1;
}
}
if ((set_conf) || (unset_conf)) {
/* Apply new configuration */
uint8_t new_conf = sht1x_devs[dev_num].conf;
new_conf &= ~(unset_conf);
new_conf |= set_conf;
switch (sht1x_configure(&sht1x_devs[dev_num], new_conf)) {
case 0:
break;
case -EIO:
error_msg("gpio_init() failed");
return -1;
case -EBADMSG:
error_msg("CRC checksum error");
return -1;
case -ECANCELED:
error_msg("Sensor did not apply configuration");
return -1;
case -EPROTO:
error_msg("Sensor did not acknowledge command");
return -1;
default:
/* Should never happen, but better safe the sorry */
error_msg("Unknown error");
return -1;
}
}
if (temp_off != INT16_MAX) {
if ((temp_off > 2000) || (temp_off < -2000)) {
printf("A temperature offset of %i.%02i°C is unreasonable\n",
(int)temp_off / 100, (int)temp_off % 100);
return -1;
}
sht1x_devs[dev_num].temp_off = temp_off;
}
if (hum_off != INT16_MAX) {
if ((hum_off > 1000) || (hum_off < -1000)) {
printf("A humidity offset of %i.%02i%% is unreasonable\n",
(int)hum_off / 100, (int)hum_off % 100);
return -1;
}
sht1x_devs[dev_num].hum_off = hum_off;
}
print_config(&sht1x_devs[dev_num]);
return 0;
}
#endif

View File

@ -37,11 +37,11 @@ extern int _heap_handler(int argc, char **argv);
extern int _ps_handler(int argc, char **argv);
#endif
#ifdef MODULE_SHT11
#ifdef MODULE_SHT1X
extern int _get_temperature_handler(int argc, char **argv);
extern int _get_humidity_handler(int argc, char **argv);
extern int _get_weather_handler(int argc, char **argv);
extern int _set_offset_handler(int argc, char **argv);
extern int _sht_config_handler(int argc, char **argv);
#endif
#ifdef MODULE_LTC4150
@ -153,11 +153,11 @@ const shell_command_t _shell_command_list[] = {
#ifdef MODULE_PS
{"ps", "Prints information about running threads.", _ps_handler},
#endif
#ifdef MODULE_SHT11
#ifdef MODULE_SHT1X
{"temp", "Prints measured temperature.", _get_temperature_handler},
{"hum", "Prints measured humidity.", _get_humidity_handler},
{"weather", "Prints measured humidity and temperature.", _get_weather_handler},
{"offset", "Set temperature offset.", _set_offset_handler},
{"sht-config", "Get/set SHT10/11/15 sensor configuration.", _sht_config_handler},
#endif
#ifdef MODULE_LTC4150
{"cur", "Prints current and average power consumption.", _get_current_handler},

View File

@ -0,0 +1,12 @@
include ../Makefile.tests_common
DRIVER ?= sht11
BOARD ?= msba2
USEMODULE += $(DRIVER)
USEMODULE += shell
USEMODULE += saul_default
USEMODULE += shell_commands
USEMODULE += ps
include $(RIOTBASE)/Makefile.include

172
tests/driver_sht1x/main.c Normal file
View File

@ -0,0 +1,172 @@
/*
* Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @ingroup tests
* @{
*
* @file
* @brief Test application for the SHT10/11/15 family of temperature and
* humidity sensors
*
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*
* @}
*/
#include <stdio.h>
#include "shell.h"
#include "shell_commands.h"
#include "sht1x_params.h"
#define SHT1X_NUM (sizeof(sht1x_params) / sizeof(sht1x_params[0]))
extern sht1x_dev_t sht1x_devs[SHT1X_NUM];
static sht1x_dev_t *dev = &sht1x_devs[0];
static int run_tests(void)
{
const char *resolution[] = { "high", "low" };
const char *calibration[] = { "on", "off" };
const char *heater[] = { "off", "on" };
const char *crc[] = { "on", "off" };
uint8_t conf = 0;
puts("Reading the sensor three times for all possible configurations:");
for (int i_res = 0; i_res < 2; i_res++) {
if (i_res) {
conf |= SHT1X_CONF_LOW_RESOLUTION;
}
else {
conf &= ~(SHT1X_CONF_LOW_RESOLUTION);
}
for (int i_cal = 0; i_cal < 2; i_cal++) {
if (i_cal) {
conf |= SHT1X_CONF_SKIP_CALIBRATION;
}
else {
conf &= ~(SHT1X_CONF_SKIP_CALIBRATION);
}
for (int i_heater = 0; i_heater < 2; i_heater++) {
if (i_heater) {
conf |= SHT1X_CONF_ENABLE_HEATER;
}
else {
conf &= ~(SHT1X_CONF_ENABLE_HEATER);
}
for (int i_crc = 0; i_crc < 2; i_crc++) {
if (i_crc) {
conf |= SHT1X_CONF_SKIP_CRC;
}
else {
conf &= ~(SHT1X_CONF_SKIP_CRC);
}
printf("Resolution: %s, calibration: %s, heater: %s, "
"CRC-checking: %s\n",
resolution[i_res],
calibration[i_cal],
heater[i_heater],
crc[i_crc]);
switch (sht1x_configure(dev, conf)) {
case 0:
break;
case -EIO:
puts("Error: gpio_init() failed");
return -1;
case -EPROTO:
puts("Error: Sensor did not acknowledge command");
return -1;
case -ECANCELED:
puts("Error: Sensor did not apply configuration");
return -1;
case -EBADMSG:
puts("Error: CRC error while validating "
"configuration");
return -1;
default:
/* Will never happen, but better safe than sorry */
puts("Unknown error");
return -1;
}
for (int i = 0; i < 3; i++) {
int16_t temp, hum;
switch (sht1x_read(dev, &temp, &hum)) {
case 0:
break;
case -EIO:
puts("Error: gpio_init() failed");
return -1;
case -EPROTO:
puts("Error: Sensor did not acknowledge "
"command");
return -1;
case -ECANCELED:
puts("Error: Measurement timed out");
return -1;
default:
/* Won't happen, but better safe than sorry */
puts("Unknown error");
return -1;
}
printf("Temperature: %i.%02i°C, Humidity: %i.%02i%%\n",
(int)temp / 100, (int)temp % 100,
(int)hum / 100, (int)hum % 100);
}
}
}
}
}
puts("Restoring default configuration");
switch (sht1x_configure(dev, 0)) {
case 0:
break;
case -EIO:
puts("Error: gpio_init() failed");
return -1;
case -EPROTO:
puts("Error: Sensor did not acknowledge command");
return -1;
case -ECANCELED:
puts("Error: Sensor did not apply configuration");
return -1;
case -EBADMSG:
puts("Error: CRC error while validating "
"configuration");
return -1;
default:
/* Will never happen, but better safe than sorry */
puts("Unknown error");
return -1;
}
return 0;
}
int main(void)
{
if (run_tests()) {
puts("TESTS FAILED!");
}
else {
puts("All automatic tests finished.");
}
puts("Dropping to shell for manual testing");
char line_buf[SHELL_DEFAULT_BUFSIZE];
shell_run(NULL, line_buf, SHELL_DEFAULT_BUFSIZE);
return 0;
}

View File

@ -0,0 +1 @@
include $(RIOTBASE)/Makefile.base

View File

@ -0,0 +1 @@
USEMODULE += sht1x

View File

@ -0,0 +1,110 @@
/*
* Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
#include <sht1x.h>
#include <stdlib.h>
#include "embUnit/embUnit.h"
#include "tests-sht1x.h"
/** @brief Maximum difference from correct temperature value [in e-02 °C] */
static const int16_t max_diff_temp = 1;
/** @brief Maximum difference from correct humidity value [in e-02 %] */
static const int16_t max_diff_hum = 10;
static int16_t expected_temp(const sht1x_dev_t *dev, uint16_t _raw)
{
static const double d1_table[] = { -40.1, -39.8, -39.7, -39.6, -39.4 };
double d1 = d1_table[dev->vdd];
double d2 = (dev->conf & SHT1X_CONF_LOW_RESOLUTION) ? 0.04 : 0.01;
double raw = (double)_raw;
double temp = d1 + d2 * raw;
return (int16_t)(temp * 100.0);
}
static int16_t expected_hum(const sht1x_dev_t *dev, uint16_t _raw, int16_t _temp)
{
static const double c1 = -2.0468;
static const double t1 = 0.01;
double temp = ((double)_temp) / 100.0;
double raw = (double)_raw;
double c2, c3, t2, hum_linear, hum_real;
if (dev->conf & SHT1X_CONF_LOW_RESOLUTION) {
c2 = 0.5872;
c3 = -4.0845e-04;
t2 = 0.00128;
}
else {
c2 = 0.0367;
c3 = -1.5955e-06;
t2 = 0.00008;
}
hum_linear = c1 + c2 * raw + c3 * (raw * raw);
hum_real = (temp - 25.0) * (t1 + t2 * raw) + hum_linear;
return (int16_t)(hum_real * 100.0);
}
static void test_sht1x_conversion(void)
{
const uint8_t vdds[] = {
SHT1X_VDD_5_0V, SHT1X_VDD_4_0V, SHT1X_VDD_3_5V, SHT1X_VDD_3_0V,
SHT1X_VDD_2_5V,
};
const uint8_t confs[] = { SHT1X_CONF_LOW_RESOLUTION, 0 };
const uint16_t max_raw_temps[] = { 0xfff, 0x3fff };
const uint16_t max_raw_hums[] = { 0xff, 0xfff };
sht1x_dev_t dev = { .conf = 0 };
for (size_t i_res = 0; i_res < sizeof(confs) / sizeof(confs[0]); i_res++) {
dev.conf = confs[i_res];
uint16_t max_raw_temp = max_raw_temps[i_res];
uint16_t max_raw_hum = max_raw_hums[i_res];
for (size_t i_vdd = 0; i_vdd < sizeof(vdds) / sizeof(vdds[0]); i_vdd++) {
dev.vdd = vdds[i_vdd];
for (uint16_t raw_temp = 0; raw_temp <= max_raw_temp; raw_temp++) {
int16_t got_temp = sht1x_temperature(&dev, raw_temp);
int16_t exp_temp = expected_temp(&dev, raw_temp);
TEST_ASSERT(((got_temp - max_diff_temp) <= exp_temp) &&
((got_temp + max_diff_temp) >= exp_temp));
}
}
/* Testing for temperatures in -10.00°C and 65.00°C in steps of 0.13°C */
for (int16_t temp = -1000; temp < 6500; temp += 13) {
for (uint16_t raw_hum = 0; raw_hum <= max_raw_hum; raw_hum++) {
int16_t exp_hum = expected_hum(&dev, raw_hum, temp);
if ((exp_hum < 0) || (exp_hum > 10000)) {
/* Result out of range, ignore it */
continue;
}
int16_t got_hum = sht1x_humidity(&dev, raw_hum, temp);
TEST_ASSERT(((got_hum - max_diff_hum) <= exp_hum) &&
((got_hum + max_diff_hum) >= exp_hum));
}
}
}
}
Test *tests_sht1x_tests(void)
{
EMB_UNIT_TESTFIXTURES(fixtures) {
new_TestFixture(test_sht1x_conversion),
};
EMB_UNIT_TESTCALLER(sht1x_tests, NULL, NULL, fixtures);
return (Test *)&sht1x_tests;
}
void tests_sht1x(void)
{
TESTS_RUN(tests_sht1x_tests());
}

View File

@ -0,0 +1,36 @@
/*
* Copyright (C) 2018 Otto-von-Guericke-Universität Magdeburg
*
* This file is subject to the terms and conditions of the GNU Lesser
* General Public License v2.1. See the file LICENSE in the top level
* directory for more details.
*/
/**
* @addtogroup unittests
* @{
*
* @file
* @brief Unittests for the conversions used in the sht1x driver
*
* @author Marian Buschsieweke <marian.buschsieweke@ovgu.de>
*/
#ifndef TESTS_SHT1X_H
#define TESTS_SHT1X_H
#include "embUnit.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief The entry point of this test suite.
*/
void tests_sht1x(void);
#ifdef __cplusplus
}
#endif
#endif /* TESTS_SHT1X_H */
/** @} */