溫溼度傳感器驅動SHT85 單片機STM32 HAL庫

  • 功能介紹:讀取傳感器SHT85數據,轉換成溫度、溼度 、飽和水蒸氣含量。
  • 注意事項: 
  1. SDA腳設置爲開漏輸出,外部上拉電阻10k。或者設置成推輓,軟件切換SDA輸入輸出。
  2. 調試時可適當加長延時時間。
  3. 在while(1)循環之前調用 TH_Class_SHT85.init(),每隔1S調用一次TH_Class_SHT85.loop()。

SHT85.h

#ifndef __SHT85_H__
#define __SHT85_H__
#include "main.h"

#define CRC_POLYNOMIAL  0x131 // P(x) = x^8 + x^5 + x^4 + 1 = 100110001
#define I2C_ADDR        0x44  //SHT85地址

/****************************錯誤碼***************************/
#define NO_ERROR        0x00
#define ACK_ERROR       0x01
#define CHECKSUM_ERROR  0x02
#define TIMEOUT_ERROR   0x04


/****************************IIC錯誤碼***************************/
typedef enum{
  ACK    = 0,
  NO_ACK = 1,
}etI2cAck;

/****************************CMD定義***************************/
typedef enum {
  CMD_READ_SERIALNBR = 0x3780, // read serial number
  CMD_READ_STATUS    = 0xF32D, // read status register
  CMD_CLEAR_STATUS   = 0x3041, // clear status register
  CMD_HEATER_ENABLE  = 0x306D, // enabled heater
  CMD_HEATER_DISABLE = 0x3066, // disable heater
  CMD_SOFT_RESET     = 0x30A2, // soft reset
  CMD_MEAS_SINGLE_H  = 0x2400, // single meas., high repeatability
  CMD_MEAS_SINGLE_M  = 0x240B, // single meas., medium repeatability
  CMD_MEAS_SINGLE_L  = 0x2416, // single meas., low repeatability
  CMD_MEAS_PERI_05_H = 0x2032, // periodic meas. 0.5 mps, high repeatability
  CMD_MEAS_PERI_05_M = 0x2024, // periodic meas. 0.5 mps, medium repeatability
  CMD_MEAS_PERI_05_L = 0x202F, // periodic meas. 0.5 mps, low repeatability
  CMD_MEAS_PERI_1_H  = 0x2130, // periodic meas. 1 mps, high repeatability
  CMD_MEAS_PERI_1_M  = 0x2126, // periodic meas. 1 mps, medium repeatability
  CMD_MEAS_PERI_1_L  = 0x212D, // periodic meas. 1 mps, low repeatability
  CMD_MEAS_PERI_2_H  = 0x2236, // periodic meas. 2 mps, high repeatability
  CMD_MEAS_PERI_2_M  = 0x2220, // periodic meas. 2 mps, medium repeatability
  CMD_MEAS_PERI_2_L  = 0x222B, // periodic meas. 2 mps, low repeatability
  CMD_MEAS_PERI_4_H  = 0x2334, // periodic meas. 4 mps, high repeatability
  CMD_MEAS_PERI_4_M  = 0x2322, // periodic meas. 4 mps, medium repeatability
  CMD_MEAS_PERI_4_L  = 0x2329, // periodic meas. 4 mps, low repeatability
  CMD_MEAS_PERI_10_H = 0x2737, // periodic meas. 10 mps, high repeatability
  CMD_MEAS_PERI_10_M = 0x2721, // periodic meas. 10 mps, medium repeatability
  CMD_MEAS_PERI_10_L = 0x272A, // periodic meas. 10 mps, low repeatability
  CMD_FETCH_DATA     = 0xE000, // readout measurements for periodic mode
  CMD_BREAK          = 0x3093, // stop periodic measurement
}etCommands;

// Single Shot Measurement Repeatability
typedef enum {
  SINGLE_MEAS_LOW        = CMD_MEAS_SINGLE_L, // low repeatability
  SINGLE_MEAS_MEDIUM     = CMD_MEAS_SINGLE_M, // medium repeatability
  SINGLE_MEAS_HIGH       = CMD_MEAS_SINGLE_H  // high repeatability
}etSingleMeasureModes;

// Periodic Measurement Configurations
typedef enum {
  PERI_MEAS_LOW_05_HZ    = CMD_MEAS_PERI_05_L,
  PERI_MEAS_LOW_1_HZ     = CMD_MEAS_PERI_1_L,
  PERI_MEAS_LOW_2_HZ     = CMD_MEAS_PERI_2_L,
  PERI_MEAS_LOW_4_HZ     = CMD_MEAS_PERI_4_L,
  PERI_MEAS_LOW_10_HZ    = CMD_MEAS_PERI_10_L,
  PERI_MEAS_MEDIUM_05_HZ = CMD_MEAS_PERI_05_M,
  PERI_MEAS_MEDIUM_1_HZ  = CMD_MEAS_PERI_1_M,
  PERI_MEAS_MEDIUM_2_HZ  = CMD_MEAS_PERI_2_M,
  PERI_MEAS_MEDIUM_4_HZ  = CMD_MEAS_PERI_4_M,
  PERI_MEAS_MEDIUM_10_HZ = CMD_MEAS_PERI_10_M,
  PERI_MEAS_HIGH_05_HZ   = CMD_MEAS_PERI_05_H,
  PERI_MEAS_HIGH_1_HZ    = CMD_MEAS_PERI_1_H,
  PERI_MEAS_HIGH_2_HZ    = CMD_MEAS_PERI_2_H,
  PERI_MEAS_HIGH_4_HZ    = CMD_MEAS_PERI_4_H,
  PERI_MEAS_HIGH_10_HZ   = CMD_MEAS_PERI_10_H,
}etPeriodicMeasureModes;


/****************************溫溼度傳感器結構體定義**************************/
typedef struct _TH_Class{
  u32 SerialNumber;//傳感器SN號
  float Temperature;//溫度
  float Humidity;//相對溼度
  float H2O;//絕對溼度

  void (*init)(void);//初始化函數指針
  void (*loop)(void);//loop函數指針,循環讀取溫溼度,週期:1S
}TH_Class_t;

extern TH_Class_t TH_Class_SHT85;


#endif

SHT85.c 

/********************************************
*Filename:       SHT85.c
*Revised:        Date: 06-22 14:42
*Author:         SYMBEL
*Description:    SHT85驅動
*********************************************/
#include "SHT85.h"
#include <stdbool.h>

/****************************IIC引腳定義**************************/
#define SHT85_SCL(x) HAL_GPIO_WritePin(SHT85_SCK_GPIO_Port, SHT85_SCK_Pin, x?GPIO_PIN_SET:GPIO_PIN_RESET)
#define SHT85_SDA(x) HAL_GPIO_WritePin(SHT85_SDA_GPIO_Port, SHT85_SDA_Pin, x?GPIO_PIN_SET:GPIO_PIN_RESET)
#define IS_SHT85_SDA() HAL_GPIO_ReadPin(SHT85_SDA_GPIO_Port, SHT85_SDA_Pin) //讀取SDA腳電平
/****************************IIC引腳定義**************************/

/*****************************函數聲明***************************/
static u8 StartWriteAccess(void);
static u8 StartReadAccess(void);
static void StopAccess(void);
static u8 WriteCommand(etCommands command);
static u8 Read2BytesAndCrc(uint16_t* data, bool finAck, uint8_t timeout);
static uint8_t CalcCrc(uint8_t data[], uint8_t nbrOfBytes);
static u8 CheckCrc(uint8_t data[], uint8_t nbrOfBytes, uint8_t checksum);
static float CalcTemperature(uint16_t rawValue);
static float CalcHumidity(uint16_t rawValue);
void SHT85_Init(void);
void SHT85_FSM(void);

/****************************結構體初始化**************************/
TH_Class_t TH_Class_SHT85 = {
  .SerialNumber = 0,
  .Temperature = 0.0f,
  .Humidity = 0.0f,
  .H2O = 0.0f,
  .init = SHT85_Init,
  .loop = SHT85_FSM,
};


/**********************************************************
*函數:DelayUs
*功能:延時1us
*參數:us:延時時間 單位:us
*返回:無
*描述:無
**********************************************************/
static void DelayUs(u32 us)
{
  for(int i=0; i<us; i++){
    __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
    __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
    __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
    __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
    __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
    __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
    __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
    __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
    __NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();__NOP();
  }
}

static void I2c_StartCondition(void)
{
	SHT85_SDA(1);
	SHT85_SCL(1);
	DelayUs(3);
	SHT85_SDA(0);
	DelayUs(3);
	SHT85_SCL(0);
	DelayUs(3);
}

static void I2c_StopCondition(void)
{
	SHT85_SDA(0);
	SHT85_SCL(0);
	DelayUs(2);
	SHT85_SCL(1);
	DelayUs(3);
	SHT85_SDA(1);
	DelayUs(3);
}

static u8 I2c_WriteByte(uint8_t txByte)
{
  uint8_t mask,error=0,i;
//  SHT85_SDA(0);
  for(i=1;i<20;i++); 
  for(mask=0x80; mask>0; mask>>=1)//shift bit for masking (8 times)
  { 
    if ((mask & txByte) == 0) 
      SHT85_SDA(0);        //masking txByte, write bit to SDA-Line
    else 
      SHT85_SDA(1);
    DelayUs(1);     //data hold time(t_HD;DAT)
    SHT85_SCL(1);           //generate clock pulse on SCL
    DelayUs(1);     //data set-up time (t_SU;DAT)
    SHT85_SCL(0);
    DelayUs(1);     //SCL high time (t_HIGH)
  }
  error = IS_SHT85_SDA();             //release SDA-line
  SHT85_SCL(1);             //clk #9 for ack
  DelayUs(1);       //data set-up time (t_SU;DAT)

  error = IS_SHT85_SDA();

  SHT85_SCL(0);
  DelayUs(3);       //wait time to see byte package on scope
  return error;           //return error code
}

static uint8_t I2c_ReadByte(etI2cAck ack)
{
	uint8_t mask,rxByte=0,i,rxb;

  SHT85_SDA(1);

	rxb = IS_SHT85_SDA(); 						//release SDA-line
	for(i=1;i<20;i++); 
	for(mask=0x80; mask>0; mask>>=1)//shift bit for masking (8 times)
	{ 
		SHT85_SCL(1); 					//start clock on SCL-line
		DelayUs(2); 		//data set-up time (t_SU;DAT)
		rxb = IS_SHT85_SDA();
		if(rxb) 
			rxByte=(rxByte | mask); //read bit
		SHT85_SCL(0);
		DelayUs(2); 		//data hold time(t_HD;DAT)
	}
	if(ack == ACK)
		SHT85_SDA(0);
	else
		SHT85_SDA(1);
	DelayUs(2); 			//data set-up time (t_SU;DAT)
	SHT85_SCL(1); 						//clk #9 for ack
	DelayUs(5); 			//SCL high time (t_HIGH)
	SHT85_SCL(0);
	//SHT85_SDA(1); 						//release SDA-line
	DelayUs(2); 			//wait time to see byte package on scope
	
	return rxByte; //return error code
}

u8 I2c_GeneralCallReset(void)
{
  u8 error;
  
  I2c_StartCondition();
  error = I2c_WriteByte(0x00);
  if(error == NO_ERROR) {
    error = I2c_WriteByte(0x06);
  }
  return error;
}

u8 SHT85_ReadSerialNumber(uint32_t* serialNumber)
{
  u8 error; // error code
  uint16_t serialNumWords[2];
  error = StartWriteAccess();
  // write "read serial number" command
  if(error == NO_ERROR) {
    error = WriteCommand(CMD_READ_SERIALNBR);
  }
  // if no error, start read access
  if(error == NO_ERROR) {
    error = StartReadAccess();
  }
  // if no error, read first serial number word
  if(error == NO_ERROR) {
    error = Read2BytesAndCrc(&serialNumWords[0], true, 100);
  }
  // if no error, read second serial number word
  if(error == NO_ERROR) {
    error = Read2BytesAndCrc(&serialNumWords[1], false, 0);
  }
  StopAccess();
  // if no error, calc serial number as 32-bit integer
  if(error == NO_ERROR) {
    *serialNumber = (serialNumWords[0] << 16) | serialNumWords[1];
  }
  return error;
}

u8 SHT85_ReadStatus(uint16_t* status)
{
  u8 error; // error code
  error = StartWriteAccess();
  // if no error, write "read status" command
  if(error == NO_ERROR) {
    error = WriteCommand(CMD_READ_STATUS);
  }
  // if no error, start read access
  if(error == NO_ERROR) {
    error = StartReadAccess();
  }
  // if no error, read status
  if(error == NO_ERROR) {
    error = Read2BytesAndCrc(status, false, 0);
  }
  StopAccess();
  return error;
}

u8 SHT85_ClearAllAlertFlags(void)
{
  u8 error; // error code
  error = StartWriteAccess();
  // if no error, write clear status register command
  if(error == NO_ERROR) {
    error = WriteCommand(CMD_CLEAR_STATUS);
  }
  StopAccess();
  return error;
}

u8 SHT85_SingleMeasurment(float* temperature, float* humidity, etSingleMeasureModes measureMode, uint8_t timeout)
{
  u8  error;           // error code
  uint16_t rawValueTemp;    // temperature raw value from sensor
  uint16_t rawValueHumi;    // humidity raw value from sensor
  error  = StartWriteAccess();
  // if no error
  if(error == NO_ERROR) {
    // start measurement
    error = WriteCommand((etCommands)measureMode);
  }
  // if no error, wait until measurement ready
  if(error == NO_ERROR) {
    // poll every 1ms for measurement ready until timeout
    while(timeout--) {
      // check if the measurement has finished
      error = StartReadAccess();
      // if measurement has finished -> exit loop
      if(error == NO_ERROR) break;
      // delay 1ms
      DelayUs(1000);
    }
    // check for timeout error
    if(timeout == 0) {
      error = TIMEOUT_ERROR;
    }
  }
  // if no error, read temperature and humidity raw values
  if(error == NO_ERROR) {
    error |= Read2BytesAndCrc(&rawValueTemp, true, 0);
    error |= Read2BytesAndCrc(&rawValueHumi, false, 0);
  }
  StopAccess();
  // if no error, calculate temperature in °C and humidity in %RH
  if(error == NO_ERROR) {
    *temperature = CalcTemperature(rawValueTemp);
    *humidity = CalcHumidity(rawValueHumi);
  }
  return error;
}

u8 SHT85_StartPeriodicMeasurment(etPeriodicMeasureModes measureMode)
{
  u8 error; // error code
  
  error = StartWriteAccess();
  // if no error, start periodic measurement 
  if(error == NO_ERROR) {
    error = WriteCommand((etCommands)measureMode);
  }
  StopAccess();
  return error;
}

u8 SHT85_StopPeriodicMeasurment(void)
{
  u8 error; // error code
  error = StartWriteAccess();
  // if no error, write breake command
  if(error == NO_ERROR) {
    error = WriteCommand(CMD_BREAK);
  }
  StopAccess();
  return error;
}

u8 SHT85_ReadMeasurementBuffer(float* temperature, float* humidity)
{
  u8  error;        // error code
  uint16_t rawValueTemp; // raw temperature from sensor
  uint16_t rawValueHumi; // raw humidity from sensor
  
  error = StartWriteAccess();
  // if no error, read measurements
  if(error == NO_ERROR) {
    error = WriteCommand(CMD_FETCH_DATA);
  }
  if(error == NO_ERROR) {
    error = StartReadAccess();  
  }
  if(error == NO_ERROR) {
    error = Read2BytesAndCrc(&rawValueTemp, true, 0);
  }
  if(error == NO_ERROR) {
    error = Read2BytesAndCrc(&rawValueHumi, false, 0);
  }
  // if no error, calculate temperature in °C and humidity in %RH
  if(error == NO_ERROR) {
    *temperature = CalcTemperature(rawValueTemp);
    *humidity = CalcHumidity(rawValueHumi);
  }
  StopAccess();
  return error;
}

u8 SHT85_EnableHeater(void)
{
  u8 error; // error code
  error = StartWriteAccess();
  // if no error, write heater enable command
  if(error == NO_ERROR) {
    error = WriteCommand(CMD_HEATER_ENABLE);
  }
  StopAccess();
  return error;
}

u8 SHT85_DisableHeater(void)
{
  u8 error; // error code
  error = StartWriteAccess();
  // if no error, write heater disable command
  if(error == NO_ERROR) {
    error = WriteCommand(CMD_HEATER_DISABLE);
  }
  StopAccess();
  return error;
}

u8 SHT85_SoftReset(void)
{
  u8 error; // error code
  error = StartWriteAccess();
  // write reset command
  if(error == NO_ERROR) {
    error  = WriteCommand(CMD_SOFT_RESET);
  }
  StopAccess();
  // if no error, wait 50 ms after reset
  if(error == NO_ERROR) {
    DelayUs(50000);
  }
  return error;
}

static u8 StartWriteAccess(void)
{
  u8 error; // error code
  // write a start condition
  I2c_StartCondition();
  // write the sensor I2C address with the write flag
  error = I2c_WriteByte(I2C_ADDR << 1);
  return error;
}

static u8 StartReadAccess(void)
{
  u8 error; // error code
  // write a start condition
  I2c_StartCondition();
  // write the sensor I2C address with the read flag
  error = I2c_WriteByte(I2C_ADDR << 1|0x01);
  return error;
}

static void StopAccess(void)
{
  // write a stop condition
  I2c_StopCondition();
}

static u8 WriteCommand(etCommands command)
{
  u8 error; // error code
  // write the upper 8 bits of the command to the sensor
  error = I2c_WriteByte(command >> 8);
  // write the lower 8 bits of the command to the sensor
  error |= I2c_WriteByte(command & 0xFF);
  return error;
}

static u8 Read2BytesAndCrc(uint16_t* data, bool finAck, uint8_t timeout)
{
  u8 error;    // error code
  uint8_t bytes[2]; // read data array
  uint8_t checksum; // checksum byte
  // read two data bytes and one checksum byte
  bytes[0] = I2c_ReadByte(ACK);
  bytes[1] = I2c_ReadByte(ACK);
  checksum = I2c_ReadByte(finAck ? ACK : NO_ACK);
  // verify checksum
  error = CheckCrc(bytes, 2, checksum);
  // combine the two bytes to a 16-bit value
  *data = (bytes[0] << 8) | bytes[1];
  return error;
}

static uint8_t CalcCrc(uint8_t data[], uint8_t nbrOfBytes)
{
  uint8_t bit;        // bit mask
  uint8_t crc = 0xFF; // calculated checksum
  uint8_t byteCtr;    // byte counter
  
  // calculates 8-Bit checksum with given polynomial
  for(byteCtr = 0; byteCtr < nbrOfBytes; byteCtr++) {
    crc ^= (data[byteCtr]);
    for(bit = 8; bit > 0; --bit) {
      if(crc & 0x80) {
        crc = (crc << 1) ^ CRC_POLYNOMIAL;
      } else {
        crc = (crc << 1);
      }
    }
  }
  
  return crc;
}

static u8 CheckCrc(uint8_t data[], uint8_t nbrOfBytes, uint8_t checksum)
{
  // calculates 8-Bit checksum
  uint8_t crc = CalcCrc(data, nbrOfBytes);
  // verify checksum
  return (crc != checksum) ? CHECKSUM_ERROR : NO_ERROR;
}


/**********************************************************
*函數:CalcTemperature
*功能:溫度轉換
*參數:rawValue:溫度採樣值
*返回:溫度,單位℃
*描述:
**********************************************************/
static float CalcTemperature(uint16_t rawValue)
{
  // calculate temperature [°C]
  // T = -45 + 175 * rawValue / (2^16-1)
  return 175.0f * (float)rawValue / 65535.0f - 45.0f;
}

/**********************************************************
*函數:CalcHumidity
*功能:相對溼度轉換
*參數:rawValue:相對溼度採樣值
*返回:相對溼度,單位%
*描述:
**********************************************************/
static float CalcHumidity(uint16_t rawValue)
{
  // calculate relative humidity [%RH]
  // RH = rawValue / (2^16-1) * 100
  return 100.0f * (float)rawValue / 65535.0f;
}

/**********************************************************
*函數:FnTandRHToH2O
*功能:飽和水蒸氣含量計算
*參數:nInTemp:溫度,單位℃
*      nInRH:  相對溼度,單位%
*返回:飽和水蒸氣含量,單位℃
*描述:
**********************************************************/
static float FnTandRHToH2O(float nInTemp, float nInRH)
{
	float fCnH2O; //H2O含量
	float fCnH2OMax;
	float fTemp; 

	fTemp = nInTemp;
	fCnH2OMax = 0.0000008734* fTemp* fTemp* fTemp 
						- 0.0000013617* fTemp* fTemp
						+ 0.0004784740* fTemp
						+ 0.0068091716;
	fCnH2O = nInRH*fCnH2OMax;
	return(fCnH2O);
}

/**********************************************************
*函數:SHT85_Init
*功能:SHT85初始化
*參數:無
*返回:無
*描述:IIC引腳初始化,讀取SN,配置測量頻率。
**********************************************************/
void SHT85_Init(void)
{
  /*IIC引腳初始化。此程序使用STM32 HAL庫,已在main()初始化*/
  /*讀取SN*/
  SHT85_ReadSerialNumber(&TH_Class_SHT85.SerialNumber);
  /*設置測量頻率*/
  SHT85_StartPeriodicMeasurment(PERI_MEAS_MEDIUM_10_HZ);
}

/**********************************************************
*函數:SHT85_FSM
*功能:SHT85 loop函數
*參數:無
*返回:無
*描述:讀取溫度、相對溼度、計算飽和水蒸氣含量。建議執行頻率1Hz。
**********************************************************/
void SHT85_FSM(void)
{
  /*讀取溫度、相對溼度*/
  SHT85_ReadMeasurementBuffer(&TH_Class_SHT85.Temperature, &TH_Class_SHT85.Humidity);
  /*計算飽和水蒸氣含量*/
  TH_Class_SHT85.H2O = FnTandRHToH2O(TH_Class_SHT85.Temperature, TH_Class_SHT85.Humidity);
}	

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章