/**
* @file SHT3X_ATY.c
*
* @param Project DEVICE_GENERAL_ATY_LIB
*
* @author ATY
*
* @copyright
* - Copyright 2017 - 2026 MZ-ATY
* - This code follows:
* - MZ-ATY Various Contents Joint Statement -
*
* https://mengze.top/MZ-ATY_VCJS
* - CC 4.0 BY-NC-SA -
*
* https://creativecommons.org/licenses/by-nc-sa/4.0/
* - Your use will be deemed to have accepted the terms of this statement.
*
* @brief functions of SHT3X tem&hum transistor for all devices
*
* @version
* - 1_01_200318 > ATY
* -# Preliminary version, first Release
* - 1_02_231229 > ATY
* -# add multy addr and channel
********************************************************************************
*/
#ifndef __SHT3X_ATY_C
#define __SHT3X_ATY_C
#include "SHT3X_ATY.h"
/* ------------------------ Dev-style helpers & APIs ------------------------ */
static uint8_t _sht3x_calc_crc(uint8_t* data, uint8_t len)
{
uint8_t bit_t;
uint8_t crc = 0xFF;
uint8_t i;
for(i = 0; i < len; i++)
{
crc ^= data[i];
for(bit_t = 8; bit_t > 0; --bit_t)
{
if(crc & 0x80)
crc = (crc << 1) ^ POLYNOMIAL;
else
crc = (crc << 1);
}
}
return crc;
}
static uint8_t _sht3x_check_crc(uint8_t* data, uint8_t len, uint8_t checksum)
{
return (_sht3x_calc_crc(data, len) != checksum);
}
static int _sht3x_write_cmd(SHT3X_ATY_Dev* dev, uint16_t cmd)
{
uint8_t buf[2];
buf[0] = (uint8_t)(cmd >> 8);
buf[1] = (uint8_t)(cmd & 0xFF);
return dev && dev->i2c_write ? dev->i2c_write(dev->addr, buf, 2, dev->channel) : -1;
}
static void _sht3x_value_process(SHT3X_ATY_Dev* dev, uint16_t* temperature, uint16_t* humidity)
{
if(!dev || !temperature || !humidity) return;
dev->lastTemperatureC = -45.0f + 175.0f * (1.0f * (*temperature) / 65535.0f);
dev->lastHumidityPct = 100.0f * (1.0f * (*humidity) / 65535.0f);
dev->warningFlag = 0;
if(dev->lastTemperatureC < 0 || dev->lastTemperatureC > 65)
dev->warningFlag = 1;
else if(dev->lastTemperatureC < -40)
{
dev->warningFlag = 2;
dev->lastTemperatureC = -40;
}
else if(dev->lastTemperatureC > 120)
{
dev->warningFlag = 2;
dev->lastTemperatureC = 120;
}
if(dev->lastHumidityPct < 10 || dev->lastHumidityPct > 90)
dev->warningFlag = 1;
else if(dev->lastHumidityPct < 0)
{
dev->warningFlag = 2;
dev->lastHumidityPct = 0;
}
else if(dev->lastHumidityPct > 100)
{
dev->warningFlag = 2;
dev->lastHumidityPct = 100;
}
}
static int _sht3x_read_data_and_crc(SHT3X_ATY_Dev* dev, uint16_t* temperature, uint16_t* humidity)
{
if(!dev || !dev->i2c_read) return -1;
uint8_t bytes[6] = {0};
int rc = dev->i2c_read(dev->addr, bytes, 6, dev->channel);
if(rc) return rc;
if(!_sht3x_check_crc(bytes, 2, bytes[2]))
*temperature = (uint16_t)((bytes[0] << 8) | bytes[1]);
else return -2;
if(!_sht3x_check_crc(bytes + 3, 2, bytes[5]))
*humidity = (uint16_t)((bytes[3] << 8) | bytes[4]);
else return -3;
_sht3x_value_process(dev, temperature, humidity);
return 0;
}
void SHT3X_InitDev(SHT3X_ATY_Dev* dev, uint8_t addr, uint8_t channel)
{
if(!dev) return;
dev->addr = addr;
dev->channel = channel;
dev->lastTemperatureC = 0.0f;
dev->lastHumidityPct = 0.0f;
dev->warningFlag = 0;
if(dev->lock) dev->lock(1);
SHT3X_StartPeriodicDev(dev, REPEATAB_HIGH, FREQUENCY_10HZ);
for(int i = 0; i < 3; i++)
{
if(dev->delay_ms) dev->delay_ms(110);
(void)SHT3X_ReadMeasurementDev(dev);
}
if(dev->lock) dev->lock(0);
}
void SHT3X_StartPeriodicDev(SHT3X_ATY_Dev* dev, sht3xRepeatability repeatability, sht3xFrequency frequency)
{
if(!dev) return;
if(dev->lock) dev->lock(1);
switch(repeatability)
{
case REPEATAB_LOW:
switch(frequency)
{
case FREQUENCY_HZ5: _sht3x_write_cmd(dev, CMD_MEAS_PERI_05_L); break;
case FREQUENCY_1HZ: _sht3x_write_cmd(dev, CMD_MEAS_PERI_1_L); break;
case FREQUENCY_2HZ: _sht3x_write_cmd(dev, CMD_MEAS_PERI_2_L); break;
case FREQUENCY_4HZ: _sht3x_write_cmd(dev, CMD_MEAS_PERI_4_L); break;
case FREQUENCY_10HZ: _sht3x_write_cmd(dev, CMD_MEAS_PERI_10_L); break;
default: break;
}
break;
case REPEATAB_MEDIUM:
switch(frequency)
{
case FREQUENCY_HZ5: _sht3x_write_cmd(dev, CMD_MEAS_PERI_05_M); break;
case FREQUENCY_1HZ: _sht3x_write_cmd(dev, CMD_MEAS_PERI_1_M); break;
case FREQUENCY_2HZ: _sht3x_write_cmd(dev, CMD_MEAS_PERI_2_M); break;
case FREQUENCY_4HZ: _sht3x_write_cmd(dev, CMD_MEAS_PERI_4_M); break;
case FREQUENCY_10HZ: _sht3x_write_cmd(dev, CMD_MEAS_PERI_10_M); break;
default: break;
}
break;
case REPEATAB_HIGH:
switch(frequency)
{
case FREQUENCY_HZ5: _sht3x_write_cmd(dev, CMD_MEAS_PERI_05_H); break;
case FREQUENCY_1HZ: _sht3x_write_cmd(dev, CMD_MEAS_PERI_1_H); break;
case FREQUENCY_2HZ: _sht3x_write_cmd(dev, CMD_MEAS_PERI_2_H); break;
case FREQUENCY_4HZ: _sht3x_write_cmd(dev, CMD_MEAS_PERI_4_H); break;
case FREQUENCY_10HZ: _sht3x_write_cmd(dev, CMD_MEAS_PERI_10_H); break;
default: break;
}
break;
default: break;
}
if(dev->lock) dev->lock(0);
}
int SHT3X_ReadMeasurementDev(SHT3X_ATY_Dev* dev)
{
if(!dev) return -1;
if(dev->lock) dev->lock(1);
int rc = _sht3x_write_cmd(dev, CMD_FETCH_DATA);
if(rc == 0)
{
uint16_t t = 0, h = 0;
rc = _sht3x_read_data_and_crc(dev, &t, &h);
}
if(dev->lock) dev->lock(0);
return rc;
}
int SHT3X_GetTempAndHumiClkStretchDev(SHT3X_ATY_Dev* dev, sht3xRepeatability repeatability)
{
if(!dev) return -1;
if(dev->lock) dev->lock(1);
switch(repeatability)
{
case REPEATAB_LOW: _sht3x_write_cmd(dev, CMD_MEAS_CLOCKSTR_L); break;
case REPEATAB_MEDIUM: _sht3x_write_cmd(dev, CMD_MEAS_CLOCKSTR_M); break;
case REPEATAB_HIGH: _sht3x_write_cmd(dev, CMD_MEAS_CLOCKSTR_H); break;
default: break;
}
uint16_t t = 0, h = 0;
int rc = _sht3x_read_data_and_crc(dev, &t, &h);
if(dev->lock) dev->lock(0);
return rc;
}
float SHT3X_GetTemperatureCDev(const SHT3X_ATY_Dev* dev)
{
return dev ? dev->lastTemperatureC : 0.0f;
}
float SHT3X_GetHumidityPctDev(const SHT3X_ATY_Dev* dev)
{
return dev ? dev->lastHumidityPct : 0.0f;
}
uint8_t SHT3X_GetWarningFlagDev(const SHT3X_ATY_Dev* dev)
{
return dev ? dev->warningFlag : 0;
}
/******************************* For user *************************************/
/******************************************************************************/
#if 0 /* legacy implementation disabled in Dev refactor */
float temperatureSHT3X = 0.0;
float humiditySHT3X = 0.0;
/* 0: 0-65T, 10-90H, Best accuracy
1: -40-0/65-120T, 0-10/90-100H, not good accuracy, warning
2: out of limit data, error
*/
uint8_t warningFlag = 0;
/**
* @brief calc crc with SHT3X data
* @param sht3xData data to calc
* @param nbrOfBytes length of data to calc
* @return uint8_t crc value
*/
uint8_t SHT3X_CalcCrc(uint8_t* sht3xData, uint8_t nbrOfBytes)
{
uint8_t bit_t; // 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 ^= sht3xData[byteCtr];
for(bit_t = 8; bit_t > 0; --bit_t)
{
if(crc & 0x80)
crc = (crc << 1) ^ POLYNOMIAL;
else
crc = (crc << 1);
}
}
return crc;
}
/**
* @brief check crc with SHT3X data
* @param sht3xData data to check
* @param nbrOfBytes length of data to check
* @param checksum compare value with calculated crc
* @return !0: wrong, 0: success
*/
uint8_t SHT3X_CheckCrc(uint8_t* sht3xData, uint8_t nbrOfBytes, uint8_t checksum)
{
// calculates 8-Bit checksum
uint8_t crc = SHT3X_CalcCrc(sht3xData, nbrOfBytes);
if(crc != checksum)
return 1;
else
return 0;
}
/**
* @brief write command to SHT3X
* @param cmd command to send
* @param addr chip address
* @param channel chip channel
*/
void SHT3X_WriteCommand(sht3xCommands cmd, uint8_t addr, uint8_t channel)
{
uint8_t cmd_t[2];
cmd_t[0] = cmd >> 8;
cmd_t[1] = cmd & 0xFF;
I2C_Write(addr, cmd_t, 2, channel);
}
/**
* @brief start periodic measurment
* @param repeatability repeatability
* @param frequency frequency
* @param addr chip address
* @param channel chip channel
* @note use depending on the required repeatability and frequency,
* the corresponding command
*/
void SHT3X_StartPeriodicMeasurment(sht3xRepeatability repeatability, sht3xFrequency frequency, uint8_t addr, uint8_t channel)
{
switch(repeatability)
{
case REPEATAB_LOW: // low repeatability
switch(frequency)
{
case FREQUENCY_HZ5: // low repeatability, 0.5 Hz
SHT3X_WriteCommand(CMD_MEAS_PERI_05_L, addr, channel);
break;
case FREQUENCY_1HZ: // low repeatability, 1.0 Hz
SHT3X_WriteCommand(CMD_MEAS_PERI_1_L, addr, channel);
break;
case FREQUENCY_2HZ: // low repeatability, 2.0 Hz
SHT3X_WriteCommand(CMD_MEAS_PERI_2_L, addr, channel);
break;
case FREQUENCY_4HZ: // low repeatability, 4.0 Hz
SHT3X_WriteCommand(CMD_MEAS_PERI_4_L, addr, channel);
break;
case FREQUENCY_10HZ: // low repeatability, 10.0 Hz
SHT3X_WriteCommand(CMD_MEAS_PERI_10_L, addr, channel);
break;
default:
break;
}
break;
case REPEATAB_MEDIUM: // medium repeatability
switch(frequency)
{
case FREQUENCY_HZ5: // medium repeatability, 0.5 Hz
SHT3X_WriteCommand(CMD_MEAS_PERI_05_M, addr, channel);
break;
case FREQUENCY_1HZ: // medium repeatability, 1.0 Hz
SHT3X_WriteCommand(CMD_MEAS_PERI_1_M, addr, channel);
break;
case FREQUENCY_2HZ: // medium repeatability, 2.0 Hz
SHT3X_WriteCommand(CMD_MEAS_PERI_2_M, addr, channel);
break;
case FREQUENCY_4HZ: // medium repeatability, 4.0 Hz
SHT3X_WriteCommand(CMD_MEAS_PERI_4_M, addr, channel);
break;
case FREQUENCY_10HZ: // medium repeatability, 10.0 Hz
SHT3X_WriteCommand(CMD_MEAS_PERI_10_M, addr, channel);
break;
default:
break;
}
break;
case REPEATAB_HIGH: // high repeatability
switch(frequency)
{
case FREQUENCY_HZ5: // high repeatability, 0.5 Hz
SHT3X_WriteCommand(CMD_MEAS_PERI_05_H, addr, channel);
break;
case FREQUENCY_1HZ: // high repeatability, 1.0 Hz
SHT3X_WriteCommand(CMD_MEAS_PERI_1_H, addr, channel);
break;
case FREQUENCY_2HZ: // high repeatability, 2.0 Hz
SHT3X_WriteCommand(CMD_MEAS_PERI_2_H, addr, channel);
break;
case FREQUENCY_4HZ: // high repeatability, 4.0 Hz
SHT3X_WriteCommand(CMD_MEAS_PERI_4_H, addr, channel);
break;
case FREQUENCY_10HZ: // high repeatability, 10.0 Hz
SHT3X_WriteCommand(CMD_MEAS_PERI_10_H);
break;
default:
break;
}
break;
default:
break;
}
}
/**
* @brief calc real value from 16 bit data
* @param temperature temperature 16 bit origin value
* @param humidity humidity 16 bit origin value
*/
void SHT3X_ValuePorcess(uint16_t* temperature, uint16_t* humidity)
{
temperatureSHT3X = -45 + 175 * (1.0 * (*temperature) / 65535);
humiditySHT3X = 100 * (1.0 * (*humidity) / 65535);
warningFlag = 0;
if(temperatureSHT3X < 0 || temperatureSHT3X>65)
warningFlag = 1;
else if(temperatureSHT3X < -40)
{
warningFlag = 2;
temperatureSHT3X = -40;
}
else if(temperatureSHT3X > 120)
{
warningFlag = 2;
temperatureSHT3X = 120;
}
if(humiditySHT3X < 10 || humiditySHT3X>90)
warningFlag = 1;
else if(humiditySHT3X < 0)
{
warningFlag = 2;
humiditySHT3X = 0;
}
else if(humiditySHT3X > 100)
{
warningFlag = 2;
humiditySHT3X = 100;
}
}
/**
* @brief read all data from SHT3X
* @param temperature temperature 16 bit origin value
* @param humidity humidity 16 bit origin value
* @param addr chip address
* @param channel chip channel
*/
void SHT3X_ReadDataAndCrc(uint16_t* temperature, uint16_t* humidity, uint8_t addr, uint8_t channel)
{
uint8_t bytes[6]; // read 2 data array and 1 checksum byte
// read two data bytes and one checksum byte
I2C_Read(addr, bytes, 6, channel);
// verify checksum then combine the two bytes to a 16-bit value
if(!SHT3X_CheckCrc(bytes, 2, bytes[2]))
*temperature = (bytes[0] << 8) | bytes[1];
// else
// *temperature = 0;
if(!SHT3X_CheckCrc(bytes + 3, 2, bytes[5]))
*humidity = (bytes[3] << 8) | bytes[4];
// else
// *humidity = 0;
SHT3X_ValuePorcess(temperature, humidity);
}
/**
* @brief read data and calc real value
* @param addr chip address
* @param channel chip channel
*/
void SHT3X_ReadMeasurementBuffer(uint8_t addr, uint8_t channel)
{
uint16_t hexValueTemp = 0;
uint16_t hexValueHumi = 0;
SHT3X_WriteCommand(CMD_FETCH_DATA, addr, channel);
SHT3X_ReadDataAndCrc(&hexValueTemp, &hexValueHumi, addr, channel);
}
/**
* @brief start measurement in clock stretching mode
* @param repeatability repeatability
* @param addr chip address
* @param channel chip channel
* @note use depending on the required repeatability, the corresponding command
*/
void SHT3X_GetTempAndHumiClkStretch(sht3xRepeatability repeatability, uint8_t addr, uint8_t channel)
{
uint16_t hexTempValue = 0;
uint16_t hexHumiValue = 0;
switch(repeatability)
{
case REPEATAB_LOW:
SHT3X_WriteCommand(CMD_MEAS_CLOCKSTR_L, addr, channel);
break;
case REPEATAB_MEDIUM:
SHT3X_WriteCommand(CMD_MEAS_CLOCKSTR_M, addr, channel);
break;
case REPEATAB_HIGH:
SHT3X_WriteCommand(CMD_MEAS_CLOCKSTR_H, addr, channel);
break;
default:
break;
}
SHT3X_ReadDataAndCrc(&hexTempValue, &hexHumiValue, addr, channel);
}
/**
* @brief init SHT3X, check device
* @param addr chip address
* @param channel chip channel
* @note put at main init
*/
void SHT3X_InitBegin(uint8_t addr, uint8_t channel)
{
uint8_t i = 0;
SHT3X_StartPeriodicMeasurment(REPEATAB_HIGH, FREQUENCY_10HZ, addr, channel);
for(i = 0; i < 9; i++)
{
DelayMs(110);
SHT3X_ReadMeasurementBuffer(addr, channel);
// SHT3X_GetTempAndHumiClkStretch(REPEATAB_LOW, addr, channel);
}
// SHT3X_StartPeriodicMeasurment(REPEATAB_LOW, FREQUENCY_HZ1, addr, channel);
SHT3X_StartPeriodicMeasurment(REPEATAB_HIGH, FREQUENCY_10HZ, addr, channel);
}
// todo: not tested
// void main()
// {
// SHT3X_InitBegin(addr, channel);
// while(1)
// {
// SHT3X_ReadMeasurementBuffer(addr, channel);
// UartSendStr("\r\nHT: ");
// UartSendStr(TemperatureStr);
// UartSendStr(" - ");
// UartSendStr(HumidityStr);
// DelayMs(2000);
// }
// }
// // declare 5byte group, last with '\0' for show
// uint8_t Temperature[5] = {0, 0, '.', 0};
// uint8_t Humidity[5] = {0, 0, '.', 0};
// uint8_t TemperatureStr[5] = {0, 0, '.', 0};
// uint8_t HumidityStr[5] = {0, 0, '.', 0};
// uint8_t temperatureHexI = 0; // integer
// uint8_t temperatureHexD = 0; // decimal
// uint8_t humidityHexI = 0;
// uint8_t humidityHexD = 0;
// temperature = ((uint8_t)decTempValue << 8) + ((uint16_t)(decTempValue * 100) % 100);
// humidity = ((uint8_t)decHumiValue << 8) + ((uint16_t)(decHumiValue * 100) % 100);
// temperatureHexI = temperature >> 8;
// temperatureHexD = temperature;
// humidityHexI = humidity >> 8;
// humidityHexD = humidity;
// // todo higher than 100 or below 0
// // todo only get origin data, do not change type here
// // todo AHT20 deal the same, and change I2C function to standard
// // if()
// Temperature[0] = temperatureHexI / 10;
// Temperature[1] = temperatureHexI % 10;
// Temperature[3] = temperatureHexD / 10;
// Humidity[0] = humidityHexI / 10;
// Humidity[1] = humidityHexI % 10;
// Humidity[3] = humidityHexD / 10;
// TemperatureStr[0] = Temperature[0] + '0';
// TemperatureStr[1] = Temperature[1] + '0';
// TemperatureStr[3] = Temperature[3] + '0';
// HumidityStr[0] = Humidity[0] + '0';
// HumidityStr[1] = Humidity[1] + '0';
// HumidityStr[3] = Humidity[3] + '0';
#endif /* __SHT3X_ATY_C */
#endif /* legacy implementation disabled in Dev refactor */
/******************************** End Of File *********************************/