summaryrefslogtreecommitdiff
path: root/alarmclock.ino
diff options
context:
space:
mode:
Diffstat (limited to 'alarmclock.ino')
-rw-r--r--alarmclock.ino433
1 files changed, 433 insertions, 0 deletions
diff --git a/alarmclock.ino b/alarmclock.ino
new file mode 100644
index 0000000..a7aa8c9
--- /dev/null
+++ b/alarmclock.ino
@@ -0,0 +1,433 @@
+#include <RTClib.h>
+#include <LiquidCrystal.h>
+
+#include <time.h>
+
+#define TRUE 1
+#define FALSE 1
+
+// Pins
+#define JOY_X A0
+#define JOY_Y A1
+#define JOY_BTN 22
+int JoyX, JoyY;
+int JoyBtn;
+int JoyDirection;
+
+#define SOUND 50
+bool Sound;
+
+#define BUZZER 45
+
+#define D4 30
+#define D5 31
+#define D6 32
+#define D7 33
+#define RS 38
+#define E 39
+
+RTC_DS1307 rtc;
+
+LiquidCrystal lcd(RS, E, D4, D5, D6, D7);
+
+byte clock_symbol[8] = {
+ B00000,
+ B10001,
+ B01110,
+ B10101,
+ B10111,
+ B10001,
+ B01110,
+ B11011,
+};
+
+// Current menu position
+unsigned int MenuPosition;
+// True if we are to display a menu
+bool inMenu;
+// The time of the last menu interaction so that we can return to the clock screen after some time
+// 32 bit unixtime, das leben am limit
+uint32_t menuTime;
+#define MENU_TIMEOUT 5
+// This will be true if we are in a submenu
+bool inSubmenu;
+
+// This will be set if the alarm is on
+bool alarmOn = false;
+// This will be on if the user has shoutet the alarm into silence
+bool alarmKilled = false;
+
+void setup() {
+ // put your setup code here, to run once:
+ Serial.begin(57600);
+ Serial.println("Hallo");
+ // Joystick setup
+ pinMode(JOY_BTN, INPUT_PULLUP);
+ pinMode(SOUND, INPUT);
+ pinMode(BUZZER, OUTPUT);
+ // RTC Setup
+ Wire.begin();
+ if(!rtc.begin()) {
+ Serial.println("RTC konnte nicht initialisiert werden");
+ while(1);
+ }
+ MenuPosition = 0;
+ inMenu = 0;
+ menuTime = 0;
+ inSubmenu = false;
+ if (!rtc.isrunning())
+ Serial.println("RTC is NOT running!");
+
+ // LCD Setup
+ lcd.begin(16,2);
+ lcd.createChar('\n', clock_symbol);
+
+ menuTime = rtc.now().unixtime();
+
+}
+
+#define MENU_ENTRIES_N 3
+// All the menu entries
+char MenuEntries[MENU_ENTRIES_N][32] = {
+ "Wecker",
+ "Uhrzeit",
+ "Datum"
+};
+
+unsigned short int alarmTime[2] = {0};
+bool alarmEn = false;
+// The position of the cursor in the alarm submenu, 0 for hours, 1 for minutes
+short int alarmSetPosition = 0;
+
+unsigned int setTime[3] = {0};
+uint16_t setDate[3] = {0};
+// The position of the cursor in the time set menu
+short int timeSetPosition = 0;
+short int dateSetPosition = 0;
+
+enum JoyPosition {joy_mid, joy_left, joy_right, joy_up, joy_down};
+char alarmString[16] = "";
+char timeSetString[16] = "";
+char dateSetString[20] = "";
+struct tm* curtm;
+time_t curtime_ux = 0;
+
+short int date_lut_max[12] = {
+ 31,
+ 28,
+ 31,
+ 30,
+ 31,
+ 30,
+ 31,
+ 31,
+ 30,
+ 31,
+ 30,
+ 31
+};
+
+void update_menu() {
+ lcd.home();
+
+ if(!inSubmenu) {
+ // If we are on the last menu entry the active entry will be at the bottom
+ if(MenuPosition == MENU_ENTRIES_N - 1) {
+ lcd.setCursor(1,0);
+ lcd.print(MenuEntries[MenuPosition -1]);
+ lcd.setCursor(0,1);
+ lcd.print(">");
+ lcd.print(MenuEntries[MenuPosition]);
+ } else {
+ lcd.print(">");
+ lcd.print(MenuEntries[MenuPosition]);
+ lcd.setCursor(1, 1);
+ lcd.print(MenuEntries[MenuPosition + 1]);
+ }
+ // This is the menu select
+ switch (JoyDirection) {
+ case joy_down :
+ // Unten
+ MenuPosition = (MenuPosition + 1) % MENU_ENTRIES_N;
+
+ delay(300);
+ lcd.clear();
+ menuTime = rtc.now().unixtime();
+ break;
+ case joy_up :
+ // Oben
+ MenuPosition = (MenuPosition - 1) % MENU_ENTRIES_N;
+
+ delay(300);
+ lcd.clear();
+ menuTime = rtc.now().unixtime();
+ break;
+ default:
+ if(JoyBtn) {
+ inSubmenu = true;
+ // Set up the submenu
+ switch(MenuPosition) {
+ case 1:
+ setTime[0] = rtc.now().hour();
+ setTime[1] = rtc.now().minute();
+ setTime[2] = rtc.now().second();
+ break;
+ case 2:
+ setDate[0] = rtc.now().day();
+ setDate[1] = rtc.now().month();
+ setDate[2] = rtc.now().year();
+ break;
+ }
+ menuTime = UINT32_MAX;
+ lcd.clear();
+ delay(300);
+ }
+ break;
+ }
+ } else {
+ menuTime = rtc.now().unixtime();
+ // This is where the submenu magic happens
+ switch(MenuPosition) {
+ case 0:
+ alarmOn = false;
+ // Weckfunktion
+ switch(JoyDirection) {
+ case joy_up:
+ if(alarmSetPosition == 2) {
+ alarmEn = !alarmEn;
+ } else
+ alarmTime[alarmSetPosition] = (alarmTime[alarmSetPosition] + 1) % (alarmSetPosition == 0 ? 24 : 60);
+ break;
+ case joy_down:
+ if(alarmSetPosition == 2) {
+ alarmEn = !alarmEn;
+ } else
+ alarmTime[alarmSetPosition] = (alarmTime[alarmSetPosition] - 1) % (alarmSetPosition == 0 ? 24 : 60);
+ break;
+ case joy_left:
+ if(alarmSetPosition == 0)
+ alarmSetPosition = 2;
+ else
+ alarmSetPosition = (alarmSetPosition - 1) % 3;
+ break;
+ case joy_right:
+ alarmSetPosition = (alarmSetPosition + 1) % 3;
+ break;
+ }
+ sprintf(alarmString, "%02hd:%02hd %s", alarmTime[0], alarmTime[1], alarmEn ? "On" : "Off");
+ lcd.clear();
+ lcd.home();
+ lcd.print(alarmString);
+ lcd.setCursor(alarmSetPosition + (alarmSetPosition << 1), 1);
+ lcd.print("^^");
+ delay(200);
+ break;
+ case 1:
+ switch(JoyDirection) {
+ case joy_up:
+ setTime[timeSetPosition] = (setTime[timeSetPosition] + 1) % (timeSetPosition == 0 ? 24 : 60);
+ break;
+ case joy_down:
+ setTime[timeSetPosition] = (setTime[timeSetPosition] - 1) % (timeSetPosition == 0 ? 24 : 60);
+ break;
+ case joy_left:
+ if(timeSetPosition == 0)
+ timeSetPosition = 2;
+ else
+ timeSetPosition = (timeSetPosition - 1) % 3;
+ break;
+ case joy_right:
+ timeSetPosition = (timeSetPosition + 1) % 3;
+ break;
+ }
+ sprintf(timeSetString, "%02hd:%02hd:%02hd", setTime[0], setTime[1], setTime[2]);
+ lcd.clear();
+ lcd.home();
+ lcd.print(timeSetString);
+ lcd.setCursor(timeSetPosition + (timeSetPosition << 1), 1);
+ lcd.print("^^");
+
+ curtime_ux = rtc.now().unixtime();
+ curtm = gmtime(&curtime_ux);
+
+ // Get the current time
+ curtm->tm_hour = setTime[0];
+ curtm->tm_min = setTime[1];
+ curtm->tm_sec = setTime[2];
+
+ delay(200);
+ break;
+ case 2:
+ lcd.clear();
+ lcd.home();
+
+ switch(JoyDirection) {
+ case joy_up:
+ switch(dateSetPosition) {
+ case 0:
+ setDate[0] = (setDate[0] + 1) % (date_lut_max[setDate[1] - 1] + 1);
+ break;
+ case 1:
+ setDate[1] = (setDate[1] + 1) % 13;
+ if(setDate[0] > date_lut_max[setDate[1] - 1]) setDate[0] = date_lut_max[setDate[1] - 1];
+ break;
+ case 2:
+ setDate[2]++;
+ if(setDate[2] < 2000) setDate[2] = 2000;
+ if(setDate[2] < 2099) setDate[2] = 2099;
+ }
+ // Check if any date is 0
+ for(int i = 0; i < 3; i++) {
+ if(setDate[i] == 0) setDate[i] = 1;
+ }
+ break;
+ case joy_down:
+ switch(dateSetPosition) {
+ case 0:
+ setDate[0] = (setDate[0] - 1) % (date_lut_max[setDate[1] - 1] + 1);
+ break;
+ case 1:
+ setDate[1] = (setDate[1] - 1) % 13;
+ if(setDate[0] > date_lut_max[setDate[1] - 1]) setDate[0] = date_lut_max[setDate[1] - 1];
+ break;
+ case 2:
+ setDate[2]--;
+ if(setDate[2] < 2000) setDate[2] = 2000;
+ if(setDate[2] > 2099) setDate[2] = 2099;
+ }
+ // Check if any date is 0
+ for(int i = 0; i < 3; i++) {
+ if(setDate[i] == 0) setDate[i] = 1;
+ }
+ break;
+ case joy_left:
+ if(dateSetPosition == 0)
+ dateSetPosition = 2;
+ else
+ dateSetPosition = (dateSetPosition - 1) % 3;
+ break;
+ case joy_right:
+ dateSetPosition = (dateSetPosition + 1) % 3;
+ break;
+ }
+ sprintf(dateSetString, "%02hd.%02hd.%04hd", setDate[0], setDate[1], setDate[2]);
+ lcd.clear();
+ lcd.home();
+ lcd.print(dateSetString);
+ lcd.setCursor(dateSetPosition + (dateSetPosition << 1), 1);
+ lcd.print("^^");
+ delay(200);
+
+ break;
+ default:
+ Serial.println("I should not be here");
+ lcd.print(MenuPosition);
+ break;
+ }
+ if(JoyBtn) {
+ inSubmenu = false;
+ if(MenuPosition == 1) {
+ rtc.adjust(DateTime(mktime(curtm)));
+ menuTime = rtc.now().unixtime();
+ } else if(MenuPosition == 2) {
+ rtc.adjust(DateTime(setDate[2], setDate[1], setDate[0], rtc.now().hour(), rtc.now().minute(), rtc.now().second()));
+ menuTime = rtc.now().unixtime();
+ }
+ lcd.clear();
+ delay(300);
+ }
+ }
+}
+
+const char Weekday[7][3] {
+ "Mo",
+ "Di",
+ "Mi",
+ "Do",
+ "Fr",
+ "Sa",
+ "So"
+};
+
+void print_time_now() {
+ DateTime now = rtc.now();
+ lcd.home();
+ char timestring_s[20] = "";
+ // AHHHHHHHH don't touch the trinaries!!!
+ sprintf(timestring_s, "%02d:%02d:%02d %c", now.hour(), now.minute(), now.second(), alarmEn ?
+ (!alarmOn || rtc.now().unixtime() % 2 ? '\n' : ' ') :
+ ' ');
+ lcd.print(timestring_s);
+ lcd.setCursor(0,1);
+ char datestring[20] = "";
+ sprintf(datestring, "%s %02d.%02d.%04d", Weekday[now.dayOfTheWeek() - 1], now.day(), now.month(), now.year());
+ lcd.print(datestring);
+}
+
+
+void playSound() {
+ for(int i = 0; i < 10; i++) {
+ digitalWrite(BUZZER, HIGH);
+ delay(1);
+ digitalWrite(BUZZER, LOW);
+ delay(1);
+ }
+}
+
+void loop() {
+ //if(!menuTime) menuTime = rtc.now().unixtime();
+ // Analoger Joystick
+ // 1024 - entfernen wenn gedreht wird
+ JoyX = analogRead(JOY_X);
+ JoyY = analogRead(JOY_Y);
+
+ Serial.println(JoyY);
+
+ JoyDirection = joy_mid;
+ if(JoyX < 50) {
+ JoyDirection = joy_down;
+ } else if(JoyX > 850) {
+ JoyDirection = joy_up;
+ } else if(JoyY < 50) {
+ JoyDirection = joy_left;
+ } else if(JoyY > 850) {
+ JoyDirection = joy_right;
+ }
+
+ // Joystick button
+ JoyBtn= !digitalRead(JOY_BTN);
+
+ // Read in the sound
+ Sound = digitalRead(SOUND);
+
+ // If the button is pressed and we are not in a menu enter the menu
+ if(JoyBtn && !inMenu && !alarmOn) {
+ inMenu = true;
+ inSubmenu = false;
+ lcd.clear();
+ menuTime = rtc.now().unixtime();
+ delay(300);
+ } else if(inMenu) { // Do this if we are in a menu
+ update_menu();
+ if(menuTime < rtc.now().unixtime() -5 ) { // Check if the menu interaction has timed out.
+ Serial.println(rtc.now().unixtime());
+ Serial.println(menuTime);
+ inMenu = false;
+ MenuPosition = 0;
+ lcd.clear();
+ }
+ } else {
+ print_time_now();
+ // Check the alarm, ring if we pass it
+ if(alarmTime[0] == rtc.now().hour() && alarmTime[1] == rtc.now().minute() && alarmEn) {
+ if(!alarmKilled) alarmOn = true;
+ } else alarmKilled = false;
+ if(alarmOn && Sound) {
+ alarmKilled = true;
+ alarmOn = false;
+ }
+ if(alarmOn) {
+ playSound();
+ }
+ }
+}
Jeremias Stotters git repositories generated by CGIT