DS1302 RTC와 아두이노 우노로 만드는 신뢰할 수 있는 알람 시계
부품 및 소모품
부품
수량
실시간 시계(RTC) 모듈 - DS1302
1
부저
1
Adafruit 표준 LCD - 16x2 흰색/파란색 (I2C)
1
아두이노 우노
1
4x4 매트릭스 키패드 모듈
1
프로젝트 소개
안녕하세요, 이번 프로젝트에서는 아두이노 우노 보드로 간단한 알람 시계를 만들어보겠습니다. 이 프로젝트는 이전에 사용했던 다양한 모듈들을 조합한 것입니다. 막히는 부분이 있으면 각 모듈별 튜토리얼을 참고하세요. 저는 보통 모듈별로 따로 테스트한 후 조합하는 방식으로 작업합니다. :D
필요한 부품
아두이노 우노 보드 (또는 호환 보드)
DS1302 RTC 모듈
4x4 매트릭스 키패드 모듈
LCD I2C 화면
부저 모듈 또는 2핀 부저
참고 튜토리얼
DS1302 RTC 모듈을 키패드 + 아두이노 + LCD와 함께 설정하는 방법
DS1302 RTC 모듈을 아두이노 보드와 LCD 화면으로 간단하게 사용하는 방법
아두이노 LCD I2C 간단 사용법 및 시리얼 모니터에서 직접 쓰기
아두이노 우노 + 4x4 키패드 매트릭스 + LCD I2C 화면
아두이노로 부저/피에조 스피커 사용하기
배선도
라이브러리 및 코드
LCD I2C 라이브러리 (이것 또는 직접 다운로드)
키패드 라이브러리 (아두이노 IDE에서 다운로드 가능)
RTC DS1302 virtuabotix 라이브러리
코드 설명
코드 다운로드 후 모듈 배선을 완료하면, "*" 키를 눌러 DS1302 RTC의 시간과 날짜를 설정할 수 있습니다. 디스플레이에 현재 요일과 시간이 표시됩니다. 알람을 설정하려면 "A" 키를 눌러 시간과 분을 설정하고, "B" 키를 눌러 알람을 비활성화할 수 있습니다. 알람이 울릴 때 아무 버튼이나 눌러도 끌 수 있습니다.
궁금한 점이 있으면 연락 주세요.
소스 코드
// DS1302 RTC 모듈 + 4x4 키패드 + LCD I2C + 아두이노 + 부저용 코드
// 모듈 배선 후 LCD에 기본 날짜/시간 또는 이전에 설정한 값 표시
// 이 프로젝트의 목적: 키패드로 RTC 모듈 설정 가능, 설정값 저장, 화면 표시, 알람 설정
// Surtrtech.com 또는 SurtrTech 유튜브 채널 참조
#include <Keypad.h>
#include <Wire.h>
#include <virtuabotixRTC.h>
#include <LiquidCrystal_I2C.h>
#define I2C_ADDR 0x27
#define BACKLIGHT_PIN 3
#define En_pin 2
#define Rw_pin 1
#define Rs_pin 0
#define D4_pin 4
#define D5_pin 5
#define D6_pin 6
#define D7_pin 7
LiquidCrystal_I2C lcd(I2C_ADDR, En_pin, Rw_pin, Rs_pin, D4_pin, D5_pin, D6_pin, D7_pin);
virtuabotixRTC myRTC(2, 3, 4); // RTC 배선 (CLK, DAT, RST) - 배선 변경 시 여기 수정
const byte numRows = 4;
const byte numCols = 4;
char keymap[numRows][numCols] = {
{'1', '2', '3', 'A'},
{'4', '5', '6', 'B'},
{'7', '8', '9', 'C'},
{'*', '0', '#', 'D'}
};
byte rowPins[numRows] = {12, 11, 10, 9};
byte colPins[numCols] = {8, 7, 6, 5};
int i1, i2, i3, i4;
char c1, c2, c3, c4;
char keypressed, keypressedx;
int A_hour = NULL;
int A_minute = NULL;
int AlarmIsActive = NULL;
int buzzer = 13;
Keypad myKeypad = Keypad(makeKeymap(keymap), rowPins, colPins, numRows, numCols);
void setup() {
Serial.begin(9600);
lcd.begin(16, 2);
lcd.setBacklightPin(BACKLIGHT_PIN, POSITIVE);
lcd.setBacklight(HIGH);
lcd.home();
}
void loop() {
while (keypressed == NO_KEY) {
keypressed = myKeypad.getKey();
lcd.clear();
myRTC.updateTime();
if (myRTC.hours == A_hour && myRTC.minutes == A_minute && AlarmIsActive == 1 && myRTC.seconds >= 0 && myRTC.seconds <= 2) {
while (keypressedx == NO_KEY) {
tone(buzzer, 1000);
delay(100);
tone(buzzer, 2000);
delay(100);
lcd.clear();
lcd.print("Get up !!!");
keypressedx = myKeypad.getKey();
}
}
keypressedx = NO_KEY;
noTone(buzzer);
lcd.setCursor(0, 0);
lcd.print(myRTC.dayofmonth);
lcd.print("/");
lcd.print(myRTC.month);
lcd.print("/");
lcd.print(myRTC.year);
lcd.setCursor(0, 1);
lcd.print(myRTC.hours);
lcd.print(":");
lcd.print(myRTC.minutes);
lcd.print(":");
lcd.print(myRTC.seconds);
delay(100);
}
if (keypressed == '*') {
lcd.clear();
lcd.print(" Setup");
delay(1000);
lcd.clear();
lcd.print("Setup year");
// 연도(4자리), 월(2자리), 일(2자리), 시(2자리), 분(2자리) 순으로 입력
// 키패드 입력은 문자(char)이므로 정수(int)로 변환하여 저장
// 월은 04, 03처럼 두 자리로 입력해야 함
// 라이브러리가 잘못된 날짜/시간(45/17/1990, 58:90:70)을 거부함
char keypressed2 = myKeypad.waitForKey();
if (keypressed2 != NO_KEY && keypressed2 != '*' && keypressed2 != '#' && keypressed2 != 'A' && keypressed2 != 'B' && keypressed2 != 'C' && keypressed2 != 'D') {
c1 = keypressed2; lcd.setCursor(0, 1); lcd.print(c1);
}
char keypressed3 = myKeypad.waitForKey();
if (keypressed3 != NO_KEY && keypressed3 != '*' && keypressed3 != '#' && keypressed3 != 'A' && keypressed3 != 'B' && keypressed3 != 'C' && keypressed3 != 'D') {
c2 = keypressed3; lcd.setCursor(1, 1); lcd.print(c2);
}
char keypressed4 = myKeypad.waitForKey();
if (keypressed4 != NO_KEY && keypressed4 != '*' && keypressed4 != '#' && keypressed4 != 'A' && keypressed4 != 'B' && keypressed4 != 'C' && keypressed4 != 'D') {
c3 = keypressed4; lcd.setCursor(2, 1); lcd.print(c3);
}
char keypressed5 = myKeypad.waitForKey();
if (keypressed5 != NO_KEY && keypressed5 != '*' && keypressed5 != '#' && keypressed5 != 'A' && keypressed5 != 'B' && keypressed5 != 'C' && keypressed5 != 'D') {
c4 = keypressed5; lcd.setCursor(3, 1); lcd.print(c4);
}
i1 = (c1 - 48) * 1000;
i2 = (c2 - 48) * 100;
i3 = (c3 - 48) * 10;
i4 = c4 - 48;
int N_year = i1 + i2 + i3 + i4;
delay(500);
lcd.clear();
lcd.print("Setup month");
// 월 입력 (2자리)
char keypressed6 = myKeypad.waitForKey();
if (keypressed6 != NO_KEY && keypressed6 != '*' && keypressed6 != '#' && keypressed6 != 'A' && keypressed6 != 'B' && keypressed6 != 'C' && keypressed6 != 'D') {
c1 = keypressed6; lcd.setCursor(0, 1); lcd.print(c1);
}
char keypressed7 = myKeypad.waitForKey();
if (keypressed7 != NO_KEY && keypressed7 != '*' && keypressed7 != '#' && keypressed7 != 'A' && keypressed7 != 'B' && keypressed7 != 'C' && keypressed7 != 'D') {
c2 = keypressed7; lcd.setCursor(1, 1); lcd.print(c2);
}
i1 = (c1 - 48) * 10;
i2 = c2 - 48;
int N_month = i1 + i2;
delay(500);
lcd.clear();
lcd.print("Setup Day");
// 일 입력 (2자리)
char keypressed8 = myKeypad.waitForKey();
if (keypressed8 != NO_KEY && keypressed8 != '*' && keypressed8 != '#' && keypressed8 != 'A' && keypressed8 != 'B' && keypressed8 != 'C' && keypressed8 != 'D') {
c1 = keypressed8; lcd.setCursor(0, 1); lcd.print(c1);
}
char keypressed9 = myKeypad.waitForKey();
if (keypressed9 != NO_KEY && keypressed9 != '*' && keypressed9 != '#' && keypressed9 != 'A' && keypressed9 != 'B' && keypressed9 != 'C' && keypressed9 != 'D') {
c2 = keypressed9; lcd.setCursor(1, 1); lcd.print(c2);
}
i1 = (c1 - 48) * 10;
i2 = c2 - 48;
int N_day = i1 + i2;
delay(500);
lcd.clear();
lcd.print("Setup hour");
// 시 입력 (2자리)
char keypressed10 = myKeypad.waitForKey();
if (keypressed10 != NO_KEY && keypressed10 != '*' && keypressed10 != '#' && keypressed10 != 'A' && keypressed10 != 'B' && keypressed10 != 'C' && keypressed10 != 'D') {
c1 = keypressed10; lcd.setCursor(0, 1); lcd.print(c1);
}
char keypressed11 = myKeypad.waitForKey();
if (keypressed11 != NO_KEY && keypressed11 != '*' && keypressed11 != '#' && keypressed11 != 'A' && keypressed11 != 'B' && keypressed11 != 'C' && keypressed11 != 'D') {
c2 = keypressed11; lcd.setCursor(1, 1); lcd.print(c2);
}
i1 = (c1 - 48) * 10;
i2 = c2 - 48;
int N_hour = i1 + i2;
delay(500);
lcd.clear();
lcd.print("Setup minutes");
// 분 입력 (2자리)
char keypressed12 = myKeypad.waitForKey();
if (keypressed12 != NO_KEY && keypressed12 != '*' && keypressed12 != '#' && keypressed12 != 'A' && keypressed12 != 'B' && keypressed12 != 'C' && keypressed12 != 'D') {
c1 = keypressed12; lcd.setCursor(0, 1); lcd.print(c1);
}
char keypressed13 = myKeypad.waitForKey();
if (keypressed13 != NO_KEY && keypressed13 != '*' && keypressed13 != '#' && keypressed13 != 'A' && keypressed13 != 'B' && keypressed13 != 'C' && keypressed13 != 'D') {
c2 = keypressed13; lcd.setCursor(1, 1); lcd.print(c2);
}
i1 = (c1 - 48) * 10;
i2 = c2 - 48;
int N_minutes = i1 + i2;
delay(500);
lcd.clear();
myRTC.setDS1302Time(22, N_minutes, N_hour, 1, N_day, N_month, N_year);
// 22는 초(원하면 설정 추가 가능), 1은 요일(화면에 표시 안 함)
keypressed = NO_KEY;
}
// 알람 설정
if (keypressed == 'A') {
lcd.clear();
lcd.print(" Alarm setup ");
delay(1000);
lcd.clear();
lcd.print("Set alarm hour");
char keypressed14 = myKeypad.waitForKey();
if (keypressed14 != NO_KEY && keypressed14 != '*' && keypressed14 != '#' && keypressed14 != 'A' && keypressed14 != 'B' && keypressed14 != 'C' && keypressed14 != 'D') {
c1 = keypressed14; lcd.setCursor(0, 1); lcd.print(c1);
}
char keypressed15 = myKeypad.waitForKey();
if (keypressed15 != NO_KEY && keypressed15 != '*' && keypressed15 != '#' && keypressed15 != 'A' && keypressed15 != 'B' && keypressed15 != 'C' && keypressed15 != 'D') {
c2 = keypressed15; lcd.setCursor(1, 1); lcd.print(c2);
}
i1 = (c1 - 48) * 10;
i2 = c2 - 48;
A_hour = i1 + i2;
delay(500);
lcd.clear();
lcd.print("Set alarm minutes");
char keypressed16 = myKeypad.waitForKey();
if (keypressed16 != NO_KEY && keypressed16 != '*' && keypressed16 != '#' && keypressed16 != 'A' && keypressed16 != 'B' && keypressed16 != 'C' && keypressed16 != 'D') {
c1 = keypressed16; lcd.setCursor(0, 1); lcd.print(c1);
}
char keypressed17 = myKeypad.waitForKey();
if (keypressed17 != NO_KEY && keypressed17 != '*' && keypressed17 != '#' && keypressed17 != 'A' && keypressed17 != 'B' && keypressed17 != 'C' && keypressed17 != 'D') {
c2 = keypressed17; lcd.setCursor(1, 1); lcd.print(c2);
}
i1 = (c1 - 48) * 10;
i2 = c2 - 48;
A_minute = i1 + i2;
delay(500);
lcd.clear();
AlarmIsActive = 1;
keypressed = NO_KEY;
}
if (keypressed == 'B') {
lcd.clear();
lcd.print("Alarm deactivated");
AlarmIsActive = 0;
keypressed = NO_KEY;
delay(500);
} else {
myRTC.updateTime();
keypressed = NO_KEY;
}
}
회로도