| 
 
高级会员 
 
	积分566金钱566 注册时间2016-9-28在线时间158 小时 | 
 
| 本帖最后由 mftang2016 于 2024-1-18 15:35 编辑 
 说明: 应用STM32驱动SHT20
 
 I2C 部分驱动参考:http://www.openedv.com/forum.php?mod=viewthread&tid=100058
 
 测试结果:
   
 sht2x.c
 
 复制代码/*******************************************************************************
* LOCAL INCLUDE FILES
*******************************************************************************/
#include "sht2x.h"
/******************************************************************************
* LOCAL MACROS AND DEFINITIONS
******************************************************************************/
#define I2C_ADDRESS         (0x40 << 1)
#define POLY                 0x131;       //P(x)=x^8+x^5+x^4+1 = 100110001
#define DELAY_CNT            4500          //for N32G45, sleep time is 6.4 ms 
static shtOpt s_ShtOpt;
/******************************************************************************
* LOCAL FUNCTION DECLARATIONS
******************************************************************************/
static void i2c_Delay(uint16_t value );
static uint8_t sht2xdrv_CheckCrc(uint8_t data[], uint8_t nbrOfBytes, uint8_t checksum);
static uint8_t sht2xdrv_CheckOk(void);
static int32_t sht2xdrv_CalcTemperatureC(uint16_t u16sT);
static int32_t sht2xdrv_CalcRH(uint16_t u16sRH);
static void i2c_Delay(uint16_t value )
{
    uint16_t i;
    for (i = 0; i < value; i++);
}
static uint8_t sht2xdrv_CheckCrc(uint8_t data[], uint8_t nbrOfBytes, uint8_t checksum)
{
    uint8_t res = 0;
    uint8_t crc = 0;
    uint8_t byteCtr;
    
    //calculates 8-Bit checksum with given polynomial
    for (byteCtr = 0; byteCtr < nbrOfBytes; ++byteCtr)
    {
      crc ^= (data[byteCtr]);
      for (uint8_t bit = 8; bit > 0; --bit)
      {
        if (crc & 0x80)
        {
          crc = (crc << 1) ^ POLY;
        }
        else
        {
          crc = (crc << 1);
        }
      }
    }
    if (crc != checksum)
    {
      res = 1;
    }
    return res;
}
static uint8_t sht2xdrv_CheckOk(void)
{
    if (i2c_CheckDevice( I2C_ADDRESS ) == 0)
    {
         /* sensor is online*/
            return 1;
    }
    else
    {
          /* fail: send stop */
            i2c_Stop();
            return 0;
    }
}
static uint8_t sht2xdrv_ReadUserRegister( uint8_t *pRegisterValue )
{
    uint8_t ret = SHT2x_STATUS_OK;
    uint8_t cmd = USER_REG_R;
    // write address 
    i2c_Start();
    i2c_SendByte( I2C_ADDRESS | I2C_WR );  // Device address 
    if (i2c_WaitAck() != 0)
    {
        goto cmd_fail;
    }
    
    i2c_SendByte( cmd);
    if (i2c_WaitAck() != 0)
    {
        goto cmd_fail;
    }
    
    //Read register value 
    i2c_Start();
    i2c_SendByte(I2C_ADDRESS | I2C_RD);
    if (i2c_WaitAck() != 0)
    {
        goto cmd_fail;
    } 
    
    *pRegisterValue = i2c_ReadByte();
    i2c_NAck();
    
    i2c_Stop();
    return ret;
    
cmd_fail:    
    i2c_Stop();
    ret = SHT2x_STATUS_ERR_BAD_DATA;
    
    return ret;
}
static int32_t sht2xdrv_CalcTemperatureC(uint16_t u16sT)
{
  int32_t temperatureC;       // variable for result
  u16sT &= ~0x0003;           // clear bits [1..0] (status bits)
  /*
     * Formula T = -46.85 + 175.72 * ST / 2^16 from data sheet 6.2,
     * optimized for integer fixed point (3 digits) arithmetic
  */
  temperatureC = (((uint32_t)17572 * u16sT) >> 16) - 4685;
  return (int32_t)temperatureC;
}
static int32_t sht2xdrv_CalcRH(uint16_t u16sRH)
{
  uint32_t humidityRH;       // variable for result
  u16sRH &= ~0x0003;          // clear bits [1..0] (status bits)
  /*
     * Formula RH = -6 + 125 * SRH / 2^16 from data sheet 6.1,
     * optimized for integer fixed point (3 digits) arithmetic
  */
  humidityRH = (((uint32_t)12500 * u16sRH) >> 16) - 600;
  return (int32_t)humidityRH;
}
uint8_t  sht2xdrv_ResetSht2x( void )
{
    uint8_t ret = SHT2x_STATUS_OK;
    uint8_t cmd = SOFT_RESET;
    
    i2c_Start();
    i2c_SendByte( I2C_ADDRESS | I2C_WR );  // Device address 
    if (i2c_WaitAck() != 0)
    {
        goto cmd_fail;
    }
    
    i2c_SendByte( cmd);
    if (i2c_WaitAck() != 0)
    {
        goto cmd_fail;
    }
    
cmd_fail: 
    i2c_Stop();
    ret = SHT2x_STATUS_ERR_TIMEOUT;
    
    return ret;
}
uint8_t  sht2xdrv_GetBatteryStatus(void)
{
  uint8_t reg;
  uint8_t error = SHT2x_STATUS_OK;
  error = sht2xdrv_ReadUserRegister(&174;);
  if (error != SHT2x_STATUS_OK)
  {
    return error;
  }
  return (reg & 0x40);
}
uint8_t sht2xdrv_GetHeaterStatus(void)
{
  uint8_t reg;
  uint8_t error = SHT2x_STATUS_OK;
  error = sht2xdrv_ReadUserRegister(&174;);
  if (error != SHT2x_STATUS_OK)
  {
    return error;
  }
  return (reg & 0x04);
}
uint8_t sht2xdrv_GetResolution(sht2xResolution_t *pResolution)
{
    uint8_t error = SHT2x_STATUS_OK;
    uint8_t reg = 0;
    error = sht2xdrv_ReadUserRegister(&174;);
    if (error != SHT2x_STATUS_OK)
    {
        return error;
    }
    *pResolution = (sht2xResolution_t)(reg & SHT2x_RES_MASK);
    return error;
}
static void sht2xdrv_readVal(uint8_t cmd, shtdrv *pShtdrv )
{
    uint8_t checksum;                   //checksum
    uint8_t data[3] = {0, 0, 0};        //data array for checksum v
    uint8_t cmd_fail = 0;
    
    if(  pShtdrv->finish )
         return;
    
    pShtdrv->ret = SHT2x_STATUS_ERR_BAD_DATA;
    switch( pShtdrv->_step )
    {
        default:
        case 0:
            i2c_Start();
            i2c_SendByte( I2C_ADDRESS | I2C_WR );  // Device address 
            if (i2c_WaitAck() != 0)
            {
                cmd_fail = 1;
                break;
            }
            pShtdrv->_step = 1;
            break;
            
        case 1:
            // send command and prepare to reading data value 
            i2c_SendByte( cmd);
            if (i2c_WaitAck() != 0)
            {
                cmd_fail = 1;
                break;
            }
            pShtdrv->_step = 2;
            pShtdrv->_tryCnt = 0;
            break;
            
        case 2:
           // set the address for reading data 
            i2c_Start();
            i2c_SendByte(I2C_ADDRESS | I2C_RD);
            if (i2c_WaitAck() != 0)
            {
                pShtdrv->_tryCnt ++;
                if( pShtdrv->_tryCnt > 10 )
                {
                    cmd_fail = 1;
                    break;
                }
            }
            pShtdrv->_step = 3;
            pShtdrv->_tryCnt = 0;
            break;
            
        case 3:
            // Notes: convert time must >= 4 ms 
            i2c_Delay( 3 );
            pShtdrv->_tryCnt ++;
            if( pShtdrv->_tryCnt > 4500 )
            {
                pShtdrv->_tryCnt = 0;
                pShtdrv->_step = 4;
            }
            break;
        
        case 4:
            // read sensor's data
            data[0] = i2c_ReadByte();
            i2c_Ack();
            
            data[1] = i2c_ReadByte();
            i2c_Ack();
            
            data[2] = i2c_ReadByte();
            i2c_NAck();
            i2c_Stop();
            
            checksum = data[2];
            pShtdrv->ret = sht2xdrv_CheckCrc(data, 2, checksum);
         
            if ( pShtdrv->ret != SHT2x_STATUS_OK)
            {
                pShtdrv->_step = 2;
                break;
            }
            
            pShtdrv->_binValue = ((uint16_t)data[0] << 8) | data[1];
            pShtdrv->_step = 0;
            pShtdrv->finish = 1;
            break;
    }
    
    if( cmd_fail )
    {
        pShtdrv->finish = 1;
        pShtdrv->_tryCnt =0;
        pShtdrv->_step = 0;
        pShtdrv->ret = SHT2x_STATUS_ERR_BAD_DATA;
        i2c_Stop();
    }
}
static void sht2xdrv_readTempOrRH(  uint8_t cmd, shtdrv *pShtdrv )
{
    switch( cmd )
    {
        case  TRIG_T_MEASUREMENT_HM:
             sht2xdrv_readVal(cmd, pShtdrv);
             if( pShtdrv->ret == SHT2x_STATUS_OK)
             {
                pShtdrv->outValue = sht2xdrv_CalcTemperatureC( pShtdrv->_binValue );
                pShtdrv->dataValid = 1;
             }
            break;
             
        case  TRIG_RH_MEASUREMENT_POLL:
             sht2xdrv_readVal(cmd, pShtdrv);
             if( pShtdrv->ret == SHT2x_STATUS_OK)
             {
                pShtdrv->outValue = sht2xdrv_CalcRH( pShtdrv->_binValue );
                pShtdrv->dataValid = 1;
             }
            break;
    }
}
static void _sht2xdrv_Init( shtOpt *pshtOpt )
{
    sht2xResolution_t sht2xResolutionvalue;
    
    uint8_t _res = sht2xdrv_CheckOk();
    if( _res )
    {
        sht2xdrv_ResetSht2x();
        sht2xdrv_GetBatteryStatus();
        sht2xdrv_GetResolution( &sht2xResolutionvalue );
        return;
    }
    
    pshtOpt->errorCode |= SHT2x_RES_I2C_ERR;
}
/******************************************************************************
* EXPORTED FUNCTIONS
******************************************************************************/
void sht2xdrv_Init( void )
{
   _sht2xdrv_Init( &s_ShtOpt );
}
shtOpt *sht2xdrv_getResult( void )
{
      return &s_ShtOpt;
}
void sht2xdrv_ClearReadFlag( shtdrv *pShtdrv )
{
    pShtdrv->dataValid = 0;
}
void sht2xdrv_readValue( shtOpt *pshtOpt )
{
    static uint8_t _step = TRIG_T_MEASUREMENT_HM;
    shtdrv *pTempData = &pshtOpt->st_Temp;
    shtdrv *pRhData = &pshtOpt->st_RH;
    
    if( pshtOpt ->errorCode & SHT2x_RES_I2C_ERR )
        return;
    
    switch ( _step )
    {
        default:
        case TRIG_T_MEASUREMENT_HM:
            sht2xdrv_readTempOrRH( TRIG_T_MEASUREMENT_HM,pTempData );
            if( pTempData->finish )
            {
               _step = TRIG_RH_MEASUREMENT_POLL;
               pTempData->finish  = 0;
            }
            break;
        case TRIG_RH_MEASUREMENT_POLL:
            sht2xdrv_readTempOrRH( TRIG_RH_MEASUREMENT_POLL, pRhData);
            if( pRhData->finish )
            {
               _step = TRIG_T_MEASUREMENT_HM;
               pRhData->finish  = 0;
            }
            break;
    }
}
void SHT2X_test( void )
{
    sht2xdrv_readValue( &s_ShtOpt );
}
/* End of this file */
sht2x.h
 
 复制代码#ifndef __SHT2X_H
#define __SHT2X_H
/******************************************************************************
* C++ DECLARATION WRAPPER
******************************************************************************/
#ifdef __cplusplus
extern "C" {
#endif
typedef enum sht2xOptErrorCode
{
    SHT2x_RES_I2C_ERR = 0X01,
}sht2xOptErrorCode;
/******************************************************************************
* EXPORTED MACROS AND DEFINITIONS
******************************************************************************/ 
typedef enum sht2xResolution_t
{
  SHT2x_RES_12_14BIT       = 0x00, // RH=12bit, T=14bit
  SHT2x_RES_8_12BIT        = 0x01, // RH= 8bit, T=12bit
  SHT2x_RES_10_13BIT       = 0x80, // RH=10bit, T=13bit
  SHT2x_RES_11_11BIT       = 0x81, // RH=11bit, T=11bit
  SHT2x_RES_MASK           = 0x81  // Mask for res. bits (7,0) in user reg.
} sht2xResolution_t;
typedef enum sht2xStatusCode {
  SHT2x_STATUS_OK                = 0x00,
  SHT2x_STATUS_VALID_DATA        = 0x01,
  SHT2x_STATUS_NO_CHANGE         = 0x02,
  SHT2x_STATUS_ABORTED           = 0x03,
  SHT2x_STATUS_BUSY              = 0x04,
  SHT2x_STATUS_SUSPEND           = 0x05,
  SHT2x_STATUS_ERR_IO            = 0x06,
  SHT2x_STATUS_ERR_BAD_DATA      = 0x07,
  SHT2x_STATUS_ERR_TIMEOUT       = 0x08
}sht2xStatusCode;
// sensor command
typedef enum{
  TRIG_T_MEASUREMENT_HM    = 0xE3, // command trig. temp meas. hold master
  TRIG_RH_MEASUREMENT_HM   = 0xE5, // command trig. humidity meas. hold master
  TRIG_T_MEASUREMENT_POLL  = 0xF3, // command trig. temp meas. no hold master
  TRIG_RH_MEASUREMENT_POLL = 0xF5, // command trig. humidity meas. no hold master
  USER_REG_W               = 0xE6, // command writing user register
  USER_REG_R               = 0xE7, // command reading user register
  SOFT_RESET               = 0xFE  // command soft reset
}sht2xCommand_t;
typedef enum {
  SHT2x_EOB_ON             = 0x40, // end of battery
  SHT2x_EOB_MASK           = 0x40, // Mask for EOB bit(6) in user reg.
} sht2xEob_t;
typedef enum {
  SHT2x_HEATER_ON          = 0x04, // heater on
  SHT2x_HEATER_OFF         = 0x00, // heater off
  SHT2x_HEATER_MASK        = 0x04, // Mask for Heater bit(2) in user reg.
} etSHT2xHeater;
// measurement signal selection
typedef enum{
  HUMIDITY,
  TEMP
}etSHT2xMeasureType;
typedef enum{
  I2C_ADR_W                = 128,   // sensor I2C address + write bit
  I2C_ADR_R                = 129    // sensor I2C address + read bit
}etI2cHeader;
typedef struct {
    uint8_t _step;
    uint8_t ret;
    
    uint8_t finish;     //1: finished, 0: idle
    uint8_t dataValid;  //1: valid, 0: invalid
    
    int32_t _tryCnt;
    int32_t _binValue;   // primordial value from sht20 register 
    int32_t outValue;    // true temperature or humidity
} shtdrv;
typedef struct {
    shtdrv st_Temp;
    shtdrv st_RH;
    int32_t errorCode;
}shtOpt;
/******************************************************************************
* EXPORTED FUNCTIONS
******************************************************************************/
void sht2xdrv_Init( void );
void sht2xdrv_readValue( shtOpt *pshtOpt );
shtOpt *sht2xdrv_getResult( void );
void SHT2X_test( void );
/******************************************************************************
* END OF C++ DECLARATION WRAPPER
******************************************************************************/
#ifdef __cplusplus
}
#endif
#endif /* __SHT2X_H */
 
 | 
 |