Projekt przedstawia realizację prostego układu zegara czasu rzeczywistego (Fig. 1). Projekty tego typu są wykorzystywane jako samodzielne zegary bądź jako moduły pomocnicze w realizacjach układów wymagających ciągłego dostępu do informacji o aktualnym czasie (np. systemy rejestrujące, alarmowe itp.).
Urządzenie zrealizowano w oparciu o popularny moduł zegara czasu rzeczywistego DS3231 (Fig. 2). Układ wymaga baterii podtrzymującej napięcie w momencie ustania napięcia zasadniczego źródła zasilania (Fig. 3).
Sercem układu jest platforma Arduino Leonardo (Fig. 4). Do mikrokontrolera, za pośrednictwem magistrali I2C podłączono moduł zegara czasu rzeczywistego DS3231. Do tej samej magistrali I2 podłączono wyświetlacz LCD 20 × 4.
Układ w czasie rzeczywistym wyświetla bieżący czas oraz datę na wyświetlaczu ciekłokrystalicznym oraz przekazuje te informacje do minitora portu szeregowego.
Zasadnicza część kodu pochodzi z książki Boxal J., 2014. Arduino 65 praktycznych projektów. Helion, Gliwice.
#include "Wire.h"
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE); // Ustawienie adresu ukladu na 0x27
#define DS3231_I2C_ADDRESS 0x68
// Konwersja liczby dziesiętnej do postaci binarnej
byte decToBcd(byte val){
return( (val/10*16) + (val%10) );
}
// Konwersja liczby binarnej do postaci dziesiętnej
byte bcdToDec(byte val){
return( (val/16*10) + (val%16) );
}
void setup(){
Wire.begin();
Serial.begin(9600);
// Ustawienie czasu w momencie inicjacji układu:
// DS3231 seconds, minutes, hours, day, date, month, year
// setDS3231time(00,01,11,7,11,03,17);
lcd.begin(20,4);
lcd.backlight(); // załączenie podświetlenia
lcd.setCursor(0,0);
lcd.print("Prosty zegar");
delay(500);
}
void setDS3231time(byte second, byte minute, byte hour, byte dayOfWeek, byte
dayOfMonth, byte month, byte year)
{
// ustawienie czasu i daty w DS3231
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0); // określa, że następna wartość ma trafić do rejestru sekund
Wire.write(decToBcd(second)); // ustawienie sekund
Wire.write(decToBcd(minute)); // ustawienie minuty
Wire.write(decToBcd(hour)); // ustawienie godziny
Wire.write(decToBcd(dayOfWeek)); // ustawienie dnia tygodnia (1=niedziela, 7=sobota)
Wire.write(decToBcd(dayOfMonth)); // ustawienie dnia (1-31)
Wire.write(decToBcd(month)); // ustawienie miesiąca
Wire.write(decToBcd(year)); // ustawienie roku (0-99)
Wire.endTransmission();
}
void readDS3231time(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
Wire.beginTransmission(DS3231_I2C_ADDRESS);
Wire.write(0); // ustawia rejestr DS3231 na 00h
Wire.endTransmission();
Wire.requestFrom(DS3231_I2C_ADDRESS, 7);
// żąda 7 bajtów danych od modułu DS3231 począwszy od rejestru 00h
*second = bcdToDec(Wire.read() & 0x7f);
*minute = bcdToDec(Wire.read());
*hour = bcdToDec(Wire.read() & 0x3f);
*dayOfWeek = bcdToDec(Wire.read());
*dayOfMonth = bcdToDec(Wire.read());
*month = bcdToDec(Wire.read());
*year = bcdToDec(Wire.read());
}
void displayTime(){
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
// retrieve data from DS3231
readDS3231time(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month,
&year);
// Przekazanie danych do wyświetlenie w serial monitorze i do LCD
// CZAS
// Godziny
// podczas wyświetlania konwertuje wartość zmiennej typu bitowego do postaci dziesiętnej
Serial.print(hour, DEC);
if (hour<10) {
lcd.setCursor(0,1);
lcd.print("0");
lcd.print(hour, DEC);
} else {
lcd.setCursor(0,1);
lcd.print(hour, DEC);
}
Serial.print(":");
// lcd.setCursor(2,1);
lcd.print(":");
// Minuty
Serial.print(minute, DEC);
if (minute<10) {
Serial.print("0");
lcd.setCursor(3,1);
lcd.print("0");
lcd.print(minute, DEC);
} else {
lcd.setCursor(3,1);
lcd.print(minute, DEC);
}
Serial.print(":");
lcd.print(":");
//Sekundy
if (second<10){
Serial.print("0");
lcd.setCursor(6,1);
lcd.print("0");
lcd.print(second, DEC);
} else {
Serial.print(second, DEC);
lcd.setCursor(6,1);
lcd.print(second, DEC);
}
// DATA
Serial.print(" ");
Serial.print(dayOfMonth, DEC);
Serial.print("/");
Serial.print(month, DEC);
Serial.print("/");
Serial.print(year, DEC);
lcd.setCursor(0,2);
lcd.print("0");
// Dzień
if (dayOfMonth<10){
lcd.setCursor(0,2);
lcd.print("0");
lcd.print(dayOfMonth, DEC);
} else {
lcd.setCursor(0,2);
lcd.print(dayOfMonth, DEC);
}
lcd.print(".");
// Miesiąc
if (month<10){
lcd.setCursor(3,2);
lcd.print("0");
lcd.print(month, DEC);
} else {
lcd.setCursor(3,2);
lcd.print(month, DEC);
}
lcd.print(".");
//Rok
lcd.print("20");
if (year<10){
lcd.setCursor(8,2);
lcd.print("0");
lcd.print(year, DEC);
} else {
lcd.setCursor(8,2);
lcd.print(year, DEC);
}
Serial.print(" ");
lcd.setCursor(0,3);
switch(dayOfWeek){
case 1:
Serial.println("Niedziela");
lcd.print("Niedziela");
break;
case 2:
Serial.println("Poniedzialek");
lcd.print("Poniedzialek");
break;
case 3:
Serial.println("Wtorek");
lcd.print("Wtorek");
break;
case 4:
Serial.println("Środa");
lcd.print("Środa");
break;
case 5:
Serial.println("Czwartek");
lcd.print("Czwartek");
break;
case 6:
Serial.println("Piątek");
lcd.print("Piątek");
break;
case 7:
Serial.println("Sobota");
lcd.print("Sobota");
break;
}
}
void loop()
{
displayTime(); // wyświetlanie czasu rzeczywistego
delay(1000); // odśwież co sekundę
}