2022년 2월 13일 일요일

RTC1302를 이용한 아두이노 시계 코드

Michael Miller("Makuna")의 Rtc 라이브러리에 포함된 예제(DS1302_Simple)를 활용한 아두이노 시계의 코드를 싣는다. 택트 스위치를 누르면 인터럽트가 발동하여 12시-24시 표시를 전환하게 만드느라 이곳 저곳을 참조하여 코드 조각을 가져다가 일단은 돌아가게 만들어 놓았다.

// CONNECTIONS:
// DS1302 CLK/SCLK --> 7
// DS1302 DAT/IO --> 6
// DS1302 RST/CE --> 5
// DS1302 VCC --> 3.3v - 5v
// DS1302 GND --> GND

#include <ThreeWire.h>  
#include <RtcDS1302.h>
#include <LiquidCrystal.h> 
#define debounceTime 75 // <<- Set debounce Time (unit ms)

int interruptPin1 = 3; // 2 or 3
volatile int state = LOW;

char *dayArray[] = {
  "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
};

ThreeWire myWire(6,7,5); // IO, SCLK, CE
RtcDS1302<ThreeWire> Rtc(myWire);
LiquidCrystal lcd(8, 9, 10, 11, 12, 13); //RS, EN, data(4,5,6,7)

void setup () 
{
    Serial.begin(9600);

    Serial.print("Compiled: ");
    Serial.print(__DATE__);
    Serial.print("\t");
    Serial.println(__TIME__);

    lcd.begin(16, 2);
    lcd.clear();

    pinMode(interruptPin1, INPUT_PULLUP); // pulled down using a 10K resistor
    attachInterrupt(digitalPinToInterrupt(interruptPin1), buttonPushed, FALLING);
    
    Rtc.Begin();

    RtcDateTime compiled = RtcDateTime(__DATE__, __TIME__);

    if (!Rtc.IsDateTimeValid()) 
    {
        // Common Causes:
        //    1) first time you ran and the device wasn't running yet
        //    2) the battery on the device is low or even missing

        Serial.println("RTC lost confidence in the DateTime!");
        Rtc.SetDateTime(compiled);
    }
    if (Rtc.GetIsWriteProtected())
    {
        Serial.println("RTC was write protected, enabling writing now");
        Rtc.SetIsWriteProtected(false);
    }
    if (!Rtc.GetIsRunning())
    {
        Serial.println("RTC was not actively running, starting now");
        Rtc.SetIsRunning(true);
    }

    RtcDateTime now = Rtc.GetDateTime();

    if (now < compiled) 
    {
        Serial.println("RTC is older than compile time!  (Updating DateTime)");
        Rtc.SetDateTime(compiled);
    }
    else if (now > compiled) 
    {
        Serial.println("RTC is newer than compile time. (this is expected)");
    }
    else if (now == compiled) 
    {
        Serial.println("RTC is the same as compile time! (not expected but all is fine)");
    }
}

void loop () 
{
    RtcDateTime now = Rtc.GetDateTime();
    printDateTime(now);

    if (!now.IsValid())
    {
        // Common Causes:
        //    1) the battery on the device is low or even missing and the power line was disconnected
        //Serial.println("RTC lost confidence in the DateTime!?!");
    }

    delay(1000); // one seconds
}

void printDateTime(const RtcDateTime& dt)
{
    char daystring[16];
    char timestring[16];
    String flag = "AM";
    String stateStr = "24-hr system";
    short DOW = dt.DayOfWeek();
    
    sprintf(daystring, " %4u-%02u-%02u %s", dt.Year(), dt.Month(), dt.Day(), dayArray[DOW]);

    short Hour = dt.Hour();

    if ( state ) { // 24-hr system
      lcd.clear();
      sprintf(timestring, "    %02u:%02u:%02u", dt.Hour(), dt.Minute(), dt.Second());
    } else {  // 12-hr system with AM/PM designation
       if (dt.Hour() > 12) {
         Hour = dt.Hour() - 12;
         flag = "PM";
       }     
       stateStr = "12-hr system with AM/PM designation";
       sprintf(timestring, "  %2d:%02u:%02u <%s>", Hour, dt.Minute(), dt.Second(), flag.c_str());
    }
    Serial.print("State ");
    Serial.print(state);
    Serial.print(": "); 
    Serial.println(stateStr);
    lcd.setCursor(0, 0);
    lcd.print(timestring);
    lcd.setCursor(0, 1);
    lcd.print(daystring);
}

void buttonPushed() {
    static unsigned long lastTime = 0;
    unsigned long Now = millis();
    if((Now - lastTime) > debounceTime)
    {
        state=!state;
        Serial.print("Button pressed: state changed to ");
        Serial.println(state);
        RtcDateTime now = Rtc.GetDateTime();
        printDateTime(now);
    }
    lastTime = Now;
}

C++ 함수 선언부에서 참조를 통하여 파라미터를 전송하는 방법을 겨우 이해하는 수준이다. 따라서 추가로 장착한 버튼을 눌러 시간 설정을 고치도록 개선한 버전 2 코드를 만들려면 아직 갈 길이 멀다. 그 다음 목표는 알람 기능 추가하기.

12시-24시 전환은 3번 버튼이 담당한다.

버튼을 이용한 시 변경 기능은 Accurate Clock Just Using an Arduino을 참조할 예정이다.  paulsb가 공개한 이 프로젝트에서는 그러나 RTC 모듈이라는 외부 하드웨어를 전혀 사용하지 않기 때문에 전원을 새로 연결할 때마다 시각을 새롭게 맞추어야 한다. Makuna의 Rtc 라이브러리를 가져다가 RTC 모듈에 데이터를 써 넣고 읽어오는 기능을 만들어 넣는 일이 필요하다. paulsb의 코드는 시간과 관련한 특별한 객체를 전혀 사용하지 않아서 시간 증가 및 표현을 전부 계산을 통해 구현한다. 공부 목적으로 살펴볼 가치가 있다.

LCD 또는 7-세그먼트 표시기를 이용한 시계 만들기는 아두이노 입문자의 프로젝트로 널리 인식되고 있다. 매우 단순한 목표라고 생각할 수도 있으나 시간이라는 데이터 구조가 의외로 복잡하여 공부를 할 것이 많다. 1970년 1월 1일 0시라는 유닉스 세계의 epoch time이 정해진 이유(사실 명확한 것은 없음) 등에 대해서도 흥미로운 이야깃거리가 많을 것이다.

댓글 없음: