DS3231 jest bardzo precyzyjnym ukÅ‚adem RTC sÅ‚użącym do odmierzania czasu, czÄ™sto spotykanym w niektórych moduÅ‚ach dla Arduino.
Jego ogromną zaletą jest brak konieczności podłączania zewnętrznego rezonatora kwarcowego oraz wbudowany termometr do kompensacji temperaturowej.
JeÅ›li przypomnimy sobie, jaki wpÅ‚yw ma temperatura na standardowy kwarc zegarkowy, stosowany w opisywanym niedawno DS1307 i jakie może mieć to skutki po upÅ‚ywie miesiÄ…ca czasu, to z pewnoÅ›ciÄ… docenicie dokÅ‚adność jakÄ… oferuje DS3231, która wynosi staÅ‚e ±2ppm w zakresie temperatur 0°C ÷ 40°C oraz ±3.5ppm w zakresie temperatur -40°C ÷ 85°C. Tak duża dokÅ‚adność gwarantuje maksymalnÄ… odchyÅ‚kÄ™ odmierzanego czasu do okoÅ‚o 1 minuty w skali roku.
DS3231 pozwala również na bezpoÅ›redni odczyt temperatury z wbudowanego termometru, konfiguracjÄ™ dwóch alarmów obsÅ‚ugujÄ…cych przerwania, a także generator przebiegu prostokÄ…tnego o zadanej czÄ™stotliwoÅ›ci 1Hz ÷ 32768Hz. Posiada również dodatkowe wyjÅ›cie o staÅ‚ym sygnale prostokÄ…tnym o czÄ™stotliwoÅ›ci 32kHz.
Układ DS3231 dostępny jest jedynie w obudowie SOIC:
Dokumentacja techniczna: http://www.jarzebski.pl/datasheets/DS3231.pdf
Sposób podÅ‚Ä…czenia DS3231 jest bardzo podobny do ukÅ‚adu DS1307. PodÅ‚Ä…czamy wiÄ™c zasilanie 5V (nóżka 2) oraz masÄ™ GND (nóżka 13). Bardzo ważne jest, aby również podÅ‚Ä…czyć do masy wszystkie wyprowadzenia oznaczone jako NC (nóżki 5,6,7,8,9,10,11,12). DS3231 również komunikuje siÄ™ z Arduino za pomocÄ… magistrali I2C, a wiÄ™c Å‚Ä…czymy SCL (nóżka 16) do pinu A5, a SDA (nóżka 15) do pinu A4. Na koniec nie zapomnijmy podciÄ…gnąć linii sygnaÅ‚owych rezystorami o wartoÅ›ci 10kΩ do zasilania 5V. BateriÄ™ 3V podÅ‚Ä…czamy natomiast do VBAT (nóżka 14). WyjÅ›cia SQW/OUT oraz 32kHz, również podciÄ…gamy rezystorami o wartoÅ›ci 10kΩ do zasilania 5V. Jest to zabieg niezbÄ™dny, ponieważ i tutaj wyjÅ›cia dziaÅ‚ajÄ… w ukÅ‚adzie otwartego drenu. Dlatego, jeÅ›li chcemy wykorzystać do nich diodÄ™ LED, należy podÅ‚Ä…czyć tutaj katodÄ™ - anodÄ™ zaÅ› do masy. JeÅ›li nie planujemy korzystać z SQW/OUT oraz wyjÅ›cia sygnaÅ‚u 32kHz, możemy pozostawić je "w powietrzu".
Ja zamiast zasilania bateryjnego wykorzystaÅ‚em napiÄ™cie 3.3V z Arduino oraz podÅ‚Ä…czyÅ‚em sobie diody LED do sygnalizacji stanów na wyjÅ›ciach z rezystorami 220Ω.
Do obsÅ‚ugi moduÅ‚ów z ukÅ‚adami DS3231 przygotowaÅ‚em bibliotekÄ™ dla Arduino, którÄ… można pobrać z repozytorium Git: https://github.com/jarzebski/Arduino-DS3231. Bazuje ona bibliotekach JeeLabs oraz Adafruit, jednak oferuje ona dodatkowe funkcje do sterowania wyjÅ›ciami SQW/OUT oraz 32kHz, ustawiania alarmów oraz formatowanie daty na wzór funkcji date() znanej z jÄ™zyka PHP.
#include
#include
DS3231 clock;
RTCDateTime dt;
void setup()
{
Serial.begin(9600);
// Inicjalizacja DS3231
Serial.println("Initialize DS3231");;
clock.begin();
// Ustawiany date i godzine kompilacji szkicu
clock.setDateTime(__DATE__, __TIME__);
}
void loop()
{
// Odczytujemy i wyswietlamy czas
dt = clock.getDateTime();
Serial.print("Raw data: ");
Serial.print(dt.year); Serial.print("-");
Serial.print(dt.month); Serial.print("-");
Serial.print(dt.day); Serial.print(" ");
Serial.print(dt.hour); Serial.print(":");
Serial.print(dt.minute); Serial.print(":");
Serial.print(dt.second); Serial.println("");
delay(1000);
}
Jeśli chcemy wyświetlić czas i datę w odpowiednim dla nas formacie, możemy skorzystać z funkcji dateFormat().
#include
#include
DS3231 clock;
RTCDateTime dt;
void setup()
{
Serial.begin(9600);
// Inicjalizacja DS3231
Serial.println("Initialize DS3231");;
clock.begin();
// Ustawiamy date i czas z kompilacji szkicu
clock.setDateTime(__DATE__, __TIME__);
// Lub recznie (YYYY, MM, DD, HH, II, SS
// clock.setDateTime(2014, 4, 13, 19, 21, 00);
}
void loop()
{
// Odczytujemy czas i formatujemy za pomoca funkcji dateFormat
dt = clock.getDateTime();
Serial.print("Long number format: ");
Serial.println(clock.dateFormat("d-m-Y H:i:s", dt));
Serial.print("Long format with month name: ");
Serial.println(clock.dateFormat("d F Y H:i:s", dt));
Serial.print("Short format witch 12h mode: ");
Serial.println(clock.dateFormat("jS M y, h:ia", dt));
Serial.print("Today is: ");
Serial.print(clock.dateFormat("l, z", dt));
Serial.println(" days of the year.");
Serial.print("Actual month has: ");
Serial.print(clock.dateFormat("t", dt));
Serial.println(" days.");
Serial.print("Unixtime: ");
Serial.println(clock.dateFormat("U", dt));
Serial.println();
delay(1000);
}
W poniższym przykÅ‚adzie możemy zobaczyć jak wÅ‚Ä…czyć lub wyÅ‚Ä…czyć generator przebiegu prostokÄ…tnego na wyjÅ›ciu 32kHz oraz ustawić interesujÄ…cy nas przebieg prostokÄ…tny na wyjÅ›ciu SQW. SygnaÅ‚ SQW możemy wykorzystać do obsÅ‚ugi przerwania lub podÅ‚Ä…czyć diodÄ™ LED jako sygnalizator sekund, oszczÄ™dzajÄ…c tym samym cyfrowy pin Arduino. Kiedy bÄ™dziemy mieli zamiar skorzystać z alarmów to wyjÅ›cie SQW/INT bÄ™dzie nam sÅ‚użyÅ‚o wÅ‚aÅ›nie do obsÅ‚ugi przerwaÅ„.
#include
#include
DS3231 clock;
boolean state;
void setup()
{
Serial.begin(9600);
// Inicjalizyjemy DS3231
Serial.println("Initialize DS3231");;
clock.begin();
// Wylaczamy wyjscie 32kHz
clock.enable32kHz(false);
// Ustawiamy wyjscie SQW na sygnal 1Hz
clock.setOutput(DS3231_1HZ);
// Wlaczamy wyjsscie SQW
clock.enableOutput(true);
if (clock.isOutput())
{
Serial.println("Oscilator is enabled");
} else
{
Serial.println("Oscilator is disabled");
}
switch (clock.getOutput())
{
case DS3231_1HZ: Serial.println("SQW = 1Hz"); break;
case DS3231_4096HZ: Serial.println("SQW = 4096Hz"); break;
case DS3231_8192HZ: Serial.println("SQW = 8192Hz"); break;
case DS3231_32768HZ: Serial.println("SQW = 32768Hz"); break;
default: Serial.println("SQW = Unknown"); break; }
}
void loop()
{
// Wlaczamy i wylaczamy wyjscie 32kHz co 2 sekundy
clock.enable32kHz(state);
state = !state;
delay(2000);
}
DS3231 pozwala nam również na dostÄ™p do wbudowanego termometru o rozdzielczoÅ›ci 10-bitów. Co daje nam odczyt z precyzjÄ… 0.25°C i dokÅ‚adnoÅ›ciÄ… ±3°C. DomyÅ›lnie pomiar temperatury odbywa siÄ™ co 64 sekundy na potrzeby kompensacji , jednak możemy wymusić ponowny pomiar za pomocÄ… funkcji forceConversion().
#include
#include
DS3231 clock;
RTCDateTime dt;
void setup()
{
Serial.begin(9600);
// Inicjalizyjemy DS3231
Serial.println("Initialize DS3231");;
clock.begin();
}
void loop()
{
// Wymuszamy konwersje temperatury, poniweaz domyslnie jest ona odswiezana co 64 sekundy
clock.forceConversion();
Serial.print("Temperature: ");
Serial.println(clock.readTemperature());
delay(1000);
}
UkÅ‚ad pozwala na konfiguracjÄ™ dwóch alarmów, które różniÄ… siÄ™ od siebie gÅ‚ównie metodÄ… porównania czasu z ustawionym alarmem.
Alarm 1 pozwala na aktywowanie przerwania do następujących dopasowań:
Alarm 2 pozwala natomiast na aktywowanie przerwania do następujących dopasowań:
Åatwo wiÄ™c zauważyć, że Alarm 1 operuje na sekundach natomiast Alarm 2 na minutach. W ramach tego przykÅ‚adu w funkcji setup() wyÅ‚Ä…czamy i resetujemy przerwania za pomocÄ… funkcji armAlarmX(false) oraz clearAlarmX() ponieważ wartoÅ›ci te sÄ… podtrzymywane bateryjnie. W normalnej pracy oczywiÅ›cie powinniÅ›my pominąć ten fragment, ponieważ bÄ™dzie on powodowaÅ‚ kasowanie ustawieÅ„ przy powrocie gÅ‚ównego zasilania.
#include
#include
DS3231 clock;
RTCDateTime dt;
void setup()
{
Serial.begin(9600);
// Inicjalizacja DS3231
Serial.println("Initialize DS3231");;
clock.begin();
// Wylaczamy alarmy i resetujemy przerwania do przykladu,
// poniewaz ustawienia sa podtrzymywane bateryjnie
clock.armAlarm1(false);
clock.armAlarm2(false);
clock.clearAlarm1();
clock.clearAlarm2();
// Ustawiamy date (Year, Month, Day, Hour, Minute, Second)
clock.setDateTime(2014, 4, 25, 0, 0, 0);
// Ustawiamy Alarm1 na 20s kazdej minutu z dopasowaniem sekund
// setAlarm1(Date or Day, Hour, Minute, Second, Mode, Armed = true)
clock.setAlarm1(0, 0, 0, 20, DS3231_MATCH_S);
// Usyawiamy Alarm2 - Kazda pierwsza minuta kazdej godziny z dopasowaniem do minut
// setAlarm2(Date or Day, Hour, Minute, Mode, Armed = true)
clock.setAlarm2(0, 0, 1, DS3231_MATCH_M);
}
void loop()
{
// Odczytujemy date
dt = clock.getDateTime();
Serial.println(clock.dateFormat("d-m-Y H:i:s - l", dt));
// Sprawdzamy alaram 1
if (clock.isAlarm1())
{
Serial.println("ALARM 1 TRIGGERED!");
}
// Sprawdzamy alaram 1
if (clock.isAlarm2())
{
Serial.println("ALARM 2 TRIGGERED!");
}
delay(1000);
}
W tym przykÅ‚adzie zademonstrowaÅ‚em jak obsÅ‚użyć alarmy programowo, jednak w repozytorium Git znajdziecie przykÅ‚ad z wykorzystaniem przerwania INT0 w Arduino UNO. PrzykÅ‚ad ten zostaÅ‚ również omówiony na filmie poniżej.
Dokumentacja techniczna: http://www.jarzebski.pl/datasheets/DS3231.pdf
Biblioteka Arduino: https://github.com/jarzebski/Arduino-DS3231