Kaynağa Gözat

Add module for AHTxx sensor.

Vladimir N. Shilov 2 yıl önce
ebeveyn
işleme
6f45dfede4
4 değiştirilmiş dosya ile 351 ekleme ve 19 silme
  1. 263 0
      app/AHTxx.cpp
  2. 45 19
      app/application.cpp
  3. 41 0
      include/AHTxx.h
  4. 2 0
      include/tm1650.h

+ 263 - 0
app/AHTxx.cpp

@@ -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;
+}

+ 45 - 19
app/application.cpp

@@ -7,19 +7,21 @@
 
 #include "webserver.h"
 #include "tm1650.h"
+#include "AHTxx.h"
 
 Timer procTimer, procRTimer;
 Timer displayTimer, tmpTimer;
 Timer showHighTimer, showLowTimer;
 Timer brightTimer;
-// Sensors string values
+// Sensors values
 float SensorT, SensorH, SensorHI, SensorCR;
 String StrCF;
 // Time values
 time_t Time, NTPLastUpdate;
 DateTime dt;
 
-void process(void);
+void RequestData(void);
+void GetData(void);
 void connectOk(const String& SSID, MacAddress bssid, uint8_t channel);
 void connectFail(const String& ssid, MacAddress bssid, WifiDisconnectReason reason);
 void gotIP(IpAddress ip, IpAddress netmask, IpAddress gateway);
@@ -34,8 +36,9 @@ void setBright(void);
 void onNtpReceive(NtpClient& client, time_t timestamp);
 NtpClient ntpClient("ntp.time.in.ua", 1500, onNtpReceive); // every 15 min
 
-void init()
-{
+AHTxx sensor;
+
+void init(void) {
 	spiffs_mount(); // Mount file system, in order to work with files
 
 	Serial.begin(SERIAL_BAUD_RATE);  // 115200 by default
@@ -55,12 +58,11 @@ void init()
 	WifiEvents.onStationDisconnect(connectFail);
 	WifiEvents.onStationGotIP(gotIP);
 
-	// Sensors start
-	//dht.begin();
-
-	// polling sensors - once a minute?
-	procTimer.initializeMs(60000, process).start();
-	process();
+	// Sensors start. Possible infinity loop...
+//	Serial.println("Wait for Sensor...");
+//	while (sensor.IsReadyToRequest() == false);
+	// polling sensors - once per two seconds
+	procTimer.initializeMs(2000, RequestData).start();
 
 	// Low LED output
 	TM1650_Init();
@@ -142,25 +144,49 @@ void showHumidity(void) {
 
 /*
  * Автоматическая регулировка яркости индикаторов
- * GY-49
+ * GY-49 (MAX44009)
  */
 void setBright(void) {
 		// ...
 }
 
 /**
- * @brief Get data from Temperature/Humidity Sensor
- * Currently planed AHT10. Пока заглушка.
+ * @brief Start Sensor measure.
  */
-void process() {
-	float t = 25.0;
-	float h = 60.5;
+void RequestData(void) {
+	if (sensor.IsReadyToRequest()) {
+		sensor.StartMeasure();
+		tmpTimer.initializeMs(1000, GetData).startOnce();
+	} else {
+		Serial.println("Sensor: not ready to request.");
+	}
+}
+
+/**
+ * @brief Get data from Temperature/Humidity Sensor.
+ */
+void GetData(void) {
+	if (sensor.IsDataReady() == false) {
+		Serial.println("Sensor: Data not ready!");
+		return;
+	}
+
+	ahtxx_t data;
+
+	sensor.GetData(&data);
+	if (data.Error != St_OK) {
+		Serial.println("Sensor: Data error!");
+		return;
+	}
+
+	SensorH = data.Humidity / 10;
+	SensorT = data.Temperature / 10;
 
 	Serial.print("Humidity: ");
-	Serial.print(h);
+	Serial.print(SensorH);
 	Serial.print("%. Temperature: ");
-	Serial.print(t);
-	Serial.println("*C");
+	Serial.print(SensorT);
+	Serial.print("*C");
 }
 
 void connectOk(const String& SSID, MacAddress bssid, uint8_t channel)

+ 41 - 0
include/AHTxx.h

@@ -0,0 +1,41 @@
+#pragma once
+#ifndef _AHTxx_H_
+#define _AHTxx_H_
+
+#include <SmingCore.h>
+
+/* Status code */
+typedef enum {
+  St_OK = 0,
+  St_DataToLong = 1,
+  St_NACK_Addr = 2,
+  St_NACK_Data = 3,
+  St_Error = 4,
+  St_Timeout = 5
+} ahtxx_st_t;
+
+/* Data type */
+typedef struct {
+  uint16_t Humidity;
+  int16_t Temperature;
+  ahtxx_st_t Error;
+} ahtxx_t;
+
+class AHTxx
+{
+public:
+  AHTxx(void);
+  void StartMeasure(void);
+  void SoftReset(void);
+  void GetData(ahtxx_t * data);
+  bool IsReadyToRequest(void);
+  bool IsDataReady(void);
+
+private:
+  static void Init(void);
+  static ahtxx_st_t I2CWriteTo(uint8_t DataToSend);
+  static uint8_t Calc_CRC8(uint8_t *message, uint8_t Num);
+  static ahtxx_st_t JH_Reset_REG(uint8_t addr);
+};
+
+#endif /* _AHTxxH_ */

+ 2 - 0
include/tm1650.h

@@ -1,6 +1,8 @@
 #ifndef INCLUDE_TM1650_H_
 #define INCLUDE_TM1650_H_
 
+#include <SmingCore.h>
+
 #define LED_NUM   4
 
 typedef enum {