DS3231 RTC óra

Tartalom:

  • A DS3231 modul tulajdonságai, összekötése az Arduino-val
  • Az SQW és 32K kivezetések funkciója és működésük
  • A DS3231 chip regisztereinek működése
  • Modul használata letölthető programkönyvtár nélkül (letölthető programkönyvtárak forráskódjai alapján), az elemi parancsok megismeréséhez

————————————————————————————–

Mivel az Arduino Uno R3-ban nincs beépített óra, a pontos idő kijelzéséhez valamilyen külső modulra lesz szükségünk. Elvben megírható lenne programként is egy óra funkció, hiszen a 16Mhz-es kvarcz kristály elég pontos órajelet állít elő egy átlagos időméréshez, de a program elég bonyolult lenne. Egyszerűbbnek tűnik egy külső óra modul beszerzése. Elsőre a DS3231 RTC modult választottam. Van azonban több beszerezhető modul is, itt megismerhetsz egy másikat is, ha ez nem fog tetszeni.

A DS3231 modul ára kb. 1000Ft. Nagy előnye még ennek a modulnak, hogy nem csak óra van benne, hőmérsékletet is képes mérni. A hőmérséklet mérés azért került a chip-be, mert a kvarc kristály frekvenciáját a hőmérséklet függvényében automatikusan korrigálja a chip. Így tudnak elérni évi egy perc körüli óra pontosságot. Egy 4Kbyte-os EEPROM-ot is tartalmaz a modul, amit a gyári adatlap szerint legalább 1 milliószor lehet újraírni, így korlátozottan adatgyűjtésre is felhasználható. A modul I2C buszon keresztül használható, így nem fog újabb kivezetéseket lefoglalni. Simán párhuzamosan köthetjük az LCD kijelzővel, és kész is a hőmérős óra!
Így néz ki a modul:

…és így kell összekötni az Arduino-val:

A kivezetéseiből a 32K jelű kivezetésen 32.768Hz négyszög jelet kapunk, ha ezt a lehetőséget szeretnénk és bekapcsoljuk. A SQW kivezetés lehet egy kimenet, ami két beállítható riasztási időpont elérkeztét jelzi, de lehetséges négyszög jelet is kapni rajta, ami 1Hz, 1024Hz, 4096Hz vagy 8192Hz frekvenciára állítható. Én ezeket még nem igazán tudtam semmire használni, de vannak! Már érik a gondolat bennem egy elemes adatgyűjtő elkészítésére, aminek a működésében szerepe lehet a beépített két riasztási időpontnak. Az elképzelés szerit az odagyűjtő program beállítja a következő mérés időpontját, és elmegy aludni. Amikor az időpont elérkezik, az óra modul felébreszti alvásból az ATmega328P chip-et. Azért nem az Arduino-t, mert annak nagyon nagy az alap fogyasztása az elemes tápláláshoz még akkor is, ha alszik a ráépített vezérlő. A chip elvégzi a szükséges méréseket, tárolja az adatokat az eeprom-ban, és újra aludni megy. Alvási üzemmódban rendkívül kicsi a fogyasztása, évekig működhet elemről. A DS3231 szintén működik elemről, sőt ezt már rá is építették, az én első példányom 4 éve megy, megy és egész pontos.

A modulnak az I2C buszon konkrét címe van, amit meg tudunk változtatni az A0,A1,A2 átkötések felhasználásával. Erre akkor lehet szükség, ha több hasonló modult is az I2C buszra szeretnénk kötni, és ütközne a címük.

Természetesen ehhez az óramodulhoz is rengeteg előre elkészített programkönyvtárat találunk. Az LCD kijelzőnél leírt módon nyissuk meg a “könyvtárak kezelése” menüpontot az Arduino IDE programban, és a keresőbe írjuk be a DS3231 szót. Már csak választani kell. Én azt szoktam használni az utóbbi időben, melynek neve pontosan “DS3231”. Érdemes tanulmányozni a példa programokat.

Most azonban megragadnám az alkalmat, és szeretném megmutatni, hogy mit is tartalmaznak ezek a programkönyvtárak belül a színfala mögött. Alább található egy olyan példaprogram, ami csak a “Wire.h”-t használja fel, ami az I2C kommunikációhoz szükséges. Nem vagyok annyira ügyes, hogy magamtól írtam az alábbi programot, az egyik DS3231 programcsomag forrást emeltem ki, és addig alakítgattam, amíg működni nem kezdett. Ezek a forráskódok a programkönyvtárak “cpp” kiterjesztésű állományaiban lelhetők fel. Simán megnyithatók pl. a notepad++ prgrammal, ami ingyenesen letölthető. A Github.com weboldalon rengeteg forráskód megtalálható, és ott közvetlenül bele lehet olvasni ezekbe az állományokba. Itt egy példa a DS3231-hez: https://github.com/rodan/ds3231 Ha egy programkönyvtárat letöltünk magunknak a könyvtár kezelő menüpontban, akkor azt a gépünkön a felhasználók alatti alkönyvtárakban helyezi el az Arduino IDE. Nálam pl. itt található: C:\Users\Zoli\Documents\Arduino\libraries Ez persze mindenkinél más. A könyvtárakban megtalálhatók a forráskódok és a példa programok is „Examples” alkönyvtárakban. Ezek azok a példaprogramok, amiket az Arduino IDE Fájl/Példák menüpontjából is betölthetünk!
A cpp kiterjesztésű állományokban található kódok szinte egy-az egyben átemelhetők. A fordító jelezni fog hibákat, egy-egy változó hiányzik stb., de még az én szerény tudásommal is sikerült kijavítani. Így maradt a végén a következő forrásprogram, amit kommentekkel láttam el. Talán hasznos lehet másnak is, hogy megismerje egy-egy modul alacsonyabb szintű használatát. A program megértéséhez feltétlenül szükséges még a DS3231 IC belső regisztereinek a tanulmányozása. A forráskód után megtaláljátok azt a táblázatot, amit az IC adatlapjából emeltem ki.

Itt a forráskód:

#define CLOCK_ADDRESS 0x68  //a modulon található óra IC címe az I2C buszon. 
                                                               //A cím vezetékek átforrasztásával változhat
#include <Wire.h>

int masodperc,perc,ora,nap,honap,ev,het_napja;
bool h12;             //ha true, akkor 12 órás üzemmód, false esetén 24 órás üzzemmód
bool PM;              //12 órás üzemmód esetén a délelőtt délután jelzése fals=AM, true=PM
float temperature;

void setup() {
Wire.begin();                                               // I2C busz használat indítása
enableOscillator(true, true, 2);               //Paraméterek jelentése:oscillátor eng. ha nincs Vcc,
                                                                       // battery mód, frekvencia
                     //Az oszcillátor mindíg megy, ha van Vcc. Ha első paraméter true, akkor 
                     //elemes táplálásnál is megy az oszcillátor.
                     //Ha második paraméter true, akkor elemes táplásálásnál is van oszzcillátor.
                     //Nekem ezek nem működnek, valamit biztosan félreértek. 
                    //Azonban a frekvenciát tudtam állítani.
enable32kHz(false); //a 32K kimeneti lábon engedélyezi true-val az oszcillátort. 
                                      //False kikapcsolja.
//  setClockMode(false);  //true értékkel 12 órás, false értékkel 24 órás üzemmód, 
                                              //ha átállítod az üzemmódot ujra be kell állítani az órát
                                              // ( setTime() ), mert fals eredményt ad vissza.  
              // a kövekező két sorból kell kivenni a kommentet és beállítani a változókat, 
              //lefordítani a programot, egyszer futtatni
              // majd újra betenni a kommenteket. Primitív órabeállítási mód!
// masodperc=0;perc=14;ora=20;het_napja=1;nap=1;honap=8;ev=16; 
// setTime();   //óra beállítása
 Serial.begin(115200);
}

void loop() {
  getTime();            //kiolvassuk az időt a DS3132-ből a "masodperc, perc, ora, 
                                  //het_napja, nap, honap, ev" változókba
  Serial.print("20");
  Serial.print(ev,DEC);
  Serial.print('-');
  Serial.print(honap,DEC);
  Serial.print('-');
  Serial.print(nap,DEC);
  Serial.print(' ');
  Serial.print(ora,DEC);
  Serial.print(':');
  Serial.print(perc,DEC);
  Serial.print(':');
  Serial.print(masodperc,DEC);
  if (h12) {                //ha 12órás mód, akkor kiírjuk az idő mögé a PM vagy AM-et
    if (PM) {Serial.print(" PM ");}
    else {Serial.print(" AM ");}
  }
  Serial.print("  ");
  Serial.print(het_napja);
  Serial.print('\n');
  temperature=getTemperature();
  Serial.print("Temperature=");
  Serial.println(temperature);
  if (oscillatorCheck()) {Serial.println("Az ora valoszinuleg pontos");}
                  else {Serial.println("Az ora valoszinuleg NEM pontos");}
  delay(5000);
}

void setClockMode(bool h12) {
  // beállítja a 12 órás vagy 24 órás üzemmódot
  // true 12 órás üzemmód
  // false24 órás üzemmód
  byte temp_buffer;
  // kiolvassa a 0x02 regisztert (Hour)
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(uint8_t(0x02));
  Wire.endTransmission();
  Wire.requestFrom(CLOCK_ADDRESS, 1);
  temp_buffer = Wire.read();
  // beállítja bit6-ot (12/24 vezérlő bit)
  if (h12) {
    temp_buffer = temp_buffer | 0b01000000;
  } else {
    temp_buffer = temp_buffer & 0b10111111;
  }
  // visszaírja a 0x02 registerbe az új értéket
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(uint8_t(0x02));
  Wire.write(temp_buffer);
  Wire.endTransmission();
}

void setTime() {
  // Beállítja az órát és torli az OSF regisztert
  // This function also resets the Oscillator Stop Flag, which is set
  // whenever power is interrupted.
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(uint8_t(0x02));
  Wire.endTransmission();
  Wire.requestFrom(CLOCK_ADDRESS, 1);
  h12 = (Wire.read() & 0b01000000);                     //kiolvassa a 12 órás üzemmód jelzőbitjét
  if (h12) {                                                               //ha true, akkor 24 órás üzemmódban vagyunk
    if (ora > 12) {                                                    //ha a megadott óra nagyobb mint 12, akkor délután van
      ora = dec_bcd(ora-12) | 0b01100000;           //ki kell vonni 12 órár
    } else {
      ora = dec_bcd(ora) & 0b11011111;
    }
  } else {
    // 24 hour
    ora = dec_bcd(ora) & 0b10111111;
  }
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(uint8_t(0x00));
  Wire.write(dec_bcd(masodperc));
  Wire.write(dec_bcd(perc));
  Wire.write(ora);
  Wire.write(dec_bcd(het_napja)); 
  Wire.write(dec_bcd(nap));
  Wire.write(dec_bcd(honap));
  Wire.write(dec_bcd(ev)); 
  Wire.endTransmission();
                // OSF flag törlése a 0x0F control registerben
                // OSF true-val jelzi, ha az óra valószínűleg nem pontos (leállt az oszcillátor stb.)
  byte temp_buffer = readControlByte(1);
  writeControlByte((temp_buffer & 0b01111111), 1);
}

void getTime() {
  //kiolvassa a dátumot és az időpontot 
  byte tempBuffer;
  bool PM;
  bool h12;
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(uint8_t(0x00));
  Wire.endTransmission();
  Wire.requestFrom(CLOCK_ADDRESS, 7);
  masodperc = bcd_Dec(Wire.read());
  perc = bcd_Dec(Wire.read());
  tempBuffer = bcd_Dec(Wire.read());
  h12 = tempBuffer & 0b01000000;
  if (h12) {
    PM = tempBuffer & 0b00100000;
    ora = bcd_Dec(tempBuffer & 0b00011111);
  } else {
    ora = bcd_Dec(tempBuffer & 0b00111111);
  }
  het_napja = bcd_Dec(Wire.read());
  nap = bcd_Dec(Wire.read());
  honap = bcd_Dec(Wire.read() & 0b01111111);
  ev = bcd_Dec(Wire.read());
}

float getTemperature() {
                // Kiolvassa a hőmérséklet értékét a 0x11h és 0x12h regiszterekből
  byte temp;
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(uint8_t(0x11));
  Wire.endTransmission();
  Wire.requestFrom(CLOCK_ADDRESS, 2);
  temp = Wire.read(); // MSB temp tegiszter
  return float(temp) + 0.25*(Wire.read()>>6);
}
byte bcd_Dec(byte val) {
// Ckonvertál bcd számból decimalisba
  return ( (val/16*10) + (val%16) );
}
byte dec_bcd(byte val) {
// Convertál decimalis számból bcd-be
  return ( (val/10*16) + (val%10) );
}

byte readControlByte(bool which) {
                // Read selected control byte: (0); reads 0x0e, (1) reads 0x0f
                // Read selected control byte
                // első byte (0) is 0x0e, második (1) is 0x0f
  Wire.beginTransmission(CLOCK_ADDRESS);
  if (which) {
                // 0x0f  control byte
    Wire.write(uint8_t(0x0f));
  } else {
                // 0x0e control byte
    Wire.write(uint8_t(0x0e));
  }
  Wire.endTransmission();
  Wire.requestFrom(CLOCK_ADDRESS, 1);
  return Wire.read();
}

void writeControlByte(byte control, bool which) {
                // Write the selected control byte.
                // which=false -> 0x0e, true->0x0f.
  Wire.beginTransmission(CLOCK_ADDRESS);
  if (which) {
    Wire.write(uint8_t(0x0f));
  } else {
    Wire.write(uint8_t(0x0e));
  }
  Wire.write(control);
  Wire.endTransmission();
}

void enableOscillator(bool TF, bool battery, byte frequency) {
 // bekapcsolja az oszcillátort. True - on, false - off.
  // if battery is true, turns on even for battery-only operation,
  // otherwise turns off if Vcc is off.
  // frequency must be 0, 1, 2, or 3.
  // 0 = 1 Hz
  // 1 = 1.024 kHz
  // 2 = 4.096 kHz
  // 3 = 8.192 kHz (Default if frequency byte is out of range)
  if (frequency > 3) frequency = 3;
                // read control byte in, but zero out current state of RS2 and RS1.
  byte temp_buffer = readControlByte(0) & 0b11100111;
  if (battery) {
                // turn on BBSQW flag
    temp_buffer = temp_buffer | 0b01000000;
  } else {
                // turn off BBSQW flag
    temp_buffer = temp_buffer & 0b10111111;
  }
  if (TF) {
                // set ~EOSC to 0 and INTCN to zero.
    temp_buffer = temp_buffer & 0b01111011;
  } else {
                // set ~EOSC to 1, leave INTCN as is.
    temp_buffer = temp_buffer | 0b10000000;
  }
                // shift frequency into bits 3 and 4 and set.
  frequency = frequency << 3;
  temp_buffer = temp_buffer | frequency;
                // And write the control bits
  writeControlByte(temp_buffer, 0);
}

void enable32kHz(bool TF) {
  // A 32Khz kimenetet kapcsolja ki vagy be
  // on (true);
  // off (false).
  byte temp_buffer = readControlByte(1);
  if (TF) {
                // turn on 32kHz pin
    temp_buffer = temp_buffer | 0b00001000;
  }
  else {
                // turn off 32kHz pin
    temp_buffer = temp_buffer & 0b11110111;
  }
  writeControlByte(temp_buffer, 1);
}

bool oscillatorCheck() {
  // ellenőrzi az OSF (oszcillátor stop Flag) állapotát.
  // Ha false értékkel tér vissza, akkor az óra valószínűleg nem pontos.
  // Az OSF értékét egy óra beállítással lehet törölni ( setTime() )
  byte temp_buffer = readControlByte(1);
  bool result = true;
  if (temp_buffer & 0b10000000) {
    // Ha az OSF true, akkor az függvény fals értékkel tér vissza
    result = false;
  }
  return result;
}


Ha szeretnénk a program működését részletesen megismerni és megérteni, akkor a DS3132 IC adatlapjából a következő táblázatot ajánlom tanulmányozni:

A táblázat az I2C buszon keresztül elérhető regisztereket tartalmazza. Ezek címe 00H-tól 12H-ig terjed. Ezeket a regisztereket tudjuk olvasni és írni. Az egyes regiszterekből olvassuk ki az időt, dátumot. A program megértéséhez néhány adalék:
Az óra IC 12 illetve 24 órás üzemmódban tud működni. Ezt a 02H regiszter BIT6 bitjével tudjuk beállítani. Ha ez a bit 0, akkor 24 órás üzemmód, ha 1, akkor 12 órás üzemmód. Nyilván az ugyanebben a regiszterben található BIT3-BIT0 bitekben található számot kell megfelelően értelmeznünk a BIT6 segítségével. Ha 12 órás üzemmódban vagyunk, akkor a BIT3-BIT0 biteket kell BCD kódból visszaalakítanunk decimálisba, és egy 0-9-ig terjedő számot kell kapnunk. A BIT4-nek ekkor a 10 óra kijelzés a feladata, értéke 0-1 lehet.  Ekkor a BIT5 jelzi, hogy a kiolvasott idő délután, vagy délelőtt. Ha tartalma 1, akkor azt jelzi, hogy délután van (PM), illetve 0 esetén délelőtt (AM). Ha 24 órás üzemmódban vagyunk, akkor a BIT5-BIT4 adja meg a 10 óra értékét, ami értelem szerűen 0-2 tartományban lehet.

Én a programban nem használtam a 05H regiszterben található BIT7-ben kódolt “Century” értéket. Ezzel ugyanis az évszázadot lehet jelezni. Értéke alapértelmezetten 0, és akkor vált át 1-re, ha a 99-es év átfordul 00-ba. Ez legközelebb 2099-et követően 2100 január 1.én 0.00 órakor fog előfordulni. Ezzel azért nem foglalkoztam, mert én már biztosan nem érem meg, hogy ez megtörténjen, a gyönyör a jövő ifjúságának problémája marad.

Lényegesen részletesebb leírást találhatsz még a leírások menüben a DS3231 óra megszakítások használata című jegyzetemben. Abban a leírásban már a riasztási időpontok használatával is foglalkoztam, és összekombináltam a dolgot az Arduino megszakítás kezelésével. Ha még nem tudod mi a megszakítás kezelés, akkor ezt olvasd el előtte!

Az előbb említett DS3231 megszakítás használat leírásomnál megállapítottam, hogy elemes táplálás esetén nem működik az SQW kimenet, vagyis ez a modul nem alkalmas arra, hogy nagyon kis fogyasztású áramkörökben használjuk, hiszen nem tudja így felébreszteni az eszközünket egy adott időpontban. Az áramkör adatlapja szerint a fogyasztása 100 mikroA körüli, így még bőven felhasználható elemes kapcsolásokban is. Azonban a fenti modulon van egy EEPROM és LED is, ami jelentősen megnöveli az áramfelvételét. Ezért kerestem a net-en egy olyan modult, ami csak a DS3231 IC-t tartalmazza. Erre sajnos ráfaragtam, mert nincs neki kivezetve az INT/SQW kimenete. Bár a modul áramfelvétele valóban elég alacsony kb. 110 mikroA, ébresztésre nem tudom felhasználni. Csak a tanulság kedvéért írtam le az esetet, nehogy más is pórul járjon. Itt egy fotó az érintett modulról:

Azonban még nem adtam fel, mert látható, hogy van egy nem használt kivezetés, erre esetleg egy kis ügyeskedéssel ráforraszthatom a chip SQW lábát egy darab dróttal. Ez azonban ilyen méretekben már nem tuti.

Időközben megérkezett a rendelésem, és megismerkedtem egy PCF8563 chip-et tartalmazó modullal. Ez kevésbé pontos órát tartalmaz, de visszaszámláló időzítője is van. Nagyon kicsi az áramfelvétele, és elemes működés közben is ad az INT kimenete megszakító jelet. Itt ismerkedhetsz meg a használatával.


Telt múlt az idő, és elérkezett a pillanat, amikor a fenti, Rapberry Pi-hez tervezett óramodulomat felhasználtam. Mátrix kijelzővel építettem egy órát a hálószobába, ami szabályozza a fényerőt, és éjszaka kisebb fénnyel világit. Még mindig nincs kész, mert a legkisebb fényerőn is túlzottan világit, küzdök még vele. Azonban már szereztem tapasztalatokat a fenti modullal. 3db-ot vettem összesen kb. 1000Ft-ért. Az egyiken kapásból rossz volt az elem. Szerencsére könnyedén cserélhető. Másik nagy tapasztalat, hogy a fentebb ismertetett program hibás. 15 óra után 16 óra helyett 10 órára vált. Nem is értem pontosan, hiszen egy kész és jól működő programkönyvtárból másolgattam össze, de tény, hogy nem jól működik. Úgy tűnik sikerült az órát nem bcd-ben kiolvasni, és valóban a 16 óra bcd-ből számmá konvertálva 10. A szerény C++ tudásom akadályoz abban, hogy megfejtsem mi a hiba oka. Azonban kísérletezgetés, hiba javítás közben született egy jó kis prorgramocska. A hiba attól javult ki, hogy kivettem azokat a programsorokat, amik a 24/12 órás üzemmód jelzőbit állapotát kiolvassák.

Abból indultam ki, hogy nekem nem kell 12 órás üzemmód, nem kellenek a megszakítás kimenetek (hiszen ki sincs vezetve), és nem kell a négyszögjel kimenet sem. Így aztán két függvény született. Egy amivel beállítom az órát (és ezzel együtt az üzemmódot is automatikusan 24 órára állítom), és egy amivel kiolvasom a pontos időt. Csináltam a programban egy „dat_ido” típusú struktúrát, és ezzel a változó típussal deklarálok egy ds3231 globális változót. A globális változók használatától óva intenek a profik, és biztosan amatőr megoldás, de nekem így volt kényelmes. A leendő programban bárhol rendelkezésre áll a pontos idő, amit egy másodpercenként frissítek. AZ órabeállítás és a kiolvasás is roppant egyszerű és pár soros program lett. A hőmérséklet kiolvasást hagytam úgy, ahogy volt.

Kiegészítő programokat is írtam. Született egy program arra, hogy a dátumból automatikusan meghatározzam a hét napját, így ezt már külön nem kell beállítani. Sajnos a DS3231 nem kezeli automatikusan a téli és nyári óraállítást. Erre is sikerült kezelőfüggvényt késztenem. Ezeket a forrásokat még érdemes megnézni!

DS3231 saját kezelőfüggvény forrása példaprogrammal:

//Az óra használatához szükséges dolgok
#include <Wire.h>       //I2C kezelőkönyvtár

#define CLOCK_ADDRESS 0x68  //a DS3231 óra IC címe az I2C buszon. 
long ido_tmp=millis();      //egy másodpercenként fogjuk kiolvasni az időt, ennek időzítéséhez segédváltozó

struct dat_ido {      // a dátum és idő beállításához illetve kiolvasásához létrehozunk egy struktúrát dat_ido néven (változó típus)
  int ev;             //év tárolása a stuktúrában (évszázadokkal kell megadni, illetve így kapjuk meg az eredményt a dátum kiolvasásakor)
  byte ho;            //ho tárolása a struktúrában
  byte nap;           //nap tárolása a struktúrában
  byte het_napja;     //hét napja a struktúrában (1-hétfő....7-vasárnap)
  byte ora;           //óra tárolása a struktúrában (24 órás üzemmódot fogunk használni)
  byte perc;          //perc tárolása a struktúrában
  byte masodperc;     //másodperc tárolása a struktúrában
  bool pontos;        //ez a változó fogja megadni az IDO kiolvasását követően, hogy pontos-e a kiolvasott időpont 
                      //(ha elemes működés közben leáll a DS3231 oszcillátora, akkor az "OSF" flag bebillen, és ezt olvassuk ki
};

dat_ido ds3231;  //létrehozzuk az dat_ido típusú változónkat DS3231 változó néven


void setup(void) {
  Serial.begin(115200);
  Wire.begin();
  //az óra beállítása (csak egyszer kell megcsinálni, aztán ki kell kommentezni
  /* ds3231.masodperc=55;
  ds3231.perc=59;
  ds3231.ora=15;
  ds3231.het_napja=1;
  ds3231.nap=21;
  ds3231.ho=2;
  ds3231.ev=2022; 
  setTime24();   //óra beállítása: négyszög kimenő jelet kikapcsolja, 
                 //32Khz-s kimenetet kikapcsolja és 24 órás üzemmódot állít be.
                 //Beállítj a pontos időt a feti változók értékével */
  Serial.println("Indul.."); 
}

void loop() {
  if (ido_tmp+1000<millis()) {     //másodpercenként teljesül a feltétel
    ido_tmp=millis();              //innen indul a következő másodperc időzítése
    getTime24();                   //kiolvassuk az időt a DS3132-ből a ds3231 változóba (dat_idő típusú változó)
    Serial.print(ds3231.ev,DEC);Serial.print('-');
    Serial.print(ds3231.ho,DEC);Serial.print('-');
    Serial.print(ds3231.nap,DEC);Serial.print("  ");
    Serial.print(ds3231.het_napja);
    Serial.print("  ");Serial.print(ds3231.ora,DEC);
    Serial.print(':');Serial.print(ds3231.perc,DEC);
    Serial.print(':');Serial.print(ds3231.masodperc,DEC);
    Serial.print("  ");Serial.println(ds3231.pontos,DEC);
  }
}


void setTime24() {
  //status regiszter beállítása
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(0x0e);               //A control regiszterbe fogunk írni, azt címezzük meg
  Wire.write(0b01100011);         //BBSQW bit 1, vagyis elemes táplálásnál is működik az oszcillátor
                                  //ha 1-re állítanánk, elemes táplálásnál nem járna az óra, csak őrizni az utolsó időpontot
                                  //A RS2 és RS1 bit 0-val beállítja a négyszögjel kimenetet 1Hz-ra, ezen lehet változtatni:
                                  // 0b01101011 esetén 1024Khz, 0b01110011 esetén 4096Khz, 0b01111011 esetén 8192Khz.
                                  //A INTCN bit 0-val beállítja, hogy az INT/SQW kimenet beállított frekvenciájú jelet ad ki.
  //címbet a státus regiszter következik, nem kell megcímezni csak írni, és az adat oda kerül
  Wire.write(0b00000000);         //A status regiszterben töröljük az OSF fleg-et, ami 1-el jelzi majd, ha elemes táplálásnál 
                                  //nem működött az oszcillátor, vagyis az óra valószínűleg nem pontos.
                                  //Az EN32Khz bit-et is 0-ra írjuk, azaz letiltjuk a 32Khz-s kimenetet
  Wire.endTransmission();
  //dátum és időpont beállítása
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(0x00);
  Wire.write(dec_bcd(ds3231.masodperc));
  Wire.write(dec_bcd(ds3231.perc));
  Wire.write(dec_bcd(ds3231.ora) & 0b10111111);
  Wire.write(dec_bcd(ds3231.het_napja)); 
  Wire.write(dec_bcd(ds3231.nap));
  Wire.write(dec_bcd(ds3231.ho));
  Wire.write(dec_bcd(ds3231.ev-2000)); 
  Wire.endTransmission();
}

void getTime24() {
  //kiolvassa a dátumot és az időpontot 
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(CLOCK_ADDRESS, 7);
  ds3231.masodperc = bcd_Dec(Wire.read());
  ds3231.perc = bcd_Dec(Wire.read());
  ds3231.ora = bcd_Dec(Wire.read());
  ds3231.het_napja = bcd_Dec(Wire.read());
  ds3231.nap = bcd_Dec(Wire.read());
  ds3231.ho = bcd_Dec(Wire.read() & 0b01111111);
  ds3231.ev = bcd_Dec(Wire.read())+2000;
  //status regiszterből az OSF bit kiolvasása.
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(0x0f);
  Wire.endTransmission();
  Wire.requestFrom(CLOCK_ADDRESS, 1);
  if (Wire.read()& 0b10000000) {ds3231.pontos=0;} else {ds3231.pontos=1;}  //1-el jelezzük, ha az óra valószínűleg pontos
}

float getTemperature() {
                // Kiolvassa a hőmérséklet értékét a 0x11h és 0x12h regiszterekből
  byte temp;
  Wire.beginTransmission(CLOCK_ADDRESS);
  Wire.write(0x11);         //a DS3231 chip 0x11 és 0x12-es regisztere a hőmérséklet regiszter
  Wire.endTransmission();
  Wire.requestFrom(CLOCK_ADDRESS, 2);         //2 byte-ot kérünk el a chip-től
  temp = Wire.read();                         //hőmérséklet MSB regisztere
  return float(temp) + 0.25*(Wire.read()>>6); //hőmérséklet LSB regiszterének kiolvasása
}

byte bcd_Dec(byte val) {  // Convertál bcd számból decimálisba
  return ( (val/16*10) + (val%16) );
}
byte dec_bcd(byte val) {  // Convertál decimális számból bcd-be
  return ( (val/10*16) + (val%10) );
}

Mennyire volt hasznos amit olvastál? Értékelés után szövegesen is leírhatod megjegyzéseidet és véleményedet!

Kattints egy csillagra az értékeléshez!

Szövegesen is leírhatod véleményedet! Ha kérdésed van, ne felejtsd el megadni az email címedet!