适用平台

  • STM32、M5311(需电平转换电路)、DA14531 等无特定要求

驱动优势

  • 实现与接口分离(对象封装)
  • 平台移植层分离(GPIO 工作模式)
  • 总线自动管理(总线空闲时低功耗处理)
  • 不同工作电压的矫正系数管理

特别说明

  • 本文件未对 SHT10 做系统性介绍,需要使用者自行查阅规格书了解
  • 使用者仅需要修改 .h 文件中的系统移植层部分

    • 连接的 GPIO (SCK, SDA)
    • SHT10 的工作电压

文件:main.c

#include "bsp_sht10.h"

int main()
{
    float temp = 0.0f;
    float humi = 0.0f;
    float dew_poiusernt = 0.0f;
    
    SHT_HandlerSdef *sht_handler = sht_init();                // 参数初始化
    
    for (;;)
    {
        if (sht_handler->user_getTempAndHumi(&temp, &humi))    // 温湿度读取
        {
            printf("temp:%f, humi:%f\n", temp, humi);
        }
        
        if (sht_handler->user_getDewPoiusernt())            // 露点读取
        {
            printf("DewPoiusernt:%f\n", dew_poiusernt);
        }
    }
}

文件:bsp_sht10.h

#ifndef BSP_SHT10_H
#define BSP_SHT10_H

/** Inlcude --------------------------------------------------*/
#include <stdint.h>

/**
 * @brief 系统移植层
 * @{
 */
#include "gpio.h"

#define SHT10_DATA_PIN  GPIO_PIN_1
#define SHT10_SCK_PIN   GPIO_PIN_0
#define SHT10_DATA_PORT GPIO_PORT_0
#define SHT10_SCK_PORT  GPIO_PORT_0
 
#define SHT10_DATA_H()  GPIO_SetActive(SHT10_DATA_PORT, SHT10_DATA_PIN)
#define SHT10_DATA_L()  GPIO_SetInactive(SHT10_DATA_PORT, SHT10_DATA_PIN)
#define SHT10_DATA_R()  GPIO_GetPinStatus(SHT10_DATA_PORT, SHT10_DATA_PIN)
 
#define SHT10_SCK_H()   GPIO_SetActive(SHT10_SCK_PORT, SHT10_SCK_PIN)
#define SHT10_SCK_L()   GPIO_SetInactive(SHT10_SCK_PORT, SHT10_SCK_PIN)

#define sht10_pinConfig()  {GPIO_ConfigurePin(SHT10_DATA_PORT, SHT10_DATA_PIN, OUTPUT, PID_GPIO, true);GPIO_ConfigurePin(SHT10_SCK_PORT, SHT10_SCK_PIN, OUTPUT, PID_GPIO, true);}
// 总线释放时的低功耗处理
#define sht10_pinRelease() {GPIO_ConfigurePin(SHT10_DATA_PORT, SHT10_DATA_PIN, INPUT, PID_GPIO, false);GPIO_ConfigurePin(SHT10_SCK_PORT, SHT10_SCK_PIN, INPUT, PID_GPIO, false);}
#define sht10_setDataOut() GPIO_ConfigurePin(SHT10_DATA_PORT, SHT10_DATA_PIN, OUTPUT, PID_GPIO, true)
#define sht10_setDataIn()  GPIO_ConfigurePin(SHT10_DATA_PORT, SHT10_DATA_PIN, INPUT_PULLUP, PID_GPIO, false)

/*
__inline void sht10_pinConfig(void)
{
   GPIO_ConfigurePin(SHT10_DATA_PORT, SHT10_DATA_PIN, OUTPUT, PID_GPIO, true);
   GPIO_ConfigurePin(SHT10_SCK_PORT, SHT10_SCK_PIN, OUTPUT, PID_GPIO, true);
}
// 总线释放时的低功耗处理
__inline void sht10_pinRelease(void)
{
    GPIO_ConfigurePin(SHT10_DATA_PORT, SHT10_DATA_PIN, INPUT, PID_SPI_DI, false);
    GPIO_ConfigurePin(SHT10_SCK_PORT, SHT10_SCK_PIN, INPUT, PID_SPI_DI, false);
}

__inline void sht10_setDataOut(void)
{
   GPIO_ConfigurePin(SHT10_DATA_PORT, SHT10_DATA_PIN, OUTPUT, PID_GPIO, true);
}

__inline void sht10_setDataIn(void)
{
    GPIO_ConfigurePin(SHT10_DATA_PORT, SHT10_DATA_PIN, INPUT_PULLUP, PID_GPIO, false);
}
*/

 /**
 * @brief SHT10 当前的工作电压值(影响矫正系数)
 */
//#define SHT10_POWER_LEVEL_5V 
//#define SHT10_POWER_LEVEL_4V 
//#define SHT10_POWER_LEVEL_3_5V 
#define SHT10_POWER_LEVEL_3V 
//#define SHT10_POWER_LEVEL_2_5V 

/**
 * @}
 */

 /**
 * @brief SHT10 handler
 */
typedef struct 
{
    uint8_t (*user_reset)(void);
    uint8_t (*user_getTempAndHumi)(float *temp, float *humi);
    uint8_t (*user_getDewPoiusernt)(float *value);
    
}SHT_HandlerSdef;

/** Export function ------------------------------------*/
SHT_HandlerSdef* sht_init(void);

#endif

文件:bsp_sht10.c

/**
  **************************************************
  *@file    bsp_sht10.c
  *@brief   SHT10 底层驱动文件
  *@version v0.0.1
  *@history
  
    <version>  <data>      <author>  <description>
    v0.0.1     2020/07/06  吴天送    正式发布
    
  *************************************************
  */

/** Inlcude --------------------------------------------------*/
#include "bsp_sht10.h"

#include <math.h>

/**Private macros ----------------------*/
                                      //addr  command     r/w
#define SHT10_STATUS_REG_W    0x06    //000     0011      0
#define SHT10_STATUS_REG_R    0x07    //000     0011      1
#define SHT10_MEASURE_TEMP    0x03    //000     0001      1
#define SHT10_MEASURE_HUMI    0x05    //000     0010      1
#define SHT10_SOFTRESET       0x1E    //000     1111      0

#define SHT10_NOACK    0
#define SHT10_ACK      1

#ifdef SHT10_POWER_LEVEL_5V
const float SHT10_D1 = -40.1;
#elif defined SHT10_POWER_LEVEL_4V
const float SHT10_D1 = -39.8;
#elif defined SHT10_POWER_LEVEL_3_5V
const float SHT10_D1 = -39.7;
#elif defined SHT10_POWER_LEVEL_3V
const float SHT10_D1 = -39.6;
#elif defined SHT10_POWER_LEVEL_2_5V
const float SHT10_D1 = -39.4;
#else
#error "没有指定SHT10工作电压"
#endif

typedef enum 
{
    SHT_Temp = 0u,
    SHT_Humi
    
}SHT_ModeEdef;

/** Pravite function prototypes ------------------------------*/
static uint8_t sht10_writeByte(uint8_t data);
static uint8_t sht10_readByte(uint8_t is_ack);
static void sht10_transStart(void);
static void sht10_conReset(void);
static uint8_t sht10_reset(void);
static uint8_t sht10_measure(uint16_t *p_value, SHT_ModeEdef mode);
static uint8_t sht10_getTempAndHumi(float *temp, float *humi);
static uint8_t get_getDewPoint(float *value);

/** Pravite variable -----------------------------------------*/
static SHT_HandlerSdef g_sht_handler;

/** Applation */

/**
  *@brief  重要数据注册及初始化
  *@param  none
  *@retval none
  */
SHT_HandlerSdef* sht_init(void)
{
    g_sht_handler.user_reset           = sht10_reset;
    g_sht_handler.user_getTempAndHumi  = sht10_getTempAndHumi;
    g_sht_handler.user_getDewPoiusernt = get_getDewPoint;
    
    sht10_reset();
    
    return &g_sht_handler;
}

/**
  *@brief  延时函数 ( > 10us )
  *@param  none
  *@retval none
  */
static void sht10_delay(void)
{
    for (uint16_t i=0; i<100; ++i)
    { }
}

/**
  *@brief  写一个字节
  *@param  data : 要写的字节
  *@retval 0    成功
  *@retval 其它 失败
  */
static uint8_t sht10_writeByte(uint8_t data)
{
    uint8_t ret = 0;
    
    sht10_setDataOut();
 
    for(uint8_t i = 0x80; i > 0; i>>=1)
    {
        if(i & data)
            SHT10_DATA_H();
        else
            SHT10_DATA_L();
        sht10_delay();
        SHT10_SCK_H();
        sht10_delay();
        SHT10_SCK_L();
        sht10_delay();
    }
    
    sht10_setDataIn();
    SHT10_SCK_H();
    ret = SHT10_DATA_R();
    SHT10_SCK_L();
 
    return ret;
}

/**
  *@brief  读取一个字节
  *@param  is_ack : 0 不应答 ; 1 应答
  *@retval 0    成功
  *@retval 其它 失败
  */
static uint8_t sht10_readByte(uint8_t is_ack)
{
    uint8_t ret = 0;
 
    sht10_setDataIn();
    
    for(uint8_t i = 0x80; i > 0; i>>=1)
    {
        sht10_delay();
        SHT10_SCK_H();
        sht10_delay();
        if(SHT10_DATA_R())
            ret |= i;
        SHT10_SCK_L();
    }
    
    sht10_setDataOut();
    if(is_ack)
        SHT10_DATA_L();
    else
        SHT10_DATA_H();
    sht10_delay();
    SHT10_SCK_H();
    sht10_delay();
    SHT10_SCK_L();
    sht10_delay();
 
    return ret;
}

/**
  *@brief  开始传输信号
  *@param  none
  *@retval none
  */
static void sht10_transStart(void)
{
    sht10_setDataOut();
 
    SHT10_DATA_H();
    SHT10_SCK_L();
    sht10_delay();
    SHT10_SCK_H();
    sht10_delay();
    SHT10_DATA_L();
    sht10_delay();
    SHT10_SCK_L();
    sht10_delay();
    SHT10_SCK_H();
    sht10_delay();
    SHT10_DATA_H();
    sht10_delay();
    SHT10_SCK_L();
}

/**
  *@brief  通讯复位
  *@param  none
  *@retval none
  */
static void sht10_conReset(void)
{
    sht10_setDataOut();
 
    SHT10_DATA_H();
    SHT10_SCK_L();
 
    for(uint8_t i = 0; i < 9; i++)
    {
        SHT10_SCK_H();
        sht10_delay();
        SHT10_SCK_L();
        sht10_delay();
    }
    
    sht10_transStart();
}

/**
  *@brief  软复位
  *@param  none
  *@retval 0    成功
  *@retval 其它 失败
  */
static uint8_t sht10_reset(void)
{
    uint8_t ret = 0;
    
    sht10_pinConfig();
    
    sht10_conReset();
    
    ret = sht10_writeByte(SHT10_SOFTRESET);
    
    sht10_pinRelease();
    
    return ret;
}

/**
  *@brief  温/湿度寄存器原始值读取
  *@param  p_value : 数据保存地址
  *@param  mode    : SHT_Temp 温度 ; SHT_Humi 湿度
  *@retval 0    成功
  *@retval 其它 失败
  */
static uint8_t sht10_measure(uint16_t *p_value, SHT_ModeEdef mode)
{
    uint8_t status = 0;
    
    sht10_transStart();
    
    switch(mode)
    {
        case SHT_Temp:
            status = sht10_writeByte(SHT10_MEASURE_TEMP);
        break;
        case SHT_Humi:
            status =sht10_writeByte(SHT10_MEASURE_HUMI);
        break;
    }
    
    sht10_setDataIn();
    
    if (status == 1)
    {
        sht10_conReset();
        return 1;
    }
    
    for(uint32_t i = 0; i < 72000000; ++i) 
        if(SHT10_DATA_R() == 0) break;  
    
    if (SHT10_DATA_R() == 1)
    {
        sht10_conReset();
        return 1;
    }
    
    uint8_t value_H = 0;
    uint8_t value_L = 0;
    
    value_H = sht10_readByte(SHT10_ACK);
    value_L = sht10_readByte(SHT10_ACK);
    
    sht10_readByte(SHT10_NOACK);
    
    *p_value = (value_H << 8) | value_L;
    
    return 0;
}

/**
  *@brief  可读的温湿度读取
  *@param  temp : 温度值
  *@param  humi : 湿度值
  *@retval 0    成功
  *@retval 其它 失败
  */
static uint8_t sht10_getTempAndHumi(float *temp, float *humi)
{
    const float d1 = SHT10_D1;
    const float d2 = +0.01;
    const float C1 = -2.0468;
    const float C2 = +0.0367;
    const float C3 = -0.0000015955;
    const float T1 = +0.01;
    const float T2 = +0.00008;
    
    float rh_line = 0;
    
    uint16_t temp_value_original = 0;
    uint16_t humi_value_original = 0;
    
    sht10_pinConfig();
    
    if ((sht10_measure(&temp_value_original, SHT_Temp) != 0) || (sht10_measure(&humi_value_original, SHT_Humi) != 0))
    {
        sht10_pinRelease();
        return 1;
    }
    
    rh_line = C1 + C2 * humi_value_original + C3 * humi_value_original * humi_value_original;
    
    *temp = d1 + d2 * temp_value_original;
    *humi = (*temp -25) * (T1 + T2 * humi_value_original) + rh_line;
    
    sht10_pinRelease();
    
    return 0;
}

/**
  *@brief  计算露点
  *@param  value : 读取到的露点值
  *@retval 0    成功
  *@retval 其它 失败
  */
static uint8_t get_getDewPoint(float *value)
{
    float temp = 0;
    float humi = 0;
    float logEx =0.0f;
    
    sht10_pinConfig();
    
    if (sht10_getTempAndHumi(&temp, &humi) != 0)
    {
        sht10_pinRelease();
        return 1;
    }
    
    logEx = 0.66077 + 7.5 * temp / (237.3 + temp) + (log10(humi) - 2);
    *value = ((0.66077 - logEx) * 237.3) / (logEx - 8.16077);
    
    sht10_pinRelease();
    
    return 0;
}

TianSong
734 声望138 粉丝

阿里山神木的种子在3000年前已经埋下,今天不过是看到当年注定的结果,为了未来的自己,今天就埋下一颗好种子吧