Okos otthon is fókuszban

Arduino kalandok

Arduino kalandok

ESP32 és RTC + Loggolás

2019. december 17. - denx

Előző kiegészítő írásomban leíram hogyan is lehet rávenni az ESP32-t, hogy a belső flash memóriájába mentse el a menet közben előálló adatokat. Ez azért jön nekem jól, mert az okosautó projektemben a következő lépés az lesz, hogy próbálok töltés közben minnél több adatot összegyűjteni, hogy ebből minél pontosabb saccolást csinálhassak idővel. Ehhez viszont sokat segít, ha a loggolt adatokat időbélyeggel együtt látom, ide viszont már mindenképp kelleni fog egy RTC.

Előzmények

Emlékeim szerint az RTC-kről már elég sokat írtam korábban, így nem térek most ki az alapokra. (RTC írásaim itt.) Elővettem hát a fiókból egy DS3231-es modult, ami I2C buszon kommunikál és van rajta egy elem is, hogy táp nélkül se felejtse el mennyi az idő. 

Kapcsolás

Nem bonyoult, az ESP32 modulomat 4 vezetékkel összekötöttem az RTC modulommal:

ESP32 RTC
3V3 VCC
GND GND
GPIO22 SCL
GPIO21 SDA

 

Elég magától értetődő a dolog és szerencsére nem kell hozzá semmiféle felhúzó/lehúzó ellenállás, vagy bármi egyéb aktív, vagy passzív alkatrész, csak pár jumper kábel.

Könyvtár

Elég sok ember használtt már/használ most is RTC-t, szerencsére ESP32-re is van választék a libekből. Én az Adafruit RTClib nevű könyvtárát választottam. Ha nem is vagyok 100%-ig megelégedve vele, de az igényeimet kiszolgálja.

Az egyik példakód jól mutatja mennyire egyszerűen lehet inicializálni egy még sosem használt RTC modult (vagy egy olyat, amiben offline állapotban cserélt az ember elemet.)

RTC_DS3231 rtc;
/*...*/
void setup() {
  rtc.begin()
  if (rtc.lostPower()) {
    Serial.println("RTC lost power, lets set the time!");
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
}

Ez a kis elmés kódrészlet azt csinálja, hogy ha az RTC úgy találja magáról, hogy nincs még inicializálva, akkor két fordítási makró segítségével gyorsan be is állítja a fordítás pontos dátumára és idejére az RTC óráját. Mivel az Atom-PlatformIO páros - de gyanítom szinte minden más IDE is - úgy működik, hogy a program feltöltése után rögtön újra is indítja az MCU-t, ezért ha nem túl nagy a forráskódunk és tart percekig a buildelés, akkor az RTC pár másodperces késéssel ugyan, de mondhatjuk hogy viszonlag pontos dátumot és időt fog kapni. Innentől kezdve már csak arra kell vigyázni, hogy a benne lévő elem ne merüljön le és ne legyen kiszedve a helyéről, max akkor ha táp alatt van a kicsike.

Loggolás

Igazi célom az volt, hogy a logfájlom ne egy nehezen kigobozható és mindentől független hatalmas egész számot tartalmazzon minden bejegyzés elején, hanem egy könnyen értlemezhető timestamp-et, így az RTC-ből kapott időt bele kellett gyógyítanom a log-bejegyzéseimbe. Viszont arra jöttem rá, hogy én valahányszor megkérdezem az RTC libet, hogy mennyi az idő, ő minden egyes alkalommal az RTC-hez fordul Ilyenkor a buszon kiküld egy csomagot majd a visszaérkező csomagból kiszámolja az MCU a pontos időt. Ez nekem nem tetszett, így kicsit mókoltam rajta.

Az Arduino-ban van az alap függvény, ami visszaadja, hogy az indítás óta hány ezredmásodperc telt el: millis().  Ezzel csak annyi a gond, hogy minden indítás után 0-ról kezd megint számolni. Az RTC egyrészt nincs ilyen pontosságú, hiszen csak másodperceket képes visszaadni, másrészt viszont nem befolyásolja a restart, sőt az sem, ha nincs tápellátás. Szóval arra jutottam, hogy a loggolást kiegészítve nem fogok minden alkalommal az RTC-hez fordulni, csak nagy ritkán:

uint32_t diff = 0;
/*...*/
void refreshRTC() {
  DateTime now = rtc.now();
  diff = now.unixtime() - (millis()/1000);
}
String getTimestamp() {
  uint32_t m = millis();
  static uint32_t lastCalled = m;
  char result[100];
  if (m <= lastCalled) {
    refreshRTC();
  }
  lastCalled = m;
  DateTime mcuNow = DateTime((m/1000)+diff);
  snprintf(result, sizeof(result), "%04d.%02d.%02d %02d:%02d:%02d ",
      mcuNow.year(),
      mcuNow.month(),
      mcuNow.day(),
      mcuNow.hour(),
      mcuNow.minute(),
      mcuNow.second());
  return result;
}

Szóval a fenti kódocska annyit csinál, hogy ha meghívja az ember a getTimestamp() függvényt, akkor az:

  1. Megnézi mikor volt utoljára hívva.
  2. Ha még sosem volt, vagy már azóta (legalább) egyszer körbefordult a millis() számlálója (ami kb 70 naponta fordul elő), akkor ismét lekérdezi az RTC-től, hogy mennyi is az ő ideje és a mi belső óránk közötti eltérés.
  3. Ezután elmenti, hogy most meg lett hvva.
  4. És összerak egy 0-kal kitöltött timestamp-et a belső órája és a fent kiszámolt különbség alapján a következő formátumban: ÉÉÉÉ.HH.NN óó:pp:mm

Ezt már csak bele kell gyúgyítani a loggoló függvényünkbe és kész is vagyunk:

void log(String text) {
  String s = getTimestamp() + ": " + text + "\r";
  myLog.append(s, false);
  Serial.print(s);
}

Az append hívása mögé azért kell a második paraméter, hogy ne akarja még a logger is berakni a saját timestamp-jét, ami igazából csak a millis() értékének kiiratása.

Pontosság

Próbaképpen az ESP-re dugott RTC-t egy napra a kocsiban hagytam és percenként loggoltam az eltérést az ESP "órája" és az RTC értéke között. Azt olvastam hogy a DS3231 azért tud annyira pontos lenni, mert van benne egy hőmérő és a hőmérsékletnek megfelelően korrigálni tud a benne lévő oszcillátor pontatlanságán. Vagyis az átlagos oszcillátorok nem annyira pontosak ha nagy hidegben vagy nagy melegben kell dolgozniuk, nos ez nagyjából látszik is az eredményeken:

Megjegyzés: nem vagyok valami jó chartkészítésben, ennyit tudtam kihozni a dologból. A vízszintes skálán rengeteg szöveg akart megjelenni, így inkább kikapcsoltam.

A vízszintes skála bal széle első nap dél, a jobb széle másnap reggel 8 óra. Hozzátartozik a dologhoz, hogy volt 2 restart, ami ugye nullázza az értékeket, az egyik az előtt volt, mielőtt az első -1 értékek jelennek meg, a másik pedig amikor a második ilyen rész van. Kicsit hamisítja az is az értékeket, hogy amikor nullázódott, az azért volt, mert arrébbraktam a kütyüt, amikor belütem a kocsiba, vagyis mielőtt elkezdett melegedni az környezet.

A kolnklúzió szerintem az, hogy ha óránként lekérdezzük az RTC-t, akkor a pontosság értelmezhető marad. Igazából akkor sincs semmi para, ha 1-2 másodperc eltérés van, hiszen itt csak arról van szó, hogy a logba kerülő időpontok jók legyenek.

A bejegyzés trackback címe:

https://ardu.blog.hu/api/trackback/id/tr9315345064

Kommentek:

A hozzászólások a vonatkozó jogszabályok  értelmében felhasználói tartalomnak minősülnek, értük a szolgáltatás technikai  üzemeltetője semmilyen felelősséget nem vállal, azokat nem ellenőrzi. Kifogás esetén forduljon a blog szerkesztőjéhez. Részletek a  Felhasználási feltételekben és az adatvédelmi tájékoztatóban.

Nincsenek hozzászólások.
süti beállítások módosítása