Arduino ile basit bir LED göstergeli saat
Arduino ve 7-segment göstergeler kullanılarak yapılabilecek en basit saatlerden biri. Saati göstermesinin yanında tarihi ve haftanın hangi gün olduğunu da gösterebiliyor.
Normalde piyasada oldukça ucuza satılan kitler ile çok daha basit saatler yapılabilir. Benim kullandığım multiplex LED gösterge yerine seri veri girişi olan daha basit bir gösterge de kullanılabilir. Ancak benim amacım prensiplerin daha iyi anlaşılmasını sağlamak. Videodan da yararlanarak kolayca bu saati yapabilirsiniz.
Fotoğrafta videoda yaptığım prototipi görebilirsiniz.
Gerçek Zamanlı Saat (RTC) olarak o anda elimde olan DS1302'li bir modül kullandım. Bu modül Arduino ile 3 tel üzerinden iletişim sağlıyor. Daha gelişmiş modüller ile sadece 2 tel ile de iletişim sağlanabilir. Diğer modüllerin kullanımı için yazılımda ufak değişiklikler gerekecek, onları da bu blogu okuyanlara ev ödevi olarak bırakalım.
Bu devre için ilk çizdiğim şema aşağıda (üzerine tıklayarak büyütebilirsiniz);
Devreyi fiziksel olarak yaptığımda kabloları kolayıma geldiği gibi lehimledim. Arduino ile çalışmanın güzel yanlarından biri de bu. Fiziksel bağlantılara göre yazılımdan düzeltmeleri yaparak devreyi o şekilde kullanabiliyorsunuz. Yaptığım fiziksel devrenin karşılığı, bağlantıların yer değiştirdiği aşağıdaki cizim oldu:
YOUTUBE VİDEO;
Yazmış olduğum programı aşağıda bulabilirsiniz. Program Arduino Nano üzerinde çalıştırılmıştır. Diğer Arduino modüllerinde de sorunsuz çalışacağını tahmin ediyorum. Katkıları için değerli arkadaşım Tolga Mırmırık'a da teşekkür ederim. Açıklamalar hem İngilizce hem de Türkçe yazılmıştır.
------------------------------------------------------------------------------------------------
// Generic LED Clock with Arduino
// Fırat Tarman September 2022
// Contribution by : Tolga Mırmırık
#include "virtuabotixRTC.h" // Library for DS 1302
// DS1302 CONNECTIONS : DS1302 BAĞLANTILARI
// DS1302 RST/CE --> A2
// DS1302 DAT/IO --> A1
// DS1302 CLK/SCLK --> A0
virtuabotixRTC myRTC(A0, A1, A2); // CLK/SCLK, DAT/IO, RST
// Sample use of the RTC : RTC kullanımı için örnek
// myRTC.setDS1302Time(0,19,15,0,6,9,2022);
// myRTC.setDS1302Time(Seconds,Minutes,Hours,DayOfWeek,Date,Month,Year);
const int Total_Digits = 4; // 6 if we include seconds : Saniye varsa 6 olacak
const int Displays[Total_Digits] = {11,12,5,4}; // Digits 1,2,3,4; left to right (two more outputs for seconds) : Soldan sağa 1,2,3,4 (saniye varsa iki hane daha)
const int Total_Segments = 7;
const int Segments[Total_Segments] = {2,A3,7,9,10,A4,6}; // Segments a,b,c,d,e,f,g
const int General_Delay = 1; // Delay used in various part of the program : Programın çeşitli kısımlarında kullanılan gecikme
const int CorrectionSec = 0; // Correction for seconds (if the clock drifts more than a second a day) : Saat günde bir saniyeden fazla şaşıyorsa günlük düzeltme
boolean CorrectedSec = false;
int Counter = 250; // Counter for RTC read frequency : RTC okuma sıklığı için sayaç
const int MaxLEDCount = 300; // Colon LED blink speed : İkili LED'lerin yanıp sönme hızı
int LED_Counter = MaxLEDCount; // Counter for blinking LEDs : Yanıp sönen LED'ler için sayaç
int Display_Counter = 2000; // Counter for alternating time/date : Saat ve tarih gösterimleri için sayaç
int Hours_10 = 0;
int Hours_01 = 0;
int Minutes_10 = 0;
int Minutes_01 = 0;
int DigitValues[3];
int CurrentHour = 0; // Current date/time information : Güncel saat/tarih bilgisi
int CurrentMinute = 0;
int CurrentSecond = 0;
int CurrentYear = 2022;
int CurrentMonth = 9;
int CurrentDate = 11;
int DayOfWeek = 0; // Sunday=0; Monday=1; Tuesday=2... : 0:Pazar, 1:Pazartesi, 2:Salı...
boolean ButtonPlus; // (+) Button : (+) düğmesi
boolean ButtonSet; // Set Button : Ayar düğmesi
const int PinPlus = A5; // Input for (+) Button : (+) düğmesi için giriş
const int PinSet = 3; // Input for Set Button : Ayar düğmesi için giriş
int CurrentMode = 1; // 1:Normal, 2:Set Year, 3:Set Month, 4:Set Date, 5:Set Hour, 6:Set Minute : 1:Normal, 2:Yıl ayarı,3:Ay ayarı,4:Tarih ayarı,5:Saat ayarı,6:Dakika ayarı
boolean NeedUpdate = false; // Do we need to update the RTC? : RTC'yi ayarlamamız gerekiyor mu?
const int TheColon = 8; // Colon between digits with two LEDs : Saat ve dakika arasındaki yanıp sönen LEDler
// Segments a, b, c, d, e, f, g - NUMBERS : RAKAMLAR
int Numbers[10][Total_Segments] = {
HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, LOW, // 0
LOW, HIGH, HIGH, LOW, LOW, LOW, LOW, // 1
HIGH, HIGH, LOW, HIGH, HIGH, LOW,HIGH, // 2
HIGH, HIGH, HIGH, HIGH, LOW, LOW, HIGH, // 3
LOW, HIGH, HIGH, LOW, LOW, HIGH, HIGH, // 4
HIGH, LOW, HIGH, HIGH, LOW, HIGH, HIGH, // 5
HIGH, LOW, HIGH, HIGH, HIGH, HIGH, HIGH, // 6
HIGH, HIGH, HIGH, LOW, LOW, LOW, LOW, // 7
HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, HIGH, // 8
HIGH, HIGH, HIGH, HIGH, LOW, HIGH, HIGH // 9
};
// Segments a, b, c, d, e, f, g - LETTERS : HARFLER
int Letters[15][Total_Segments] = {
HIGH, HIGH, LOW, LOW, HIGH, HIGH, HIGH, // P, 0
HIGH, HIGH, HIGH, LOW, HIGH, HIGH, HIGH, // A, 1
HIGH, HIGH, LOW, HIGH, HIGH, LOW, HIGH, // Z, 2
LOW,LOW, LOW, LOW, HIGH, LOW, HIGH, // r, 3
LOW, LOW, LOW, HIGH, HIGH, HIGH, HIGH, // t, 4
HIGH, LOW, HIGH, HIGH, LOW, HIGH, HIGH, // S, 5
LOW, LOW, LOW, HIGH, HIGH, HIGH, LOW, // L, 6
LOW, LOW, LOW, LOW, HIGH, HIGH, LOW, // I, 7
HIGH, LOW, LOW, HIGH, HIGH, HIGH, LOW, // C, 8
HIGH, LOW, LOW, HIGH, HIGH, HIGH, HIGH, // E, 9
LOW, HIGH, HIGH, HIGH, HIGH, HIGH, LOW, // U, 10
HIGH, HIGH, HIGH, LOW, HIGH, HIGH, LOW, // n, 11
LOW,HIGH, HIGH, HIGH, LOW, HIGH, HIGH, // Y, 12
HIGH, HIGH, HIGH, HIGH, LOW, HIGH, HIGH, // g, 13
LOW, HIGH, HIGH, HIGH, HIGH, LOW, HIGH // d, 14
};
void setup()
{ for (int i = 0; i < Total_Digits; i++) // Digit outputs : Hane çıkışları
{ pinMode(Displays[i], OUTPUT);}
for (int i = 0; i < Total_Segments; i++) // Segment outputs : Segment çıkışları
{ pinMode(Segments[i], OUTPUT);}
pinMode(PinPlus, INPUT_PULLUP); // (+) Button : (+) düğmesi
pinMode(PinSet, INPUT_PULLUP); // SET Button : Ayar düğmesi
pinMode(TheColon, OUTPUT);} // Blinking colon : Yanıp sönen LEDler
void BlankDigits() // Blank digits : Haneleri söndür
{ for (int i = 0; i < Total_Digits; i++)
{ digitalWrite(Displays[i], LOW);}
}
void BlankSegments() // Blank segments : Segmentleri söndür
{ for (int i = 0; i < Total_Segments; i++)
{ digitalWrite(Segments[i], LOW);}
}
void BlankAll()
{
BlankDigits();
BlankSegments();
}
void WriteANumber(int TheNumber, int digit)
{
BlankAll();
for (int i = 0; i < Total_Segments; i++)
{digitalWrite(Segments[i], Numbers[TheNumber][i]);}
digitalWrite(Displays[digit], HIGH);
delay(General_Delay);
}
void WriteAChar(int TheChar, int digit)
{ BlankAll();
for (int i = 0; i < Total_Segments; i++)
{digitalWrite(Segments[i], Letters[TheChar][i]);}
digitalWrite(Displays[digit], HIGH);
delay(General_Delay);
}
void ReadTheRTC() // Read RTC : RTC'yi oku
{ myRTC.updateTime();
CurrentHour = myRTC.hours;
CurrentMinute = myRTC.minutes;
CurrentSecond = myRTC.seconds;
if (CurrentHour==1 & CurrentMinute==11)
{ if(!CorrectedSec)
{ CurrentSecond = CurrentSecond + CorrectionSec;
CorrectedSec = true; }}
if (CurrentHour==1 & CurrentMinute==10) CorrectedSec=false;
CurrentYear = myRTC.year;
CurrentMonth = myRTC.month;
CurrentDate = myRTC.dayofmonth;
Hours_10 = CurrentHour / 10;
Hours_01 = CurrentHour - 10 * Hours_10;
Minutes_10 = CurrentMinute / 10;
Minutes_01 = CurrentMinute - 10 * Minutes_10;
DigitValues[0] = Hours_10;
DigitValues[1] = Hours_01;
DigitValues[2] = Minutes_10;
DigitValues[3] = Minutes_01;
}
void CalculateDOW() // Calculate Day of Week : Haftanın gününü hesaplayan fonksiyon
{
int xx, a1, y1;
if (CurrentYear < 2000)
CurrentYear += 2000;
xx = (14 - CurrentMonth) / 12;
a1 = CurrentMonth + 12 * xx - 2;
y1 = CurrentYear - xx;
DayOfWeek = (CurrentDate + (13 * a1 - 1) / 5 + y1 + y1 / 4 - y1 / 100 + y1 / 400) %7;
}
void DisplayTime()
{
for (int i = 0; i < Total_Digits; i++)
{ WriteANumber(DigitValues[i],i);}
}
void SelectWorkingMode()
{ int xx;
int R1;
int R2;
BlankAll();
switch (CurrentMode)
{
case 1:
break;
case 2: // Set year (display YL "YIL") : Yıl ayarı
WriteAChar(12, 0); // Y
WriteAChar(6, 1); // L
xx = CurrentYear - 2000; // Last two digits of the year : Yılın son iki hanesi
R1 = xx / 10;
R2 = xx - 10 * R1;
WriteANumber(R1,2); // 3. Display
WriteANumber(R2,3); // 4. Display
ButtonPlus = digitalRead(PinPlus);
delay(General_Delay);
if (ButtonPlus == 0)
{ CurrentYear++;
delay(250);
NeedUpdate = true;}
if (CurrentYear >= 2100) CurrentYear = 2022;
break;
case 3: // Set Month, display "AY" : Ayı ayarla
WriteAChar(1,0); // A 1. Display
WriteAChar(12,1); // Y 2. Display
R1 = CurrentMonth / 10;
R2 = CurrentMonth;
if (R2 > 9)
R2 = R2 - 10;
WriteANumber(R1,2); // 3. Display
WriteANumber(R2,3); // 4. Display
ButtonPlus = digitalRead(PinPlus);
delay(General_Delay);
if (ButtonPlus == 0)
{ CurrentMonth++;
delay(250);
NeedUpdate = true;}
if (CurrentMonth > 12) CurrentMonth = 1;
break;
case 4: // Set Date, display "gn" (GÜN) : Gün ayarı
WriteAChar(13, 0); // g
WriteAChar(11, 1); // n
R1 = CurrentDate / 10;
R2 = CurrentDate - 10 * R1;
WriteANumber(R1,2); // 3. Display
WriteANumber(R2,3); // 4. Display
ButtonPlus = digitalRead(PinPlus);
delay(General_Delay);
if (ButtonPlus == 0)
{ CurrentDate++;
delay(250);
NeedUpdate = true;}
if (CurrentDate >= 32) CurrentDate = 1;
break;
case 5: // Set hour, display "SA" (Saat) : Saat ayarı
WriteAChar(5, 0); // S
WriteAChar(1, 1); // A
R1 = CurrentHour / 10;
R2 = CurrentHour - 10 * R1;
WriteANumber(R1,2); // 3. Display
WriteANumber(R2,3); // 4. Display
ButtonPlus = digitalRead(PinPlus);
delay(General_Delay);
if (ButtonPlus == 0)
{ CurrentHour++;
delay(250);
NeedUpdate = true;}
if (CurrentHour >= 24) CurrentHour = 0;
break;
case 6: // Set Minute, display "dA" (Dakika) : Dakika ayarla
WriteAChar(14, 0); // d
WriteAChar(1, 1); // A
R1 = CurrentMinute/10;
R2 = CurrentMinute - (10 * R1);
WriteANumber(R1,2); // 3. Display
WriteANumber(R2,3); // 4. Display
ButtonPlus = digitalRead(PinPlus);
delay(General_Delay);
if (ButtonPlus == 0)
{ CurrentMinute++;
delay(250);
NeedUpdate = true;}
if (CurrentMinute >= 60) CurrentMinute = 0;
break;
default:
break;
}
}
void BlinkColon()
{ int HalfCount;
if (LED_Counter == MaxLEDCount) digitalWrite(TheColon, LOW);
LED_Counter--;
HalfCount = MaxLEDCount / 2;
if (LED_Counter == HalfCount) digitalWrite(TheColon, HIGH);
if (LED_Counter == 0) LED_Counter = MaxLEDCount;
}
void CheckButtons()
{ ButtonSet = digitalRead(PinSet);
delay(General_Delay);
if (ButtonSet == 0)
{ CurrentMode++;
delay(250);}
if (CurrentMode == 7)
{ if (NeedUpdate)
{ CalculateDOW();
myRTC.setDS1302Time(CurrentSecond, CurrentMinute, CurrentHour, DayOfWeek, CurrentDate, CurrentMonth, CurrentYear);
NeedUpdate = false;}
CurrentMode = 1;}
}
void DisplayDate()
{
int R1;
int R2;
int MyTempCounter = 1;
do
{ R1 = CurrentDate / 10;
R2 = CurrentDate - 10 * R1;
WriteANumber(R1,0); // 1. Display
WriteANumber(R2,1); // 2. Display
R1 = CurrentMonth / 10;
R2 = CurrentMonth;
if (R2 > 9)
R2 = R2 - 10;
WriteANumber(R1,2); // 3. Display
WriteANumber(R2,3); // 4. Display
MyTempCounter++;
} while (MyTempCounter <= 400);
MyTempCounter = 1;
CalculateDOW();
do
{ MyTempCounter++;
switch (DayOfWeek)
{
case 0: // Sunday - PAZr
WriteAChar(0, 0);
WriteAChar(1, 1);
WriteAChar(2, 2);
WriteAChar(3, 3);
break;
case 1: // Monday - PZtS
WriteAChar(0, 0);
WriteAChar(2, 1);
WriteAChar(4, 2);
WriteAChar(5, 3);
break;
case 2: // Tuesday - SALI
WriteAChar(5, 0);
WriteAChar(1, 1);
WriteAChar(6, 2);
WriteAChar(7, 3);
break;
case 3: // Wednesday - CArS
WriteAChar(8, 0);
WriteAChar(1, 1);
WriteAChar(3, 2);
WriteAChar(5, 3);
break;
case 4: // Thursday - PErS
WriteAChar(0, 0);
WriteAChar(9, 1);
WriteAChar(3, 2);
WriteAChar(5, 3);
break;
case 5: // Friday - CUnA
WriteAChar(8, 0);
WriteAChar(10, 1);
WriteAChar(11, 2);
WriteAChar(1, 3);
break;
case 6: // Saturday - CtSI
WriteAChar(8, 0);
WriteAChar(4, 1);
WriteAChar(5, 2);
WriteAChar(7, 3);
break;
}
} // DO
while (MyTempCounter <= 400);
}
void loop()
{
CheckButtons();
if (CurrentMode == 1)
{
DisplayTime();
BlinkColon();
Counter--;
if (Counter == 0) // Read RTC in every 250 loops : RTC'yi her 250 döngüde bir okuyoruz
{ ReadTheRTC();
Counter = 250;}
Display_Counter--;
if (Display_Counter == 0)
{ digitalWrite(TheColon, LOW); // Blank the colon : Orta LED'leri söndür
DisplayDate();
Display_Counter = 2000;}
}
else
SelectWorkingMode();
}
Hocam transistorlerin kodu yok
ReplyDeleteBasit bir NPN küçük sinyal transistörü olabilir. Örneğin BC547.
ReplyDeleteHocam öncelikle elinize emeklerinize sağlık
ReplyDeleteben bu prejeyi yapmak istiyorum ancak elimde ortakKATOT display yok, elimde ortakANOT displayım var programlamada ortak anot ile düzenlenecek yazılımı rica edebilirmiyim
Öncelikle 4 transistörü PNP transistörler ile değiştirmek lazım. Transistörlerin emetörleri de (+) ya bağlanacak. Ondan sonra programda HIGH gördüğünüz her yere LOW, LOW gördüğünüz her yere de HIGH yazmanız yetecektir.
Delete