Moduł RTC, inaczej zegar czasu rzeczywistego, służy do precyzyjnego odmierzania czasu. Znajdzie więc zastosowanie w rozmaitych zegarach, budzikach, rejestratorach i wszędzie tam, gdzie dodatkowo zechcemy pokazywać bieżący czas. Opisywany moduł dodatkowo oferuje pomiar temperatury, pamięć EEPROM i baterię podtrzymującą zasilanie.
Specyfikacja
![]() |
| Moduł RTC DS3231 i EEPROM AT24C32 |
Specyfikacja
- zasilanie 3,3 - 5,5V
- interfejs komunikacji: I2C
- układ zegara DS3231
- dokładność:
- ±2ppm od 0°C to +40°C
- ±3.5ppm od -40°C to +85°C
- pomiar temperatury z dokładnością ±3°C
- adres I2C: 0x68
- podtrzymanie pamięci (wymienialną) baterią 2032
- pamięć EEPROM
- pojemność 32kb
- adres I2C 0x57
- dodatkowe wyjścia: SDA, SCL, VCC i GND do kaskadowego podłączenia kolejnego modułu pracującego na magistrali I2C
- wymiary: 38x22mm
Piny
- Vcc, GND - zasilanie
- SCL, SDA - piny magistrali I2C
- SQW - wyjście sygnału prostokątnego lub źródło przerwań dla alarmów
- 32K - sygnał prostokątny o częstotliwości 32kHz
Funkcje
- zegar RTC z podtrzymaniem pamięci (wbudowana bateria)
- odmierza sekundy, minuty, godziny, dni miesiąca, miesiące, dni tygodnia, lata
- dwa możliwe alarmy do ustawienia (z wieloma możliwymi interwałami do wyboru)
- wyznacza lata przestępne do roku 2100
- pomiar temperatury (niezbyt dokładny)
- pamięć EEPROM (konfigurowalny adres na magistrali I2C za pomocą zworek A0, A1 i A2)
Uruchomienie
W użytej w bibliotece DS3232RTC (3) (korzystającej z biblioteki Time (4)) jest wiele przykładów pokazujących możliwości pracy z opisywanym modułem RTC. Wybrałem trzy podstawowe warianty pracy z modułem, które mogą się przydać. Są to kolejno ustawianie czasu, odczyt czasu oraz ustawianie alarmu.Kod został uruchomiony na Arduino Uno.
![]() |
| Układ uruchomieniowy |
Ustawianie czasu
W funkcji setRtcTime() ustawiony jest najpierw czas systemowy, potem modułu RTC na podstawie bieżącego czasu systemowego.
#include <TimeLib.h>
#include <Time.h>
#include <DS3232RTC.h>
void setup() {
Serial.begin(9600);
setSyncProvider(RTC.get); // the function to get the time from the RTC
if (timeStatus() != timeSet) {
Serial.println("Unable to sync with the RTC");
} else {
Serial.println("RTC has set the system time");
}
setRtcTime();
}
void loop() {
}
void setRtcTime() {
setTime(15, 24, 30, 7, 4, 2018); //set the system time to 15h24m30s on 7 kwietnia 2018
RTC.set(now()); //set the RTC from the system time
}
![]() |
| Wyniki na terminalu |
Pokazywanie czasu
Co jedną sekundę odczytywany jest bieżący czas i data, formatowany i przesyłany na terminal komputera. Dla minut i sekund poniżej 10-ki dostawiane są wiodące zera.
#include <TimeLib.h>
#include <Time.h>
#include <DS3232RTC.h>
void setup() {
Serial.begin(9600);
setSyncProvider(RTC.get); // the function to get the time from the RTC
if (timeStatus() != timeSet) {
Serial.println("Unable to sync with the RTC");
} else {
Serial.println("RTC has set the system time");
}
}
void loop() {
digitalClockDisplay();
delay(1000);
}
void digitalClockDisplay() {
// digital clock display of the time
Serial.print(hour());
printDigits(minute());
printDigits(second());
Serial.print(' ');
Serial.print(day());
Serial.print(' ');
Serial.print(month());
Serial.print(' ');
Serial.print(year());
Serial.println();
}
void printDigits(int digits) {
// utility function for digital clock display: prints preceding colon and leading 0
Serial.print(':');
if (digits < 10) {
Serial.print('0');
}
Serial.print(digits);
}
![]() |
| Wyniki na terminalu |
Ustawianie alarmu
Przykład pokazuje ustawianie i sprawdzanie alarmu 1. W f-cji setup() następuje inicjalizacja i określenia działania alarmu 1 - jest uruchamiany co jedną sekundę (wskazuje na to stała ALM1_EVERY_SECOND). Z kolei w f-cji loop() przy każdym jej przejściu następuje sprawdzanie, czy wystąpił alarm 1.
#include <TimeLib.h>
#include <Time.h>
#include <DS3232RTC.h>
void setup() {
Serial.begin(9600);
// initialize the alarms to known values, clear the alarm flags, clear the alarm interrupt flags
RTC.setAlarm(ALM1_MATCH_DATE, 0, 0, 0, 1);
RTC.setAlarm(ALM2_MATCH_DATE, 0, 0, 0, 1);
RTC.alarm(ALARM_1);
RTC.alarm(ALARM_2);
RTC.alarmInterrupt(ALARM_1, false);
RTC.alarmInterrupt(ALARM_2, false);
RTC.squareWave(SQWAVE_NONE);
// set Alarm 1 to occur once per second
RTC.setAlarm(ALM1_EVERY_SECOND, 0, 0, 0, 0);
// clear the alarm flag
RTC.alarm(ALARM_1);
Serial.print(" Start ");
printDateTime(RTC.get());
Serial.println();
}
void loop() {
// check to see if the alarm flag is set (also resets the flag if set)
if ( RTC.alarm(ALARM_1) ) {
Serial.print(" ALARM_1 ");
printDateTime(RTC.get());
}
}
void printDateTime(time_t t) {
Serial.print((day(t) < 10) ? "0" : "");
Serial.print(day(t));
Serial.print(" ");
Serial.print(monthShortStr(month(t)));
Serial.print(" ");
Serial.print(year(t));
Serial.print(" ");
Serial.print((hour(t) < 10) ? "0" : "");
Serial.print(hour(t));
Serial.print(" ");
Serial.print((minute(t) < 10) ? "0" : "");
Serial.print(minute(t));
Serial.print(" ");
Serial.print((second(t) < 10) ? "0" : "");
Serial.print(second(t));
Serial.println();
}
![]() |
| Wyniki na terminalu |
Tytułem wyjaśnienia, sam moduł i oczywiście biblioteka obsługuje dwa typy alarmów.
Alarm 1, który można wykorzystać do ustawiania różnych interwałów z dokładnością do jednej sekundy. W przykładzie powyżej była to wspomniana ALM1_EVERY_SECOND ustawiająca alarm 1 co jedną sekundę. Mamy do dyspozycji następujące możliwości (wywołania) dla tego alarmu:
- ALM1_EVERY_SECOND - co jedna sekunda
- ALM1_MATCH_SECONDS - dla określonej sekundy (na minutę)
- ALM1_MATCH_MINUTES - dla określonej sekundy i minuty
- ALM1_MATCH_HOURS - dla określonej godziny, minuty i sekundy
- ALM1_MATCH_DATE - dla określonego miesiąca, godziny, minuty i sekundy
- ALM1_MATCH_DAY - dla określonego dnia tygodnia, godziny, minuty i sekundy
Alarm 2 także określa interwały, tyle że inne i z dokładnością do jednej minuty:
- ALM2_EVERY_MINUTE - co jedna minuta
- ALM2_MATCH_MINUTES - dla określonej minuty (na godzinę)
- ALM2_MATCH_HOURS - dla określonej godziny i minuty
- ALM2_MATCH_DATE - dla określonego miesiąca, godziny i minuty
- ALM2_MATCH_DAY - dla określonego dnia tygodnia, godziny i minuty
Jak widać możliwości jest sporo, każdy alarm jest ustawiany f-cją:
RTC.setAlarm(alarmType, seconds, minutes, hours, dayOrDate);
RTC.setAlarm(alarmType, seconds, minutes, hours, dayOrDate);
Jest jeszcze jedna rzecz warta odnotowania. Mianowicie sposób sprawdzania, czy wystąpił alarm.
W przykładzie powyżej było to ciągłe odpytywanie f-cją RTC.alarm(ALARM_1). Istnieją jednak jeszcze inne możliwości, które prezentują przykłady z biblioteki DS3232RTC (3). Chodzi o wykorzystanie pinu SQW. F-cją squareWave() za pomocą stałych można ustawiać następujące sygnały wyjściowe:
- SQWAVE_NONE
- SQWAVE_1_HZ
- SQWAVE_1024_HZ
- SQWAVE_4096_HZ
- SQWAVE_8192_HZ
Czyli można wyłączyć generowanie sygnału prostokątnego przekazując stałą SQWAVE_NONE lub włączyć, przekazując dowolną inną stałą. W przypadku wyłączenia generowania sygnału, pin SQW można wykorzystać do informowania o alarmie. Stan niski na wyjściu SQW oznacza wystąpienie alarmu i można go identyfikować sprawdzając stan pinu (przykład alarm_ex7.ino). Można także wykorzystać przerwania do sprawdzania stanu pinu SQW (przykład alarm_ex6.ino).
W specyfikacji wspomniałem o pomiarze temperatury, można ją odczytać f-cją RTC.temperature();
Schemat
Schemat pochodzi ze artykułu Arduino and DS3231 RTC example (6). Schemat jak schemat, ale jedna rzecz jest w nim dyskusyjna. Chodzi o obecność elementów R5 (200) i dioda D2 (1N4148). Problem pojawia się, gdy zgodnie ze specyfikacją powyżej moduł zostanie zasilony napięciem 5V. W takim przypadku bateria będzie ładowana napięciem pomniejszonym o spadek na diodzie. A że nie jest to akumulator to mamy problem. Mi wprawdzie bateria nie wybuchła ani nie zmieniła wymiarów/objętości, ale dla spokoju ducha można pomyśleć o wylutowaniu albo rezystora, albo diody z tej dwójki.
![]() |
| Schemat elektryczny modułu |






Bardzo ciekawie napisane. Jestem pod wielkim wrażaniem.
OdpowiedzUsuń