반응형

아두이노 Proj1시간! 2가지 스타일 시계 뚝딱 만들기! 
TM1637(시계 & 온도계)   //   LCD(시계 & 온도계 & 날짜 & 요일)


DS3231 Clock 모듈을 이용해서 디지털 시계 겸 온도계를 뚝딱! 만들어 보겠습니다.

아두이노를 이용하여 시계류를 만들 때 고려해야 할 사항은 몇 일이 지나도 시간이 정확해야 하며, 
작품의 전원이 차단 되더라도 흘러가는 시간이 기억되어 있어야 합니다.
이 두 가지 기능을 제공해주는 RTC 모듈이 바로 DS3231인데요, 
가격도 저렴하면서, 온도 센서가 있어 주변 온도 값도 출력해주는 멋진 모듈입니다.

그럼, 이 모듈을 가지고 영상에서처럼, 두 가지 버전으로 만들어 보겠습니다.
하나는 TM1637 숫자표시 모듈을 가지고 만들어 볼 텐데요,  평상시에는 시간을 표시하다가, 터치센서 또는 스위치를 누르면 온도값을 표시해주도록 하겠습니다. 


두 번째로 LCD 액정 디스플레이를 이용해서 시간 온도뿐 아니라 날짜와 요일까지 모두 표시할 수 있는 장치를 만들어 볼게요. 


물론, 이 모든 데이터는 DS3231 모듈에서 얻을 수 있기 때문에 어렵지 않게 제작할 수 있습니다. 

 《 TM1637 시계 & 온도계  만들기

① 연결도면

1번. TM1637 모듈과 터치 센서를 사용한 회로 연결은 아래와 같이 합니다.


여기서 한가지, 저렴한 복제 나노보드의 경우 CH340 통신칩을 이용하게 되는데요, 처음 사용되는 PC에는 관련 드라이버가 없기 때문에, 드라이버 설치가 필요할 수 있습니다. 
Window키 +‘X’키를 함께 눌러 장치관리자를 열어보세요. 
만약 이 부분 포트 영역에 드라이버가 잡히지 않거나, 경고 표시가 뜬다면 지금 보여드리는 것처럼 드라이버를 설치해 보세요. 
만약, 드라이버가 잘 잡혀 있거나, 아두이노 정품 보드를 사용하는 경우에는 이 과정을 건너뛰면 됩니다. 

그게 아니라면 아래처럼  "CH340"으로 구글 검색 후 아래 보이는 중국어 사이트를 여세요. 

운영체제 버전을 확인하고 파란색의 내려 받기 버튼을 클릭합니다.
위 다운로드 파일 직접 링크했으니 아래 파일을 받아도 됩니다. 
1. Windows 버전용( ↓ )

CH341SER.ZIP
0.28MB

 

2. Mac OS 버전용( ↓ )

CH341SER_MAC.ZIP
0.24MB

 

다운로드 받은 파일의 압축을 풀고 설치를 진행하세요. 


그런 다음, 장치관리자의 포트 부분을 확인해 보면 화면처럼 드라이버가 잘 잡혀 있는 것을 볼 수 있습니다.
아두이노 나노의 경우, 펌웨어를 개인적으로 업뎃 하지 않았다면, 프로세서는 “(Old Bootloader)”로 선택해주세요.

② 아두이노 코드

< 날짜&시간 설정 코드 > 
 :  1번 TM1637회로와  2번 LCD 회로에 공통적으로 사용되는 DS3231의 현재 시간 설정용 코드입니다.

/* [ DS3231 RTC 모듈에 시간 날짜 셋팅하기 코드 ] 
 * 아래 코드를 입력하고 시간 설정은 아두이노IDE의 시리얼모니터로 아래와 같이 입력함
 * 예시) T:설정명령, 22년 01월 07일 18시 55분 00초 금요일 이라면, => :T2201071855006  
 * 요일(1~7, 1:일 2:월 3:화 4:수 5:목 6:금 7:토)
 */

#include <Wire.h>
#define DS3231_I2C_ADDRESS 104
//만약 컴파일 에러시 아래 5줄의 주석 부분을 해제하세요.
//byte decToBcd(byte val);
//void watchConsole();
//void set3231Date();
//void get3231Date();
//float get3231Temp();
 
// DS3231의 데이터핀 연결은 아래처럼 하세요(우노/나노 동일)
// SCL - pin A5
// SDA - pin A4
 
byte seconds, minutes, hours, day, date, month, year;
char weekDay[4];
 
byte tMSB, tLSB;
float temp3231;
 
void setup()
{
  Wire.begin();
  Serial.begin(9600);
}
 
void loop()
{ 
  watchConsole();
  get3231Date();
  Serial.print(weekDay);
  Serial.print(", 20");
  Serial.print(year, DEC);
  Serial.print("/");
  Serial.print(month, DEC);
  Serial.print("/");
  Serial.print(date, DEC);
  Serial.print(" - ");
  Serial.print(hours, DEC); 
  Serial.print(":"); 
  Serial.print(minutes, DEC); 
  Serial.print(":"); 
  Serial.print(seconds, DEC);
  Serial.print(" - Temp: "); 
  Serial.println(get3231Temp());
  delay(1000);
}
 
// 10진수를 2진화 10진수인 BCD 로 변환 (Binary Coded Decimal)
byte decToBcd(byte val)
{
  return ( (val/10*16) + (val%10) );
}
 
void watchConsole()
{
  if (Serial.available()) {      // Look for char in serial queue and process if found
    if (Serial.read() == 84) {   //If command = "T" Set Date
      set3231Date();
      get3231Date();
      Serial.println(" ");
    }
  }
}
 
//시간설정
// T(설정명령) + 년(00~99) + 월(01~12) + 일(01~31) + 시(00~23) + 분(00~59) + 초(00~59) + 요일(1~7, 일1 월2 화3 수4 목5 금6 토7)
// 예: T1605091300002 (2016년 5월 9일 13시 00분 00초 월요일)
void set3231Date()
{
  year    = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  month   = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  date    = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  hours   = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  minutes = (byte) ((Serial.read() - 48) *10 +  (Serial.read() - 48));
  seconds = (byte) ((Serial.read() - 48) * 10 + (Serial.read() - 48));
  day     = (byte) (Serial.read() - 48);
 
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0x00);
  Wire.write(decToBcd(seconds));
  Wire.write(decToBcd(minutes));
  Wire.write(decToBcd(hours));
  Wire.write(decToBcd(day));
  Wire.write(decToBcd(date));
  Wire.write(decToBcd(month));
  Wire.write(decToBcd(year));
  Wire.endTransmission();
}
 
 
void get3231Date()
{
  // send request to receive data starting at register 0
  Wire.beginTransmission(DS3231_I2C_ADDRESS); // 104 is DS3231 device address
  Wire.write(0x00); // start at register 0
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 7); // request seven bytes
 
  if(Wire.available()) {
    seconds = Wire.read(); // get seconds
    minutes = Wire.read(); // get minutes
    hours   = Wire.read();   // get hours
    day     = Wire.read();
    date    = Wire.read();
    month   = Wire.read(); //temp month
    year    = Wire.read();
       
    seconds = (((seconds & B11110000)>>4)*10 + (seconds & B00001111)); // convert BCD to decimal
    minutes = (((minutes & B11110000)>>4)*10 + (minutes & B00001111)); // convert BCD to decimal
    hours   = (((hours & B00110000)>>4)*10 + (hours & B00001111)); // convert BCD to decimal (assume 24 hour mode)
//  필요한 경우, 아래 24시간을 12시간 단위로 표시하는 코드 추가
    if (hours > 12 ) {
      hours = hours - 12;
    }
    day     = (day & B00000111); // 1-7
    date    = (((date & B00110000)>>4)*10 + (date & B00001111)); // 1-31
    month   = (((month & B00010000)>>4)*10 + (month & B00001111)); //msb7 is century overflow
    year    = (((year & B11110000)>>4)*10 + (year & B00001111));
  }
  else {
    //oh noes, no data!
  }
 
  switch (day) {
    case 1:
      strcpy(weekDay, "Sun");
      break;
    case 2:
      strcpy(weekDay, "Mon");
      break;
    case 3:
      strcpy(weekDay, "Tue");
      break;
    case 4:
      strcpy(weekDay, "Wed");
      break;
    case 5:
      strcpy(weekDay, "Thu");
      break;
    case 6:
      strcpy(weekDay, "Fri");
      break;
    case 7:
      strcpy(weekDay, "Sat");
      break;
  }
}
 
float get3231Temp()
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0x11);
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 2);
  if (Wire.available()) {
    tMSB = Wire.read(); 
    tLSB = Wire.read(); 
    temp3231 = (tMSB & B01111111); 
    temp3231 += ( (tLSB >> 6) * 0.25 ); //소수점 아래 단위의 온도값을 0.25단위씩 처리
  }
  else {
    // 에러일 경우 아무 데이터도 출력하지 아니함
  }
  return temp3231;
}

<  날짜&시간 설정 코드 다운로드 >

01_DS3231RTC_Setting.zip
0.00MB


< 1번 TM1637 시간&온도 표시 코드 >

/* 
 *  DS3231 & TM1637 & 터치(SW)센서로 시계/온도 번갈아 출력하는 코드.
 *  터치센서는 어떤 종류든 사용 가능하며, 기계적인 토글스위치, 슬라이드스위치 등도 가능.
 *  RTClib 라이브러리를 검색하여 설치하거나, 만약 설치한 라이브러리가 맞지 않다면, 삭제하고 아래 제공하는 라이브러리를 다운 받으세요.
 *  TM1637Display 라이브러리도 함께 제공합니다.(비슷한 라이브러리가 여러 개이기 때문에 반드시 제공하는 라이브러리로 설치하세요)
  */
#include <Wire.h>           // 아두이노 IDE 설치시 기본 제공됨
#include <RTClib.h>         // RTClib 라이브러리
#include <TM1637Display.h>  // TM1637Display 라이브러리
#define CLK 8            // TM1637 CLK 핀
#define DIO 9            // TM1637 DIO 핀
#define DS3231_I2C_ADDRESS 104
#define Touch 7
RTC_DS3231 rtc;         // RTC 모듈 객체 생성
TM1637Display display(CLK, DIO);
int Time, Minute;       // 시간, 분 변수 지정
char daysOfTheWeek[7][12] = {"SUN", "MON", "TUE", "WEN", "THU", "FRI", "SAT"};
float temp3231;
byte tMSB, tLSB;

void setup () {
  Wire.begin();
  display.setBrightness(7); // 0~7, 밝기 조절 : 0(가장 어두움)~ 7(가장 밝음)
  Serial.begin(9600);     // RTC 모듈 체크 루틴
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  pinMode(Touch, INPUT);
}
void loop () {
  get3231Temp();
  //  Serial.println(temp3231);
  int SW = digitalRead(Touch);
  //  Serial.println(SW);
  delay(100);
  DateTime now = rtc.now();
  int Time = now.hour();
//  필요한 경우, 아래 24시간을 12시간 단위로 표시하는 코드 추가
  if (Time>12) { Time=Time-12; }
  
  int Minute = now.minute();
  int digitoneT = Time / 10;
  int digittwoT = Time % 10;
  int digitoneM = Minute / 10;
  int digittwoM = Minute % 10;
  uint8_t data[] = { 0x0, 0x0, 0x0, 0x0};
  uint8_t segto;
  // 아래, 스위치 터치가 없으면 시간을 표시하고, 터치 시 온도를 표시함.
  if (SW == 0) {
    data[0] = display.encodeDigit(digitoneT);
    data[1] = display.encodeDigit(digittwoT);
    data[2] = display.encodeDigit(digitoneM);
    data[3] = display.encodeDigit(digittwoM);
    segto = 0x80 | display.encodeDigit(digittwoT);//시계도트 제어
    display.setSegments(&segto, 1, 1); //시계도트 제어
    delay(500);
    display.setSegments(data);  // 배열값에 있는 시계 데이터 출력
    delay(500);
  } else {
    //    Serial.println(tMSB);   // 온도 값 앞 두자리
    //    Serial.println("\t");
    //    Serial.println(((tLSB >> 6) * 0.25)*100);  // 온도 값 소수점 이하 두 자리(0.25 단위로 표시함)
    //    delay(100);

    int tempLSB = ((tLSB >> 6) * 0.25) * 100;
    int digitTemp1 = tMSB / 10;         // 십의 자리 온도 값
    int digitTemp2 = tMSB % 10;         // 일의 자리 온도 값
    int digitTemp3 = tempLSB / 10;    // 소수 첫 자리 온도 값
    int digitTemp4 = tempLSB % 10;    // 소수 둘째 자리 온도 값
    data[0] = display.encodeDigit(digitTemp1);
    data[1] = display.encodeDigit(digitTemp2);
    data[2] = display.encodeDigit(12);   // 온도 기호(C)표시 숫자 12를 엔코딩해서 세번째 FND에 출력함.
//    data[3] = display.encodeDigit(12); // 네번째 자리 비움
    display.setSegments(data);  // 배열값에 있는 데이터 출력
  }
}

float get3231Temp()
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0x11);
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 2);
  if (Wire.available()) {
    tMSB = Wire.read(); 
    tLSB = Wire.read(); 
    temp3231 = (tMSB & B01111111); 
    temp3231 += ( (tLSB >> 6) * 0.25 ); //소수점 아래 단위의 온도값을 0.25단위씩 처리
  }
  else {
    // 에러일 경우 아무 데이터도 출력하지 아니함
  }
  return temp3231;
}

< 라이브러리 다운로드 >
1. RTClib

RTClib.zip
0.02MB

2. TM1637Display

TM1637-master.zip
1.36MB

3. LiquidCrystal_I2C (2번째 I2C LCD를 활용한 코드 실행을 위해 필요한 라이브러리 입니다)

Arduino-LiquidCrystal-I2C-library-master.zip
0.01MB

 

앞의 연결 도면을 보고,  가지고 있는 브레드보드를 이용해서 연결하면 됩니다.
터치 센서는 어떤 종류든 상관 없습니다, 지금은 터치를 하면 불빛이 들어오는 센서를 사용해 볼게요.
일반 On/Off 스위치와의 차이점은 터치시 Signal 단자로 전압이 출력됩니다. 
그럼, 그 전압을 아두이노 포트로 체크하여 처리해 주면 됩니다.

 

날짜 및 시간 값을 저장하고 제공해 주는 RTC 모듈은 몇가지가 있지만, 오차가 거의 없는 이 DS3231모듈을 추천합니다.

좌우 대칭으로 핀이 설계 되어 있어, 연결하기 편한 쪽을 사용하면 됩니다.
기존에 납땜되어 있는 핀은 브레드보드에 세우듯이 꽂아야 하기에 이 핀을 사용하지 않고, 브레드보드에 밀착될 수 있도록 새로 연결하면 좋습니다.
그리고 모든 핀을 사용할 필요 없고, SCL / SDA / VCC / GND 핀만 사용하면 됩니다.
물론 인두기가 없다면 그냥 점프선을 연결해서 사용하면 됩니다.

 

TM1637 디스플레이는 4개의 FND로 연결되어 있어 시간을 나타내기에 편리한 모듈입니다.

TM1637 또한 그냥 연결해도 되지만 기존 핀을 제거하고 보기 좋게 밀착시켜 볼게요.


브레드보드의 내부 연결 구조상 직접 꽂으려면 핀 작업을 해야 밀착시킬 수 있습니다.

그럼, 제공해 드리는 DS3231RTC_Setting 파일을 가지고 시간을 설정해 보세요.

코드가 업로드 된 상태에서 시리얼 모터를 열면 아래처럼 초기화된 시간을 볼 수 있습니다. 


현재시간으로 설정하는 방법은 코드 속에도 적혀 있는데요,
예를 들어, 먼저 시리얼 모니터 입력창에 T를 입력하고 22년 01월 07일 19시 23분 00초, 금요일 6 형태로 입력합니다. 
→  T2201071923006   엔터

입력 완료 후 엔터를 치면, 바뀐 시간으로 적용되는 것을 볼 수 있습니다.


Temp는 모듈 주변에 체크되는 온도 값을 보여주는데요, 초기 값이 실제 온도치보다 좀 더 높게 나타나는 경우가 있지만, 시간이 지나면서 실제 온도로 맞춰지게 됩니다.


이제, RTC 모듈에 현재 시간을 설정했으니, RTC모듈의 Data를 받아와서 TM1637에 표시해주는 "TM1637..." 코드를 나노에 업로드하면 됩니다. 

그리고 , 라이브러리 파일이 설치되어야 하는데요, 
라이브러리 관리창에서 검색 후 설치하거나, 링크해 드리는 파일을 설치하면 됩니다.
TM1637Display 라이브러리의 경우 이름이 같더라도 내용이 다른 라이브러리를 설치하게 되면, 컴파일 시 에러가 날 수 있는데요, 그럴 경우 위에서 제공해 드리는 라이브러리를 설치해 보세요.

 기본적으로 시간을 표시하고 있다가 스위치를 터치하면 온도 표시가 됩니다.
온도는 31℃로 정확하게 잘 표시되고 있습니다. (온풍기 옆에서 테스트 중)
간혹 온도가 비정상적으로 높게(7~10℃이상) 측정되는 경우가 있는데요, 측정 초기에만 그렇고 시간이 지나면 대부분은 정상적인 온도를 표시해 줍니다.

< 1번. TM1637 시계 회로 완성 및 동작 모습 >

스위치를 터치하면, 시계 표시에서 온도 표시로 바뀝니다. 

 

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

그럼, 두 번째 LCD 시계를 조립해 볼게요.

 《 LCD 날짜 & 시계 & 온도계  만들기 

① 연결도면

2번. I2C LCD 모듈과 DS3231 모듈을 사용한 회로 연결은 아래와 같이 합니다.

나노 보드의 연결도 우노 보드의 핀과 거의 일치하기 때문에 쉽게 연결할 수 있습니다.  위 회로를 참고해서 나노보드를 조립해 보세요. 

I2C 타입의 LCD를 사용하면 매우 쉽게 연결할 수 있는데요, 
I2C 타입의 모듈을 2개 이상 여러개를 사용하더라도 모듈의 SDA(데이터)핀과 SCL(클럭신호)핀들을 각각 묶어주고 우노(나노)의 SDA, SCL에 연결해 주면 됩니다.
I2C 모듈에는 ‘고유주소’들이 매겨져 있기 때문에 아두이노에서 구분 처리할 수 있습니다.
LCD의 경우, 핀이‘ㄱ’자로 되어 있어 브레드보드에 꽂기 편하도록 공구를 이용해서 세워보세요.


준비되었으면, 제공해드리는 LCD용 시계 코드를 열고 업로드 하세요.
LCD를 사용할 때 장점은 데이터를 표시할 수 있는 영역이 훨씬 넓은 것인데요,
년, 월, 일, 시, 분, 초와 온도 등 DS3231에서 추출할 수 있는 모든 데이터를 출력해 볼 수 있습니다.


나노가 연결된 포트와 보드 선택을 확인하고 아래 제공해 드리는 코드를 업로드 합니다.

< 2번 LCD 날짜 & 시간 & 온도 표시 코드 >

/* 
 *  DS3231 RTC이용하여 LCD에 날자(요일)/ 시계 / 온도 값 출력하는 코드 
 *  LCD는 I2C 모듈이 있는 것을 사용하고 있음. 대부분의 I2C LCD의 I2C주소는 0x27임 
 */
#include <LiquidCrystal_I2C.h> 
LiquidCrystal_I2C lcd (0x27, 16,2); 
 
#include <Wire.h>                  // 아두이노 IDE 설치시 기본 제공됨
#include <RTClib.h>                // RTClib 라이브러리
#define DS3231_I2C_ADDRESS 104     // DS3231의 I2C 주소
RTC_DS3231 rtc;        
int Time, Minute;       
char daysOfTheWeek[7][12] = {"SUN", "MON", "TUE", "WEN", "THU", "FRI", "SAT"};
float temp3231;
byte tMSB, tLSB;

void setup () {
  Wire.begin();
  Serial.begin(9600);    
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  lcd.begin();  
  lcd.clear();
}
void loop () {
  get3231Temp();
  delay(100);
  DateTime now = rtc.now();
  int HOUR=now.hour();
//  필요한 경우, 아래 3줄의 24시간을 12시간 단위로 표시하는 코드 추가, 필요 없다면 주석처리!
  int Time = now.hour();
  if (Time>12) { HOUR=now.hour()-12; 
  } else { HOUR=now.hour(); }

  lcd.setCursor(0,0); 
  lcd.print(now.year());
  lcd.print("/");
  lcd.print(now.month());
  lcd.setCursor(7,0); 
  lcd.print("/");
  lcd.print(now.day());    
  lcd.setCursor(10,0); 
  lcd.print(&daysOfTheWeek[now.dayOfTheWeek()][0]);
  lcd.print("day");
  lcd.setCursor(0,1); 
  lcd.print(HOUR);
  lcd.setCursor(2,1); 
  lcd.print(":");
  lcd.print(now.minute());
  lcd.setCursor(5,1); 
  lcd.print(":");
  lcd.print(now.second());
  //"0 " 0뒤에 공백이 있으며, 표시 단위가 변할 때 잔상을 제거하기 위함임.
  if (now.second()==0) { lcd.setCursor(6,1); lcd.print("0 "); }    
  if (now.minute()==0) { lcd.setCursor(3,1); lcd.print("0 "); }    
  if (HOUR==0) { lcd.setCursor(0,1); lcd.print("0 "); }    
  if (now.month()==0) { lcd.setCursor(5,0); lcd.print("0 "); }    
  if (now.day()==0) { lcd.setCursor(8,0); lcd.print("0 "); }    
  lcd.setCursor(9,1);
  lcd.print(temp3231);
  lcd.print(char(223)); // '˚' 표시용 특수문자 아스키 코드값
  lcd.print("C"); 
}

float get3231Temp()
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0x11);
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 2);
  if (Wire.available()) {
    tMSB = Wire.read(); 
    tLSB = Wire.read(); 
    temp3231 = (tMSB & B01111111); 
    temp3231 += ( (tLSB >> 6) * 0.25 ); //소수점 아래 단위의 온도값을 0.25단위씩 처리
  }
  else {
    // 에러일 경우 아무 데이터도 출력하지 아니함
  }
  return temp3231;
}

< LCD 날짜 & 시계 & 온도 표시용 코드 다운로드 >

03_LCD_DS3231_Temp_Clock.zip
0.00MB


 시간뿐 아니라 달력 기능까지 표시할 수 있고, 온도까지 한 번에 출력할 수 있어 좋습니다.
만약, LCD에 불은 들어오지만 데이터 표시가 안 되는 경우가 있다면 지금처럼 LCD 뒷면에 있는 반고정저항 값을 좌 또는 우로 조금씩 조절해 보세요.


저항 값의 위치가 한 쪽으로 치우쳐져 있을 경우 지금처럼 데이터 표시가 되지 않거나 과하게 표시 될 수 있으니, 적절한 위치로 조절해 보세요.
참고로, LCD관련 코딩을 할 때는 잔상 효과를 고려해서 작성해 주어야 하는데요, 
예를 들어, 59초에서 0초로 넘어 갈때, 앞자리 5가 계속 남아 있게 됩니다.
 ( 59 → 0 → 1 → 2 → 3,   실제 : 59 → 50 → 51 → 52 → 53 )

이럴때는 숫자 데이터를 표시할 때 공백을 넣어 앞 숫자를 지워주는 방법으로 간단히 해결 할 수 있습니다.

코드에는 12시간제로 표시하거나 24시간제 표시로 변경할 수 있도록 하였습니다.
참고로, 저렴한 DS3231모듈의 경우 내장된 플래시 메모리가 불량인 경우가 간혹 있습니다 .
이럴 경우, 시간을 설정하여도 전원이 제거되고 다시 연결하면 시간이 리셋되기도 합니다 .
 혹은 DS3231에 있는 리튬배터리가 다된(방전) 경우가 있는데요,  이럴 때는 일반적으로 PC나  자동차 리모컨키에 많이 들어가는 CR2032로 교체해 주면 됩니다.

그럼, 드라이버 관련 다른 문제가 없다고 보고, 코드를 아두이노에 업로드합니다.

< 2번 LCD 날짜 & 시간 & 온도 표시 코드 >

/* 
 *  DS3231 RTC이용하여 LCD에 날자(요일)/ 시계 / 온도 값 출력하는 코드 
 *  LCD는 I2C 모듈이 있는 것을 사용하고 있음. 대부분의 I2C LCD의 I2C주소는 0x27임 
 */
 
#include <LiquidCrystal_I2C.h> 
LiquidCrystal_I2C lcd (0x27, 16,2); 
 
#include <Wire.h>                  // 아두이노 IDE 설치시 기본 제공됨
#include <RTClib.h>                // RTClib 라이브러리
#define DS3231_I2C_ADDRESS 104     // DS3231의 I2C 주소
RTC_DS3231 rtc;        
int Time, Minute;       
char daysOfTheWeek[7][12] = {"SUN", "MON", "TUE", "WEN", "THU", "FRI", "SAT"};
float temp3231;
byte tMSB, tLSB;

void setup () {
  Wire.begin();
  Serial.begin(9600);    
  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }
  lcd.begin();  
  lcd.clear();
}
void loop () {
  get3231Temp();
  delay(100);
  DateTime now = rtc.now();
  int HOUR=now.hour();
//  필요한 경우, 아래 3줄의 24시간을 12시간 단위로 표시하는 코드 추가, 필요 없다면 주석처리!
  int Time = now.hour();
  if (Time>12) { HOUR=now.hour()-12; 
  } else { HOUR=now.hour(); }

  lcd.setCursor(0,0); 
  lcd.print(now.year());
  lcd.print("/");
  lcd.print(now.month());
  lcd.setCursor(7,0); 
  lcd.print("/");
  lcd.print(now.day());    
  lcd.setCursor(10,0); 
  lcd.print(&daysOfTheWeek[now.dayOfTheWeek()][0]);
  lcd.print("day");
  lcd.setCursor(0,1); 
  lcd.print(HOUR);
  lcd.setCursor(2,1); 
  lcd.print(":");
  lcd.print(now.minute());
  lcd.setCursor(5,1); 
  lcd.print(":");
  lcd.print(now.second());
  //"0 " 0뒤에 공백이 있으며, 표시 단위가 변할 때 잔상을 제거하기 위함임.
  if (now.second()==0) { lcd.setCursor(6,1); lcd.print("0 "); }    
  if (now.minute()==0) { lcd.setCursor(3,1); lcd.print("0 "); }    
  if (HOUR==0) { lcd.setCursor(0,1); lcd.print("0 "); }    
  if (now.month()==0) { lcd.setCursor(5,0); lcd.print("0 "); }    
  if (now.day()==0) { lcd.setCursor(8,0); lcd.print("0 "); }    
  lcd.setCursor(9,1);
  lcd.print(temp3231);
  lcd.print(char(223)); // '˚' 표시용 특수문자 아스키 코드값
  lcd.print("C"); 
}

float get3231Temp()
{
  Wire.beginTransmission(DS3231_I2C_ADDRESS);
  Wire.write(0x11);
  Wire.endTransmission();
  Wire.requestFrom(DS3231_I2C_ADDRESS, 2);
  if (Wire.available()) {
    tMSB = Wire.read(); 
    tLSB = Wire.read(); 
    temp3231 = (tMSB & B01111111); 
    temp3231 += ( (tLSB >> 6) * 0.25 ); //소수점 아래 단위의 온도값을 0.25단위씩 처리
  }
  else {
    // 에러일 경우 아무 데이터도 출력하지 아니함
  }
  return temp3231;
}

< 2번 LCD용 시계 코드 다운로드 >

03_LCD_DS3231_Temp_Clock.zip
0.00MB

코드 업로드 하면, 아래처럼 동작이 됩니다.

 

네, 이렇게 DS3231 모듈을 이용해서 두 가지 버전의 시계겸 온도계를 만들어 보았습니다.

감사합니다.

 《 디지털 시계 뚝딱! 만들기 동영상 설명 참고하세요

 

반응형