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();
}


Arduino ile basit bir LED göstergeli saat Arduino ile basit bir LED göstergeli saat Reviewed by Fırat Tarman on 10:40 AM Rating: 5

2 comments:

  1. Hocam transistorlerin kodu yok

    ReplyDelete
  2. Basit bir NPN küçük sinyal transistörü olabilir. Örneğin BC547.

    ReplyDelete

Fırat Tarman Devreler. Powered by Blogger.