#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--; }