616 lines
14 KiB
C++
616 lines
14 KiB
C++
#include "SHT20.h"
|
|
|
|
|
|
SHT20Var_t SHT20;
|
|
|
|
//---------- Defines -----------------------------------------------------------
|
|
// CRC 累加和校验常量
|
|
const uint32_t POLYNOMIAL = 0x131; //P(x)=x^8+x^5+x^4+1 = 100110001
|
|
|
|
/*
|
|
************************************************************
|
|
* 函数名称: SHT2x_CheckCrc
|
|
*
|
|
* 函数功能: 检查数据正确性
|
|
*
|
|
* 入口参数: data:读取到的数据
|
|
* nbrOfBytes:需要校验的数量
|
|
* checksum:读取到的校对比验值
|
|
*
|
|
* 返回参数: 校验结果
|
|
*
|
|
* 说明: 0-成功 1-失败
|
|
************************************************************
|
|
*/
|
|
uint8_t SHT2x_CheckCrc(uint8_t *data, uint8_t nbrOfBytes, uint8_t checksum)
|
|
{
|
|
uint8_t crc = 0;
|
|
uint8_t bit = 0;
|
|
uint8_t byteCtr = 0;
|
|
|
|
//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) ^ POLYNOMIAL;
|
|
else
|
|
crc = (crc << 1);
|
|
}
|
|
}
|
|
|
|
if(crc != checksum)
|
|
return 1;
|
|
return 0;
|
|
|
|
}
|
|
|
|
void delay_us(int dlycnt)
|
|
{
|
|
for(int i = 0; i < dlycnt; i++) {
|
|
uint8_t temp = 10;
|
|
while(temp--);
|
|
}
|
|
}
|
|
|
|
#ifdef I2C_SOFTWARE
|
|
#define ACK 0 //应答信号
|
|
#define NACK 1 //非应答信号
|
|
#define SHT20_IN_SDA SHT20_I2C_SDA_Read() //读取SDA值
|
|
#define IIC_Delay() delay_us(10) //时钟延时
|
|
|
|
/*================================================================
|
|
[ Name ]void IO_I2CInit(void)
|
|
[Function]I2C初始化 空闲状态
|
|
[ Notes ]
|
|
[ Author ]LZH
|
|
[ Data ]2016.06.22
|
|
================================================================*/
|
|
void IO_I2CInit(void)
|
|
{
|
|
//
|
|
}
|
|
|
|
//
|
|
/*================================================================
|
|
[ Name ]SHT20_I2C_SDA_Read
|
|
[Function]读取SDA数据线上值
|
|
[ Notes ]
|
|
[ Author ]LZH
|
|
[ Data ]2016.06.22
|
|
================================================================*/
|
|
uint8_t SHT20_I2C_SDA_Read(void)
|
|
{
|
|
SHT20_SDA_IN();
|
|
if(SHT20_SDA_GET())
|
|
return 1;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
/*================================================================
|
|
[ Name ]I2CStart
|
|
[Function]开始
|
|
[ Notes ]
|
|
[ Author ]LZH
|
|
[ Data ]2016.06.22
|
|
================================================================*/
|
|
void I2CStart(void)
|
|
{
|
|
//uint8_t retval;
|
|
SHT20_SDA_OUT(); //设置成输出
|
|
//SHT20_SCL_OUT();
|
|
SHT20_I2C_SDA_HIGH(); //为SDA下降启动做准备
|
|
SHT20_I2C_SCL_HIGH(); //在SCL高电平时,SDA为下降沿时候总线启动
|
|
|
|
IIC_Delay();
|
|
SHT20_I2C_SDA_LOW(); //突变,总线启动
|
|
IIC_Delay();
|
|
SHT20_I2C_SCL_LOW();
|
|
IIC_Delay();
|
|
|
|
//SHT20_SDA_IN(); //设置成输入
|
|
// if(SHT20_IN_SDA)
|
|
// {
|
|
// retval= NACK;
|
|
// }
|
|
// else
|
|
// {
|
|
// retval= ACK;
|
|
// }
|
|
// retval=retval;
|
|
}
|
|
|
|
/*================================================================
|
|
[ Name ]I2CStop
|
|
[Function]结束
|
|
[ Notes ]
|
|
[ Author ]LZH
|
|
[ Data ]2016.06.22
|
|
================================================================*/
|
|
void I2CStop(void)
|
|
{
|
|
SHT20_SDA_OUT(); //设置成输出
|
|
SHT20_I2C_SDA_LOW(); //为SDA上升做准备
|
|
SHT20_I2C_SCL_LOW();
|
|
|
|
IIC_Delay();
|
|
SHT20_I2C_SCL_HIGH(); //在SCL高电平时,SDA为上升沿时候总线停止
|
|
IIC_Delay();
|
|
SHT20_I2C_SDA_HIGH(); //突变,总线停止
|
|
IIC_Delay();
|
|
}
|
|
|
|
/*================================================================
|
|
[ Name ]I2C_Write_Byte
|
|
[Function]写一个字节 返回ACK或NACK
|
|
[ Notes ]从高到低发
|
|
[ Author ]LZH
|
|
[ Data ]2016.06.22
|
|
================================================================*/
|
|
uint8_t I2C_Write_Byte(uint8_t Write_Byte) //Sendbyte
|
|
{
|
|
uint8_t i,retval=3;
|
|
|
|
SHT20_SDA_OUT(); //设置成输出
|
|
//SHT20_SCL_OUT() ;
|
|
for(i = 0;i < 8;i++) {
|
|
if(Write_Byte & 0x80)
|
|
SHT20_I2C_SDA_HIGH(); //判断发送位,先发送高位
|
|
else
|
|
SHT20_I2C_SDA_LOW();
|
|
|
|
//IIC_Delay();
|
|
SHT20_I2C_SCL_HIGH(); //为SCL下降做准备
|
|
IIC_Delay();
|
|
SHT20_I2C_SCL_LOW(); //突变,将数据位发送过去
|
|
IIC_Delay();
|
|
Write_Byte<<=1; //数据左移一位
|
|
} //字节发送完成,开始接收应答信号
|
|
IIC_Delay();
|
|
SHT20_I2C_SDA_HIGH(); //释放数据线
|
|
IIC_Delay();
|
|
SHT20_SDA_IN(); //设置成输入
|
|
//IIC_Delay();
|
|
SHT20_I2C_SCL_HIGH(); //为SCL下降做准备
|
|
IIC_Delay();
|
|
|
|
if(SHT20_IN_SDA)
|
|
retval= NACK;
|
|
else
|
|
retval= ACK;
|
|
|
|
SHT20_I2C_SCL_LOW();
|
|
IIC_Delay();
|
|
return retval;
|
|
}
|
|
//
|
|
/*================================================================
|
|
[ Name ]I2C_Read_Byte
|
|
[Function]读一个字节,入库参数用于控制应答状态 ACK或NAC
|
|
[ Notes ]从高到低
|
|
[ Author ]LZH
|
|
[ Data ]2016.06.22
|
|
================================================================*/
|
|
uint8_t I2C_Read_Byte(uint8_t AckValue)//receivebyte
|
|
{
|
|
uint8_t i;
|
|
uint8_t RXDATA=0;
|
|
// SHT20_SDA_OUT(); //设置成输出
|
|
// SHT20_I2C_SDA_HIGH(); //首先置数据线为高电平
|
|
// SHT20_I2C_SCL_LOW();
|
|
SHT20_SDA_IN(); //设置成输入
|
|
|
|
for(i = 0;i < 8;i++) {
|
|
SHT20_I2C_SCL_HIGH(); //突变
|
|
IIC_Delay();
|
|
RXDATA <<= 1; //读入数据,高位在前
|
|
if(SHT20_IN_SDA) RXDATA |= 0x01; //收到高电平
|
|
else RXDATA &= 0xfe;
|
|
IIC_Delay();
|
|
SHT20_I2C_SCL_LOW();
|
|
IIC_Delay();
|
|
} //数据接收完成
|
|
|
|
SHT20_SDA_OUT();
|
|
if(AckValue)
|
|
SHT20_I2C_SDA_HIGH();
|
|
else
|
|
SHT20_I2C_SDA_LOW();
|
|
|
|
IIC_Delay();
|
|
SHT20_I2C_SCL_HIGH();
|
|
IIC_Delay();
|
|
SHT20_I2C_SCL_LOW();
|
|
IIC_Delay();
|
|
|
|
return RXDATA; //返回读取到的数据
|
|
}
|
|
|
|
/*================================================================
|
|
[ Name ]SHT20_SoftReset
|
|
[Function]SHT20软件复位
|
|
[ Notes ]从高到低
|
|
[ Author ]LZH
|
|
[ Data ]2016.06.22
|
|
================================================================*/
|
|
void SHT20_Reset(void)
|
|
{
|
|
// IO_I2CInit(); //I2C initialize
|
|
I2CStart(); //start I2C
|
|
I2C_Write_Byte(SHT20_ADDRESS&0xfe); //I2C address + write
|
|
I2C_Write_Byte(0xfe); //soft reset
|
|
I2CStop(); //stop I2C
|
|
}
|
|
|
|
/*================================================================
|
|
[ Name ]SET_Resolution
|
|
[Function]写寄存器 设置分辨率
|
|
[ Notes ]从高到低
|
|
[ Author ]LZH
|
|
[ Data ]2016.06.22
|
|
================================================================*/
|
|
void SET_Resolution(void)
|
|
{
|
|
I2CStart(); //Start I2C
|
|
if(I2C_Write_Byte(SHT20_ADDRESS&0xfe) == ACK) { //I2C address + write + ACK
|
|
if(I2C_Write_Byte(0xe6) == ACK) { //写用户寄存器
|
|
if(I2C_Write_Byte(0x83) == ACK)
|
|
__NOP(); //设置分辨率 11bit RH% 测量时间:12ms(typ.) & 11bit T测量时间:9ms(typ.)
|
|
}
|
|
}
|
|
I2CStop(); //Stop I2C
|
|
}
|
|
|
|
/*================================================================
|
|
[ Name ]ReadSht20
|
|
[Function]非主机模式,读取温湿度值
|
|
[ Notes ]入口控制读取温度或湿度 复位需要15ms 温度转换最大需要85ms
|
|
[ Author ]LZH SHT20上电后等待20ms 再读取sht20
|
|
[ Data ]2016.06.22
|
|
================================================================*/
|
|
float SHT2x_MeasureHM(uint8_t whatdo)
|
|
{
|
|
float temp;
|
|
uint8_t MSB,LSB,checksum=0,checktemp[2];
|
|
float Humidity,Temperature;
|
|
uint32_t waitt= 1000;
|
|
//SET_Resolution(); //此处之前出过问题 所以屏蔽掉
|
|
|
|
I2CStart();
|
|
if(I2C_Write_Byte(SHT20_ADDRESS&0xfe)==ACK) { //I2C address + write + ACK
|
|
if(I2C_Write_Byte(whatdo)==ACK) { //Command
|
|
do{
|
|
delay_us(100); //加入超时
|
|
I2CStart();
|
|
if(--waitt==0)
|
|
break;
|
|
} while(I2C_Write_Byte(SHT20_ADDRESS|0x01) == NACK); //I2C address + read + NACK
|
|
|
|
if(waitt != 0) {
|
|
MSB = I2C_Read_Byte(ACK); //Data(MSB)
|
|
LSB = I2C_Read_Byte(ACK); //Data(LSB)
|
|
checksum=I2C_Read_Byte(NACK); //Checksum + NACK 累加和校验值
|
|
I2CStop(); //Stop I2C
|
|
checktemp[0]=MSB;
|
|
checktemp[1]=LSB;
|
|
if(SHT2x_CheckCrc(checktemp,2,checksum)) { //累加和校验成功
|
|
LSB &= 0xfc; //Data (LSB) 后两位清零
|
|
temp = MSB*256 + LSB; //十六进制转十进制
|
|
if (whatdo==((uint8_t)0xf5)) { //No Hold Master Mode,read humidity
|
|
/*-- calculate relative humidity [%RH] --*/
|
|
Humidity =(temp*125)/65536-6; //公式: RH%= -6 + 125 * SRH/2^16
|
|
return Humidity; //返回:humidity
|
|
}
|
|
else{ //No Hold Master Mode,read temperature
|
|
/*-- calculate temperature [℃] --*/
|
|
Temperature = (temp*175.72)/65536-46.85; //公式:T= -46.85 + 175.72 * ST/2^16
|
|
return Temperature; //返回:temperature
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
I2CStop(); //CT add
|
|
return 0;
|
|
}
|
|
//
|
|
/********************************************************
|
|
[ Name ]GetMiddleNum
|
|
[Function] 中值滤波
|
|
[ Notes ] 传入数据buf bArray, iFilterLen滤波数据长度
|
|
[ Author ] CSDN
|
|
[ Data ]2018.10.25
|
|
|
|
**********************************************************/
|
|
|
|
float GetMiddleNum(float * bArray, uint8_t iFilterLen)
|
|
{
|
|
uint8_t i,j;// 循环变量
|
|
float bTemp;
|
|
|
|
if(iFilterLen>100)
|
|
return 0;
|
|
// 用冒泡法对数组进行排序
|
|
for (j = 0; j < iFilterLen - 1; j ++) {
|
|
for (i = 0; i < iFilterLen - j - 1; i ++) {
|
|
if (bArray[i] > bArray[i + 1]) {
|
|
// 互换
|
|
bTemp = bArray[i];
|
|
bArray[i] = bArray[i + 1];
|
|
bArray[i + 1] = bTemp;
|
|
}
|
|
}
|
|
}
|
|
// 计算中值
|
|
if ((iFilterLen & 1) > 0) {
|
|
// 数组有奇数个元素,返回中间一个元素
|
|
bTemp = bArray[(iFilterLen -1) / 2];
|
|
}
|
|
else {
|
|
// 数组有偶数个元素,返回中间两个元素平均值
|
|
bTemp = (bArray[iFilterLen / 2-1] + bArray[iFilterLen / 2 ]) / 2;
|
|
}
|
|
return bTemp;
|
|
}
|
|
//
|
|
/********************************************************
|
|
[ Name ]ReadSht20_Medium
|
|
[Function] 获取中值
|
|
[ Notes ] 读取完后关闭上拉 设为低 (解决干扰问题)
|
|
[ Author ]
|
|
[ Data ]2018.10.25
|
|
|
|
**********************************************************/
|
|
float ReadSht20_Medium (void)
|
|
{
|
|
float arry3[3];
|
|
//SHT20_I2C_SET_PULL_UP(); //开启引脚上拉
|
|
for(uint8_t ui=0; ui<3; ui++) {
|
|
arry3[ui]= SHT2x_MeasureHM(SHT20_Measurement_T_HM);
|
|
delay_us(20);
|
|
//printf("sht origin %.2f \r\n",arry3[ui]);
|
|
}
|
|
float retv = GetMiddleNum(arry3, 3);
|
|
|
|
#ifdef I2C_SOFTWARE
|
|
//SHT20_I2C_SET_PULL_NO(); //关闭上拉
|
|
SHT20_I2C_LOW(); //读取完温度后拉低
|
|
#endif
|
|
return retv;
|
|
}
|
|
|
|
#else
|
|
|
|
/*
|
|
************************************************************
|
|
* 函数名称: SHT20_reset
|
|
*
|
|
* 函数功能: SHT20复位
|
|
*
|
|
* 入口参数: 无
|
|
*
|
|
* 返回参数: 无
|
|
*
|
|
* 说明:
|
|
************************************************************
|
|
*/
|
|
void SHT20_Reset(void)
|
|
{
|
|
uint8_t Data = SHT20_SOFT_RESET;
|
|
Sht20_Reg_Write(SHT20_ADDRESS, &Data, 1);
|
|
Sht20_Delay(15);
|
|
}
|
|
|
|
/*
|
|
************************************************************
|
|
* 函数名称: SHT20_read_user_reg
|
|
*
|
|
* 函数功能: SHT20读取用户寄存器
|
|
*
|
|
* 入口参数: 无
|
|
*
|
|
* 返回参数: 读取到的用户寄存器的值
|
|
*
|
|
* 说明:
|
|
************************************************************
|
|
*/
|
|
uint8_t SHT20_read_user_reg(void)
|
|
{
|
|
uint8_t val = 0;
|
|
uint8_t reg = SHT20_READ_REG;
|
|
Sht20_Read(SHT20_ADDRESS, ®, &val, 1);
|
|
return val;
|
|
}
|
|
|
|
/*
|
|
************************************************************
|
|
* 函数名称: SHT2x_CalcTemperatureC
|
|
*
|
|
* 函数功能: 温度计算
|
|
*
|
|
* 入口参数: u16sT:读取到的温度原始数据
|
|
*
|
|
* 返回参数: 计算后的温度数据
|
|
*
|
|
* 说明:
|
|
************************************************************
|
|
*/
|
|
float SHT2x_CalcTemperatureC(uint16_t u16sT)
|
|
{
|
|
float temperatureC = 0; // variable for result
|
|
|
|
u16sT &= ~0x0003; // clear bits [1..0] (status bits)
|
|
//-- calculate temperature [℃] --
|
|
temperatureC = -46.85 + 175.72 / 65536 * (float)u16sT; //T= -46.85 + 175.72 * ST/2^16
|
|
|
|
return temperatureC;
|
|
}
|
|
|
|
/*
|
|
************************************************************
|
|
* 函数名称: SHT2x_CalcRH
|
|
*
|
|
* 函数功能: 湿度计算
|
|
*
|
|
* 入口参数: u16sRH:读取到的湿度原始数据
|
|
*
|
|
* 返回参数: 计算后的湿度数据
|
|
*
|
|
* 说明:
|
|
************************************************************
|
|
*/
|
|
float SHT2x_CalcRH(uint16_t u16sRH)
|
|
{
|
|
float humidityRH = 0; // variable for result
|
|
|
|
u16sRH &= ~0x0003; // clear bits [1..0] (status bits)
|
|
//-- calculate relative humidity [%RH] --
|
|
//humidityRH = -6.0 + 125.0/65536 * (float)u16sRH; // RH= -6 + 125 * SRH/2^16
|
|
humidityRH = ((float)u16sRH * 0.00190735) - 6;
|
|
|
|
return humidityRH;
|
|
}
|
|
|
|
/*
|
|
************************************************************
|
|
* 函数名称: SHT2x_MeasureHM
|
|
*
|
|
* 函数功能: 测量温湿度
|
|
*
|
|
* 入口参数: cmd:测量温度还是湿度
|
|
*
|
|
* 返回参数: 测量结果
|
|
*
|
|
* 说明:
|
|
************************************************************
|
|
*/
|
|
float SHT2x_MeasureHM(uint8_t cmd)
|
|
{
|
|
uint8_t checksum = 0; //checksum
|
|
uint8_t data[3]; //data array for checksum verification
|
|
uint16_t tmp = 0;
|
|
float t = 0;
|
|
|
|
Sht20_Read(SHT20_ADDRESS, &cmd, data, 3);
|
|
checksum = data[2];
|
|
if(SHT2x_CheckCrc(data, 2, checksum) == 0) {
|
|
tmp = (data[0] << 8) + data[1];
|
|
if(cmd == SHT20_Measurement_T_NHM)
|
|
t = SHT2x_CalcTemperatureC(tmp);
|
|
else
|
|
t = SHT2x_CalcRH(tmp);
|
|
}
|
|
|
|
return t;
|
|
}
|
|
|
|
|
|
#endif
|
|
|
|
/*
|
|
************************************************************
|
|
* 函数名称: SHT20_GetValue
|
|
*
|
|
* 函数功能: 获取温湿度数据
|
|
*
|
|
* 入口参数: 无
|
|
*
|
|
* 返回参数: 无
|
|
*
|
|
* 说明: 温湿度结果保存在SHT20结构体里
|
|
************************************************************
|
|
*/
|
|
void SHT20_GetValue(float *Tempreture, float *Humidity)
|
|
{
|
|
if(Tempreture != NULL) {
|
|
*Tempreture = SHT20.Tempreture;
|
|
}
|
|
if(Humidity != NULL) {
|
|
*Humidity = SHT20.Humidity;
|
|
}
|
|
//SHT20_reset();
|
|
}
|
|
|
|
void SHT20Start(void)
|
|
{
|
|
memset(&SHT20, 0x00, sizeof(SHT20));
|
|
SHT20.Sht20Status = SHT20_INIT;
|
|
}
|
|
void SHT20LoopHandler(void)
|
|
{
|
|
uint8_t ret;
|
|
uint8_t rData[3];
|
|
|
|
switch(SHT20.Sht20Status) {
|
|
case SHT20_IDLE:
|
|
break;
|
|
|
|
case SHT20_INIT:
|
|
SHT20_Reset();
|
|
SHT20.Sht201mSDelayCnt = 200;
|
|
SHT20.Sht20Status = SHT20_READ_HUMI;
|
|
break;
|
|
|
|
case SHT20_READ_TEMPR:
|
|
if(SHT20.Sht201mSDelayCnt > 0)
|
|
break;
|
|
SHT20.Cmd = SHT20_Measurement_T_NHM;
|
|
ret = SHT20_StartMeas(SHT20_ADDRESS, &SHT20.Cmd);
|
|
if(ret == true) {
|
|
SHT20.Sht201mSDelayCnt = 90;
|
|
SHT20.Sht20Status = SHT20_READ_DATA;
|
|
}
|
|
else {
|
|
SHT20.Sht201mSDelayCnt = 1000;
|
|
SHT20.Sht20Status = SHT20_INIT;
|
|
}
|
|
break;
|
|
|
|
case SHT20_READ_HUMI:
|
|
if(SHT20.Sht201mSDelayCnt > 0)
|
|
break;
|
|
SHT20.Cmd = SHT20_Measurement_RH_NHM;
|
|
ret = SHT20_StartMeas(SHT20_ADDRESS, &SHT20.Cmd);
|
|
if(ret == true) {
|
|
SHT20.Sht201mSDelayCnt = 90;
|
|
SHT20.Sht20Status = SHT20_READ_DATA;
|
|
}
|
|
else {
|
|
SHT20.Sht201mSDelayCnt = 1000;
|
|
SHT20.Sht20Status = SHT20_INIT;
|
|
}
|
|
break;
|
|
|
|
case SHT20_READ_DATA:
|
|
if(SHT20.Sht201mSDelayCnt > 0)
|
|
break;
|
|
ret = SHT20_Readata(SHT20_ADDRESS, rData, 3);
|
|
if(ret == true) {
|
|
if(SHT2x_CheckCrc(rData, 2, rData[2]) == 0) {
|
|
uint16_t tmp = (rData[0] << 8) + rData[1];
|
|
if(SHT20.Cmd == SHT20_Measurement_T_NHM) {
|
|
SHT20.Tempreture = SHT2x_CalcTemperatureC(tmp);
|
|
SHT20.Sht20Status = SHT20_READ_HUMI;
|
|
}
|
|
else {
|
|
SHT20.Humidity = SHT2x_CalcRH(tmp);
|
|
SHT20.Sht20Status = SHT20_READ_TEMPR;
|
|
}
|
|
SHT20.Sht201mSDelayCnt = 5;
|
|
}
|
|
}
|
|
else {
|
|
SHT20.Sht201mSDelayCnt = 1000;
|
|
SHT20.Sht20Status = SHT20_INIT;
|
|
}
|
|
}
|
|
}
|
|
|
|
void SHT201mSRoutine(void)
|
|
{
|
|
if(SHT20.Sht201mSDelayCnt > 0)
|
|
SHT20.Sht201mSDelayCnt--;
|
|
}
|
|
|