Arduino Alarmlı Butonlu Saat Takvim

Bir arduino projesi daha... Bu seferki saatimiz yine saat ve tarihi gösterecek fakat alarmlı ve butonlarla ayarlanabilir olacak.
Devremizde Arduino Uno modülü, DS1302 zaman modülü, I2C&1602A LCD, 4 adet buton ve buzzer kullanıyoruz. Programın üzerinde ufak tefek türkçeleştirmeler yaptım. Ayrıca I2C modüllü LCD'ye göre ayarlamalar yaptım.


ARDUINO IDE KODLARI:

/*******************************************************************************
   Arduino Clock with alarm function and DS1302 RTC module
   Version 1.0
   Copyright (C) 2018 One Transistor <https://www.onetransistor.eu>

   More information at:
   https://www.onetransistor.eu/2018/12/alarm-clock-with-ds1302-rtc.html

   Developed on Arduino Uno compatible board (ATmega328p) with LCD, DS1302
   module, active buzzer and 4 push buttons.

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation, either version 3 of the License, or
   (at your option) any later version.
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <https://www.gnu.org/licenses/>.
*******************************************************************************/

#define RTC_CLK 4 // clock
#define RTC_DAT 3 // data
#define RTC_RST 2 // enable

#define BTN_AL  A0
#define BTN_DN  A1
#define BTN_UP  A2
#define BTN_SET A3

#define AL_BUZZ 11

#include <LCD.h>
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C  lcd(0x27,2,1,0,4,5,6,7);

unsigned long timeUpdate = 0;
unsigned long timeButton = 0;
unsigned long timeAlarm = 0;
bool buttonPress = false;
byte alarmOn = 0;
bool alarmSw = 1;
byte setMode = 0;
byte setAlarm = 0;

byte daysOfMonth[13] = {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
const char* months[13] = {"---", "Oca", "Sub", "Mar", "Nis", "May", "Haz", "Tem", "Agu", "Eyl", "Eki", "Kas", "Ara"};
const char* wdays[8] = {"---", "Pts", "Sal", "Car", "Per", "Cum", "Cts", "Paz"};

byte hh, mm, ss; // hour, minute, second  (saat, dakika, saniye)
byte dd, MM, yy; // day, month, year      (gün, ay, yıl)
byte dw; // day of the week               (haftanın kaçıncı günü)
byte ae, ah, am; // alarm: enabled, hour, minute   (alarm: etkin, saat, dakika)

static byte bcd2bin (byte val) {
  return val - 6 * (val >> 4);
}

static byte bin2bcd (byte val) {
  return val + 6 * (val / 10);
}

// DS1302 communication from https://github.com/NeiroNx/RTCLib
void rtc_write(byte val) {
  pinMode(RTC_DAT, OUTPUT);
  shiftOut(RTC_DAT, RTC_CLK, LSBFIRST, val);
}

void rtc_write_reg(byte addr, byte val) {
  digitalWrite(RTC_RST, HIGH);
  rtc_write(addr);
  rtc_write(val);
  digitalWrite(RTC_RST, LOW);
}

byte rtc_read() {
  pinMode(RTC_DAT, INPUT);
  byte value = 0;
  for (byte i = 0; i < 8; i++) {
    value |= (digitalRead(RTC_DAT) << i);
    digitalWrite(RTC_CLK, HIGH);
    digitalWrite(RTC_CLK, LOW);
  }
  return value;
}

byte rtc_read_reg(byte addr) {
  digitalWrite(RTC_RST, HIGH);
  rtc_write(addr);
  byte val = rtc_read();
  digitalWrite(RTC_RST, LOW);
  return val;
}

void rtc_read_time() {
  digitalWrite(RTC_RST, HIGH);
  rtc_write(0xBF); // veri bloğu okuma modu

  byte ss_reg = rtc_read();
  if (bitRead(ss_reg, 7)) {// saat durdu
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("RTC not running");
    lcd.setCursor(0, 1);
    lcd.print("Saati ayarla");
    return; // TO DO
  }

  ss = bcd2bin(ss_reg & 0x7F);
  mm = bcd2bin(rtc_read());
  hh = bcd2bin(rtc_read());
  dd = bcd2bin(rtc_read());
  MM = bcd2bin(rtc_read());
  dw = bcd2bin(rtc_read());
  yy = bcd2bin(rtc_read());
  digitalWrite(RTC_RST, LOW);
}

void initTimeDisplay() {
  lcd.clear();
  lcd.setCursor(6, 0); lcd.print(':');
  lcd.setCursor(9, 0); lcd.print(':');
  lcd.setCursor(2, 1); lcd.print('-');
  lcd.setCursor(6, 1); lcd.print('-');
  lcd.setCursor(11, 1); lcd.print(',');
}

void updateDisplay() {
  rtc_read_time();

  lcd.setCursor(7, 0);
  if (mm < 10) lcd.print('0');
  lcd.print(mm, DEC);

  lcd.setCursor(4, 0);
  if (hh < 10) lcd.print('0');
  lcd.print(hh, DEC);

  lcd.setCursor(0, 1);
  if (dd < 9) lcd.print('0');
  lcd.print(dd, DEC);

  lcd.setCursor(13, 1);
  lcd.print(wdays[dw]);

  lcd.setCursor(3, 1);
  lcd.print(months[MM]);

  lcd.setCursor(7, 1);
  lcd.print(yy + 2000, DEC);

  lcd.setCursor(15, 0);
  ae ? lcd.print('*') : lcd.print(' ');
}

void setVariable() {  //zaman ayarları----------------------------------
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Ayar");
  lcd.setCursor(0, 1);
  lcd.print("< >");

  rtc_write_reg(0x8E, 0x00);

  switch (setMode) {
    case 1: // year
      lcd.setCursor(7, 0);
      lcd.print("Yil");
      lcd.setCursor(6, 1);
      lcd.print(yy + 2000, DEC);
      break;
    case 2: // month
      rtc_write_reg(0x8C, bin2bcd(yy));

      lcd.setCursor(7, 0);
      lcd.print("Ay");
      lcd.setCursor(6, 1);
      lcd.print(months[MM]);
      break;
    case 3: // day
      rtc_write_reg(0x88, bin2bcd(MM));

      lcd.setCursor(7, 0);
      lcd.print("Gun");
      lcd.setCursor(6, 1);
      if (dd < 10) lcd.print('0');
      lcd.print(dd, DEC);
      break;
    case 4: // day of week
      rtc_write_reg(0x86, bin2bcd(dd));

      lcd.setCursor(7, 0);
      lcd.print("Haf.Gunu");
      lcd.setCursor(6, 1);
      lcd.print(wdays[dw]);
      break;
    case 5: // hour
      rtc_write_reg(0x8A, bin2bcd(dw));

      lcd.setCursor(7, 0);
      lcd.print("Saat");
      lcd.setCursor(6, 1);
      if (hh < 10) lcd.print('0');
      lcd.print(hh, DEC);
      break;
    case 6: // minutes
      rtc_write_reg(0x84, bin2bcd(hh));

      lcd.setCursor(7, 0);
      lcd.print("Dakika");
      lcd.setCursor(6, 1);
      if (mm < 10) lcd.print('0');
      lcd.print(mm, DEC);
      break;
    case 7:
      rtc_write_reg(0x82, bin2bcd(mm));
      rtc_write_reg(0x80, 0x00); // saatin durmadığından ve saniyeleri sıfırladığından emin ol
    default:
      setMode = 0;
      rtc_write_reg(0x8E, 0x80); // yazma koruması
      initTimeDisplay();
      updateDisplay();
  }
}

void adjustVariable(char a = 1) {
  lcd.setCursor(6, 1);
  lcd.print("    ");
  lcd.setCursor(6, 1);
  char t;

  switch (setMode) {
    case 1: // year
      t = yy; t += a;
      if ((t >= 0) && (t < 100)) yy = t;
      lcd.print(yy + 2000, DEC);
      break;
    case 2: // month
      t = MM; t += a;
      if ((t > 0) && (t <= 12)) MM = t;
      lcd.print(months[MM]);
      break;
    case 3: // day
      t = dd; t += a;
      if ((t > 0) && (t <= daysOfMonth[MM])) dd = t;
      if (dd < 10) lcd.print('0');
      lcd.print(dd, DEC);
      break;
    case 4: // day of week
      t = dw; t += a;
      if ((t > 0) && (t <= 7)) dw = t;
      lcd.print(wdays[dw]);
      break;
    case 5: // hour
      t = hh; t += a;
      if ((t >= 0) && (t < 24)) hh = t;
      if (hh < 10) lcd.print('0');
      lcd.print(hh, DEC);
      break;
    case 6: // minutes
      t = mm; t += a;
      if ((t >= 0) && (t < 60)) mm = t;
      if (mm < 10) lcd.print('0');
      lcd.print(mm, DEC);
      break;
  }

  switch (setAlarm) {  
    case 1: // enable
      ae = 1 - ae;
      ae ? lcd.print("Evet") : lcd.print("Hayir");
      break;
    case 2: // hour
      t = ah; t += a;
      if ((t >= 0) && (t < 24)) ah = t;
      if (ah < 10) lcd.print('0');
      lcd.print(ah, DEC);
      break;
    case 3: // minutes
      t = am; t += a;
      if ((t >= 0) && (t < 60)) am = t;
      if (am < 10) lcd.print('0');
      lcd.print(am, DEC);
      break;
  }
}

void setAlVariable() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Alarm");
  lcd.setCursor(0, 1);
  lcd.print("< >");

  rtc_write_reg(0x8E, 0x00);

  switch (setAlarm) {
    case 1: // alarm enabled
      lcd.setCursor(6, 0);
      lcd.print("Etkin");
      lcd.setCursor(6, 1);
      ae ? lcd.print("Evet") : lcd.print("Hayir");
      break;
    case 2: // alarm hour
      rtc_write_reg(0xC0, ae);
      if (ae == 0) { // is disabled, do not ask for ah and am
        setAlarm = 0;
        rtc_write_reg(0x8E, 0x80); // yazma koruması
        initTimeDisplay();
        updateDisplay();
        return;
      }

      lcd.setCursor(6, 0);
      lcd.print("Saat");
      lcd.setCursor(6, 1);
      if (ah < 10) lcd.print('0');
      lcd.print(ah, DEC);
      break;
    case 3: // alarm minute
      rtc_write_reg(0xC2, ah);

      lcd.setCursor(6, 0);
      lcd.print("Dakika");
      lcd.setCursor(6, 1);
      if (am < 10) lcd.print('0');
      lcd.print(am, DEC);
      break;
    case 4:
      rtc_write_reg(0xC4, am);
    default:
      setAlarm = 0;
      rtc_write_reg(0x8E, 0x80); // yazma koruması
      initTimeDisplay();
      updateDisplay();
  }
}

void setup() {
  pinMode(RTC_RST, OUTPUT);
  pinMode(RTC_CLK, OUTPUT);
  pinMode(RTC_DAT, INPUT);
  digitalWrite(RTC_RST, LOW);

  pinMode(BTN_AL, INPUT_PULLUP);
  pinMode(BTN_DN, INPUT_PULLUP);
  pinMode(BTN_UP, INPUT_PULLUP);
  pinMode(BTN_SET, INPUT_PULLUP);

  pinMode(AL_BUZZ, OUTPUT);
  digitalWrite(AL_BUZZ, LOW);

  delay(1000);

  lcd.begin(16, 2);
     lcd.setBacklightPin(3,POSITIVE);
  lcd.setBacklight(HIGH);

  // get alarm info
  ae = rtc_read_reg(0xC1);
  ah = rtc_read_reg(0xC3);
  am = rtc_read_reg(0xC5);

  if ((ah > 23) || (am > 59)) {
    ae = 0;
    ah = 0;
    am = 0;
  }

  initTimeDisplay();
  updateDisplay();
}

void loop() {
  unsigned long current = millis();

  if ((current >= timeUpdate + 1000) && (setMode + setAlarm == 0)) {
    if (ss == 0) {
      updateDisplay();
      if (ae && (hh == ah) && (mm == am)) alarmOn = true;
      else alarmOn = false;
    }

    // display seconds
    lcd.setCursor(10, 0);
    if (ss < 10) lcd.print('0');
    lcd.print(ss, DEC);

    // increment seconds
    ss++;
    if (ss == 60) ss = 0;

    timeUpdate = current;
  }

  if (current >= timeButton + 10) {
    if ((digitalRead(BTN_SET) == LOW) && (setAlarm == 0)) {
      buttonPress = true;
      setMode++;
      setVariable();
    }

    if ((digitalRead(BTN_UP) == LOW) && (setMode || setAlarm)) {
      buttonPress = true;
      adjustVariable(1);
    }

    if ((digitalRead(BTN_DN) == LOW) && (setMode || setAlarm)) {
      buttonPress = true;
      adjustVariable(-1);
    }

    if ((digitalRead(BTN_AL) == LOW) && (setMode == 0)) {
      buttonPress = true;
      if (alarmOn) {
        alarmOn = 0;
        digitalWrite(AL_BUZZ, LOW);
        lcd.setCursor(0, 0); lcd.print("   ");
        lcd.setCursor(13, 0); lcd.print("   ");
      }
      else {
        setAlarm++;
        setAlVariable();
      }
    }

    timeButton = current;
    if (buttonPress) {
      timeButton += 200; // 200 ms tuş basma araları
      buttonPress = false;
    }
  }

  if (current >= timeAlarm + 300) {
    if (alarmOn) {
      digitalWrite(AL_BUZZ, alarmSw);
      lcd.setCursor(0, 0);
      alarmSw ? lcd.print("<<<") : lcd.print("   ");
      lcd.setCursor(13, 0);
      alarmSw ? lcd.print(">>>") : lcd.print("   ");
      alarmSw = 1 - alarmSw;
      timeAlarm = current;
    }
    else
      digitalWrite(AL_BUZZ, LOW);
  }
}

KULLANILAN PROGRAMLAR: Arduino Ide 1.8.9


Yorumlar