V tem projektu bomo izdelali digitalno uro, ki združuje natančnost interneta s stabilnostjo fizičnega modula za čas. Ura se ob zagonu poveže v WiFi omrežje in preko NTP protokola pridobi točen čas. Da ura ne bi izgubila časa ob izpadu povezave, uporablja DS3231 RTC modul, ki vzdržuje čas s pomočjo baterije. Podatke prikazujemo na 2.0-palčnem TFT zaslonu z visoko ločljivostjo.
Pri uporabi Arduino Nano ESP32 moramo biti pozorni na dve stvari:
Pravilna vezava je ključ do stabilnega delovanja vaše pametne ure. Pri tem projektu uporabljamo dva različna komunikacijska protokola: SPI za hiter izris podatkov na TFT zaslonu in I2C za branje časa iz RTC modula. Bodite posebej pozorni na napajalne pine; Arduino Nano ESP32 deluje na 3.3V logiki, zato vse komponente napajamo iz ustreznega izhoda na ploščici. Sledite spodnji tabeli za natančen razpored pinov, ki bodo omogočili usklajeno delovanje vseh gradnikov.
| TFT Zaslon / Pin | Arduino Nano ESP32 Pin |
|---|---|
| VCC | 3.3V |
| GND | GND |
| SCL | D13 |
| SDA | D11 |
| CS | D10 |
| DC | D9 |
| RST | D8 |
| RTC DS3231 / Pin | Arduino Nano ESP32 Pin |
|---|---|
| VCC | Vin 5V |
| GND | GND |
| SDA | A4 |
| SCL | A5 |
Programska koda je srce tega projekta in skrbi za tri glavne naloge: vzpostavitev WiFi povezave, sinhronizacijo s svetovnim časom (NTP) ter varno shranjevanje teh podatkov v lokalni RTC modul. Koda je zasnovana optimizirano – zaslon se ne osvežuje v celoti, temveč s funkcijo fillRect pobrišemo in ponovno izpišemo le tiste dele (sekunde, minute, dneve), ki so se dejansko spremenili. To preprečuje neprijetno utripanje slike in zagotavlja tekoč prikaz časa v realnem času.
/*
* PROJEKT: Arduino pametna ura z WiFi in NTP sinhronizacijo
* AVTOR: Borut Bukovnik
* DATUM: 01. 05. 2026
* OPIS: Digitalna ura s posodabljanjem časa preko WiFi (NTP), varnostno kopijo z modulom RTC DS3231 in TFT zaslonom.
* STROJNA OPREMA: Arduino Nano ESP32, DS3231, ST7789 TFT (2,0-palčni)
*/
#include <WiFi.h>
#include <NTPClient.h>
#include <WiFiUdp.h>
#include <Wire.h>
#include <RTClib.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ST7789.h>
// WiFi nastavitve
const char* ssid = "ssid ime";
const char* password = "wifi geslo";
// NTP nastavitve
WiFiUDP ntpUDP;
// 7200 sekund = GMT+2 (Slovenija poletni čas)
NTPClient timeClient(ntpUDP, "pool.ntp.org", 7200, 60000);
// TFT nastavitve (SPI)
#define TFT_CS 10
#define TFT_DC 9
#define TFT_RST 8
Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);
// DS3231 nastavitve (I2C)
#define I2C_SDA A4
#define I2C_SCL A5
RTC_DS3231 rtc;
// Spremenljivke za osveževanje zaslona
int previousSecond = -1;
int previousDay = -1;
unsigned long lastNtpSync = 0;
const unsigned long NTP_SYNC_INTERVAL = 600000; // 10 minut
void setup() {
Serial.begin(115200);
Wire.setPins(I2C_SDA, I2C_SCL);
if (!rtc.begin()) {
Serial.println("RTC ni najden!");
while (1);
}
// Inicializacija zaslona
tft.init(240, 320);
tft.setRotation(1);
tft.fillScreen(ST77XX_BLACK);
// Povezava na WiFi
tft.setCursor(10, 100);
tft.setTextColor(ST77XX_WHITE);
tft.setTextSize(2);
tft.print("Povezava na WiFi...");
WiFi.begin(ssid, password);
int timeout = 0;
while (WiFi.status() != WL_CONNECTED && timeout < 20) {
delay(500);
timeout++;
}
if (WiFi.status() == WL_CONNECTED) {
timeClient.begin();
timeClient.update();
rtc.adjust(DateTime(timeClient.getEpochTime()));
lastNtpSync = millis();
tft.fillScreen(ST77XX_BLACK);
tft.setTextColor(ST77XX_GREEN);
tft.setCursor(10, 200);
tft.print("WiFi: Povezano");
} else {
tft.fillScreen(ST77XX_BLACK);
tft.setTextColor(ST77XX_RED);
tft.setCursor(10, 200);
tft.print("WiFi: Offline (RTC)");
}
delay(1000);
}
void loop() {
// NTP sinhronizacija
if (WiFi.status() == WL_CONNECTED && (millis() - lastNtpSync >= NTP_SYNC_INTERVAL)) {
if(timeClient.update()) {
rtc.adjust(DateTime(timeClient.getEpochTime()));
lastNtpSync = millis();
}
}
DateTime now = rtc.now();
// Izpis datuma (samo ob spremembi dneva)
if (now.day() != previousDay) {
tft.fillRect(0, 20, 320, 30, ST77XX_BLACK);
tft.setCursor(10, 20);
tft.setTextColor(ST77XX_YELLOW);
tft.setTextSize(2);
char dateBuf[20];
sprintf(dateBuf, "%02d.%02d.%04d", now.day(), now.month(), now.year());
tft.print(dateBuf);
previousDay = now.day();
}
// Izpis časa (vsako sekundo)
if (now.second() != previousSecond) {
tft.fillRect(0, 80, 320, 60, ST77XX_BLACK);
tft.setCursor(10, 80);
tft.setTextColor(ST77XX_CYAN);
tft.setTextSize(5);
char timeBuf[10];
sprintf(timeBuf, "%02d:%02d:%02d", now.hour(), now.minute(), now.second());
tft.print(timeBuf);
previousSecond = now.second();
}
delay(200);
}
V naši kodi to deluje takole:
WiFi in NTP sta urejevalca, ki enkrat na 10 minut preverita, če ura morda zamuja za kakšno milisekundo in popravita RTC modul. RTC pa je delavec, ki "gara" vsako sekundo in pošilja podatke na TFT zaslon.