|
@@ -0,0 +1,263 @@
|
|
|
+#include "AHTxx.h"
|
|
|
+
|
|
|
+/* Defines */
|
|
|
+#define AHT_I2C_ADDR (uint8_t)0x38
|
|
|
+
|
|
|
+#define CMD_GET_STATUS (uint8_t)0x71
|
|
|
+#define CMD_INIT (uint8_t)0xbe
|
|
|
+#define CMD_MEASURE (uint8_t)0xac
|
|
|
+#define CMD_MEASURE_CTL (uint8_t)0x33
|
|
|
+#define CMD_MEASURE_NOP (uint8_t)0x00
|
|
|
+#define CMD_SRESET (uint8_t)0xba
|
|
|
+#define CMD_CALIBR1 (uint8_t)0x1b
|
|
|
+#define CMD_CALIBR2 (uint8_t)0x1c
|
|
|
+#define CMD_CALIBR3 (uint8_t)0x1e
|
|
|
+
|
|
|
+#define STATUS_BUSY (uint8_t)0x80
|
|
|
+#define STATUS_CMD (uint8_t)0x40
|
|
|
+#define STATUS_CYC (uint8_t)0x20
|
|
|
+#define STATUS_CAL (uint8_t)0x08
|
|
|
+#define STATUS_CALB (uint8_t)0x18
|
|
|
+
|
|
|
+/* Functions prototypes */
|
|
|
+/*
|
|
|
+uint8_t Calc_CRC8(uint8_t *message, uint8_t Num);
|
|
|
+ahtxx_st_t JH_Reset_REG(uint8_t addr);
|
|
|
+*/
|
|
|
+static bool ReadyToRequest;
|
|
|
+static bool ReadyData;
|
|
|
+static ahtxx_t Data;
|
|
|
+
|
|
|
+/**
|
|
|
+ * Initialization
|
|
|
+ */
|
|
|
+AHTxx::AHTxx(void)
|
|
|
+{
|
|
|
+ // Just powered on, it takes time for the product chip to be ready internally,
|
|
|
+ // the delay is 100~500ms, and 500ms is recommended
|
|
|
+ auto timer = new AutoDeleteTimer;
|
|
|
+ timer->initializeMs<500>(Init);
|
|
|
+ timer->startOnce();
|
|
|
+
|
|
|
+ ReadyToRequest = false;
|
|
|
+ ReadyData = false;
|
|
|
+}
|
|
|
+
|
|
|
+void AHTxx::Init(void) {
|
|
|
+ ahtxx_st_t res;
|
|
|
+ uint8_t data;
|
|
|
+
|
|
|
+ // When power on, send 0x71 to read the status word for the first time,
|
|
|
+ // and judge whether the status word is 0x18.
|
|
|
+ Wire.beginTransmission(AHT_I2C_ADDR);
|
|
|
+ Wire.write(CMD_GET_STATUS);
|
|
|
+ res = (ahtxx_st_t)Wire.endTransmission();
|
|
|
+ if (res != St_OK) {
|
|
|
+ Data.Error = res;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ Wire.requestFrom(AHT_I2C_ADDR, 1);
|
|
|
+ data = Wire.read();
|
|
|
+
|
|
|
+ if ((data & STATUS_CALB) != STATUS_CALB) {
|
|
|
+ //reinitialize registers
|
|
|
+ res = JH_Reset_REG(0x1b);
|
|
|
+ if (res != St_OK) {
|
|
|
+ Data.Error = res;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ res = JH_Reset_REG(0x1c);
|
|
|
+ if (res != St_OK) {
|
|
|
+ Data.Error = res;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ res = JH_Reset_REG(0x1e);
|
|
|
+ if (res != St_OK) {
|
|
|
+ Data.Error = res;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ delay(1);
|
|
|
+ }
|
|
|
+
|
|
|
+ Data.Error = St_OK;
|
|
|
+ ReadyToRequest = true;
|
|
|
+}
|
|
|
+
|
|
|
+void AHTxx::SoftReset(void) {
|
|
|
+ ahtxx_st_t res;
|
|
|
+ Data.Error = St_OK;
|
|
|
+
|
|
|
+ res = I2CWriteTo(CMD_SRESET);
|
|
|
+
|
|
|
+ if (res != St_OK) {
|
|
|
+ Data.Error = res;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+void AHTxx::StartMeasure(void) {
|
|
|
+ if (ReadyToRequest == false) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ ahtxx_st_t res;
|
|
|
+ Data.Error = St_OK;
|
|
|
+
|
|
|
+ Wire.beginTransmission(AHT_I2C_ADDR);
|
|
|
+ Wire.write(CMD_MEASURE);
|
|
|
+ Wire.write(CMD_MEASURE_CTL);
|
|
|
+ Wire.write(CMD_MEASURE_NOP);
|
|
|
+ res = (ahtxx_st_t)Wire.endTransmission();
|
|
|
+ if (res != St_OK) {
|
|
|
+ Data.Error = res;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ ReadyData = false;
|
|
|
+}
|
|
|
+
|
|
|
+void AHTxx::GetData(ahtxx_t * data) {
|
|
|
+ if (ReadyToRequest == false) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ ahtxx_st_t res;
|
|
|
+ uint8_t buf[8] = {0}, i = 0;
|
|
|
+ Data.Error = St_OK;
|
|
|
+
|
|
|
+ /* Now read 7 bytes of data */
|
|
|
+ Wire.requestFrom(AHT_I2C_ADDR, 7);
|
|
|
+ while (Wire.available()) {
|
|
|
+ buf[i] = Wire.read();
|
|
|
+ i ++;
|
|
|
+ }
|
|
|
+ if (i < 7) {
|
|
|
+ Data.Error = St_NACK_Data;
|
|
|
+ data->Error = Data.Error;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if ((buf[0] & STATUS_BUSY) != 0) {
|
|
|
+ Data.Error = St_Timeout;
|
|
|
+ data->Error = Data.Error;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* Calculate values */
|
|
|
+ uint32_t result;
|
|
|
+
|
|
|
+ /* Humidity = Srh * 100% / 2^20 */
|
|
|
+ result = buf[1];
|
|
|
+ result <<= 8;
|
|
|
+ result |= buf[2];
|
|
|
+ result <<= 8;
|
|
|
+ result |= buf[3];
|
|
|
+ result >>= 4;
|
|
|
+ result *= 1000;
|
|
|
+ result += 524288;
|
|
|
+ result /= 256;
|
|
|
+ result /= 256;
|
|
|
+ result /= 16;
|
|
|
+ Data.Humidity = (uint16_t)result; // in xx.x %
|
|
|
+
|
|
|
+ /* Temperature = St * 200 / 2^20 - 50 */
|
|
|
+ result = buf[3] & 0xf;
|
|
|
+ result <<= 8;
|
|
|
+ result |= buf[4];
|
|
|
+ result <<= 8;
|
|
|
+ result |= buf[5];
|
|
|
+ result *= 2000;
|
|
|
+ result += 524288;
|
|
|
+ result /= 256;
|
|
|
+ result /= 256;
|
|
|
+ result /= 16;
|
|
|
+ Data.Temperature = (int16_t)(result - 500); // in xx.x *C
|
|
|
+
|
|
|
+ data->Error = Data.Error;
|
|
|
+ data->Humidity = Data.Humidity;
|
|
|
+ data->Temperature = Data.Temperature;
|
|
|
+ ReadyData = true;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * CRC check type: CRC8/MAXIM
|
|
|
+ * Polynomial: X8+X5+X4+1
|
|
|
+ * Poly: 0011 0001 0x31
|
|
|
+ * When the high bit is placed in the back, it becomes 1000 1100 0x8c
|
|
|
+ */
|
|
|
+uint8_t AHTxx::Calc_CRC8(uint8_t *message, uint8_t Num)
|
|
|
+{
|
|
|
+ uint8_t i;
|
|
|
+ uint8_t byte;
|
|
|
+ uint8_t crc = 0xFF;
|
|
|
+
|
|
|
+ for (byte=0; byte<Num; byte++) {
|
|
|
+ crc ^= (message[byte]);
|
|
|
+ for (i=8; i>0; --i) {
|
|
|
+ if (crc & 0x80) {
|
|
|
+ crc = (crc << 1) ^ 0x31;
|
|
|
+ } else {
|
|
|
+ crc = (crc << 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return crc;
|
|
|
+}
|
|
|
+
|
|
|
+/* Reset register */
|
|
|
+ahtxx_st_t AHTxx::JH_Reset_REG(uint8_t addr) {
|
|
|
+ ahtxx_st_t res;
|
|
|
+ uint8_t Byte_first, Byte_second, Byte_third;
|
|
|
+
|
|
|
+ Wire.beginTransmission(AHT_I2C_ADDR);
|
|
|
+ Wire.write((uint8_t)0x70);
|
|
|
+ Wire.write(addr);
|
|
|
+ Wire.write((uint8_t)0x00);
|
|
|
+ Wire.write((uint8_t)0x00);
|
|
|
+ res = (ahtxx_st_t)Wire.endTransmission();
|
|
|
+ if (res != St_OK) {
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+
|
|
|
+ delay(5); //Delay about 5ms
|
|
|
+ Wire.beginTransmission(AHT_I2C_ADDR);
|
|
|
+ Wire.write((uint8_t)0x71);
|
|
|
+ res = (ahtxx_st_t)Wire.endTransmission();
|
|
|
+ if (res != St_OK) {
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+ Wire.requestFrom(AHT_I2C_ADDR, 3);
|
|
|
+ Byte_first = Wire.read();
|
|
|
+ Byte_second = Wire.read();
|
|
|
+ Byte_third = Wire.read();
|
|
|
+
|
|
|
+ delay(10); //Delay about 10ms
|
|
|
+ Wire.beginTransmission(AHT_I2C_ADDR);
|
|
|
+ Wire.write((uint8_t)0x70);
|
|
|
+ Wire.write((uint8_t)(0xB0|addr)); //register command
|
|
|
+ Wire.write(Byte_second);
|
|
|
+ Wire.write(Byte_third);
|
|
|
+ res = (ahtxx_st_t)Wire.endTransmission();
|
|
|
+ if (res != St_OK) {
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+
|
|
|
+ return St_OK;
|
|
|
+}
|
|
|
+
|
|
|
+ahtxx_st_t AHTxx::I2CWriteTo(uint8_t DataToSend) {
|
|
|
+ Wire.beginTransmission(AHT_I2C_ADDR);
|
|
|
+ Wire.write(DataToSend);
|
|
|
+ return (ahtxx_st_t)Wire.endTransmission();
|
|
|
+}
|
|
|
+
|
|
|
+bool AHTxx::IsReadyToRequest(void) {
|
|
|
+ return ReadyToRequest;
|
|
|
+}
|
|
|
+
|
|
|
+bool AHTxx::IsDataReady(void) {
|
|
|
+ return ReadyData;
|
|
|
+}
|