DS1307
ID: 217
Kategorie: Microchips
Menge: 0
Position:

Zegar czasu rzeczywistego RTC DS1307

DS1307 to chyba jeden z najpopularniejszych ukÅ‚adów RTC sÅ‚użących do odmierzania czasu w projektach Arduino podczas tworzenia różnego rodzaju zegarków. UkÅ‚ad ten możemy swobodnie kupić już za okoÅ‚o 3 zÅ‚, dlatego też jest bardzo chÄ™tnie wykorzystywany w ogromnej iloÅ›ci gotowych moduÅ‚ów.

Ma tu wpÅ‚yw nie tylko jego cena, ale zdolność  komunikacji z naszym mikrokontrolerem za poÅ›rednictwem magistrali I2C.  

 

DS1307 posiada możliwość zasilania bateryjnego z zakresu 2V ÷ 3.5V, które ma na zadanie podtrzymanie pracy zegara po zaniku gÅ‚ównego zasilania ukÅ‚adu. NapiÄ™cie zasilania  może mieÅ›cić siÄ™ w zakresie od 4.5V ÷ 5.5V przy poborze prÄ…du na poziomie 1mA. Do poprawnego dziaÅ‚ania wymagany jest zewnÄ™trzny kwarc 32.768Hz o pojemnoÅ›ci obciążenia CL=12.5pF.

Warto tutaj wspomnieć o dodatkowych wÅ‚aÅ›ciwoÅ›ciach ukÅ‚adu, takich jak generator przebiegu prostokÄ…tnego, o czÄ™stotliwoÅ›ciach 1Hz, 4096Hz, 8192Hz lub 32768Hz. DS1307 oferuje również podtrzymywanÄ… bateryjne  pamięć o rozmiarze 56 bajtów. Te dwie cechy sÄ… sukcesywnie pomijane przez twórców bibliotek oraz producentów gotowych moduÅ‚ów, poprzez  nie umieszczanie wyprowadzenia do odpowiedniego pinu SQW/OUT.

A szkoda - sygnaÅ‚ 1Hz możemy wykorzystać do obsÅ‚ugi przerwania aktualizacji wyÅ›wietlania czasu na ekranie LCD lub podÅ‚Ä…czenia mrugajÄ…cego dwukropka pomiÄ™dzy godzinÄ… a minutÄ…, oszczÄ™dzajÄ…c tym samym pin cyfrowy Arduino i miejsce w pamiÄ™ci na zbÄ™dny fragment programu. Ale o tym późnej.

UkÅ‚ad DS1307 dostÄ™pny jest w dwóch obudowach SO-8 oraz DIP-8. W obu wariantach, rozkÅ‚ad nóżek jest identyczny:

Dokumentacja techniczna: http://www.jarzebski.pl/datasheets/DS1307.pdf

Schemat połączeń

PoÅ‚Ä…czenie DS1307 jest bardzo proste. PodÅ‚Ä…czamy zasilanie 5V (nóżka 8), masÄ™ GND (nóżka 4) oraz kwarc zegarkowy 32768Hz pomiÄ™dzy nóżki 1 i  2 . Jak wspomniaÅ‚em wczeÅ›niej, ukÅ‚ad ten komunikuje siÄ™ z Arduino za pomocÄ… magistrali I2C, a wiÄ™c SCL (nóżka 6) do pinu A5, a SDA (nóżka 5) do pinu A4. Nie zapomnijmy podciÄ…gnąć linii sygnaÅ‚owych rezystorami o wartoÅ›ci 10kΩ do zasilania 5V.

Należy zwrócić tutaj szczególnÄ… uwagÄ™ na wyjÅ›cie SQW/OUT, które również podciÄ…gamy rezystorem o wartoÅ›ci 10kΩ do zasilania 5V. Jest to element wymagany ponieważ  wyjÅ›cie SQW/OUT dziaÅ‚a w ukÅ‚adzie otwartego drenu. Dodatkowo jeÅ›li chcemy podÅ‚Ä…czyć do niego diodÄ™ LED, należy podÅ‚Ä…czyć tutaj katodÄ™, anodÄ™ zaÅ› - do zasilania.  JeÅ›li nie planujemy korzystać z  SQW/OUT, możemy pozostawić je "w powietrzu".

Ja zamiast baterii 3V podÅ‚Ä…czyÅ‚em zwykÅ‚e zasilanie 3.3V z Arduino. W normalnych warunkach oczywiÅ›cie skorzystajmy z baterii :)

Prosty przykład

Do obsÅ‚ugi moduÅ‚ów z ukÅ‚adami DS1307 przygotowaÅ‚em bibliotekÄ™ dla Arduino, którÄ… można pobrać z repozytorium Githttps://github.com/jarzebski/Arduino-DS1307. Bazuje ona bibliotekach JeeLabs oraz Adafruit, jednak oferuje ona dodatkowe funkcje do sterowania wyjÅ›ciem SQW/OUT, dostÄ™pu do pamiÄ™ci ukÅ‚adu oraz formatowanie daty na wzór date() z PHP.

  1. #include <Wire.h>

  2. #include <DS1307.h>

  3.  

  4. DS1307 clock;

  5. RTCDateTime dt;

  6.  

  7. void setup()

  8. {

  9.   Serial.begin(9600);

  10.  

  11.   // Inicjalizacja DS1307

  12.   Serial.println("Inicjalizacja DS1307");;

  13.   clock.begin();

  14.  

  15.   // JeÅ›li nie ustawiono daty, ustawiamy

  16.   if (!clock.isReady())

  17.   {

  18.     // Data i czas z momentu kompilacji

  19.     clock.setDateTime(__DATE__, __TIME__);

  20.   }

  21. }

  22.  

  23. void loop()

  24. {

  25.   dt = clock.getDateTime();

  26.  

  27.   Serial.print("Raw data: ");

  28.   Serial.print(dt.year);   Serial.print("-");

  29.   Serial.print(dt.month);  Serial.print("-");

  30.   Serial.print(dt.day);    Serial.print(" ");

  31.   Serial.print(dt.hour);   Serial.print(":");

  32.   Serial.print(dt.minute); Serial.print(":");

  33.   Serial.print(dt.second); Serial.println("");

  34.  

  35.   delay(1000);

  36. }

Formatowanie daty

JeÅ›li chcemy wyÅ›wietlić czas i datÄ™ w odpowiednim dla nas formacie, możemy skorzystać z funkcji dateFormat().

  1. #include <Wire.h>

  2. #include <DS1307.h>

  3.  

  4. DS1307 clock;

  5. #include <DS1307.h>

  6.  

  7. void setup()

  8. {

  9.   Serial.begin(9600);

  10.  

  11.   // Inicjalizacja DS1307

  12.   Serial.println("Inicjalizacja DS1307");;

  13.   clock.begin();

  14.  

  15.   // JeÅ›li nie ustawiono daty, ustawiamy

  16.   if (!clock.isReady())

  17.   {

  18.     // Data i czas z momentu kompilacji

  19.     clock.setDateTime(__DATE__, __TIME__);

  20.  

  21.     // UNIX timestamp

  22.     // clock.setDateTime(1397408400);

  23.  

  24.     // Recznie (YYYY, MM, DD, HH, II, SS

  25.     // clock.setDateTime(2014, 4, 13, 19, 21, 00);

  26.   }

  27. }

  28.  

  29. void loop()

  30. {

  31.   dt = clock.getDateTime();

  32.  

  33.   Serial.print("Long number format:          ");

  34.   Serial.println(clock.dateFormat("d-m-Y H:i:s", dt));

  35.  

  36.   Serial.print("Long format with month name: ");

  37.   Serial.println(clock.dateFormat("d F Y H:i:s",  dt));

  38.  

  39.   Serial.print("Short format witch 12h mode: ");

  40.   Serial.println(clock.dateFormat("jS M y, h:ia", dt));

  41.  

  42.   Serial.print("Today is:                    ");

  43.   Serial.print(clock.dateFormat("l, z", dt));

  44.   Serial.println(" days of the year.");

  45.  

  46.   Serial.print("Actual month has:            ");

  47.   Serial.print(clock.dateFormat("t", dt));

  48.   Serial.println(" days.");

  49.  

  50.   Serial.print("Unixtime:                    ");

  51.   Serial.println(clock.dateFormat("U", dt));

  52.  

  53.   delay(1000);

  54. }

Dostęp do pamięci o rozmiarze 56B

Jak już wiemy, DS1307 oferuje nam pamięć o rozmiarze 56 bajtów, której zawartość jest podtrzymywana bateryjnie. DostÄ™p do tej pamiÄ™ci odbywa siÄ™ poprzez dwie funkcje writeByte() oraz readByte(). W ramach przykÅ‚adu zostaÅ‚a ona zapisana wartoÅ›ciami 0xFF - 0xC8, a nastÄ™pnie odczytana.

  1. #include <Wire.h>

  2. #include <DS1307.h>

  3.  

  4. DS1307 clock;

  5.  

  6. char tmp[16];

  7.  

  8. void setup()

  9. {

  10.   Serial.begin(9600);

  11.  

  12.   // Inicjalizacja DS1307

  13.   Serial.println("Initialize DS1307");

  14.   clock.begin();

  15.  

  16.   // Wypelniamy pamiec

  17.   Serial.println("Filling memory");

  18.   for (byte i = 0; i < 56; i++)

  19.   {

  20.     clock.writeByte(i, 255-i);

  21.   }

  22.   Serial.println("... Done");

  23.   Serial.println();  

  24. }

  25.  

  26. void loop()

  27. {

  28.   // Odczyt pamieci

  29.   Serial.println("Reading memory");

  30.   Serial.println();

  31.   Serial.print("        ");

  32.  

  33.   for (byte i = 0; i < 16; i++)

  34.   {

  35.       sprintf(tmp, "0x%.2X ", i, 2);

  36.       Serial.print(tmp);

  37.   }

  38.  

  39.   Serial.println();

  40.   Serial.println("---------------------------------------------------------------------------------------");

  41.  

  42.   for (byte j = 0; j < 4; j++)

  43.   {

  44.     sprintf(tmp, " 0x%.2X : ", (j*16), 2);

  45.  

  46.     Serial.print(tmp);

  47.  

  48.     for (byte i = 0; i < 16; i++)

  49.     {

  50.       if ((j*16 + i) > 55)

  51.       {

  52.         break;

  53.       }

  54.  

  55.       sprintf(tmp, "0x%.2X ", clock.readByte(j*16 + i), 2);

  56.  

  57.       Serial.print(tmp);

  58.     }

  59.  

  60.     Serial.println();

  61.   }

  62.  

  63.   delay(5000);

  64. }

Generator przebiegu prostokÄ…tnego SQW

W tym przykÅ‚adzie możemy zobaczyć jak wÅ‚Ä…czyć generator przebiegu prostokÄ…tnego. Należy skonfigurować odpowiedni rejestr wybierajÄ…c interesujÄ…cÄ… nas czÄ™stotliwość i wÅ‚Ä…czyć SQW. SygnaÅ‚ ten możemy wykorzystać do obsÅ‚ugi przerwania lub podÅ‚Ä…czyć diodÄ™ LED jako sygnalizator sekund, oszczÄ™dzajÄ…c tym samym cyfrowy pin Arduino. DziaÅ‚anie możecie zobaczyć na filmie znajdujÄ…cy siÄ™ na koÅ„cu artykuÅ‚u.

  1. #include <Wire.h>

  2. #include <DS1307.h>

  3.  

  4. DS1307 clock;

  5.  

  6. void setup()

  7. {

  8.   Serial.begin(9600);

  9.  

  10.   // Inicjalizacja DS1307

  11.   Serial.println("Initialize DS1307");;

  12.   clock.begin();

  13.  

  14.   // Ustawiamy date

  15.   if (!clock.isReady())

  16.   {

  17.     // Data i czas z momentu kompilacji

  18.     clock.setDateTime(__DATE__, __TIME__);

  19.   }

  20.  

  21.   // Wybieramy 1Hz

  22.   clock.setOutput(DS1307_1HZ);

  23.  

  24.   switch (clock.getOutput())

  25.   {

  26.     case DS1307_LOW:     Serial.println("SQW = LOW"); break;

  27.     case DS1307_HIGH:    Serial.println("SQW = HIGH"); break;

  28.     case DS1307_1HZ:     Serial.println("SQW = 1Hz"); break;

  29.     case DS1307_4096HZ:  Serial.println("SQW = 4096Hz"); break;

  30.     case DS1307_8192HZ:  Serial.println("SQW = 8192Hz"); break;

  31.     case DS1307_32768HZ: Serial.println("SQW = 32768Hz"); break;

  32.     default: Serial.println("SQW = Unknown"); break; }

  33. }

  34.  

  35. void loop()

  36. {

  37. }

Wyjście SQW jako pin cyfrowy

WyjÅ›cie SQW możemy również skonfigurować jako dodatkowy pin cyfrowy OUT, który traktujemy tak samo jak pin cyfrowy w Arduino. DziaÅ‚anie możecie zobaczyć na filmie znajdujÄ…cy siÄ™ na koÅ„cu artykuÅ‚u.

  1. #include <Wire.h>

  2. #include <DS1307.h>

  3.  

  4. DS1307 clock;

  5. boolean state;

  6.  

  7. void setup()

  8. {

  9.   Serial.begin(9600);

  10.  

  11.   // Inicjalizacja DS1307

  12.   Serial.println("Inicjalizacja DS1307");;

  13.   clock.begin();

  14. }

  15.  

  16. void loop()

  17. {

  18.   // Ustawiamy wyjscie

  19.   clock.setOutput(state);

  20.  

  21.   // Zmieniamy stan

  22.   state = !state;

  23.  

  24.   // Opoznienie

  25.   delay(100);

  26. }

Za wolno, za szybko. Kwarc to bardzo ważna rzecz

Bardzo ważnym elementem w zegarach czasu rzeczywistego jest odpowiedni dobór i montaż zewnÄ™trznego rezonatora kwarcowego. Najczęściej stosowane sÄ… tutaj tak zwane kwarce zegarkowe 32768 Hz o dokÅ‚adnoÅ›ci ±20ppm. Aby zrozumieć dokÅ‚adniej problem dokÅ‚adnoÅ›ci zegarów RTC musimy zastanowić siÄ™, jaki może być bÅ‚Ä…d czasu dla kwarców tego typu.

PPM to skrót od angielskiego terminu Parts Per Milion. Innymi sÅ‚owy oznacza, o ile części na jeden milion może pomylić siÄ™ ów kwarc. Na poczÄ…tek obliczmy sobie procentowy bÅ‚Ä…d dla typowej wartoÅ›ci 20ppm.

δF = = (20ppm / 1000000) * 100% = 0,002%

Niby nie dużo, ale przeliczając to na dobę, uzyskujemy całkiem pokażną wartość:

(0.002 [%] * 86400 [s]) / 100% = 1.728 [s]

W ciÄ…gu doby nasz zegarek może pomylić siÄ™ w skrajnym przypadku o 1.728 sekundy, a w ciÄ…gu miesiÄ…ca prawie o 53 sekund, rocznie zaÅ› prawie o 10 minut. OczywiÅ›cie wartość ta może być niższa ze wzglÄ™du na to, że kwarc może pomylić siÄ™ o mniejszÄ… ilość impulsów, zarówno w górÄ™ jak i w dóÅ‚.

Należy zwrócić uwagÄ™, że bÅ‚Ä…d ten jest silnie zależny od temperatury otoczenia w jakich pracuje kwarc. Typowe kwarce zegarkowe optymalizowane sÄ… najczęściej do pracy w temperaturze 25°C, gdzie bÅ‚Ä…d powinien wynosić 0%. OczywiÅ›cie w praktyce nie jest to możliwe. Zależność wielkoÅ›ci ppm od temperatury przedstawia krzywa obok, która jest zawsze podawana w karcie katalogowej danego kwarcu.

Jak widzimy na wykresie, dokÅ‚adność ±20ppm obowiÄ…zuje dla zakresu temperatur 2°C ÷ 48°C. Analogicznie - jeśłi nasz kwarc pracowaÅ‚by w temperaturze od 10°C ÷  40°C to dokÅ‚adność takiego kwarcu powinna mieÅ›cić siÄ™ w granicach ±10ppm.

JeÅ›li jednak nasz zegar myli siÄ™ powiedzmy o 5 sekund na dobÄ™, a nie pracuje w ekstremalnej temperaturze -10°C lub 60°C, to jego dokÅ‚adność jest o wiele mniejsza i wynosi:

5 [s] / 86400 [s] = 0,000057 = 57 ppm

Otrzymane 57 ppm oznacza tyle, że diabeł się nim interesuje :) Ale na poważnie, przyczyn może być kilka:

  • Nasz kwarc 32768Hz  nie posiada wymaganej pojemnoÅ›ci obciążenia CL=12.5pF, dlatego warto sprawdzić co kupiliÅ›my,
  • Nasz kwarc pamiÄ™ta czasy stanu wojennego. Kwarce podlegajÄ… procesowi starzenia, który wynosi okoÅ‚o. ±5 ppm/rok. JeÅ›li kwarc leżakowaÅ‚ u sprzedawcy 2 lata to zamiast deklarowanych ±20ppm w danym zakresie temperatur, może być już ±30ppm.
  • Na kwarc dziaÅ‚ajÄ… zakÅ‚ócenia z pobliskich Å›cieżek, w których wystÄ™pujÄ… sygnaÅ‚y szybko zmienne,
  • Kwarc jest po prostu wadliwy

A wiÄ™c, aby zminimalizować bÅ‚Ä…d zegara musimy posiadać odpowiedni kwarc. Dodatkowo powinien on znajdować siÄ™ jak najbliżej nóżek DS1307, ale w wiÄ™kszej odlegÅ‚oÅ›ci od Å›cieżek sygnaÅ‚owych. ZalecanÄ… metodÄ… jest również otoczenie poÅ‚Ä…czenia kwarcu z ukÅ‚adem pierÅ›cieniem masy (Guard ring). JeÅ›li mamy możliwość zaprojektowania pÅ‚ytki na dwóch warstwach, możemy otoczyć pole na którym znajduje siÄ™ kwarc dodatkowÄ… masÄ… (Local ground plane) i przylutować do niej metalowÄ… obudowÄ™. Odradzane jest również prowadzenie jakichkolwiek Å›cieżek sygnaÅ‚owych w tych obszarach.

JeÅ›li speÅ‚nimy wszystkie powyższe warunki... to i tak nasz zegarek nie bÄ™dzie odmierzaÅ‚ czasu dokÅ‚adnie (tada!). Nawet jeÅ›li zapewnimy mu przez caÅ‚y czas jego pracy idealnÄ… temperaturÄ™ 25°C.

Kwarce z kompensacjÄ… temperaturowÄ…

Jak już pewnie zdążyliÅ›cie zauważyć, najwiÄ™kszym problemem jest tutaj czynnik temperatury. Istnieje kilka metod poprawy dokÅ‚adnoÅ›ci kwarców. Możemy zastosować trymer poprawiajÄ…c jego stabilność, możemy co jakiÅ› czas synchronizować czas z zewnÄ™trznego wzorca (np.: komputera). Możemy oczywiÅ›cie skorzystać z innych ukÅ‚adów RTC z wbudowanÄ… kompensacjÄ… temperatury (DS3231). Jednak jeÅ›li zależy nam na DS1307 warto zainteresować siÄ™ oscylatorem DS32kHz z kompensacjÄ… temperaturowÄ… (TCXO).

DS32kHz dostÄ™pny jest w obudowach SO oraz EDIP. W naszym przykÅ‚adzie wykorzystamy ten w obudowie EDIP.

Dokumentacja techniczna: http://www.jarzebski.pl/datasheets/DS32kHz.pdf

Jego dokÅ‚adność w zakresie temperatury 0°C ÷ 40°C wynosi aż ±2ppm, a w zakresie temperatur przemysÅ‚owych -40°C ÷ 85°C aż ±7.5ppm. Dla porównania obliczmy odchyÅ‚kÄ™ czasu dla 2ppm:

δF = = (2ppm / 1000000) * 100% = 0,0002%

(0.0002 [%] * 86400 [s]) / 100% = 0.1728 [s] na dzień

0.1728 [s] * 355 [dni] = 61 [s] na rok

podczas gdy standardowy kwarc zegarkowy

1.728 [s] * 355 [dni] = 613 [s] na rok

Schemat połączenia DS32kHz i DS1307

PodÅ‚Ä…czenie DS1307 pozostaje bez zmian. JedynÄ… różnicÄ… jest podÅ‚Ä…czenie pod X1 i X2 rezystora o wartoÅ›ci 33kΩ. WyjÅ›cie 32KHZ z DS32kHz (nóżka 12) podÅ‚Ä…czamy natomiast do X1 poprzez szeregowo poÅ‚Ä…czony rezystor 1MΩ i kondensator 100pF. OczywiÅ›cie DS32kHz wymaga również zasilania bateryjnego w przypadku zaniku zasilania gÅ‚ównego. CaÅ‚y ukÅ‚ad zasilamy napiÄ™ciem 5V i podÅ‚Ä…czamy do masy (wymagane jest również podÅ‚Ä…czenie wszystkich pinów NC do masy). DS32kHz posiada jeszcze inne warianty zasilania, ale o nich możecie poczytać w dokumencie PDF (strona 7).

Od teraz, wasz zegarek będzie stabilny jak skała.

Jak to działa?

 

Materiały dodatkowe

Dokumentacja techniczna: http://www.jarzebski.pl/datasheets/DS32kHz.pdf
Dokumentacja techniczna: http://www.jarzebski.pl/datasheets/DS1307.pdf
Biblioteka Arduino: https://github.com/jarzebski/Arduino-DS1307