산업 제조
산업용 사물 인터넷 | 산업자재 | 장비 유지 보수 및 수리 | 산업 프로그래밍 |
home  MfgRobots >> 산업 제조 >  >> Manufacturing Technology >> 제조공정

DIY 아두이노 터치스크린 MP3 플레이어 & 알람 시계: 단계별 가이드

개요

이 프로젝트에서는 아두이노 터치스크린 MP3 뮤직 플레이어와 알람 시계 만드는 법을 보여드립니다. 아래 비디오를 시청하거나 작성된 튜토리얼을 읽어보세요.

화면 구성

홈 화면엔 큰 시계, 날짜, 온도 정보, 뮤직 플레이어와 알람 시계 진입 버튼 2개가 있습니다.

DIY 아두이노 터치스크린 MP3 플레이어 & 알람 시계: 단계별 가이드

뮤직 플레이어 진입 시 화면 중앙 큰 "Play" 버튼으로 음악 재생. 양옆에 이전/다음 곡 버튼.

DIY 아두이노 터치스크린 MP3 플레이어 & 알람 시계: 단계별 가이드

버튼 위엔 곡 진행 바, 하단엔 볼륨 바와 볼륨 다운/업 버튼. 우상단에 시계, 좌측에 "Menu" 버튼(홈 화면 복귀).

알람 시계 진입 시 시/분 설정용 두 버튼으로 알람 설정.

DIY 아두이노 터치스크린 MP3 플레이어 & 알람 시계: 단계별 가이드

알람 시간 되면 높은 볼륨으로 곡 재생, "Dismiss" 버튼 누를 때까지 계속 재생.

DIY 아두이노 터치스크린 MP3 플레이어 & 알람 시계: 단계별 가이드

작동 원리

이 장치 작동 원리입니다. 아두이노 메가 보드와 3.2" TFT 터치스크린, 아두이노 보드와 스크린 연결용 적합한 실드 사용. 음악 재생용 BY8001 MP3 플레이어 모듈, 알람 시계용 DS3231 RTC(실시간 시계) 모듈 사용.

DIY 아두이노 터치스크린 MP3 플레이어 & 알람 시계: 단계별 가이드

필요한 부품

회로도

DIY 아두이노 터치스크린 MP3 플레이어 & 알람 시계: 단계별 가이드

TFT 실드가 아두이노 빈 핀을 가려서 실드와 아두이노 사이에 끼울 수 있는 맞춤 핀 헤더 제작 필요.

DIY 아두이노 터치스크린 MP3 플레이어 & 알람 시계: 단계별 가이드

아두이노 전원 공급용으로 실드 5V 핀에 추가 핀 헤더 납땜 필요(실드가 아두이노 VCC 핀 모두 사용).

모든 연결 완료 후 아두이노 프로그래밍 진행. 하지만 그 전 TFT 터치스크린과 DS3231 RTC 모듈 이전 상세 튜토리얼 확인 권장. MP3 플레이어 모듈은 여기서 간단히 설명.

BY8001-16P MP3 플레이어 모듈

BY8001-16P는 마이크로 SD 카드 작동, MP3/WAV 포맷 지원 MP3 모듈. 내장 3W 파워 앰프로 단일 3W 스피커 직접 구동 가능.

DIY 아두이노 터치스크린 MP3 플레이어 & 알람 시계: 단계별 가이드

5개 입력 핀으로 버튼 제어 가능, 또는 마이크로컨트롤러로 시리얼 통신 제어 가능.

DIY 아두이노 터치스크린 MP3 플레이어 & 알람 시계: 단계별 가이드

주의: 모듈 시리얼 포트 핀은 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 라이브러리 포함)로 비트맵 변환해 사용.

DIY 아두이노 터치스크린 MP3 플레이어 & 알람 시계: 단계별 가이드

이 ".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() 반환 문자열과 동일하게 맞춰 비교 가능하게 함.

DIY 아두이노 터치스크린 MP3 플레이어 & 알람 시계: 단계별 가이드

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로 설계, 모습입니다.

DIY 아두이노 터치스크린 MP3 플레이어 & 알람 시계: 단계별 가이드

이 모델 다운로드해 치수 확인

알루미늄 판금 사용, 멀티 툴로 크기 재단. 책상 모서리와 클램프, 각재로 판금 벤딩.

DIY 아두이노 터치스크린 MP3 플레이어 & 알람 시계: 단계별 가이드

스피커용 원형 패턴 프린트해 부착, 드릴로 모든 구멍 뚫기.

DIY 아두이노 터치스크린 MP3 플레이어 & 알람 시계: 단계별 가이드

측면 적절히 재단 후 글루건으로 앞서 벤딩한 판금에 고정.

판금 박스 도색 후 전자부품 장착 준비 완료. 글루건으로 모든 부품 고정, 배선 연결, 백 리드 볼트 2개로 고정.

DIY 아두이노 터치스크린 MP3 플레이어 & 알람 시계: 단계별 가이드

이상으로 마칩니다. 질문은 댓글로 남겨주세요.

장치 전체 소스 코드:

/*
 * 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();
}

질문은 댓글로 남겨주시고, 제 아두이노 프로젝트 모음도 확인해보세요.

제조공정

  1. 아두이노 POV 클락: 퍼시스턴스 오브 비전 LED 디스플레이 제작
  2. 아두이노로 만드는 대형 LED 마스터 시계 (알람 기능 포함, 12m 거리에서도 식별 가능)
  3. 아두이노 듀(Due) + 3.2″ TFT로 만드는 실시간 시계 & 온도 모니터
  4. 아두이노 우노와 DFPlayer Mini로 오디오 재생하기 - 단계별 가이드
  5. TM1637 4자리 디지털 시계: 시간/알람 설정 기능 탑재 (아두이노 나노)
  6. 아두이노 웹 제어 MP3 플레이어 - 브라우저로 오디오 재생하기
  7. 아두이노 틱택토 게임 - MAX7219 LED 매트릭스와 골판지 케이스
  8. 아두이노와 노키아 5110 LCD로 만드는 DIY 전압계 - 단계별 가이드
  9. 스파크펀 7-세그먼트 디스플레이로 신뢰할 수 있는 아두이노 카운트다운 타이머 만들기
  10. DS1302 RTC와 아두이노 우노로 만드는 신뢰할 수 있는 알람 시계