
Az Arduino‑projektekben gyakori választás a DS1302 valós idejű óra. Háromvezetékes (CE/SCLK/I/O) soros buszon kommunikál, 32,768 kHz‑es külső kristályt használ, és 5 V‑os környezetben is stabilan működik. Erőssége az egyszerű kezelhetőség és a nagyon alacsony fogyasztás. Korlátja, hogy nincs külön órajelkimenete (SQW/OUT), a pontossága pedig a kristály minőségétől és a hőmérséklettől függ. Ha hőkompenzált, stabilabb időalapra van szükség, érdemes a DS3231‑et választani.
A kevésbé ismert extrák teszik igazán hasznossá: 31 bájt beépített RAM (gyors állapot‑ vagy konfigurációmentéshez), írásvédelem (véletlen felülírás ellen), burst mód (tömbös olvasás/írás), valamint csepptöltés a tartalék LIR2032 cellához. A készenléti áram tipikusan ~300 nA nagyságrendű, így a tápmentő elem évekig kitart. Ezekkel a szolgáltatásokkal a DS1302 jó választás akkumulátoros adatgyűjtőkbe, időzített ébresztésű szenzorokba vagy olyan projektekbe, ahol kevés lábbal, egyszerű kábelezéssel kell megbízható idő és kis mennyiségű nem kritikus adat.
Az óramodullal már korábban találkoztunk – igaz akkor csak egyszerű naptár volt még csak →DS1302 RTC óramodul használata: az óra és a dátum.
Bekötés
Ebben a példában Arduino UNO‑hoz kötjük a DS1302 modult. Más Arduino lapoknál is ugyanígy érdemes gondolkodni: a bekötés logikája azonos. Az alábbi kiosztás megmutatja, melyik vezeték hová megy, és könnyen átültethető más modellekre is (csak más pineket választasz). Így ugyanazt a rajzot és kódvázat használhatod, mindössze a pin‑számokat kell átírni. Kezdéshez az UNO jó kiindulópont, de ESP8266 és ESP32 alatt is kipróbáltan működik a kód!
A DS1302 modul 3 vezérlőlábat igényel: CE (RST), SCLK (CLK) és I/O (DAT). Ezeket bármelyik Arduino digitális pinhez rendelhetjük. A táp pedig 5 V és GND.
| DS1302 | Jelölés a modulon | Arduino példa |
|---|---|---|
| CE | RST/CE | D2 |
| SCLK | CLK/SCLK | D3 |
| I/O | DAT/I/O | D4 |

A DS1302 három vezérlőlábat használ: CE (RST), SCLK (CLK) és I/O (DAT). A CE engedélyezi a chipet, az SCLK adja az órajelet, az I/O vezetéken pedig kétirányú az adatforgalom. Ezeket tetszőleges digitális Arduino‑pinhoz kötheted, majd a kódban ehhez igazítod a beállítást; a példában a D2–D4 kiosztást használjuk. A kód elején érdemes külön megadni a lábkiosztást, hogy később könnyen cserélhető legyen. A tápellátás 5 V és GND, a kommunikáció pedig a fenti három vezetéken zajlik.
Könyvtár telepítése
Az Arduino alatt a DS1302 egyszerű kezeléséhez az Rtc by Makuna könyvtárat használom, mert többféle egyéb órachipet is támogat a DS1302-n kívül. A kiegészítő telepítése egyszerű: az Arduino IDE-ben válaszd a Tools → Manage Libraries… menüpontot, majd keress rá a DS1302 kulcsszóra. A megjelenő listából telepítheted az Rtc by Makuna könyvtárat.

Mi jön még?
A folytatásban Arduino UNO-val bemutatom, mit nyújt a DS1302 modul a szokásos órafunkción túl. A bekötés és a könyvtár beállítása után több olyan szolgáltatás is rendelkezésre áll, amelyek különféle projektekben még hasznosak lehetnek. Ezek a részletek:
- a csepptöltés helyes használata (csak LIR2032 akkumulátorral),
- a 31 bájtos SRAM célszerű alkalmazása és az írásvédelem,
- a burst mód használata,
- az energiagazdálkodási lehetőségek.
De vágjunk is bele….
Csepptöltés (trickle charge)
A DS1302 beépített csepptöltés‑vezérlést is kínál: a tartalék akkut kis, állandó árammal tölti, hogy a kapacitását szinten tartsa (gyakorlatilag az önkisülését kompenzálja illetve ha áramszünet után a főrendszer újra feszültség alá kerül, akkor az akkut visszatölti. A megoldás nem gyors utántöltésre való, hanem „életben tartásra” – ezért biztonságos – de szándékosan kis áramokkal dolgozik.
Ha LIR2032 akkut használsz, a csepptöltés kíméletesen szinten tartja és szükség esetén utántölt – ami hosszú készenlétet és üzemelést biztosít. A funkciót kizárólag tölthető gombelemnél érdemes bekapcsolni – CR2032-nél tilos, mert annak károsodását okozhatja!
Beállítási paraméterek
Három paraméter állítható, amelyek együtt adják ki a töltőáramot:
- Engedélyezés / tiltás: alapállapotban ki van kapcsolva; csak akkor kapcsold be, ha LIR2032 (vagy egyéb tölthető 2032 akku) van a foglalatban.
- Diódák száma (1 vagy 2): a sorba kötött diódák feszültségesése növeli a „feszültség-lépcsőt”, így azonos ellenállás esetén csökkenti a töltőáramot.
- Soros ellenállás (2 kΩ / 4 kΩ / 8 kΩ): minél nagyobb értékű, annál kisebb a töltőáram.
A töltőáram kiszámításához a közelítő képlet (a →DS1302 adatlap [AnalogDevices] alapján):
I ≈ (Vcc - Vd) / R, ahol:
- Vd – a diódákon az összes feszültségesés,
- R – a választott soros ellenállás,
- I – az akku töltőárama.
Megjegyzés: az eredmény a diódák számától és a diódák feszültségesésétől függ; a kiszámított érték közelítő!
Például: 1 db dióda, 5V tápfeszültség esetén és 2k ellenállásnál a töltőáram ~2.2mA.
Beállítás Makuna könyvtárral
A Makuna/Rtc könyvtár DS1302‑t támogatja és egy egyszerű API‑t ad a csepptöltés paramétereinek beállítására. Ez a rtc inicializálása után már egyből használható.
1 2 3 | //Bekapcsolva, 1 dióda és 2k ellenállással uint8_t setting = DS1302TcrStatus_Enabled | DS1302TcrDiodes_One | DS1302TcrResistor_2KOhm; rtc.SetTrickleChargeSettings(setting); |
Tipp: a GetTrickleChargeSettings() segítségével az aktuális beállítás visszaolvasható.
Gyakorlati tanácsok
- Címkézd meg a modult vagy a foglalatot ha töltést használsz: „LIR2032 szükséges”, így nem kerül bele tévedésből CR2032.
- Ha a projektben időnként hálózatról megy a rendszer, a csepptöltés stabilan szinten tartja az LIR2032‑t; tisztán elemes üzemnél nem szükséges.
- Programíráskor a beállítást érdemes külön kiemelni a kód tetejére (ellenállás, diódaszám), hogy könnyen módosítható legyen.
A tartalékcella után következhet a beépített SRAM és az írásvédelem kérdésköre.
Az órába beépített memória
A DS1302‑ban 31 bájt statikus RAM található; a címek 0–30 között érhetők el. A kisméretű, gyors tár apró állapotok, konfigurációk, számlálók vagy jelzőbitek tárolására ideális, amikor nincs szükség nagy adattömegre. A hozzáférés bájtonkénti, egyértelmű címzéssel történik, ezért rövid és kis késleltetésű műveletekkel kezelhető. A RAM az óra mellett érhető el, ezért a hozzáférés gyors; az olvasás és az írás csak minimális többletet jelent. Több bájtos értékeket érdemes egymást követő címeken elhelyezni, LSB→MSB sorrendben, és egyszerű „RAM‑térképet” vezetni, hogy később is átlátható maradjon, mi hová kerül. Fontos: ez nem tartós tároló. A tartalom illékony, tápmentő (backup) táp nélkül elveszik, ezért kritikus adatokat ne ide tároljunk, és számoljunk azzal, hogy teljes tápvesztés után a RAM‑ot inicializálni kell.
Címtartomány és címzés
A RAM címei és használatuk röviden: Érvényes címek: 0–30. Célszerű RAM‑térképet vezetni (melyik bájt mit jelent), így később is átlátható marad a projekt.
- Többbájtos értéket (pl.
uint16_t) alacsony bájt → magas bájt (LSB → MSB) sorrendben érdemes eltárolni két egymást követő címen. - Hibakeresésnél hasznos egy „RAM dump”: írasd ki a teljes 0–30 tartományt.
1 2 3 4 5 6 7 8 | // Teljes RAM dump (0–30) Serial.println("RAM dump 0..30"); for (uint8_t addr = 0; addr <= 30; addr++) { uint8_t v = rtc.GetMemory(addr); Serial.print("RAM["); Serial.print(addr); Serial.print("] = "); Serial.println(v); // szükség esetén igazítható delay(5); } |
Így gyorsan kiderül, hol írtál mellé.
Adatstratégia – egyszerű RAM‑térkép példa
- 0. bájt: verzió/érvényességi jel (
0x42). - 1–2. bájt: számláló (LSB/MSB).
- 3–7. bájt: konfigurációs jelzők (bitekenként).
- 8–… bájt: felhasználói állapotok.
Érdemes 1..10 bájtot tartalékolni (későbbi bővítéshez) – így nem kell cipőskanállal gondolkodni a helyfoglaláson. A verzió/érvényességi bájtot indításkor ellenőrizzük; ha eltér a várt értéktől, akkor az inicializáljuk a órában levő memóriát alapállapotra.
Hibalehetőség: ha az RTC tápja megszűnik vagy a tartalék cella nincs jelen, a RAM tartalma elvész. Ezért nem kritikus adatok tárolására használd csak.
Írásvédelem – mikor kapcsold be?
A DS1302 chip globális írásvédelme a RAM‑ot is érinti, és megakadályozza a véletlen felülírást: bekapcsolt állapotban minden RAM‑írási kísérlet eredménytelen (az érték változatlan marad), az olvasás viszont továbbra is engedélyezett. Írás előtt ideiglenesen kapcsold ki, majd a művelet után azonnal állítsd vissza.
Lépések
- Kapcsold ki ideiglenesen:
SetWriteProtect(false). - Végezd el az írásokat a kijelölt címeken.
- Kapcsold vissza azonnal:
SetWriteProtect(true).
Olvasáshoz nem szükséges kikapcsolni.
Burst memória-műveletek (tömbös olvasás/írás)
Ha a használt könyvtár támogatja, igénybe vehetjük az ún. burst módot, amely blokkos írás‑olvasást tesz lehetővé. Ilyenkor több, egymást követő bájtot egyetlen parancssorozattal kezelünk: kevesebb vezérlőparancs, ritkább címmódosítás, rövidebb kommunikációs idő – vagyis gyorsabb, egyenletesebb működés. Ez főként időkritikus feladatoknál hasznos, illetve ha egymás melletti címeken tárolt adatblokkot mozgatunk. Amennyiben a választott könyvtárban nincs megvalósítva a burst támogatás, a RAM továbbra is gond nélkül használható: írjunk és olvassunk címről címre, egymás után; a kis (31 bájtos) tár miatt ez a módszer is kellően gyors és megbízható. Az áltanunk most használt library már tartalmazza.
Egy fontos tipp – a DS1302-ben nincs akkulemerülés jelzőbit
A DS1302 RAM tartalma teljesen törlődik, ha megszűnik a tápellátás, és nincs tartalék feszültség (backup cella) vagy épp ez is lemerült már. Éppen ezért érdemes a memória 0. bájtra egy azonosító értéket írni (például 0x42 vagy 0xA5), amit a program minden induláskor ellenőriz. Ha nem stimmel az érték, akkor a memória és ezzel együtt az óra is valószínűleg üres vagy érvénytelen: ilyenkor automatikusan feltölthető alapbeállításokkal. Így megbízhatóan észlelhető a tápvesztésből eredő adat- és idővesztés.
És a memóriakezelés mintaprogramjai…
A következő öt minta lépésről lépésre mutatja be a DS1302 belső SRAM-jának használatát az „Rtc by Makuna” könyvtárral. A példák ugyanarra a korábban bemutatott bekötésre épülnek, és közvetlenül futtathatók. Először megtanuljuk az egybájtos műveleteket: egy adott címre írás és ugyanonnan olvasás, visszaellenőrzéssel. Ezután jön a burst (tömbös) kezelés, ahol egymást követő bájtokat egyszerre küldünk/olvasunk, így gyorsabban és kevesebb protokoll-overheaddel dolgozunk. A „full demo” mindezt összevonja: egyben végigfuttatja az írás-olvasásokat, és a soros kimeneten világosan jelzi, mi volt eredetileg a RAM-ban, mit írtunk, és végül mi látszik visszaolvasva. Végül egy írásvédelmi (WriteProtect) minta megmutatja, hogyan védi a DS1302 a RAM-ot és az órát a véletlen felülírástól, és hogyan kell ideiglenesen kikapcsolni az írásokhoz. Fontos: a DS1302 RAM csupán 31 bájt (0–30), illékony; teljes tápvesztésnél tartalom törlődik. Írás előtt mindig kapcsold ki a WP-t, és csak nem kritikus adatokat tárolj itt.
A programok használata során NE legyen az írásvédelem bekapcsolva – ekkor a beírás értelemszerűen meghiúsul. Mindig kapcsoljuk ki a WriteProtect-et (SetIsWriteProtected(false)) írás előtt, és ügyelj arra, hogy a DS1302 RAM-ját felülírjuk — ha fontos adatok vannak ott, mentsd el előtte!
Egy bájt írása adott címre
Ez a rövid példa megmutatja, hogyan írj egyetlen bájtot a DS1302 RAM egy adott címére biztonságosan és egyszerűen. A függvény figyelembe veszi a write-protect állapotot: ha szükséges, kikapcsolja azt az írás előtt, majd visszaolvasással ellenőrzi az írás sikerét. Használd ezt akkor, ha csak egy kisméretű állapotot vagy konfigurációs értéket szeretnél tárolni, és fontos, hogy azonnal visszaigazolást kapj arról, hogy a memória ténylegesen frissült.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | // singleByteWrite(addr, value) -> true ha sikeres (visszaolvasva egyezik) bool singleByteWrite(uint8_t addr, uint8_t value) { if (addr >= DS1302RamSize) { Serial.println(F("Hiba: címtartományon kívül (addr >= DS1302RamSize)")); return false; } // biztosítjuk, hogy írható legyen if (rtc.GetIsWriteProtected()) rtc.SetIsWriteProtected(false); rtc.SetMemory(addr, value); // írás (használja a könyvtár SetMemory(addr, val) függvényét) // olvassuk vissza ellenőrzésként uint8_t readBack = rtc.GetMemory(addr); if (readBack == value) { Serial.print(F("Byte írás OK. Addr: ")); Serial.print(addr); Serial.print(F(", Value: 0x")); if (value < 16) Serial.print('0'); Serial.println(value, HEX); return true; } else { Serial.print(F("Byte írás hiba. Addr: ")); Serial.print(addr); Serial.print(F(", expected 0x")); if (value < 16) Serial.print('0'); Serial.print(value, HEX); Serial.print(F(", got 0x")); if (readBack < 16) Serial.print('0'); Serial.println(readBack, HEX); return false; } } |
Egy bájt olvasása adott címről
Ez a példa egyszerűen és biztonságosan kiolvassa a DS1302 RAM egy megadott címének tartalmát. A függvény visszaadja az olvasott értéket egy referencián keresztül és kiírja a soros monitorra. Ez a módszer hasznos, amikor gyorsan szeretnéd lekérdezni egyetlen állapot- vagy konfigurációs bájt értékét anélkül, hogy a teljes RAM-ot leolvasnád.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | // singleByteRead(addr, &outValue) -> true ha sikeres, outValue feltöltve bool singleByteRead(uint8_t addr, uint8_t &outValue) { if (addr >= DS1302RamSize) { Serial.println(F("Hiba: címtartományon kívül (addr >= DS1302RamSize)")); return false; } outValue = rtc.GetMemory(addr); Serial.print(F("Byte read. Addr: ")); Serial.print(addr); Serial.print(F(", Value: 0x")); if (outValue < 16) Serial.print('0'); Serial.println(outValue, HEX); return true; } |
Több bájt — burst írás (teljes vagy részleges buffer)
A burst (gyors) írás akkor hasznos, amikor több bájtot szeretnél egyszerre feltölteni a DS1302 RAM-ba. A hatékonyságot úgy érjük el, hogy mindent byte-okra bontva előkészítünk egy lokális tömbben (buffer), majd egyetlen hívással (SetMemory(buffer, count)) elküldjük az egész tömböt az RTC-nek. Ez drasztikusan csökkenti a kommunikációs overhead-et a címenkénti íráshoz képest. Az alábbi példa feltölti a teljes DS1302 RAM-ot mintával és visszaadja, hány bájtot írt ténylegesen.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | // burstWrite(buffer, count) -> visszatér a ténylegesen írt bájtok számával uint8_t burstWrite(const uint8_t *buffer, uint8_t count) { if (count == 0) return 0; if (count > DS1302RamSize) count = DS1302RamSize; // limitáljuk a méretet if (rtc.GetIsWriteProtected()) rtc.SetIsWriteProtected(false); // SetMemory(buffer, count) - a Makuna könyvtár visszaadja az írt bájtok számát uint8_t written = rtc.SetMemory(buffer, count); Serial.print(F("Burst write: asked ")); Serial.print(count); Serial.print(F(" bytes, written ")); Serial.print(written); Serial.println(F(" bytes.")); return written; } |
Több bájt — burst olvasás (teljes vagy részleges buffer)
A burst olvasás a DS1302 RAM teljes vagy részleges tartalmának gyors leemelésére szolgál: egyszerre kérjük le a bájtokat egy előre allokált bufferbe. Mivel a kommunikáció byte-sorozatként történik, ez jóval gyorsabb, mint címről-címre olvasni. A bemutatott függvény végrehajtja a burst olvasást és visszaadja az olvasott bájtok számát, valamint feltölti a kapott adatokat a user által adott tömbbe.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | // burstRead(destBuffer, count) -> visszatér az olvasott bájtok számával uint8_t burstRead(uint8_t *destBuffer, uint8_t count) { if (count == 0) return 0; if (count > DS1302RamSize) count = DS1302RamSize; // GetMemory(destBuffer, count) - a Makuna könyvtár visszaadja az olvasott méretet uint8_t read = rtc.GetMemory(destBuffer, count); Serial.print(F("Burst read: requested ")); Serial.print(count); Serial.print(F(" bytes, read ")); Serial.print(read); Serial.println(F(" bytes.")); return read; } |
Rövid példa: full demo használat (írás + olvasás + ellenőrzés)
Ez a rövid demo bemutatja a DS1302 RAM mindkét alapvető műveletét: egyedi bájtok írását/olvasását és a teljes RAM egyszerre történő (burst) írását/olvasását. Először egy 1-bájtos példát futtatunk: írunk egy értéket egy adott címre, majd visszaolvassuk és ellenőrizzük. Ezután létrehozunk egy mintatömböt, burst módban feltöltjük vele a teljes DS1302 RAM-ot, majd visszaolvassuk és összevetjük a kapott bájtokat a küldött tömbbel. A demo világos visszajelzést ad soros monitoron az ellenőrzésről.

És a program a teljes hosszában…
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 | /* Program neve: DS1302 RTC RAM olvasás/írás benchmark és ellenőrzés – Makuna könyvtárral Verzió: 1.0 Dátum: 2025. augusztus 20. Szerző: Cseh Róbert Web: https://www.tavir.hu Leírás: Ez a program bemutatja és összehasonlítja a DS1302 RAM írás/olvasás két módját: byte-alapú (cím / egyenkénti írás/olvasás) és burst (teljes RAM egyszerre). A program: - inicializálja a DS1302 modult (ThreeWire + RtcDS1302) - kiír egy ismert tesztmintát byte-onként a RAM minden címére, visszaolvassa és ellenőrzi - kiír egy teljes buffer-t burst módban (max DS1302RamSize), visszaolvassa és ellenőrzi - méri mindkét művelethez szükséges időt micros() segítségével, és kiszámolja a byte/s sebességet Hardver (bekötés a jelen sketch-hez): - DS1302 IO (DAT) -> D3 - DS1302 SCLK (CLK) -> D4 - DS1302 CE (RST) -> D2 - VCC -> 3.3V vagy 5V (modul/IC függő) - GND -> GND FIGYELMEZTETÉS: - A DS1302 RAM kis kapacitású (31 byte). A program felülírja a RAM tartalmát. Teszt előtt győződj meg, hogy nem tárolsz ott fontos adatot. - A mérési eredmények függhetnek a ThreeWire implementációtól és az Arduino board teljesítményétől. A mikro-szekundumos időmérés pontossága elég jó a viszonyításra, de nem laboratóriumi pontosságú. */ #include <Arduino.h> #include "ThreeWire.h" #include "RtcDS1302.h" #include "RtcDateTime.h" // A Te bekötésed: const uint8_t PIN_IO = 3; // DS1302 IO (DATA) -> D3 const uint8_t PIN_CLK = 4; // DS1302 SCLK (CLOCK) -> D4 const uint8_t PIN_CE = 2; // DS1302 CE / RST -> D2 // ThreeWire konstruktor: (ioPin, clkPin, cePin) ThreeWire wire(PIN_IO, PIN_CLK, PIN_CE); RtcDS1302<ThreeWire> rtc(wire); // Ha a könyvtár nem definiálta, definiáljuk (biztonsági fallback) #ifndef DS1302RamSize #define DS1302RamSize 31 #endif // Segédfüggvény: hex + ASCII dump egy bufferhez void printBufferHex(const uint8_t* buf, uint8_t len) { for (uint8_t i = 0; i < len; ++i) { if (buf[i] < 0x10) Serial.print('0'); Serial.print(buf[i], HEX); Serial.print(' '); } Serial.println(); } // Byte-írás és olvasás teszt (egyenként): return true ha minden cím egyezik // Mérési eredmények visszaadása writeTimeMicros és readTimeMicros változókban. bool testByteMode(uint32_t &writeTimeMicros, uint32_t &readTimeMicros) { writeTimeMicros = 0; readTimeMicros = 0; // Biztosítsuk, hogy írható legyen if (rtc.GetIsWriteProtected()) rtc.SetIsWriteProtected(false); // write (cím/cím) unsigned long t0 = micros(); for (uint8_t addr = 0; addr < DS1302RamSize; ++addr) { uint8_t val = (uint8_t)(addr ^ 0xA5); rtc.SetMemory(addr, val); } unsigned long t1 = micros(); writeTimeMicros = (uint32_t)(t1 - t0); // rövid pause delay(10); // read and verify bool ok = true; t0 = micros(); for (uint8_t addr = 0; addr < DS1302RamSize; ++addr) { uint8_t expected = (uint8_t)(addr ^ 0xA5); uint8_t actual = rtc.GetMemory(addr); if (actual != expected) { Serial.print(F("Byte mode mismatch at addr ")); Serial.print(addr); Serial.print(F(": expected 0x")); if (expected < 0x10) Serial.print('0'); Serial.print(expected, HEX); Serial.print(F(", got 0x")); if (actual < 0x10) Serial.print('0'); Serial.println(actual, HEX); ok = false; } } t1 = micros(); readTimeMicros = (uint32_t)(t1 - t0); return ok; } // Burst-írás és olvasás teszt (teljes RAM egyszerre): return true ha minden bájt egyezik // Mérési eredmények visszaadása writeTimeMicros és readTimeMicros változókban. bool testBurstMode(uint32_t &writeTimeMicros, uint32_t &readTimeMicros) { writeTimeMicros = 0; readTimeMicros = 0; uint8_t writeBuf[DS1302RamSize]; uint8_t readBuf[DS1302RamSize]; // előkészítünk egy mintát: egyszerű sorozat (addr + 0x33) for (uint8_t i = 0; i < DS1302RamSize; ++i) writeBuf[i] = (uint8_t)(i + 0x33); // Biztosítsuk, hogy írható legyen if (rtc.GetIsWriteProtected()) rtc.SetIsWriteProtected(false); // burst write - visszaadott érték az írt bájtok száma unsigned long t0 = micros(); uint8_t written = rtc.SetMemory(writeBuf, DS1302RamSize); unsigned long t1 = micros(); writeTimeMicros = (uint32_t)(t1 - t0); if (written != DS1302RamSize) { Serial.print(F("Warning: burst SetMemory írt bájtok száma nem egyezik: ")); Serial.print(written); Serial.print(F(" vs ")); Serial.println(DS1302RamSize); // folytatjuk } delay(10); // burst read t0 = micros(); uint8_t read = rtc.GetMemory(readBuf, DS1302RamSize); t1 = micros(); readTimeMicros = (uint32_t)(t1 - t0); if (read != DS1302RamSize) { Serial.print(F("Warning: burst GetMemory olvasott bájtok száma nem egyezik: ")); Serial.print(read); Serial.print(F(" vs ")); Serial.println(DS1302RamSize); } // összehasonlítás bool ok = true; uint8_t minCount = min(read, (uint8_t)DS1302RamSize); for (uint8_t i = 0; i < minCount; ++i) { if (readBuf[i] != writeBuf[i]) { Serial.print(F("Burst mismatch idx ")); Serial.print(i); Serial.print(F(": expected 0x")); if (writeBuf[i] < 0x10) Serial.print('0'); Serial.print(writeBuf[i], HEX); Serial.print(F(", got 0x")); if (readBuf[i] < 0x10) Serial.print('0'); Serial.println(readBuf[i], HEX); ok = false; } } return ok; } // Full demo: meghívjuk a méréseket, kiírjuk az időket, throughput-ot és a verifikációt void fullDemo() { Serial.println(F("=== Full RAM demo: byte mode & burst mode (with timings) ===")); Serial.print(F("DS1302RamSize = ")); Serial.println(DS1302RamSize); Serial.println(); // BYTE MODE Serial.println(F("--- BYTE MODE (per-address write/read) ---")); uint32_t byteWriteUs = 0, byteReadUs = 0; bool byteOk = testByteMode(byteWriteUs, byteReadUs); Serial.print(F("Byte mode: write time (us): ")); Serial.println(byteWriteUs); Serial.print(F("Byte mode: read time (us): ")); Serial.println(byteReadUs); // egyszerű throughput számítás (bytes / sec) float byteWriteSec = byteWriteUs / 1000000.0f; float byteReadSec = byteReadUs / 1000000.0f; unsigned long writeThroughput = (unsigned long)( (byteWriteSec > 0.0f) ? (DS1302RamSize / byteWriteSec) : 0 ); unsigned long readThroughput = (unsigned long)( (byteReadSec > 0.0f) ? (DS1302RamSize / byteReadSec) : 0 ); Serial.print(F("Byte mode: write throughput (bytes/s): ")); Serial.println(writeThroughput); Serial.print(F("Byte mode: read throughput (bytes/s): ")); Serial.println(readThroughput); Serial.print(F("Byte mode verification: ")); Serial.println(byteOk ? F("OK") : F("FAILED")); Serial.println(); delay(200); // BURST MODE Serial.println(F("--- BURST MODE (full RAM write/read) ---")); uint32_t burstWriteUs = 0, burstReadUs = 0; bool burstOk = testBurstMode(burstWriteUs, burstReadUs); Serial.print(F("Burst mode: write time (us): ")); Serial.println(burstWriteUs); Serial.print(F("Burst mode: read time (us): ")); Serial.println(burstReadUs); float burstWriteSec = burstWriteUs / 1000000.0f; float burstReadSec = burstReadUs / 1000000.0f; unsigned long burstWriteTP = (unsigned long)( (burstWriteSec > 0.0f) ? (DS1302RamSize / burstWriteSec) : 0 ); unsigned long burstReadTP = (unsigned long)( (burstReadSec > 0.0f) ? (DS1302RamSize / burstReadSec) : 0 ); Serial.print(F("Burst mode: write throughput (bytes/s): ")); Serial.println(burstWriteTP); Serial.print(F("Burst mode: read throughput (bytes/s): ")); Serial.println(burstReadTP); Serial.print(F("Burst mode verification: ")); Serial.println(burstOk ? F("OK") : F("FAILED")); Serial.println(); Serial.println(F("=== Summary ===")); Serial.print(F("Byte mode (us) write/read: ")); Serial.print(byteWriteUs); Serial.print(F(" / ")); Serial.println(byteReadUs); Serial.print(F("Burst mode (us) write/read: ")); Serial.print(burstWriteUs); Serial.print(F(" / ")); Serial.println(burstReadUs); Serial.println(F("==== End of demo ====")); } void setup() { Serial.begin(115200); delay(200); Serial.println(); Serial.println(F("=== DS1302 RAM read/write benchmark and verification ===")); Serial.println(F("Pinout: IO->D3, SCLK->D4, CE->D2")); Serial.println(); // init RTC wire.begin(); rtc.Begin(); // biztosítsuk, hogy írható a memória (WP off) if (rtc.GetIsWriteProtected()) { Serial.println(F("WriteProtect ON - kapcsolom: SetIsWriteProtected(false)")); rtc.SetIsWriteProtected(false); } // futtatjuk a teljes demót (byte és burst mód időméréssel) fullDemo(); } void loop() { // semmi - a setup elvégezte a teszteket delay(1000); } |
Extra tippek
- A
SetMemory(buffer, count)ésGetMemory(buffer, count)általában visszaadja a ténylegesen írt/olvasott bájtok számát – ellenőrizd a visszatérési értéket - A
delay(5)/delay(10)segít a stabilitásban írás után – a DS1302 gyakorlati viselkedése és a ThreeWire implementáció is befolyásolja, hogy mennyi szünet szükséges. - Ha teljes biztonságot akarsz, előtte olvasd ki a WP (write-protect) állapotát és állítsd
false-ra, majd vissza, ha szükséges. Ezzel elkerülöd a használat során a véletlen módosítást!
Írásvédelem
A DS1302 RTC modul egyik kevésbé ismert, de hasznos funkciója a globális írásvédelem. Ez a beállítás a teljes belső RAM-ra (0–30 bájt) érvényes, és megakadályozza, hogy véletlenül felülírjunk fontos adatokat. A védelem aktív állapotában a SetMemory() hívások nem változtatják meg a memóriát – bár nem okoznak hibát, a RAM tartalma változatlan marad. Az olvasás (pl. GetMemory()) azonban továbbra is működik.
Mikor érdemes használni?
- Ha konfigurációs állapotot tárolunk RAM-ban, amit nem akarunk véletlenül felülírni
- Ha érzékeny projekthez készült előkonfigurált beállítások vannak a memóriában
- Ha a projektet többen fejlesztik, és szeretnénk biztosítani, hogy írás csak kódszintű engedély után történjen
Lépések – hogyan kezeld?
A DS1302 írásvédelme programból be- és kikapcsolható, így dinamikusan szabályozhatjuk, mikor engedélyezzük az írást.
1. Írás előtt kapcsold ki:
1 | rtc.SetIsWriteProtected(false); // Írás engedélyezése |
2. Végezd el az írást:
1 | rtc.SetMemory(1, 42); // Például 1. címre értéket írunk |
3. Utána kapcsold vissza:
1 | rtc.SetIsWriteProtected(true); // Védelem visszaállítása |
Tipp: Mindig használd a
GetIsWriteProtected()függvényt, ha nem vagy biztos benne, hogy a védelem aktív-e. Ezzel elkerülheted a rejtett hibákat.
Példa – állapotmentés védett módon
1 2 3 4 | // Védett írásművelet minta – RAM 2. címére írunk, de csak ideiglenes védelem-leoldással if (rtc.GetIsWriteProtected()) rtc.SetIsWriteProtected(false); rtc.SetMemory(2, 123); // adat írása rtc.SetIsWriteProtected(true); // visszakapcsoljuk a védelmet |
Ez a minta segít megelőzni a véletlen adatvesztést olyan projektekben, ahol a DS1302 RAM-ját állapotok, beállítások vagy mért értékek ideiglenes tárolására használjuk.
Gyakran ismételt kérdések és trükkök
Kérdés: Miért érdemes DS1302‑t választani Arduino projektekhez?
Válasz: A DS1302 egy alacsony fogyasztású valós idejű óra, amely egyszerű soros kapcsolattal illeszthető az Arduinohoz. Ideális választás akkumulátoros vagy energiatakarékos alkalmazásokhoz, mivel a készenléti áramfelvétele rendkívül alacsony (~300 nA). Emellett 31 bájtos beépített RAM-ot is kínál, amelyet gyors, ideiglenes adattárolásra használhatunk. Hasznos kiegészítője a csepptöltési funkció, amely hosszabb elem-élettartamot biztosít megfelelő akkumulátor használata mellett. Az eszköz stabil működése, egyszerű kezelhetősége és kedvező ára miatt kedvelt választás a hobbi és oktatási célú Arduino projektekben.
Kérdés: Hogyan zajlik a DS1302 kommunikációja az Arduinóval?
Válasz: A DS1302 három vezetékes soros kommunikációt alkalmaz: CE (chip engedélyezés), SCLK (órajel) és I/O (adat). Ezeket tetszőleges digitális pinre köthetjük az Arduinon, és a könyvtárban megadható, melyik pin milyen szerepet lát el. A kommunikáció irányított, az I/O vezetéken bidirekcionálisan történik az adatforgalom. A megfelelő könyvtár – például az Rtc by Makuna – használatával a kommunikáció gyorsan implementálható, a beállítások pedig egyszerűen módosíthatók a kód elején definiált pin-hozzárendelésekkel.
Kérdés: Mi az a csepptöltés, és mikor használható?
Válasz: A csepptöltés (trickle charge) egy biztonságos, lassú töltési mechanizmus, amely kis áramerősséggel tölti a tartalék LIR2032 gombelem kapacitását. Ez főként akkor hasznos, ha a rendszer időnként hálózatról is kap tápot, és fontos, hogy a gombelem ne merüljön le. Fontos szabály: kizárólag újratölthető típusú (LIR) gombelem esetén használható ez a funkció! Ha hagyományos, nem tölthető CR2032-t használnánk, az töltés hatására károsodhat vagy túlmelegedhet. A csepptöltés beállítható diódák és ellenállások kombinációjával, amelyek szabályozzák a töltőáram nagyságát – a cél mindig a biztonságos és hosszú távon is megbízható működés.
Kérdés: Mire használható a DS1302 beépített 31 bájtos RAM-ja?
Válasz: A beépített RAM egy gyors, kis méretű memória, amely nem tartós, de ideális ideiglenes adatok – például konfigurációs bitek, ciklusszámlálók vagy szenzorértékek – tárolására. A memóriaterület címezhető 0 és 30 között, így akár egy saját RAM-térképet is készíthetünk a jobb átláthatóság érdekében. Fontos tudni, hogy tápvesztés vagy tartalékfeszültség hiányában a RAM tartalma elveszik. Ezért csak nem kritikus adatokra ajánlott. Egy jól megtervezett RAM-struktúra segíti a stabil működést és a projekt jövőbeli bővíthetőségét is.
Kérdés: Miért fontos az írásvédelem bekapcsolása?
Válasz: A DS1302 globális írásvédelmi funkciója lehetővé teszi, hogy megakadályozzuk a RAM véletlen felülírását. Ez különösen akkor fontos, ha a RAM-ban előkonfigurált beállításokat vagy állapotjelzőket tárolunk. A védelem programból dinamikusan ki- és bekapcsolható, így az írási műveletek előtt ideiglenesen deaktiválhatjuk, majd újra aktiválhatjuk a biztonság érdekében. Az írásvédelmi állapot lekérdezhető, így megelőzhetőek a nehezen észrevehető hibák. Ez különösen fontos olyan projekteknél, ahol több modul írhat ugyanabba a RAM-régióba.
Kérdés: Mikor érdemes burst módot használni a memóriaműveletekhez?
Válasz: A burst mód használata akkor ajánlott, ha több egymás utáni RAM címet szeretnénk egyszerre kezelni. Ezzel csökkenthető a kommunikációs overhead, gyorsabb lesz a memóriaírás vagy -olvasás, és egyenletesebb működést biztosít. A DS1302 esetében a teljes 31 bájtos RAM egyszerre írható vagy olvasható burst módban. Ez különösen időkritikus vagy gyakran frissülő adatok esetén előnyös. Érdemes figyelni arra, hogy a buffer mérete mindig pontosan illeszkedjen a kívánt RAM-határhoz, és a könyvtár visszajelzését is ellenőrizzük a megbízható működés érdekében.
Kérdés: Milyen típusú gombelem való a DS1302-höz, ha csepptöltést használunk?
Válasz: A DS1302 modul esetén, ha a csepptöltési funkciót is használjuk, kizárólag újratölthető LIR2032 típusú gombelem javasolt. A nem tölthető CR2032 használata veszélyes, mivel a csepptöltés túlmelegedést, szivárgást vagy tönkremenetelt is okozhat. Célszerű a modulon vagy a foglalaton egyértelmű címkét elhelyezni („LIR2032 szükséges”), hogy elkerüljük a hibás elemhasználatot. Ez különösen fontos többfelhasználós környezetben vagy későbbi karbantartás során.
Kérdés: Hogyan lehet biztosítani a RAM-ban tárolt adatok érvényességét?
Válasz: Használj úgynevezett verzióbájtot a RAM első (0.) címén, például a 0x42 értékkel. A program indulásakor ellenőrizd ezt a bájtot: ha eltér a várt értéktől, akkor a memória vélhetően üres vagy hibás – ilyenkor inicializálhatod alapbeállításokkal. Ez egy egyszerű, de hatékony módszer arra, hogy detektáld a tápvesztés utáni memóriavesztést, és ezzel növeld a projekt stabilitását.
Kérdés: Miért érdemes RAM‑térképet vezetni Arduino projektben?
Válasz: Mivel a DS1302 RAM-ja mindössze 31 bájtos, a hatékony memóriakezelés kulcsfontosságú. Egy RAM-térkép segítségével dokumentálhatod, hogy melyik bájt milyen célra szolgál – például számlálók, beállítási flag-ek, szenzoreredmények. Ez különösen akkor hasznos, ha más fejlesztő is dolgozik a projekten, vagy hónapokkal később kell módosítanod a működést. A jól strukturált memóriahasználat segít megelőzni az adatütközéseket és megkönnyíti a hibakeresést is.
Kérdés: Mikor érdemes RAM dump ciklust futtatni?
Válasz: RAM dump futtatása hasznos eszköz hibakeresés során, különösen ha a program nem a várt módon működik, vagy elveszett adatokra gyanakszol. A dump ciklus kiolvassa a teljes 0–30 bájt közötti RAM tartalmat, és soros monitoron megjeleníti az értékeket. Ez segít megállapítani, hol lehetett hibás írás, vagy melyik címeken tárolódnak nem várt adatok. Az elemzést követően visszakereshető a RAM-térkép alapján, hogy a tartalom egyezik-e az elvárt állapotokkal – így gyorsabban megtalálhatod a hiba okát.
Források
- DS1302 óramodul [TavIR WebShop]
- DS1302 adatlap [MaximIntegrated]
- DS1302 adatlap [Analog Devices]
- Rtc by Makuna könyvtár (RTC támogatás DS1302‑re) [GitHub]
Kapcsolódó cikkek:
– A digitális idő paradoxonja: az óraátállítás árnyoldalai
– DS1302 RTC óramodul használata: az óra és a dátum
– A DS1307 órachip (RTC) használata
– Pontos idő, nagy hatás: Miért fontos a precíziós időszolgáltatás?





