- 시간 설정 기능
- 타이머 시작, 리셋 기능
- 타이머 초와 네오픽셀 연동
- 타이머 종료 시 음악 재생
왼쪽 : dec 오른쪽 INC 가운데 RED RESET 가운데 WHITE 시작
#include <Adafruit_NeoPixel.h> | |
#include <TM1637Display.h> | |
#include <ThreeWire.h> | |
#include <RtcDS1302.h> | |
#include <RtcDateTime.h> | |
#include <math.h> | |
#define NEOPIXEL_PIN 11 | |
#define NEOPIXLE_PIXELCOUNT 60 | |
#define SPEAKER_PIN 12 | |
#define SEVENSEGMENT_CLK 10 | |
#define SEVENSEGMENT_DIO 9 | |
#define START_PIN 7 | |
#define RESET_PIN 8 | |
#define INC_PIN 6 | |
#define DEC_PIN 5 | |
#define RTC_CLK 2 | |
#define RTC_DAT 3 | |
#define RTC_RST 4 | |
// utils | |
bool is_clicked(int button) { | |
return digitalRead(button) == HIGH; | |
} | |
// music module | |
int Do_1 = 32; int Do_2 = 65; int Do_3 = 130; int Do_4 = 261; int Do_5 = 523; int Do_6 = 1046; | |
int DoS_1 = 34; int DoS_2 = 69; int DoS_3 = 138; int DoS_4 = 277; int DoS_5 = 554; int DoS_6 = 1108; | |
int Re_1 = 36; int Re_2 = 73; int Re_3 = 146; int Re_4 = 293; int Re_5 = 587; int Re_6 = 1174; | |
int MiF_1 = 38; int MiF_2 = 77; int MiF_3 = 155; int MiF_4 = 311; int MiF_5 = 622; int MiF_6 = 1244; | |
int Mi_1 = 41; int Mi_2 = 82; int Mi_3 = 164; int Mi_4 = 329; int Mi_5 = 659; int Mi_6 = 1318; | |
int Fa_1 = 43; int Fa_2 = 87; int Fa_3 = 174; int Fa_4 = 349; int Fa_5 = 698; int Fa_6 = 1396; | |
int FaS_1 = 46; int FaS_2 = 92; int FaS_3 = 184; int FaS_4 = 369; int FaS_5 = 739; int FaS_6 = 1479; | |
int Sol_1 = 48; int Sol_2 = 97; int Sol_3 = 195; int Sol_4 = 391; int Sol_5 = 783; int Sol_6 = 1567; | |
int LaF_1 = 51; int LaF_2 = 103; int LaF_3 = 207; int LaF_4 = 415; int LaF_5 = 830; int LaF_6 = 1661; | |
int La_1 = 55; int La_2 = 110; int La_3 = 220; int La_4 = 440; int La_5 = 880; int La_6 = 1760; | |
int SiF_1 = 58; int SiF_2 = 116; int SiF_3 = 233; int SiF_4 = 466; int SiF_5 = 932; int SiF_6 = 1864; | |
int Si_1 = 61; int Si_2 = 123; int Si_3 = 246; int Si_4 = 493; int Si_5 = 987; int Si_6 = 1975; | |
int Melody[] = { | |
La_4, Fa_5, Re_5, Re_5, DoS_5, 0, | |
La_4, Fa_5, Re_5, Re_5, DoS_5, 0, | |
Re_4, 0, Mi_4, 0, Fa_4, 0, Sol_4, 0, | |
La_4, 0, Si_4, 0, Do_5, 0, Re_5, 0, | |
MiF_5, Mi_5, Fa_5, FaS_5, | |
Sol_5, LaF_5, La_5, DoS_5, 0, | |
La_4, SiF_4, La_4, Fa_5, Re_5, | |
DoS_5, DoS_5, Mi_5, Mi_5, Re_5, | |
MiF_5, Sol_5, MiF_5, MiF_5, Re_5, | |
Re_5, Re_5, Fa_5, Mi_5, Mi_5, Re_5, SiF_4, LaF_4, | |
Re_5, Sol_5, Fa_5, Fa_5, Si_4, SiF_4, | |
Mi_5, La_4, Sol_4, Sol_4, Fa_4, | |
Si_4, Do_4, Re_4, Re_4, | |
Re_5, Do_5, Si_4, Si_4, | |
Si_4, Do_5, Re_5, Do_5, Fa_5, | |
Fa_5, Re_5, Si_4, Do_5, SiF_4, Sol_4, | |
Fa_4 | |
}; | |
int Beat[] = { | |
4, 1, 1, 3, 2, 1, | |
2, 1, 2, 1, 2, 1, 2, 1, | |
2, 1, 2, 1, 2, 1, 2, 1, | |
2, 1, 2, 1, 2, 1, 2, 1, | |
2, 1, 2, 1, 2, 1, 2, 1, | |
4, 1, 1, 4, 1, 1, | |
4, 1, 1, 3, 3, | |
4, 1, 1, 3, 3, | |
3, 1, 1, 1, 3, 1, 1, 1, | |
3, 1, 1, 1, 3, 1, 1, 1, | |
4, 1, 1, 3, 3, | |
3, 3, 3, 3, | |
3, 3, 3, 3, | |
3, 3, 3, 2, 1, | |
3, 1, 1, 1, 3, 1, 1, 1, | |
6 | |
}; | |
void play() { | |
for(int y = 0; y < 3; y++) { | |
for (int x = 0; x < sizeof(Melody)/sizeof(int); x++) { | |
Serial.println(Melody[x]); | |
tone(SPEAKER_PIN, Melody[x]); | |
delay(Beat[x] * 400); | |
noTone(SPEAKER_PIN); | |
} | |
} | |
} | |
void speaker_setup() { | |
pinMode(SPEAKER_PIN, OUTPUT); | |
} | |
// time configuration | |
double time_set = 0; | |
void increase() { | |
Serial.println("inc"); | |
time_set += 1; | |
} | |
void decrease() { | |
Serial.println("dec"); | |
time_set -= 1; | |
} | |
void clear() { | |
time_set = 0; | |
} | |
void time_config_setup() { | |
pinMode(INC_PIN, INPUT); | |
pinMode(DEC_PIN, INPUT); | |
} | |
void handle_time_config_click() { | |
if (is_clicked(INC_PIN)) | |
increase(); | |
else if (is_clicked(DEC_PIN)) | |
decrease(); | |
} | |
// timer actions | |
ThreeWire rtc_wire(RTC_DAT, RTC_CLK, RTC_RST); | |
RtcDS1302<ThreeWire> timer(rtc_wire); | |
RtcDateTime time_timer_started; | |
double time_passed = 0; | |
bool is_running = false; | |
void start() { | |
time_timer_started = timer.GetDateTime(); | |
time_passed = 0; | |
is_running = true; | |
} | |
void end() { // end-phase color? | |
is_running = false; | |
clear(); | |
play(); | |
} | |
void reset() { | |
time_set = 0; | |
time_passed = 0; | |
is_running = false; | |
} | |
void sync_time() { | |
if (is_running) { | |
RtcDateTime now = timer.GetDateTime(); | |
uint32_t passed = now.TotalSeconds() - time_timer_started.TotalSeconds(); | |
time_passed = (double)passed / 60.0; | |
if (time_passed >= time_set) end(); | |
} | |
} | |
void timer_setup() { | |
pinMode(START_PIN, INPUT); | |
pinMode(RESET_PIN, INPUT); | |
timer.Begin(); | |
if (timer.GetIsWriteProtected()) timer.SetIsWriteProtected(false); | |
if (timer.GetIsRunning()) timer.SetIsRunning(true); | |
} | |
void handle_timer_click() { | |
if (is_clicked(START_PIN) && time_set != 0) start(); | |
else if (is_clicked(RESET_PIN)) reset(); | |
} | |
// state rendering | |
Adafruit_NeoPixel loading_bar(NEOPIXLE_PIXELCOUNT, NEOPIXEL_PIN, NEO_GRB + NEO_KHZ800); | |
void render_loading_bar() { | |
loading_bar.clear(); | |
if (is_running) { | |
double percent = time_passed / time_set; | |
int pixels_to_light = floor(60 * percent); | |
for(int i = 0; i < pixels_to_light; i++) | |
loading_bar.setPixelColor(i, loading_bar.Color(0, 150, 0)); | |
} | |
loading_bar.show(); | |
} | |
TM1637Display moniter(SEVENSEGMENT_CLK, SEVENSEGMENT_DIO); | |
void render_time_config_moniter() { | |
moniter.clear(); | |
moniter.showNumberDec(time_set); | |
} | |
void render_setup() { | |
loading_bar.begin(); | |
moniter.setBrightness(2); | |
} | |
void render() { | |
render_time_config_moniter(); | |
render_loading_bar(); | |
} | |
// lifecycle hooks | |
void setup() { | |
time_config_setup(); | |
timer_setup(); | |
render_setup(); | |
speaker_setup(); | |
} | |
void loop() { | |
if (is_running == false) handle_time_config_click(); | |
handle_timer_click(); | |
sync_time(); | |
render(); | |
} |
왼쪽 : dec 오른쪽 INC 가운데 RED RESET 가운데 WHITE 시작