/** * @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 *********************************/