Для определения влажности и температуры радиолюбители в своих проектах иногда используют датчик SHT11 от Sensirion. Этот датчик с интерфейсом I2C обладает хорошей точностью измерений, поддерживает широкие диапазоны температуры, относительной влажности и рабочего напряжения.
Проблемой для начинающих может быть настройка связи с вычислительным устройством, например, микроконтроллером. Поэтому ниже предлагается платформонезависимая библиотека, позволяющая общаться с SHT11.
Основная функция здесь представляет собой конечный автомат. Для того, чтобы прочитать с датчика все необходимые данные, в главном цикле должна быть вызвана соответствующая функция. В конце кода имеется пример такого вызова. Для адаптации кода для различных архитектур пользователь должен написать свой заголовочный файл sht_low_level_drv.h. Также он должен обозначить переменную sys_timer_ticks, которая инкрементируется каждую 1 мс.
/*********** начало заголовочного файла библиотеки sht11.h ***************/
#ifndef _SHTXX_H
#define _SHTXX_H
#include <inttypes.h>
#define HUMIDITY_BYTE 0x05
#define TEMPERATURE_BYTE 0x03
//State machine states
#define SHT_DATA_WAIT_INITIAL_STATE 0
#define SHT_DATA_WAIT_TIMEOUT_STATE 1
#define SHT_PROC_RESET_COND_STATE 0
#define SHT_PROC_START_COND_STATE 1
#define SHT_PROC_SEND_STATE 2
#define SHT_PROC_WAIT_STATE 3
#define SHT_PROC_RETURN_STATE 4
#define SHT_RH_READ_TEMPERATURE_STATE 0
#define SHT_RH_READ_HUMIDITY_STATE 1
#define SHT_RH_CONVERT_RH_STATE 2
#include <sht_low_level_drv.h>
void shtxx_init(void);
int shtxx_proc(uint8_t sht_param,uint16_t *ret_value);
int shtxx_get_temp(uint16_t *ret_temperature);
int shtxx_get_temp_RH( int16_t *ret_temperature, int16_t *ret_humidity );
#endif /* _SHTXX_H */
/*********** начало файла с исходным кодом библиотеки sht11.c ***************/
#include "sht11.h"
void shtxx_init( void )
{
shtxx_set_db();
shtxx_set_cb();
}
void shtxx_wait( void ) //SHT_WAIT должен быть настроен в соответствии с тактированием МК
{
volatile int wait_cnt;
for ( wait_cnt = 0; wait_cnt < SHT_WAIT;wait_cnt )
{
wait_cnt++;
}
}
void shtxx_reset_condition( void )
{
uint8_t i;
shtxx_set_db();
shtxx_set_out_data_dir();
for ( i = 0;i < 12;i++ )
{
if ( i % 2 == 0 )
shtxx_set_cb();
else
shtxx_clr_cb();
shtxx_wait();
}
}
void shtxx_start_condition( void )
{
shtxx_set_db();
shtxx_set_out_data_dir();
shtxx_wait();
shtxx_set_cb();
shtxx_wait();
shtxx_clr_db();
shtxx_wait();
shtxx_clr_cb();
shtxx_wait();
shtxx_wait();
shtxx_set_cb();
shtxx_wait();
shtxx_set_db();
shtxx_wait();
shtxx_clr_cb();
shtxx_wait();
}
int shtxx_send_byte( uint8_t sht_data2send )
{
uint8_t i = 0;
while ( i <= 7 )
{
if ( ( ( sht_data2send << i++ ) & 0x80 ) == 0x80 )
shtxx_set_db();
else
shtxx_clr_db();
shtxx_set_out_data_dir();
shtxx_wait();
shtxx_set_cb();
shtxx_wait();
shtxx_clr_cb();
}
shtxx_set_in_data_dir();
shtxx_wait();
shtxx_set_cb();
shtxx_wait();
if ( shtxx_get_db() == 0 )
return 1;
else
return -1;
}
int shtxx_data_wait( sht_ticks_t sht_timeout )
{
static uint8_t sht_wait_state;
static sht_ticks_t sht_previous_ticks;
switch ( sht_wait_state )
{
case SHT_DATA_WAIT_INITIAL_STATE:
sht_previous_ticks = sht_msec_ticks;
sht_wait_state = SHT_DATA_WAIT_TIMEOUT_STATE;
shtxx_set_in_data_dir();
shtxx_clr_cb();
case SHT_DATA_WAIT_TIMEOUT_STATE:
if ( shtxx_get_db() == 0 )
{
sht_wait_state = SHT_DATA_WAIT_INITIAL_STATE;
return 1;
}
else
{
if ( ( sht_msec_ticks - sht_previous_ticks ) > sht_timeout )
{
sht_wait_state = SHT_DATA_WAIT_INITIAL_STATE;
return -1;
}
else
return 0;
}
}
}
uint8_t sht_read_byte( uint8_t sht_ack )
{
shtxx_set_in_data_dir();
uint8_t temp_rx_buff = 0;
int8_t i = 7;
while ( i >= 0 )
{
shtxx_wait();
shtxx_set_cb();
temp_rx_buff |= ( ( shtxx_get_db() & 0x01 ) << i );
i--;
shtxx_wait();
shtxx_clr_cb();
}
if ( sht_ack == 1 )
{
shtxx_clr_db();
shtxx_set_out_data_dir();
shtxx_wait();
shtxx_set_cb();
shtxx_wait();
shtxx_clr_cb();
shtxx_set_in_data_dir();
}
return temp_rx_buff;
}
int shtxx_proc( uint8_t sht_param, uint16_t *ret_value )
{
static uint8_t sht_proc_state = 0;
int8_t wait_status;
switch ( sht_proc_state )
{
case SHT_PROC_RESET_COND_STATE:
shtxx_reset_condition();
case SHT_PROC_START_COND_STATE:
shtxx_start_condition();
case SHT_PROC_SEND_STATE:
shtxx_send_byte( sht_param );
case SHT_PROC_WAIT_STATE:
wait_status = shtxx_data_wait( 300 );
if ( wait_status == -1 )
{
sht_proc_state = SHT_PROC_RESET_COND_STATE;
return -1;
}
if ( wait_status == 0 )
{
sht_proc_state = SHT_PROC_WAIT_STATE;
return 0;
}
else
sht_proc_state = SHT_PROC_RETURN_STATE;
case SHT_PROC_RETURN_STATE:
*ret_value = ( ( uint16_t ) sht_read_byte( 1 ) << 8 );
shtxx_wait();
*ret_value += sht_read_byte( 0 );
sht_proc_state = SHT_PROC_START_COND_STATE;
return 1;
}
}
int shtxx_get_temp( uint16_t *ret_temperature )
{
static uint16_t tmp_temp;
if ( shtxx_proc( TEMPERATURE_BYTE, &tmp_temp ) == 1 )
{
*ret_temperature = tmp_temp - 3965;
return 1;
}
else
return 0;
}
int shtxx_get_temp_RH( int16_t *ret_temperature, int16_t *ret_humidity )
{
static uint8_t sht_humidity_state;
static uint16_t sht_humidity_raw;
static uint16_t sht_temp_C;
static float RH_linear;
static float RH_compensated;
switch ( sht_humidity_state )
{
case SHT_RH_READ_TEMPERATURE_STATE:
if ( shtxx_get_temp( &sht_temp_C ) )
sht_humidity_state = SHT_RH_READ_HUMIDITY_STATE;
break;
case SHT_RH_READ_HUMIDITY_STATE:
if ( shtxx_proc( HUMIDITY_BYTE, &sht_humidity_raw ) )
sht_humidity_state = SHT_RH_CONVERT_RH_STATE;
break;
case SHT_RH_CONVERT_RH_STATE:
RH_linear = ( float ) ( ( 0.0405 * ( float ) sht_humidity_raw ) - ( 0.0000028 * ( float ) sht_humidity_raw * ( float ) sht_humidity_raw ) - 4 );
RH_compensated = ( float ) ( ( ( ( ( ( float ) sht_temp_C ) / 100 ) - 25 ) * ( 0.01 + ( 0.00008 * ( float ) sht_humidity_raw ) ) ) + RH_linear );
sht_humidity_state = SHT_RH_READ_TEMPERATURE_STATE;
*ret_temperature = sht_temp_C;
*ret_humidity = ( ( int16_t ) ( RH_compensated * 100 ) );
return 1;
default:
sht_humidity_state = SHT_RH_READ_TEMPERATURE_STATE;
}
return 0;
}
/*** пример низкоуровневого определения (платформозависимо) sht_low_level_drv.h ***/
#ifndef _SHT_LOW_LEVEL_DRV_H
#define _SHT_LOW_LEVEL_DRV_H
#include <types.h>
#include <system_def.h> /* должны быть определены HW, SHT_PORT, SHT_DATA_BIT*/
#define SHT_MAX_CLK 100000
#define SHT_WAIT (CCLK/SHT_MAX_CLK) /* CCLK определяется тактируемой частотой */
#define sht_ticks_t uint32_t
#define sht_msec_ticks sys_timer_ticks /* эта переменная должна быть определена в BSP и инкрементироваться каждую мс*/
static inline void shtxx_set_db(void)
{
SET_OUT_PIN(SHT_PORT,SHT_DATA_BIT);
}
static inline void shtxx_clr_db(void)
{
CLR_OUT_PIN(SHT_PORT,SHT_DATA_BIT);
}
static inline void shtxx_set_cb(void)
{
SET_OUT_PIN(SHT_PORT,SHT_CLK_BIT);
}
static inline void shtxx_clr_cb(void)
{
CLR_OUT_PIN(SHT_PORT,SHT_CLK_BIT);
}
static inline uint8_t shtxx_get_db(void)
{
return( GET_IN_PIN(SHT_PORT,SHT_DATA_BIT) );
}
static inline void shtxx_set_in_data_dir(void)
{
IO0DIR &=~(SHT_DATA_BIT);
}
static inline void shtxx_set_out_data_dir(void)
{
IO0DIR |= SHT_DATA_BIT ;
}
#endif /* _SHT_LOW_LEVEL_DRV_H */
/********************* пример использования в основной программе ************************/
//..............
int16_t temperature, humidity;
while(1) //основной цикл пользовательской программы
{
if (shtxx_get_temp_RH( &temperature, &humidity )
{
//выполняем задачи
}
//выполняем прочие операции
//.....................
}
Перевод © digitrode.ru