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