DIY 아두이노 터치스크린 MP3 플레이어 & 알람 시계: 단계별 가이드
개요
이 프로젝트에서는 아두이노 터치스크린 MP3 뮤직 플레이어와 알람 시계 만드는 법을 보여드립니다. 아래 비디오를 시청하거나 작성된 튜토리얼을 읽어보세요.
화면 구성
홈 화면엔 큰 시계, 날짜, 온도 정보, 뮤직 플레이어와 알람 시계 진입 버튼 2개가 있습니다.
뮤직 플레이어 진입 시 화면 중앙 큰 "Play" 버튼으로 음악 재생. 양옆에 이전/다음 곡 버튼.
버튼 위엔 곡 진행 바, 하단엔 볼륨 바와 볼륨 다운/업 버튼. 우상단에 시계, 좌측에 "Menu" 버튼(홈 화면 복귀).
알람 시계 진입 시 시/분 설정용 두 버튼으로 알람 설정.
알람 시간 되면 높은 볼륨으로 곡 재생, "Dismiss" 버튼 누를 때까지 계속 재생.
작동 원리
이 장치 작동 원리입니다. 아두이노 메가 보드와 3.2" TFT 터치스크린, 아두이노 보드와 스크린 연결용 적합한 실드 사용. 음악 재생용 BY8001 MP3 플레이어 모듈, 알람 시계용 DS3231 RTC(실시간 시계) 모듈 사용.
필요한 부품
BY8001-16P MP3 모듈
3.2" TFT 터치 디스플레이
TFT 디스플레이 메가 실드
0.5W 스피커
DS3231 실시간 시계 모듈
아두이노 메가
회로도
TFT 실드가 아두이노 빈 핀을 가려서 실드와 아두이노 사이에 끼울 수 있는 맞춤 핀 헤더 제작 필요.
아두이노 전원 공급용으로 실드 5V 핀에 추가 핀 헤더 납땜 필요(실드가 아두이노 VCC 핀 모두 사용).
모든 연결 완료 후 아두이노 프로그래밍 진행. 하지만 그 전 TFT 터치스크린과 DS3231 RTC 모듈 이전 상세 튜토리얼 확인 권장. MP3 플레이어 모듈은 여기서 간단히 설명.
BY8001-16P MP3 플레이어 모듈
BY8001-16P는 마이크로 SD 카드 작동, MP3/WAV 포맷 지원 MP3 모듈. 내장 3W 파워 앰프로 단일 3W 스피커 직접 구동 가능.
5개 입력 핀으로 버튼 제어 가능, 또는 마이크로컨트롤러로 시리얼 통신 제어 가능.
주의: 모듈 시리얼 포트 핀은 3.3V 동작하므로 모듈 RX 핀을 1K 저항 통해 아두이노 TX 핀에 연결. 제어 모드 선택용 A, B, C 3개 패드: 마이크로컨트롤러 제어용으론 이 패드들 3개 저항 제거 필요. 6, 7번 핀은 저전력 스피커 직접 연결용, 외부 앰프 사용 시 4, 5번 핀.
아두이노 측에선 BY8001 라이브러리(GitHub 에서 다운로드) 사용이 가장 쉽습니다. 데모 예제 열면 작동법 확인 가능. setup에서 모듈 초기화 후 커스텀 함수들로 제어.
소스 코드
이제 아두이노 터치스크린 MP3 뮤직 플레이어와 알람 시계 코드 살펴봅니다. 길어서 섹션별 설명 후 마지막에 전체 코드 제공.
TFT 터치스크린, BY8001-16P MP3 플레이어, DS3231 RTC, 시리얼 통신 라이브러리 포함. 적절한 객체 생성 및 필요 변수 정의.
#include <UTFT.h>
#include <URTouch.h>
#include <SoftwareSerial.h>
#include <BY8001.h>
#include <DS3231.h>
// 객체 생성
UTFT myGLCD(SSD1289, 38, 39, 40, 41); // 디스플레이/실드 모델에 맞게 파라미터 조정
URTouch myTouch(6, 5, 4, 3, 2);
SoftwareSerial mp3Serial(11, 10); // RX, TX
BY8001 mp3; // BY8001 클래스 인스턴스 'mp3'
DS3231 rtc(SDA, SCL);
// 폰트 정의
extern uint8_t SmallFont[];
extern uint8_t BigFont[];
extern uint8_t SevenSegNumFont[];
extern unsigned int MusicPlayerButton[0x1040];
extern unsigned int AlarmButton[0x1040];
extern unsigned int ButtonPlay[0x1AE9];
extern unsigned int ButtonPause[0x1AE9];
extern unsigned int PreviousButton[0x9C4];
extern unsigned int NextButton[0x9C4];
extern unsigned int VolumeDown[0x170];
extern unsigned int VolumeUp[0x3B8];
int x, y; // 터치 좌표
char currentPage, playStatus;
int iV = 15;
int trackNum = 1;
int b = 16;
int aHours = 0;
int aMinutes = 0;
boolean alarmNotSet = true;
String alarmString = "";
float currentTemperature, temperature;
static word totalTime, elapsedTime, playback, minutes, seconds, lastSeconds, minutesR, secondsR;
String currentClock, currentHours, currentMinutes, currentSeconds, currentDate;
String timeString, hoursString, minutesString, secondsString, hoursS, minutesS, secondsS, dateS;
비트맵 정의 부분 주의. 일부 버튼은 이미지를 ImageConverter565 도구(TFT 라이브러리 포함)로 비트맵 변환해 사용.
이 ".c" 파일들을 코드 파일 디렉토리에 포함시켜야 스케치 실행 시 로드됩니다. 이미지와 .c 파일 다운로드
setup에서 객체 초기화 후 drawHomeScreen()으로 홈 화면 그래픽 그리기. playStatus, 현재 온도/날짜, 초기 볼륨 등 변수 초기값 설정.
void setup() {
myGLCD.InitLCD();
myGLCD.clrScr();
myTouch.InitTouch();
myTouch.setPrecision(PREC_MEDIUM);
rtc.begin();
Serial.begin(9600);
mp3Serial.begin(9600); // BY8001 9600 보드레이트 필수
mp3.setup(mp3Serial);
delay(800); // BY8001 콜드 부팅 대기
drawHomeScreen();
currentPage = '0'; // 홈 화면 표시
playStatus = '0';
mp3.setVolume(15);
delay(100);
currentTemperature = rtc.getTemp();
currentDate = rtc.getDateStr();
currentClock = rtc.getTimeStr();
timeString = rtc.getTimeStr();
currentHours = timeString.substring(0, 2);
currentMinutes = timeString.substring(3, 5);
currentSeconds = timeString.substring(6, 8);
}
loop 섹션. currentPage = '0'로 홈 화면. 초 단위 시계 변경 감지. TFT 라이브러리 7세그먼트 폰트는 숫자만 지원하므로 getTimeStr() 문자열에서 substring()으로 시/분/초 추출해 변경 시마다 출력. 날짜와 온도도 이전 상태와 비교해 변경 시 갱신.
void loop() {
// 홈 화면
if (currentPage == '0') {
if (currentClock != rtc.getTimeStr()) {
timeString = rtc.getTimeStr();
hoursS = timeString.substring(0, 2);
minutesS = timeString.substring(3, 5);
secondsS = timeString.substring(6, 8);
myGLCD.setFont(SevenSegNumFont);
myGLCD.setColor(0, 255, 0);
myGLCD.print(secondsS, 224, 50);
if (currentMinutes != minutesS) {
myGLCD.print(minutesS, 128, 50);
currentMinutes = minutesS;
}
if (currentHours != hoursS) {
myGLCD.print(hoursS, 32, 50);
currentHours = hoursS;
}
// 날짜 변경 체크
dateS = rtc.getDateStr();
delay(10);
if (currentDate != dateS) {
myGLCD.setColor(255, 255, 255);
myGLCD.setFont(BigFont);
myGLCD.print(rtc.getDateStr(), 153, 7);
}
// 온도 변경 체크
temperature = rtc.getTemp();
delay(10);
if (currentTemperature != temperature) {
myGLCD.setColor(255, 255, 255);
myGLCD.setFont(BigFont);
myGLCD.printNumI(temperature, 39, 7);
currentTemperature = temperature;
}
delay(10);
currentClock = rtc.getTimeStr();
}
myTouch.dataAvailable()로 터치 감지, 뮤직 플레이어/알람 버튼 터치 확인. 뮤직 플레이어 버튼 터치 시 drawFrame()으로 버튼 눌림 효과(빨간 원) 주고 while 루프로 버튼 떼기 대기. currentPage = '1', 화면 클리어 후 drawMusicPlayerScreen()으로 뮤직 플레이어 화면 그리기. 알람 버튼 유사하게 currentPage = '2'.
if (myTouch.dataAvailable()) {
myTouch.read();
x = myTouch.getX();
y = myTouch.getY();
// 뮤직 플레이어 버튼
if ((x >= 55) && (x <= 120) && (y >= 125) && (y <= 190)) {
drawFrame(87, 157, 33);
currentPage = '1';
myGLCD.clrScr();
delay(100);
drawMusicPlayerScreen();
delay(100);
}
// 알람 버튼
if ((x >= 195) && (x <= 260) && (y >= 125) && (y <= 190)) {
drawFrame(227, 160, 29);
currentPage = '2';
myGLCD.clrScr();
}
}
뮤직 플레이어 화면
터치 지속 감지. Play 버튼 터치 시 playStatus = '0'이면 mp3.playTrackFromFolder()로 SD카드 첫 곡 재생, drawPauseButton()으로 일시정지 버튼 그리기, playStatus = '2'. playStatus에 따라 재생/일시정지 토글.
// 뮤직 플레이어 화면
if (currentPage == '1') {
if (myTouch.dataAvailable()) {
myTouch.read();
x = myTouch.getX();
y = myTouch.getY();
// Play 버튼
if ((x >= 116) && (x <= 204) && (y >= 77) && (y <= 165)) {
if (playStatus == '0') {
drawFrame(159, 121, 42);
drawPauseButton();
mp3.playTrackFromFolder(00, 001);
delay(100);
playStatus = '2';
return;
}
if (playStatus == '1') {
drawFrame(159, 121, 42);
drawPauseButton();
mp3.play();
delay(100);
playStatus = '2';
return;
}
if (playStatus == '2') {
drawFrame(159, 121, 42);
drawPlayButton();
mp3.pause();
delay(100);
playStatus = '1';
return;
}
}
비슷하게 이전/다음 트랙, 볼륨 다운/업, "Menu" 버튼(홈 복귀) 처리.
// Previous 버튼
if ((x >= 45) && (x <= 95) && (y >= 97) && (y <= 147)) {
drawFrame(70, 121, 26);
mp3.previousTrack();
delay(100);
drawTrackBar();
}
// Next 버튼
if ((x >= 227) && (x <= 277) && (y >= 97) && (y <= 147)) {
drawFrame(252, 122, 26);
mp3.nextTrack();
delay(100);
drawTrackBar();
}
// VolumeDown 버튼
if ((x >= 35) && (x <= 75) && (y >= 165) && (y <= 209)) {
drawUnderline(45, 205, 65, 205);
if (iV >= 0 && iV <= 30) { iV--; drawVolume(iV); }
mp3.decreaseVolume();
delay(100);
}
// VolumeUp 버튼
if ((x >= 230) && (x <= 280) && (y >= 165) && (y <= 209)) {
drawUnderline(235, 205, 275, 205);
if (iV >= 0 && iV <= 30) { iV++; drawVolume(iV); }
mp3.increaseVolume();
delay(100);
}
// MENU 버튼
if ((x >= 0) && (x <= 75) && (y >= 0) && (y <= 30)) {
myGLCD.clrScr();
drawHomeScreen();
currentPage = '0';
return;
}
}
// 트랙 진행 바 업데이트
if (playStatus == '1' || playStatus == '2') {
trackPlayTime();
}
// 우상단 시계 출력
myGLCD.setFont(BigFont);
myGLCD.setColor(255, 255, 255);
printClock(187, 5);
}
trackPlayTime(): mp3.getElapsedTrackPlaybackTime() 등 라이브러리 함수로 경과/남은 시간 계산, 트랙 진행 바 그래픽 출력. printClock()으로 우상단 시계 출력.
void trackPlayTime() {
totalTime = mp3.getTotalTrackPlaybackTime();
delay(10);
elapsedTime = mp3.getElapsedTrackPlaybackTime();
delay(10);
minutes = (int)elapsedTime / 60;
seconds = (((float)elapsedTime / 60) - minutes) * 60;
playback = totalTime - elapsedTime;
minutesR = (int)playback / 60;
secondsR = (((float)playback / 60) - minutesR) * 60;
myGLCD.setFont(SmallFont);
myGLCD.setColor(255, 255, 255);
myGLCD.printNumI(minutes, 8, 48);
myGLCD.print(":", 16, 48);
myGLCD.printNumI((int)seconds, 24, 48, 2, '0');
myGLCD.print("-", 276, 48);
myGLCD.printNumI(minutesR, 284, 48);
myGLCD.print(":", 292, 48);
myGLCD.printNumI((int)secondsR, 300, 48, 2, '0');
int trackBarX = map(elapsedTime, 0, totalTime, 0, 224);
myGLCD.setColor(255, 0, 0);
myGLCD.fillRect(48, 50, 48 + trackBarX, 50 + 8);
if (totalTime == elapsedTime) {
mp3.nextTrack();
delay(30);
myGLCD.setColor(255, 255, 255);
myGLCD.fillRect(48, 50, 48 + 224, 50 + 8);
}
}
알람 시계 화면
그래픽, 시계, 텍스트, 버튼 그리기, alarmNotSet = true로 while 루프 진입. H/M 버튼으로 알람 설정, "Set" 버튼 클릭 시 alarmString 변수에 값 저장.
// 알람 시계 화면
if (currentPage == '2') {
myGLCD.setFont(BigFont);
myGLCD.setColor(255, 255, 255);
myGLCD.print("MENU", 5, 5);
myGLCD.print("Set Alarm", CENTER, 20);
// 시/분 사이 콜론 그리기
myGLCD.setColor(0, 255, 0);
myGLCD.fillCircle(112, 65, 4);
myGLCD.fillCircle(112, 85, 4);
myGLCD.setFont(SevenSegNumFont);
myGLCD.setColor(0, 255, 0);
myGLCD.printNumI(aHours, 32, 50, 2, '0');
myGLCD.printNumI(aMinutes, 128, 50, 2, '0');
myGLCD.setColor(255, 255, 255);
myGLCD.drawRoundRect(42, 115, 82, 145);
myGLCD.drawRoundRect(138, 115, 178, 145);
myGLCD.setFont(BigFont);
myGLCD.print("H", 54, 122);
myGLCD.print("M", 150, 122);
myGLCD.drawRoundRect(215, 60, 303, 90);
myGLCD.print("SET", 236, 67);
myGLCD.drawRoundRect(215, 115, 303, 145);
myGLCD.print("CLEAR", 220, 122);
alarmNotSet = true;
while (alarmNotSet) {
if (myTouch.dataAvailable()) {
myTouch.read();
x = myTouch.getX();
y = myTouch.getY();
// 시 설정 버튼
if ((x >= 42) && (x <= 82) && (y >= 115) && (y <= 145)) {
drawRectFrame(42, 115, 82, 145);
aHours++;
if (aHours >= 24) aHours = 0;
myGLCD.setFont(SevenSegNumFont);
myGLCD.setColor(0, 255, 0);
myGLCD.printNumI(aHours, 32, 50, 2, '0');
}
// 분 설정 버튼
if ((x >= 138) && (x <= 178) && (y >= 115) && (y <= 145)) {
drawRectFrame(138, 115, 178, 145);
aMinutes++;
if (aMinutes >= 60) aMinutes = 0;
myGLCD.setFont(SevenSegNumFont);
myGLCD.setColor(0, 255, 0);
myGLCD.printNumI(aMinutes, 128, 50, 2, '0');
}
// 알람 설정 버튼
if ((x >= 215) && (x <= 303) && (y >= 60) && (y <= 80)) {
drawRectFrame(215, 60, 303, 90);
if (aHours < 10 && aMinutes < 10) {
alarmString = "0" + (String)aHours + ":" + "0" + (String)aMinutes + ":00";
} else if (aHours < 10 && aMinutes > 9) {
alarmString = "0" + (String)aHours + ":" + (String)aMinutes + ":00";
} else if (aHours > 9 && aMinutes < 10) {
alarmString = (String)aHours + ":" + "0" + (String)aMinutes + ":00";
} else {
alarmString = (String)aHours + ":" + (String)aMinutes + ":00";
}
myGLCD.setFont(BigFont);
myGLCD.print("Alarm set for:", CENTER, 165);
myGLCD.print(alarmString, CENTER, 191);
}
// 알람 클리어 버튼
if ((x >= 215) && (x <= 303) && (y >= 115) && (y <= 145)) {
drawRectFrame(215, 115, 303, 145);
alarmString = "";
myGLCD.setColor(0, 0, 0);
myGLCD.fillRect(45, 165, 275, 210);
}
// MENU 버튼
if ((x >= 0) && (x <= 75) && (y >= 0) && (y <= 30)) {
alarmNotSet = false;
currentPage = '0';
myGLCD.clrScr();
drawHomeScreen();
}
}
}
}
alarmString 형식을 getTimeStr() 반환 문자열과 동일하게 맞춰 비교 가능하게 함.
Clear 버튼으로 alarmString 초기화, Menu 버튼으로 while 루프 탈출해 홈 화면 복귀.
알람 활성화: 알람 설정됐고 알람 시간이 현재 시간과 일치하면 SD카드 첫 곡을 높은 볼륨으로 재생. "Dismiss" 버튼 등 그래픽 그리기, alarmOn = true로 while 루프 진입해 Dismiss 버튼 누를 때까지 재생 지속.
// 알람 활성화
if (alarmNotSet == false) {
if (alarmString == rtc.getTimeStr()) {
myGLCD.clrScr();
mp3.setVolume(25);
mp3.playTrackByIndexNumber(1);
delay(100);
myGLCD.setFont(BigFont);
myGLCD.setColor(255, 255, 255);
myGLCD.print("ALARM", CENTER, 90);
myGLCD.drawBitmap(127, 10, 65, 64, AlarmButton);
myGLCD.print(alarmString, CENTER, 114);
myGLCD.drawRoundRect(94, 146, 226, 170);
myGLCD.print("DISMISS", CENTER, 150);
boolean alarmOn = true;
while (alarmOn) {
if (myTouch.dataAvailable()) {
myTouch.read();
x = myTouch.getX();
y = myTouch.getY();
// 알람 정지 버튼
if ((x >= 94) && (x <= 226) && (y >= 146) && (y <= 170)) {
drawRectFrame(94, 146, 226, 170);
alarmOn = false;
alarmString = "";
myGLCD.clrScr();
mp3.stopPlayback();
delay(100);
currentPage = '0';
playStatus = '0';
mp3.setVolume(15);
drawHomeScreen();
}
}
}
}
}
}
이게 코드 작동 방식이며, 전체 소스 코드는 기사 하단에 있습니다.
장치 제작
SolidWorks로 설계, 모습입니다.
이 모델 다운로드해 치수 확인
알루미늄 판금 사용, 멀티 툴로 크기 재단. 책상 모서리와 클램프, 각재로 판금 벤딩.
스피커용 원형 패턴 프린트해 부착, 드릴로 모든 구멍 뚫기.
측면 적절히 재단 후 글루건으로 앞서 벤딩한 판금에 고정.
판금 박스 도색 후 전자부품 장착 준비 완료. 글루건으로 모든 부품 고정, 배선 연결, 백 리드 볼트 2개로 고정.
이상으로 마칩니다. 질문은 댓글로 남겨주세요.
장치 전체 소스 코드:
/*
* Arduino Touch Screen MP3 Music Player and Alarm Clock
* Created by Dejan Nedelkovski, www.HowToMechatronics.com
* UFTF, URTouch and DS3231 libraries by Henning Karlsen (www.rinkydinkelectronics.com)
* BY8001 MP3 Player Library by borland (Arduino forum), Public domain. Download: https://github.com/r0ndL/BY8001
*/
#include <UTFT.h>
#include <URTouch.h>
#include <SoftwareSerial.h>
#include <BY8001.h>
#include <DS3231.h>
// 객체 생성
UTFT myGLCD(SSD1289, 38, 39, 40, 41);
URTouch myTouch(6, 5, 4, 3, 2);
SoftwareSerial mp3Serial(11, 10);
BY8001 mp3;
DS3231 rtc(SDA, SCL);
// 폰트 및 비트맵 정의
extern uint8_t SmallFont[];
extern uint8_t BigFont[];
extern uint8_t SevenSegNumFont[];
extern unsigned int MusicPlayerButton[0x1040];
extern unsigned int AlarmButton[0x1040];
extern unsigned int ButtonPlay[0x1AE9];
extern unsigned int ButtonPause[0x1AE9];
extern unsigned int PreviousButton[0x9C4];
extern unsigned int NextButton[0x9C4];
extern unsigned int VolumeDown[0x170];
extern unsigned int VolumeUp[0x3B8];
int x, y;
char currentPage, playStatus;
int iV = 15;
int trackNum = 1;
int b = 16;
int aHours = 0;
int aMinutes = 0;
boolean alarmNotSet = true;
String alarmString = "";
float currentTemperature, temperature;
static word totalTime, elapsedTime, playback, minutes, seconds, lastSeconds, minutesR, secondsR;
String currentClock, currentHours, currentMinutes, currentSeconds, currentDate;
String timeString, hoursString, minutesString, secondsString, hoursS, minutesS, secondsS, dateS;
void setup() {
myGLCD.InitLCD();
myGLCD.clrScr();
myTouch.InitTouch();
myTouch.setPrecision(PREC_MEDIUM);
rtc.begin();
Serial.begin(9600);
mp3Serial.begin(9600);
mp3.setup(mp3Serial);
delay(800);
drawHomeScreen();
currentPage = '0';
playStatus = '0';
mp3.setVolume(15);
delay(100);
currentTemperature = rtc.getTemp();
currentDate = rtc.getDateStr();
currentClock = rtc.getTimeStr();
timeString = rtc.getTimeStr();
currentHours = timeString.substring(0, 2);
currentMinutes = timeString.substring(3, 5);
currentSeconds = timeString.substring(6, 8);
}
void loop() {
// 홈 화면
if (currentPage == '0') {
if (currentClock != rtc.getTimeStr()) {
timeString = rtc.getTimeStr();
hoursS = timeString.substring(0, 2);
minutesS = timeString.substring(3, 5);
secondsS = timeString.substring(6, 8);
myGLCD.setFont(SevenSegNumFont);
myGLCD.setColor(0, 255, 0);
myGLCD.print(secondsS, 224, 50);
if (currentMinutes != minutesS) {
myGLCD.print(minutesS, 128, 50);
currentMinutes = minutesS;
}
if (currentHours != hoursS) {
myGLCD.print(hoursS, 32, 50);
currentHours = hoursS;
}
dateS = rtc.getDateStr();
delay(10);
if (currentDate != dateS) {
myGLCD.setColor(255, 255, 255);
myGLCD.setFont(BigFont);
myGLCD.print(rtc.getDateStr(), 153, 7);
}
temperature = rtc.getTemp();
delay(10);
if (currentTemperature != temperature) {
myGLCD.setColor(255, 255, 255);
myGLCD.setFont(BigFont);
myGLCD.printNumI(temperature, 39, 7);
currentTemperature = temperature;
}
delay(10);
currentClock = rtc.getTimeStr();
}
if (myTouch.dataAvailable()) {
myTouch.read();
x = myTouch.getX();
y = myTouch.getY();
if ((x >= 55) && (x <= 120) && (y >= 125) && (y <= 190)) {
drawFrame(87, 157, 33);
currentPage = '1';
myGLCD.clrScr();
delay(100);
drawMusicPlayerScreen();
delay(100);
}
if ((x >= 195) && (x <= 260) && (y >= 125) && (y <= 190)) {
drawFrame(227, 160, 29);
currentPage = '2';
myGLCD.clrScr();
}
}
}
// 뮤직 플레이어 화면
if (currentPage == '1') {
if (myTouch.dataAvailable()) {
myTouch.read();
x = myTouch.getX();
y = myTouch.getY();
if ((x >= 116) && (x <= 204) && (y >= 77) && (y <= 165)) {
if (playStatus == '0') {
drawFrame(159, 121, 42);
drawPauseButton();
mp3.playTrackFromFolder(00, 001);
delay(100);
playStatus = '2';
return;
}
if (playStatus == '1') {
drawFrame(159, 121, 42);
drawPauseButton();
mp3.play();
delay(100);
playStatus = '2';
return;
}
if (playStatus == '2') {
drawFrame(159, 121, 42);
drawPlayButton();
mp3.pause();
delay(100);
playStatus = '1';
return;
}
}
if ((x >= 45) && (x <= 95) && (y >= 97) && (y <= 147)) {
drawFrame(70, 121, 26);
mp3.previousTrack();
delay(100);
drawTrackBar();
}
if ((x >= 227) && (x <= 277) && (y >= 97) && (y <= 147)) {
drawFrame(252, 122, 26);
mp3.nextTrack();
delay(100);
drawTrackBar();
}
if ((x >= 35) && (x <= 75) && (y >= 165) && (y <= 209)) {
drawUnderline(45, 205, 65, 205);
if (iV >= 0 && iV <= 30) { iV--; drawVolume(iV); }
mp3.decreaseVolume();
delay(100);
}
if ((x >= 230) && (x <= 280) && (y >= 165) && (y <= 209)) {
drawUnderline(235, 205, 275, 205);
if (iV >= 0 && iV <= 30) { iV++; drawVolume(iV); }
mp3.increaseVolume();
delay(100);
}
if ((x >= 0) && (x <= 75) && (y >= 0) && (y <= 30)) {
myGLCD.clrScr();
drawHomeScreen();
currentPage = '0';
return;
}
}
if (playStatus == '1' || playStatus == '2') {
trackPlayTime();
}
myGLCD.setFont(BigFont);
myGLCD.setColor(255, 255, 255);
printClock(187, 5);
}
// 알람 시계 화면
if (currentPage == '2') {
myGLCD.setFont(BigFont);
myGLCD.setColor(255, 255, 255);
myGLCD.print("MENU", 5, 5);
myGLCD.print("Set Alarm", CENTER, 20);
myGLCD.setColor(0, 255, 0);
myGLCD.fillCircle(112, 65, 4);
myGLCD.fillCircle(112, 85, 4);
myGLCD.setFont(SevenSegNumFont);
myGLCD.setColor(0, 255, 0);
myGLCD.printNumI(aHours, 32, 50, 2, '0');
myGLCD.printNumI(aMinutes, 128, 50, 2, '0');
myGLCD.setColor(255, 255, 255);
myGLCD.drawRoundRect(42, 115, 82, 145);
myGLCD.drawRoundRect(138, 115, 178, 145);
myGLCD.setFont(BigFont);
myGLCD.print("H", 54, 122);
myGLCD.print("M", 150, 122);
myGLCD.drawRoundRect(215, 60, 303, 90);
myGLCD.print("SET", 236, 67);
myGLCD.drawRoundRect(215, 115, 303, 145);
myGLCD.print("CLEAR", 220, 122);
alarmNotSet = true;
while (alarmNotSet) {
if (myTouch.dataAvailable()) {
myTouch.read();
x = myTouch.getX();
y = myTouch.getY();
if ((x >= 42) && (x <= 82) && (y >= 115) && (y <= 145)) {
drawRectFrame(42, 115, 82, 145);
aHours++;
if (aHours >= 24) aHours = 0;
myGLCD.setFont(SevenSegNumFont);
myGLCD.setColor(0, 255, 0);
myGLCD.printNumI(aHours, 32, 50, 2, '0');
}
if ((x >= 138) && (x <= 178) && (y >= 115) && (y <= 145)) {
drawRectFrame(138, 115, 178, 145);
aMinutes++;
if (aMinutes >= 60) aMinutes = 0;
myGLCD.setFont(SevenSegNumFont);
myGLCD.setColor(0, 255, 0);
myGLCD.printNumI(aMinutes, 128, 50, 2, '0');
}
if ((x >= 215) && (x <= 303) && (y >= 60) && (y <= 80)) {
drawRectFrame(215, 60, 303, 90);
if (aHours < 10 && aMinutes < 10) {
alarmString = "0" + (String)aHours + ":" + "0" + (String)aMinutes + ":00";
} else if (aHours < 10 && aMinutes > 9) {
alarmString = "0" + (String)aHours + ":" + (String)aMinutes + ":00";
} else if (aHours > 9 && aMinutes < 10) {
alarmString = (String)aHours + ":" + "0" + (String)aMinutes + ":00";
} else {
alarmString = (String)aHours + ":" + (String)aMinutes + ":00";
}
myGLCD.setFont(BigFont);
myGLCD.print("Alarm set for:", CENTER, 165);
myGLCD.print(alarmString, CENTER, 191);
}
if ((x >= 215) && (x <= 303) && (y >= 115) && (y <= 145)) {
drawRectFrame(215, 115, 303, 145);
alarmString = "";
myGLCD.setColor(0, 0, 0);
myGLCD.fillRect(45, 165, 275, 210);
}
if ((x >= 0) && (x <= 75) && (y >= 0) && (y <= 30)) {
alarmNotSet = false;
currentPage = '0';
myGLCD.clrScr();
drawHomeScreen();
}
}
}
}
// 알람 활성화
if (alarmNotSet == false) {
if (alarmString == rtc.getTimeStr()) {
myGLCD.clrScr();
mp3.setVolume(25);
mp3.playTrackByIndexNumber(1);
delay(100);
myGLCD.setFont(BigFont);
myGLCD.setColor(255, 255, 255);
myGLCD.print("ALARM", CENTER, 90);
myGLCD.drawBitmap(127, 10, 65, 64, AlarmButton);
myGLCD.print(alarmString, CENTER, 114);
myGLCD.drawRoundRect(94, 146, 226, 170);
myGLCD.print("DISMISS", CENTER, 150);
boolean alarmOn = true;
while (alarmOn) {
if (myTouch.dataAvailable()) {
myTouch.read();
x = myTouch.getX();
y = myTouch.getY();
if ((x >= 94) && (x <= 226) && (y >= 146) && (y <= 170)) {
drawRectFrame(94, 146, 226, 170);
alarmOn = false;
alarmString = "";
myGLCD.clrScr();
mp3.stopPlayback();
delay(100);
currentPage = '0';
playStatus = '0';
mp3.setVolume(15);
drawHomeScreen();
}
}
}
}
}
}
// 각종 그리기 함수들
void drawHomeScreen() {
myGLCD.setBackColor(0, 0, 0);
myGLCD.setColor(255, 255, 255);
myGLCD.setFont(BigFont);
myGLCD.print(rtc.getDateStr(), 153, 7);
myGLCD.print("T:", 7, 7);
myGLCD.printNumI(rtc.getTemp(), 39, 7);
myGLCD.print("C", 82, 7);
myGLCD.setFont(SmallFont);
myGLCD.print("o", 74, 5);
if (alarmString == "") {
myGLCD.setColor(255, 255, 255);
myGLCD.print("by www.HowToMechatronics.com", CENTER, 215);
} else {
myGLCD.setColor(255, 255, 255);
myGLCD.print("Alarm set for: ", 68, 215);
myGLCD.print(alarmString, 188, 215);
}
drawMusicPlayerButton();
drawAlarmButton();
drawHomeClock();
}
void drawMusicPlayerScreen() {
myGLCD.setBackColor(0, 0, 0);
myGLCD.setColor(255, 255, 255);
myGLCD.setFont(BigFont);
myGLCD.print("MENU", 5, 5);
myGLCD.setColor(255, 0, 0);
myGLCD.drawLine(0, 26, 319, 26);
myGLCD.setColor(255, 255, 255);
myGLCD.setFont(SmallFont);
myGLCD.print("by www.HowToMechatronics.com", CENTER, 215);
myGLCD.setColor(255, 255, 255);
myGLCD.fillRect(78, 184, 78 + 150, 184 + 8);
myGLCD.setColor(240, 196, 30);
myGLCD.fillRect(78, 184, 78 + 75, 184 + 8);
myGLCD.setColor(255, 255, 255);
myGLCD.fillRect(48, 50, 48 + 224, 50 + 8);
myGLCD.setFont(SmallFont);
myGLCD.setColor(255, 255, 255);
myGLCD.print("0:00", 8, 48);
myGLCD.print("-0:00", 276, 48);
drawPlayButton();
if (playStatus == '2') { drawPauseButton(); }
drawPreviousButton();
drawNextButton();
drawVolumeDown();
drawVolumeUp();
}
void drawMusicPlayerButton() { myGLCD.drawBitmap(55, 125, 65, 64, MusicPlayerButton); }
void drawAlarmButton() { myGLCD.drawBitmap(195, 125, 65, 64, AlarmButton); }
void drawPlayButton() { myGLCD.drawBitmap(118, 79, 83, 83, ButtonPlay); }
void drawPauseButton() { myGLCD.drawBitmap(118, 79, 83, 83, ButtonPause); }
void drawNextButton() { myGLCD.drawBitmap(227, 97, 50, 50, NextButton); }
void drawPreviousButton() { myGLCD.drawBitmap(45, 97, 50, 50, PreviousButton); }
void drawVolumeDown() { myGLCD.drawBitmap(50, 177, 16, 23, VolumeDown); }
void drawVolumeUp() { myGLCD.drawBitmap(241, 175, 34, 28, VolumeUp); }
bool checkFor_mp3IsStopped() {
if (mp3Serial.available() > 0) {
if (mp3.getPlaybackStatus() == 0) { return true; }
}
return false;
}
void drawFrame(int x, int y, int r) {
myGLCD.setColor(255, 0, 0);
myGLCD.drawCircle(x, y, r);
while (myTouch.dataAvailable()) myTouch.read();
myGLCD.setColor(0, 0, 0);
myGLCD.drawCircle(x, y, r);
}
void drawRectFrame(int x1, int y1, int x2, int y2) {
myGLCD.setColor(255, 0, 0);
myGLCD.drawRoundRect(x1, y1, x2, y2);
while (myTouch.dataAvailable()) myTouch.read();
myGLCD.setColor(255, 255, 255);
myGLCD.drawRoundRect(x1, y1, x2, y2);
}
void drawUnderline(int x1, int y1, int x2, int y2) {
myGLCD.setColor(255, 0, 0);
myGLCD.drawLine(x1, y1, x2, y2);
while (myTouch.dataAvailable()) myTouch.read();
myGLCD.setColor(0, 0, 0);
myGLCD.drawLine(x1, y1, x2, y2);
}
void drawVolume(int x) {
myGLCD.setColor(255, 255, 255);
myGLCD.fillRect(78 + 5 * x, 184, 78 + 150, 184 + 8);
myGLCD.setColor(240, 196, 30);
myGLCD.fillRect(78, 184, 78 + 5 * x, 184 + 8);
}
void drawTrackBar() {
myGLCD.setColor(255, 255, 255);
myGLCD.fillRect(48, 50, 48 + 224, 50 + 8);
}
void trackPlayTime() {
totalTime = mp3.getTotalTrackPlaybackTime();
delay(10);
elapsedTime = mp3.getElapsedTrackPlaybackTime();
delay(10);
minutes = (int)elapsedTime / 60;
seconds = (((float)elapsedTime / 60) - minutes) * 60;
playback = totalTime - elapsedTime;
minutesR = (int)playback / 60;
secondsR = (((float)playback / 60) - minutesR) * 60;
myGLCD.setFont(SmallFont);
myGLCD.setColor(255, 255, 255);
myGLCD.printNumI(minutes, 8, 48);
myGLCD.print(":", 16, 48);
myGLCD.printNumI((int)seconds, 24, 48, 2, '0');
myGLCD.print("-", 276, 48);
myGLCD.printNumI(minutesR, 284, 48);
myGLCD.print(":", 292, 48);
myGLCD.printNumI((int)secondsR, 300, 48, 2, '0');
int trackBarX = map(elapsedTime, 0, totalTime, 0, 224);
myGLCD.setColor(255, 0, 0);
myGLCD.fillRect(48, 50, 48 + trackBarX, 50 + 8);
if (totalTime == elapsedTime) {
mp3.nextTrack();
delay(30);
myGLCD.setColor(255, 255, 255);
myGLCD.fillRect(48, 50, 48 + 224, 50 + 8);
}
}
void printClock(int x, int y) {
if (currentClock != rtc.getTimeStr()) {
myGLCD.print(rtc.getTimeStr(), x, y);
currentClock = rtc.getTimeStr();
}
}
void drawColon() {
myGLCD.setColor(0, 255, 0);
myGLCD.fillCircle(112, 65, 4);
myGLCD.fillCircle(112, 85, 4);
myGLCD.fillCircle(208, 65, 4);
myGLCD.fillCircle(208, 85, 4);
}
void drawHomeClock() {
timeString = rtc.getTimeStr();
currentHours = timeString.substring(0, 2);
currentMinutes = timeString.substring(3, 5);
currentSeconds = timeString.substring(6, 8);
myGLCD.setFont(SevenSegNumFont);
myGLCD.setColor(0, 255, 0);
myGLCD.print(currentSeconds, 224, 50);
myGLCD.print(currentMinutes, 128, 50);
myGLCD.print(currentHours, 32, 50);
drawColon();
}
질문은 댓글로 남겨주시고, 제 아두이노 프로젝트 모음도 확인해보세요.