1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2024-12-29 04:50:03 +01:00
RIOT/drivers/sht11/sht11.c

355 lines
8.3 KiB
C
Raw Normal View History

/*
* 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 sht11 SHT11
* @ingroup drivers
* @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 "hwtimer.h"
#include "mutex.h"
#include "sht11.h"
#include "sht11-board.h"
#include "bitarithm.h"
2010-11-05 22:04:11 +01:00
float sht11_temperature_offset;
/**
* @brief Perform measurement
2013-06-21 22:36:48 +02:00
*
* @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);
2013-06-21 22:36:48 +02:00
/**
* @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);
/**
2013-06-21 22:36:48 +02:00
* @brief Toggle the clock line
*/
static inline void clk_signal(void);
/* mutex for exclusive measurement operation */
mutex_t sht11_mutex = MUTEX_INIT;
/*---------------------------------------------------------------------------*/
2013-06-21 22:36:48 +02:00
static inline void clk_signal(void)
{
SHT11_SCK_HIGH;
hwtimer_wait(SHT11_CLK_WAIT);
SHT11_SCK_LOW;
hwtimer_wait(SHT11_CLK_WAIT);
}
/*---------------------------------------------------------------------------*/
static uint8_t write_byte(uint8_t value)
{
2013-06-21 22:36:48 +02:00
uint8_t i;
uint8_t ack;
SHT11_DATA_OUT;
2013-06-21 22:36:48 +02:00
/* send value bit by bit to sht11 */
for (i = 0; i < 8; i++) {
if (value & BIT7) {
2013-06-21 22:36:48 +02:00
SHT11_DATA_HIGH;
hwtimer_wait(SHT11_DATA_WAIT);
2013-06-21 22:36:48 +02:00
}
else {
SHT11_DATA_LOW;
hwtimer_wait(SHT11_DATA_WAIT);
2013-06-21 22:36:48 +02:00
}
/* trigger clock signal */
clk_signal();
/* shift value to write next bit */
2013-06-21 22:36:48 +02:00
value = value << 1;
}
/* wait for ack */
2013-06-21 22:36:48 +02:00
SHT11_DATA_IN;
hwtimer_wait(SHT11_CLK_WAIT);
2013-06-21 22:36:48 +02:00
ack = SHT11_DATA;
clk_signal();
2013-06-21 22:36:48 +02:00
return ack;
}
/*---------------------------------------------------------------------------*/
2013-06-21 22:36:48 +02:00
static uint8_t read_byte(uint8_t ack)
{
2013-06-21 22:36:48 +02:00
uint8_t i;
uint8_t value = 0;
2013-06-21 22:36:48 +02:00
SHT11_DATA_IN;
hwtimer_wait(SHT11_DATA_WAIT);
2013-06-21 22:36:48 +02:00
/* read value bit by bit */
for (i = 0; i < 8; i++) {
2013-06-21 22:36:48 +02:00
value = value << 1;
SHT11_SCK_HIGH;
hwtimer_wait(SHT11_CLK_WAIT);
if (SHT11_DATA) {
/* increase data by one when DATA is high */
value++;
}
2013-06-21 22:36:48 +02:00
SHT11_SCK_LOW;
hwtimer_wait(SHT11_CLK_WAIT);
2013-06-21 22:36:48 +02:00
}
/* send ack if necessary */
2013-06-21 22:36:48 +02:00
SHT11_DATA_OUT;
if (ack) {
2013-06-21 22:36:48 +02:00
SHT11_DATA_LOW;
hwtimer_wait(SHT11_DATA_WAIT);
2013-06-21 22:36:48 +02:00
}
else {
SHT11_DATA_HIGH;
hwtimer_wait(SHT11_DATA_WAIT);
2013-06-21 22:36:48 +02:00
}
clk_signal();
/* release data line */
2013-06-21 22:36:48 +02:00
SHT11_DATA_IN;
2013-06-21 22:36:48 +02:00
return value;
}
/*---------------------------------------------------------------------------*/
static void transmission_start(void)
{
/* _____ ________
2013-06-21 22:36:48 +02:00
DATA: |_______|
___ ___
SCK : ___| |___| |______
*/
SHT11_DATA_OUT;
/* set initial state */
2013-06-21 22:36:48 +02:00
SHT11_DATA_HIGH;
hwtimer_wait(SHT11_DATA_WAIT);
2013-06-21 22:36:48 +02:00
SHT11_SCK_LOW;
hwtimer_wait(SHT11_CLK_WAIT);
2013-06-21 22:36:48 +02:00
SHT11_SCK_HIGH;
hwtimer_wait(SHT11_CLK_WAIT);
2013-06-21 22:36:48 +02:00
SHT11_DATA_LOW;
hwtimer_wait(SHT11_DATA_WAIT);
2013-06-21 22:36:48 +02:00
SHT11_SCK_LOW;
hwtimer_wait(SHT11_CLK_WAIT);
2013-06-21 22:36:48 +02:00
SHT11_SCK_HIGH;
hwtimer_wait(SHT11_CLK_WAIT);
2013-06-21 22:36:48 +02:00
SHT11_DATA_HIGH;
hwtimer_wait(SHT11_DATA_WAIT);
2013-06-21 22:36:48 +02:00
SHT11_SCK_LOW;
hwtimer_wait(SHT11_CLK_WAIT);
}
/*---------------------------------------------------------------------------*/
static void connection_reset(void)
{
2013-06-21 22:36:48 +02:00
/* _____________________________________________________ ____
DATA: |_______|
_ _ _ _ _ _ _ _ _ ___ ___
SCK : __| |__| |__| |__| |__| |__| |__| |__| |__| |______| |___| |__
*/
uint8_t i;
2013-06-21 22:36:48 +02:00
SHT11_DATA_HIGH;
hwtimer_wait(SHT11_DATA_WAIT);
SHT11_SCK_LOW;
hwtimer_wait(SHT11_CLK_WAIT);
2013-06-21 22:36:48 +02:00
for (i = 0; i < 9; i++) {
clk_signal();
2013-06-21 22:36:48 +02:00
}
transmission_start();
}
/*---------------------------------------------------------------------------*/
static uint8_t measure(uint8_t *p_value, uint8_t *p_checksum, uint8_t mode)
{
2013-06-21 22:36:48 +02:00
uint8_t error = 0;
uint8_t ack = 1;
uint16_t i;
transmission_start();
2013-06-21 22:36:48 +02:00
error = write_byte(mode);
hwtimer_wait(HWTIMER_TICKS(1000));
/* wait untile sensor has finished measurement or timeout */
for (i = 0; (i < SHT11_MEASURE_TIMEOUT) && (!error); i++) {
2013-06-21 22:36:48 +02:00
ack = SHT11_DATA;
if (!ack) {
2013-06-21 22:36:48 +02:00
break;
}
2013-06-21 22:36:48 +02:00
hwtimer_wait(HWTIMER_TICKS(1000));
2013-06-21 22:36:48 +02:00
}
error += ack;
/* read MSB */
2013-06-21 22:36:48 +02:00
*(p_value + 1) = read_byte(SHT11_ACK);
/* read LSB */
2013-06-21 22:36:48 +02:00
*(p_value) = read_byte(SHT11_ACK);
/* read checksum */
*p_checksum = read_byte(SHT11_NO_ACK);
2013-06-21 22:36:48 +02:00
return (!error);
}
/*---------------------------------------------------------------------------*/
2013-06-21 22:36:48 +02:00
void sht11_init(void)
{
sht11_temperature_offset = 0;
SHT11_INIT;
hwtimer_wait(11 * HWTIMER_TICKS(1000));
}
/*---------------------------------------------------------------------------*/
2013-06-21 22:36:48 +02:00
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);
}
/*---------------------------------------------------------------------------*/
2013-06-21 22:36:48 +02:00
uint8_t sht11_write_status(uint8_t *p_value)
{
uint8_t error = 0;
2013-06-21 22:36:48 +02:00
transmission_start();
error += write_byte(SHT11_STATUS_REG_W);
error += write_byte(*p_value);
return (!error);
}
/*---------------------------------------------------------------------------*/
2013-06-21 22:36:48 +02:00
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;
2013-06-21 22:36:48 +02:00
/* Temperature arithmetic where S0(T) is read value
* T = D1 + D2 * S0(T) */
2013-06-21 22:36:48 +02:00
const float D1 = -39.6;
const float D2 = 0.01;
2013-06-21 22:36:48 +02:00
/* Arithmetic for linear humdity where S0(RH) is read value
* HL = C1 + C2 * S0(RH) + C3 * SO(RH)^2 */
2013-06-21 22:36:48 +02:00
const float C1 = -4.0;
const float C2 = +0.0405;
const float C3 = -0.0000028;
2013-06-21 22:36:48 +02:00
/* Arithmetic for temperature compesated relative humdity
* HT = (T-25) * ( T1 + T2 * SO(RH) ) + HL */
2013-06-21 22:36:48 +02:00
const float T1 = +0.01;
const float T2 = +0.00008;
/* check for valid buffer */
if (value == NULL) {
return 0;
}
2013-06-21 22:36:48 +02:00
value->temperature = 0;
value->relhum = 0;
value->relhum_temp = 0;
2013-06-21 22:36:48 +02:00
mutex_lock(&sht11_mutex);
connection_reset();
/* measure humidity */
if (mode & HUMIDITY) {
2013-06-21 22:36:48 +02:00
error += (!measure((uint8_t *) &humi_int, &checksum, SHT11_MEASURE_HUMI));
}
/* measure temperature */
if (mode & TEMPERATURE) {
2013-06-21 22:36:48 +02:00
error += (!measure((uint8_t *) &temp_int, &checksum, SHT11_MEASURE_TEMP));
}
/* break on error */
if (error != 0) {
2013-06-21 22:36:48 +02:00
connection_reset();
mutex_unlock(&sht11_mutex);
2013-06-21 22:36:48 +02:00
return 0;
}
if (mode & TEMPERATURE) {
2013-06-21 22:36:48 +02:00
value->temperature = D1 + (D2 * ((float) temp_int)) + sht11_temperature_offset;
}
if (mode & HUMIDITY) {
2013-06-21 22:36:48 +02:00
value->relhum = C1 + (C2 * ((float) humi_int)) + (C3 * ((float) humi_int) * ((float) humi_int));
if (mode & TEMPERATURE) {
2013-06-21 22:36:48 +02:00
value->relhum_temp = (value->temperature - 25) * (T1 + (T2 * (float) humi_int)) + value->relhum;
}
}
mutex_unlock(&sht11_mutex);
2013-06-21 22:36:48 +02:00
return 1;
}
/** @} */