Atomik Saat (Neo6Mv2 GPS modülü kullanarak saat yapımı)
Elektronik ile uğraşan pek çok meraklının ilk yaptığı devrelerden biri de saatlerdir. Günümüzde Arduino gibi mikroişlemci kartları ve RTC'ler (Real Time Clock = Gerçek Zamanlı Saat) sayesinde bu iş daha da kolaylaştı. Ancak bu şekilde yapılan her saatin bir hata payı oluyor. Bazı saatler yılda birkaç dakika şaşarken, RTC pek kaliteli değilse günde 1-2 dakika bile ileri/geri gidebiliyor.
Referans olarak kullanabileceğim bir saat yapma fikri aklıma geldiğinde, ilk olarak GSM şebekesini ya da internet üzerinde bulunabilecek atomik saatleri (örneğin time.is) kullanmayı düşündüm. Bunlar işi nispeten zorlaştırıyor - telefondan bilgiyi Arduino'ya aktarma ya da Arduino'yu internete bağlama gibi. Daha sonra aklıma GPS modülleri geldi. Nispeten ucuza bulunan bu modüller, konum bilgisi vermeleri yanında uydudan çok yüksek doğrulukta saat bilgisi de alabiliyorlar. Bu tam da benim istediğim özellikti.
Piyasadan makul sayılabilecek bir fiyata bulduğum Neo6Mv2 modülü ile böyle bir saat devresi tasarladım (tasarladım derken 1-2 bağlantı zaten). Devreyi aşağıda inceleyebilirsiniz. İkinci resim biraz daha detaylı. Üzerlerine tıklayarak büyütebilirsiniz.
Konu ile ilgili videoyu aşağıda bulabilirsiniz:
Bu modül için bir Arduino kütüphanesi de mevcut. GPS modülü ile çalışan bu saatin programını da aşağıda veriyorum. (Program henüz geliştirme aşamasında olduğu için düzeltmeler yaptıkça daha yeni sürümünü buraya ekleyebilirim)
/* NEO-6M GPS Modülü kullanılarak atomik doğrulukta saat yapımı / Atomic Clock using NEO-6M GSM Module
* RTC olarak en basit modül olan DS1302 kullanılıyor / Using a simple RTC : DS1302
* (c) Fırat Tarman June 2023
*/
#include "LiquidCrystal.h" // 2 x 16 characters LCD
#include "virtuabotixRTC.h" // Library DS 1302
#include <SoftwareSerial.h> // For GPS Module
#include <TinyGPS++.h> // For GPS Module
// DS1302 BAĞLANTILARI/CONNECTIONS
// DS1302 RST/CE --> A0
// DS1302 DAT/IO --> A1
// DS1302 CLK/SCLK --> A2
// DS1302 VCC --> 5v
// DS1302 GND --> GND
// virtuabotixRTC myRTC(A2,A1,A0); // CLK/SCLK, DAT/IO, RST : ŞEMAYA GÖRE / ACCORDING TO THE CIRCUIT DIAGRAM
virtuabotixRTC myRTC(A0,A1,A2); // CLK/SCLK, DAT/IO, RST : DEVREDE GERÇEKLEŞTİRİLEN / ACTUAL CIRCUIT
// LCD Ekran/Display
// const int RST = 2, EN = 3, d4 = 4, d5 = 5, d6 = 6, d7 = 7; ŞEMAYA GÖRE / ORIGINAL CONFIGURATION
const int RST = 2, EN = 3, d4 = 4, d5 = 5, d6 = 7, d7 = 6; // DEVREDE GERÇEKLEŞTİRİLEN / CORRECTED ACCORDING TO THE ACTUAL CIRCUIT
LiquidCrystal lcd(RST, EN, d4, d5, d6, d7);
// GPS Module bağlantıları/connections
const int RXPin = 12;
const int TXPin = 11;
SoftwareSerial gpsSerial(RXPin, TXPin);
TinyGPSPlus gps; // GPS Object
const int ContrastPin=9;
int Contrast = 100; // Varsayılan değer / Default Value
const int BackplaneLEDPin = 10; // Arka aydınlatma / Backlighting
int BackplaneLEDCurrent=100;
boolean GPSDateValid = false;
boolean GPSTimeValid = false;
boolean GPSIndicator = false;
boolean ShowingRTC = true;
int GPSValidityCounter = 10;
int Hour=0;
int Minute=0;
int Second=0;
int Year=2000;
int Month=1;
int Day=1;
int DayOfWeek=6; // Sunday=0, Monday=1, ...
boolean AddOneDay = false;
const unsigned long GPSWait = 60000; // GPS'i her 60 saniyede bir kontrol ediyoruz / Update GPS every 60 seconds
unsigned long previousMillis = 0;
void setup()
{
gpsSerial.begin(9600);
lcd.begin(16,2);
analogWrite(ContrastPin,Contrast);
analogWrite(BackplaneLEDPin,BackplaneLEDCurrent); // Aydınlatmayı açıyoruz / Backlight on
}
void CalculateDOW () // Haftanın gününü hesapla / Calculate day-of-week
{
int t1, a1, y1;
if (Year<2000) Year+=2000;
t1 = (14 - Month) / 12;
a1 = Month + 12 * t1 - 2;
y1 = Year - t1;
DayOfWeek=(Day + (13 * a1 - 1) / 5 +
y1 + y1 / 4 - y1 / 100 + y1 / 400) % 7;
}
void DisplayClock() // İlk satıra saati yaz / Display the clock on first line
{
myRTC.updateTime();
Hour = myRTC.hours;
Minute = myRTC.minutes;
Second = myRTC.seconds;
lcd.setCursor(0,0);
if (ShowingRTC) lcd.print("RTC ");
else lcd.print("GPS ");
if(Hour<10)lcd.print("0"); // Sadece sabahları saatin başına 0 koyuyoruz / Leading zero in the morning
lcd.print(Hour);
lcd.print(":");
if(Minute<10)lcd.print("0"); // Dakika 10'dan küçükse başına 0 koymak lazım / If minute is less than 10, a zero is added
lcd.print(Minute);
lcd.print(":");
if(Second<10)lcd.print("0"); // 10'dan küçük saniyenin başına da 0 koyuyoruz / If second is less than 10, a zero is added
lcd.print(Second);
if (GPSIndicator)
{ lcd.print(" GPS");
delay(500);}
else lcd.print(" ");
GPSIndicator = false;
}
void DisplayDate() // İkinci satıra tarihi yaz / Display date on second line
{
char DayNames [7][6] = {"PAZAR", "PZRTS", " SALI"," CARS", " PERS", " CUMA", "CMRTS"}; // Pazar=0, Pazartesi=1, ...
myRTC.updateTime();
Year=myRTC.year;
Month=myRTC.month;
Day=myRTC.dayofmonth;
DayOfWeek=myRTC.dayofweek; // Sunday=0, Monday=1... */
CalculateDOW ();
lcd.setCursor(0,1);
lcd.print(Day);
lcd.print("/");
lcd.print(Month);
lcd.print("/");
lcd.print(Year);
lcd.print(" ");
lcd.setCursor(11,1);
lcd.print(DayNames[DayOfWeek]);
}
void GPSDataToVariables() // GPS'den gelen veriyi saate yazıyoruz / We use GPS data for the clock variables
{
GPSIndicator = false;
if (gps.time.isValid()) // GPS'i okuyabildiysek saati düzeltiyoruz / Correcting the clock if GPS read is successful
{ Hour = gps.time.hour() + 3;
Minute = gps.time.minute();
Second = gps.time.second();
GPSTimeValid = true;
}
else GPSTimeValid = false;
if ((Hour == 0) || (Hour == 1) || (Hour == 2) || (Hour == 3)) AddOneDay = true;
else AddOneDay = false;
if (gps.date.isValid()) // GPS'i okuyabildiysek tarihi düzeltiyoruz / Correcting date if GPS read is successful
{ Month = gps.date.month();
Day = gps.date.day();
if (AddOneDay) Day++;
Year = gps.date.year();
if (Year == 2000) GPSDateValid = false;
else GPSDateValid = true;
if (GPSDateValid) CalculateDOW ();
}
else GPSDateValid = false;
if ((GPSDateValid) && (GPSTimeValid)) // Verileri okuyabilirsek ekranda "GPS" göstereceğiz / We will display "GPS" if we succesfully read the GPS data
{ myRTC.setDS1302Time(Second,Minute,Hour,DayOfWeek,Day,Month,Year);
GPSIndicator = true;
ShowingRTC = false;
GPSValidityCounter = 10;}
else
{ GPSValidityCounter--;
if (GPSValidityCounter == 0)
{ GPSValidityCounter = 1;
ShowingRTC = true;}
}
}
void ReadTheGPS()
{ while (gpsSerial.available() > 0)
if (gps.encode(gpsSerial.read())) GPSDataToVariables();
}
// MAIN LOOP
void loop()
{ unsigned long currentMillis = millis();
if ((currentMillis - previousMillis) >= GPSWait) // GPSWait kadar milisaniye aralıklarla GPS okunuyor / Read GPS with time intervals determined by GPSWait
{ previousMillis = currentMillis;
ReadTheGPS(); }
DisplayClock();
DisplayDate();
}
// END OF MAIN LOOP
No comments: