CCS811+SHT20 (eCO2+TVOC+TEMP+HUM) - тестовая программа

О программировании Arduino, использование библиотек, примеры и общие вопросы программирования.
Ответить
Berk
Сообщения: 81
Зарегистрирован: 11 окт 2017, 22:05

CCS811+SHT20 (eCO2+TVOC+TEMP+HUM) - тестовая программа

Сообщение Berk »

Приветствую всех форумчан. Предлагаю на тесты скетч для датчика CCS811, добавлен датчик температуры и влажности для компенсации значений eCO2 и TVOC. Датчик работает в импульсном режиме, делая замеры раз в минуту. Микроконтролер всегда спит, просыпаясь по прерыванию от датчика ССS811, проснувшийсь будит сам датчик CCS811:), забирает значения и переводит датчик в сон. Если значения именились то отправляет их на контролер. Так же считываются значения с датчика SHT20, отправляются на контролер если они изменились и записываются в датчик CCS811. Раз в сутки сохраняется в память МК значения бэйзлайн датчика CCS811, которые могут понадобится позже при перезагрузке всего устройства. Ну и отправка заряда батареи на контролер. Даташит датчика - https://docviewer.yandex.ru/view/107589 ... 3D&lang=en.
Потребление усего устройства в пиках - 24мА, во сне 14мкА (вышло не сразу, но что интересно это явно ниже указанных значений в даташите, а 14 это же и на МК и на SHT20 :shock: ), это замеры на 2.8-2.9в. Вроде бы получается впринципе батарейная тема...
...Давайте это пообсуждаем...

Код: Выделить всё

int8_t timer_status = 0;
String error_mes;
uint16_t old_aa = 99999;
uint16_t old_bb = 99999;
uint16_t aa;
uint16_t bb;
uint16_t aaThreshold = 10;
uint16_t bbThreshold = 2;
float tempThreshold = 0.5;
float humThreshold = 10;
float humid;
float temper;
float oldhumd;
float oldtemp;
bool simafor;
unsigned long SLEEP_TIME = 90000000; //25 hours
//unsigned long SLEEP_TIME = 60000; //test
unsigned long oldmillis;
unsigned long newmillis;
unsigned long interrupt_time;
unsigned long SLEEP_TIME_W;
unsigned int result;
unsigned int baselineToApply;
unsigned long newmillisforbatt;
unsigned long battsendinterval = 3600000;
uint16_t currentBatteryPercent;
uint16_t batteryVoltage = 0;
#include "DFRobot_SHT20.h"
DFRobot_SHT20    sht20;
//#define MY_DEBUG
#define MY_DISABLED_SERIAL
#define MY_RADIO_NRF5_ESB
//#define MY_PASSIVE_NODE
#define MY_NODE_ID 129
#define MY_PARENT_NODE_ID 0
#define MY_PARENT_NODE_IS_STATIC
#define MY_TRANSPORT_UPLINK_CHECK_DISABLED
#include <Wire.h>
#include <SparkFunCCS811.h>
#define CCS811_ADDR 0x5B
//#define CCS811_ADDR 0x5A
#define PIN_NOT_WAKE 5
#define PIN_NOT_INT 6
CCS811 myCCS811(CCS811_ADDR);
CCS811Core::status returnCode;
CCS811Core::status errorStatus;
#define C02_CHILD_ID 1
#define TVOC_CHILD_ID 3
#define TEMP_SENS_ID 5
#define HUM_SENS_ID 7
#define CHILD_ID_VOLT 254
#define BATTARY_DATA_SENS_ID 253
#define BATTERY_VCC_MIN  2100
#define BATTERY_VCC_MAX  3000
uint16_t battery_vcc_min = 2000;
uint16_t battery_vcc_max = 2950;
#include <MySensors.h>
MyMessage C02_Msg(C02_CHILD_ID, V_LEVEL);
MyMessage TVOC_Msg(TVOC_CHILD_ID, V_LEVEL);
MyMessage voltMsg(CHILD_ID_VOLT, V_VOLTAGE);
MyMessage powerMsg(BATTARY_DATA_SENS_ID, V_VAR1);
MyMessage msg_temp(TEMP_SENS_ID, V_TEMP);
MyMessage msg_hum(HUM_SENS_ID, V_HUM);

void before()
{
  NRF_POWER->DCDCEN = 1;
  NRF_UART0->ENABLE = 0;
  disableNfc();
  pinMode(PIN_NOT_WAKE, OUTPUT);
  digitalWrite(PIN_NOT_WAKE, 1);
  wait(4000);
  //########################### for test ########################
  //saveState(0, 0x00);
  //saveState(1, 0x00);
  //saveState(2, 0x00);
  //saveState(3, 0x00);
  //########################### for test ########################

}

void presentation()
{
  sendSketchInfo("EFEKTA CCS811 AIR Q", "1.1");
  present(C02_CHILD_ID, S_AIR_QUALITY, "C02 | PPM");
  wait(300);
  present(TVOC_CHILD_ID, S_AIR_QUALITY, "TVOC | PPB/T");
  wait(300);
  present(BATTARY_DATA_SENS_ID, S_CUSTOM, "BATT");
  wait(300);
  present(TEMP_SENS_ID, S_TEMP, "TEMPERATURE DATA");
  wait(300);
  present(HUM_SENS_ID, S_HUM, "HUMIDITY DATA");
  wait(300);
}

void setup()
{
  digitalWrite(PIN_NOT_WAKE, 0); //Start asleep
  sht20.initSHT20();
  wait(20);
  myCCS811.begin();
  wait(20);
  myCCS811.setDriveMode(3);
  wait(20);
  if ((loadState(0) == 0xA5) && (loadState(1) == 0xB2))
  {
    baselineToApply = ((unsigned int)loadState(2) << 8) | loadState(3);
    myCCS811.setBaseline( baselineToApply );
    wait(20);
  }
  pinMode(PIN_NOT_INT, INPUT_PULLUP);
  myCCS811.enableInterrupts();
  digitalWrite(PIN_NOT_WAKE, 1); //Start asleep
  wait(100);
  SLEEP_TIME_W = SLEEP_TIME;
  sendBatteryStatus();
}

void loop()
{
  if (timer_status == 6)
  {
    newmillis = millis();
    interrupt_time = newmillis - oldmillis;
    SLEEP_TIME_W = SLEEP_TIME_W - interrupt_time;
    sht20.initSHT20();
    wait(20);
    myCCS811.begin();
    digitalWrite(PIN_NOT_WAKE, 0);
    wait(20);
    myCCS811.readAlgorithmResults();
    aa = myCCS811.getCO2();
    wait(20);
    bb = myCCS811.getTVOC();
    wait(20);
    if (SLEEP_TIME_W < SLEEP_TIME / 1000) {
      SLEEP_TIME_W = SLEEP_TIME;
      result = myCCS811.getBaseline();
      saveState(0, 0xA5);
      saveState(1, 0xB2);
      saveState(2, (result >> 8) & 0x00FF);
      saveState(3, result & 0x00FF);
    }
    digitalWrite(PIN_NOT_WAKE, 1);
    wait(200);
    if (abs(aa - old_aa) >= aaThreshold) {
      send(C02_Msg.set(aa), 1);
      wait(2000, 1, V_LEVEL);
      wait(100);
      old_aa = aa;
    }
    if (abs(bb - old_bb) >= bbThreshold) {
      send(TVOC_Msg.set(bb), 1);
      wait(2000, 1, V_LEVEL);
      wait(100);
      old_bb = bb;
    }
    if (millis() - newmillisforbatt >= battsendinterval) {
      sendBatteryStatus();
    }


    if (simafor == 0) {
      humid = sht20.readHumidity();
      wait(100);
      temper = sht20.readTemperature();
      wait(100);
      int t_humd = humid;
      int t_temp = temper;

      if (abs(temper - oldtemp) >= tempThreshold) {
        send(msg_temp.set(temper, 1));
        wait(2000, 1, V_TEMP);
        wait(100);
        oldtemp = temper;
      }
      if (abs(humid - oldhumd) >= humThreshold) {
        send(msg_hum.set(humid, 1));
        wait(2000, 1, V_HUM);
        wait(100);
        oldhumd = humid;
      }
      TRANSPORT_DEBUG(PSTR("MyS: DATA - TEMPERATURE: %d, HUMIDITY %d\n"), t_temp, t_humd);
      digitalWrite(PIN_NOT_WAKE, 0);
      wait(20);
      myCCS811.setEnvironmentalData(humid, temper);
      wait(20);
      digitalWrite(PIN_NOT_WAKE, 1);
      wait(20);
      simafor = 1;
    } else {
      simafor = 0;
    }
  }
  if (timer_status == -1)  {
    newmillis = millis();
    SLEEP_TIME_W = SLEEP_TIME;
    digitalWrite(PIN_NOT_WAKE, 0);
    wait(20);
    result = myCCS811.getBaseline();
    saveState(0, 0xA5);
    saveState(1, 0xB2);
    saveState(2, (result >> 8) & 0x00FF);
    saveState(3, result & 0x00FF);
    digitalWrite(PIN_NOT_WAKE, 1);
    wait(20);
  }
  i2c_off();
  oldmillis = millis();
  timer_status = sleep(digitalPinToInterrupt(6), FALLING, SLEEP_TIME_W, false);
}

void disableNfc() {
  NRF_NFCT->TASKS_DISABLE = 1;
  NRF_NVMC->CONFIG = 1;
  NRF_UICR->NFCPINS = 0;
  NRF_NVMC->CONFIG = 0;
}

void turnOffAdc() {
  if (NRF_SAADC->ENABLE) {
    NRF_SAADC->TASKS_STOP = 1;
    while (NRF_SAADC->EVENTS_STOPPED) {}
    NRF_SAADC->ENABLE = 0;
    while (NRF_SAADC->ENABLE) {}
  }
}

void i2c_off()
{
  NRF_TWI1->ENABLE = TWI_ENABLE_ENABLE_Disabled << TWI_ENABLE_ENABLE_Pos;
  *(volatile uint32_t *)0x40004FFC = 0;
  *(volatile uint32_t *)0x40004FFC;
  *(volatile uint32_t *)0x40004FFC = 1;
  wait(300);
}

void sendBatteryStatus() {
  newmillisforbatt = millis();
  batteryVoltage = hwCPUVoltage();
  wait(10);

  if (batteryVoltage > battery_vcc_max) {
    currentBatteryPercent = 100;
  }
  else if (batteryVoltage < battery_vcc_min) {
    currentBatteryPercent = 0;
  } else {
    currentBatteryPercent = (100 * (batteryVoltage - battery_vcc_min)) / (battery_vcc_max - battery_vcc_min);
  }

  sendBatteryLevel(currentBatteryPercent, 1);
  wait(2000, C_INTERNAL, I_BATTERY_LEVEL);
  send(powerMsg.set(batteryVoltage), 1);
  wait(2000, 1, V_VAR1);
}

//printDriverError decodes the CCS811Core::status type and prints the
//type of error to the serial terminal.
//
//Save the return value of any function of type CCS811Core::status, then pass
//to this function to see what the output was.

/*
  void printDriverError( CCS811Core::status errorCode )
  {
  switch ( errorCode )
  {
    case CCS811Core::SENSOR_SUCCESS:
      TRANSPORT_DEBUG(PSTR("SUCCESS\n"));
      break;
    case CCS811Core::SENSOR_ID_ERROR:
      TRANSPORT_DEBUG(PSTR("ID_ERROR\n"));
      break;
    case CCS811Core::SENSOR_I2C_ERROR:
      TRANSPORT_DEBUG(PSTR("I2C_ERROR\n"));
      break;
    case CCS811Core::SENSOR_INTERNAL_ERROR:
      TRANSPORT_DEBUG(PSTR("INTERNAL_ERROR\n"));
      break;
    case CCS811Core::SENSOR_GENERIC_ERROR:
      TRANSPORT_DEBUG(PSTR("GENERIC_ERROR\n"));
      break;
    default:
      TRANSPORT_DEBUG(PSTR("Unspecified error.\n"));
  }
  }
*/
библиотечки:
DFRobot_SHT20.h
SparkFunCCS811.h

фотка:
IMG_20190608_194708.jpg
IMG_20190608_194708.jpg (203.6 КБ) 20926 просмотров
Berk
Сообщения: 81
Зарегистрирован: 11 окт 2017, 22:05

Re: CCS811+SHT20 (eCO2+TVOC+TEMP+HUM) - тестовая программа

Сообщение Berk »

в файле SparkFunCCS811.ccp надо закоментить вывод сериала, строки 416 и 419
Viking
Сообщения: 9
Зарегистрирован: 27 сен 2018, 12:31

Re: CCS811+SHT20 (eCO2+TVOC+TEMP+HUM) - тестовая программа

Сообщение Viking »

интересный хороший CCS811 датчик, но у него есть недостаток который легко победить ... он тупо может зависнуть или перестать слать данные.
я так CCS811 победил ... если данные не поступают выше заданного времени ... то тупо его переинсталлируем )))
photo_2019-11-03_07-50-10.jpg
photo_2019-11-03_07-50-10.jpg (10.89 КБ) 15912 просмотров
photo_2019-11-03_07-49-39.jpg
photo_2019-11-03_07-49-39.jpg (19 КБ) 15912 просмотров
photo_2019-11-03_07-49-09.jpg
photo_2019-11-03_07-49-09.jpg (37.19 КБ) 15912 просмотров
умееть ... могеть !!! перлы выдать )))
Viking
Сообщения: 9
Зарегистрирован: 27 сен 2018, 12:31

Re: CCS811+SHT20 (eCO2+TVOC+TEMP+HUM) - тестовая программа

Сообщение Viking »

в сетапе initCCS811() ;

#include "Adafruit_CCS811.h"
Adafruit_CCS811 ccs;

#define CCS811_PIN_Reset 15

double TempCCS811 = 0;
volatile unsigned long LastUpdatedCCS811 = 0;
volatile uint8_t LastUpdatedCCS811Error = 0;

void loop() {
if (millis() > LastUpdatedCCS811) {
LastUpdatedCCS811 = millis() + 1000;

if (ccs.available()) {
TempCCS811 = ccs.calculateTemperature();
if (!ccs.readData()) {
LastUpdatedCCS811Error = 0;
Serial.print("CO2: "); Serial.print(ccs.geteCO2()); Serial.print(" ppm, TVOC: "); Serial.print(ccs.getTVOC()); Serial.print(" Temp: "); Serial.print(TempCCS811); Serial.println("");
} else {
LastUpdatedCCS811Error++;
if (LastUpdatedCCS811Error > 5) {
initCCS811();
LastUpdatedCCS811Error = 0;
}
}
}
}
}

void initCCS811()
{
pinMode(CCS811_PIN_Reset, OUTPUT);

digitalWrite(CCS811_PIN_Reset, LOW); // зажигаем светодиод
delay(100); // ждем секунду
digitalWrite(CCS811_PIN_Reset, HIGH); // выключаем светодиод
delay(100); // ждем секунду

Serial.println("CCS811 test start.");

if (!ccs.begin()) {
Serial.println("Failed to start sensor! Please check your wiring.");
}

// Wait for the sensor to be ready
while (!ccs.available());

ccs.setTempOffset(ccs.calculateTemperature() - 85);

Serial.println("CCS811 test passed.");
}
Viking
Сообщения: 9
Зарегистрирован: 27 сен 2018, 12:31

Re: CCS811+SHT20 (eCO2+TVOC+TEMP+HUM) - тестовая программа

Сообщение Viking »

а дальше хоть на горячую в работе из колодки можно достать датчик и вставить обратно ...
Ответить