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ń