/* * LCD Alarm Clock with Temperature * * Arduino powered alarm clock that shows the time and temperature * Alarm can be set. Alarm creates tone at piezo and flashes LED * * Settings controlled with two buttons: * - button 1: set time * - button 1: cycle hr/min/24hr * - button 2: increment * - button 2: set alarm * - button 1: cycle hr/min/on-off * - button 2: increment * * pin configuration outlined in comments below * * Adjustments: * - Fixed millis() rollover causing reset to 0:00. Now using * millisSinceMidnight and reset to 0 each day at midnight * - Fixed bug resulting in clock slowing down over time due * to modulus operation between call to millis() and subsequent * setting of prevMillis = millis() * - Optimised by changing % operations to branching operations * where possible * - fixed incremental speed change of hr/min etc * * Mark Ruff, Jan 2015 */ #include // GLOBALS // ARDUINO PINS const int button1 = 6; // push buttons const int button2 = 7; const int tempPin = A0; // temperature monitor const int alarmPin = 8; // piezo const int alarmLedPin = 13; // LED // LCD // moved pin 11->10 and 3->9 to avoid interference from tone() LiquidCrystal lcd(12,10,5,4,9,2); // Byte blocks for additional icons to display in lcd // loading in setup() byte alarmIcon[8] = { B00100, B01110, B01110, B01110, B11111, B00100, B00000, }; byte heartIcon[8] = { B00000, B01010, B11111, B11111, B11111, B01110, B00100, }; byte noteIcon[8] = { B00100, B00110, B00101, B00101, B00100, B11100, B11100, }; // TIME SETTINGS // millisSinceMidnight, used to calculate the time, updated // using interval millis() - prevMillis each cycle unsigned long int millisSinceMidnight = 0; unsigned long int prevMillis = 0; int interval; // used to store millis() - prevMillis int hour24 = false; // 24 hour time // For setting the time // - 0 = not settingm time // - 1 = setting Hours // - 2 = setting Minutes // - 3 = setting am/pm int setTimeMode; int adjustedHour; int adjustedMinute; // For the flashing colon : int colonFrequency = 1000; // flash every 2 seconds int colonTimer = 0; bool colonOn = true; // For blinking digits during time / alarm set int blinkOnTime = 1000; int blinkOffTime = 333; int blinkTimer = 0; bool blinkOn = true; // for slowing increasing speed at which hrs/mins increment // based on how long button held int buttonPressedTimer = 0; int speed1Max = 1500; // 2 seconds int speed1Delay = 300; int speed2Max = 3000; // int speed2Delay = 150; int speed3Delay = 75; // ALARM SETTINGS bool alarmOn = false; int alarmHour = 0; int alarmMinute = 0; // For setting the alarm (mode similar to setTime Mode int setAlarmMode; // frequencies (notes) used by the alarm int notes[] = {261, 294, 329, 349, 392, 440, 493, 523}; // TEMPERATURE SETTINGS // How often to update the temperature int tempFrequency = 10000; int tempTimer = 0; // BUTTON SETTINGS // Held button: current state HIGH and prev state HIGH // Pressed button: current state LOW and prev state HIGH // - Pressed is really released button // Pressed time is used to vary the speed when incrementing // the time or alarm int button1State = LOW; int button2State = LOW; int prevButton1State = LOW; int prevButton2State = LOW; bool button1Pressed = false; bool button1Held = false; bool button2Pressed = false; bool button2Held = false; int button1PressedTime = 0; int button2PressedTime = 0; void setup() { // pins pinMode(button1, INPUT); pinMode(button2, INPUT); pinMode(tempPin, INPUT); pinMode(alarmPin, OUTPUT); pinMode(alarmLedPin, OUTPUT); digitalWrite(alarmLedPin, LOW); // lcd lcd.begin(16,2 ); // three characters (defined above) lcd.createChar(0, alarmIcon); lcd.createChar(1, heartIcon); lcd.createChar(2, noteIcon); // print the welcome message welcomeMessage(); // write the temperature, because we don't do it every loop writeTemp(); } void loop() { // Time keeping interval = millis() - prevMillis; prevMillis = millis(); // capture button presses // HELD = while button depressed // PRESSED = after release (reading falling edge) button1State = digitalRead(button1); button2State = digitalRead(button2); if(button1State == HIGH && prevButton1State == HIGH ) { button1Held = true; button1Pressed = false; } else if (button1State == LOW && prevButton1State == HIGH ) { button1Pressed = true; button1Held = false; buttonPressedTimer = 0; } else { button1Pressed = false; button1Held = false; } if(button2State == HIGH && prevButton2State == HIGH ) { button2Held = true; button2Pressed = false; } else if (button2State == LOW && prevButton2State == HIGH ) { button2Pressed = true; button2Held = false; buttonPressedTimer = 0; } else { button2Pressed = false; button2Held = false; } prevButton1State = button1State; prevButton2State = button2State; // Setting the time? if (setTimeMode > 0) { setTime(); } // Or setting the alarm? else if (setAlarmMode > 0 ) { setAlarm(); } // Otherwise just display the time & temperature else { // Calculate hours / minutes / seconds since Arduino reset // Used to calcuate time int hours = (millisSinceMidnight/3600000)%24; int minutes = (millisSinceMidnight/60000)%60; int seconds = (millisSinceMidnight/1000)%60; // BUTTON 1 PRESS // Change the time if ( button1Pressed ) { setTimeMode = 1; adjustedHour = hours; adjustedMinute = minutes; } // BUTTON 2 PRESS if ( button2Pressed ) { setAlarmMode = 1; adjustedHour = alarmHour; adjustedMinute = alarmMinute; } // DISPLAY THE TIME displayTime(hours, minutes, seconds); // DISPLAY ALARM ICON (if on) if ( alarmOn ) { lcd.print(" "); lcd.write( byte(0) ); // this is our alarm icon } else { lcd.print(" "); } // DISPLAY THE TEMPERATURE // update the timer, check if threshold reached, if so // write the temperature tempTimer += interval; if (tempTimer > tempFrequency) { writeTemp(); tempTimer = 0; } // Set off alarms if set on and time if ( alarmOn && hours == alarmHour && minutes == alarmMinute ) { alarm(); } } // Increment millisecond count from midnight // rollover if we've reached midnight millisSinceMidnight += interval; millisSinceMidnight = millisSinceMidnight % 86400000; } // Displays the time void displayTime(int hours, int minutes, int seconds) { // is it morning bool am = hours < 12; // HOURS lcd.setCursor(0,0); // first handle 24 hour time if( hour24 ) { if ( hours < 10 ) { lcd.print(" "); } lcd.print(hours); } // otherwise am/pm else { hours = am ? hours : hours - 12; if ( hours == 0 ) { lcd.print("12"); } else if ( hours < 10 ) { lcd.print( " " ); lcd.print(hours); } else { lcd.print(hours); } } // FlASHING COLON colonTimer += interval; if ( colonTimer > colonFrequency ) { colonTimer = 0; colonOn = !colonOn; } if (colonOn) { lcd.print(":"); } else { lcd.print(" "); } // MINUTES if ( minutes < 10 ) { lcd.print("0"); } lcd.print(minutes); // AM/PM if ( !hour24 ) { if ( am ) { lcd.print("am"); } else { lcd.print("pm"); } } else { lcd.print (" "); } } // Print a welcome message // Two lines, top line first, bottom line scrolling in with top // line scrolling out. void welcomeMessage() { char topMessage[] = " Ruffian Clock"; // bottom message split so I can put a heart in char bottomMessageLeft[] = "I "; char bottomMessageRight[] = " Arduino! "; // Write top welcome message lcd.setCursor(0,0); lcd.print(topMessage); delay(1000); // Write bottom welcome message lcd.setCursor(16,1); lcd.autoscroll(); for ( int i = 0 ; bottomMessageLeft[i] != '\0' ; i++ ) { lcd.print(bottomMessageLeft[i]); delay(500); } // print the heart lcd.write(byte(1)); delay(500); for ( int i = 0 ; bottomMessageRight[i] != '\0' ; i++ ) { lcd.print(bottomMessageRight[i]); delay(500); } delay(1000); lcd.noAutoscroll(); lcd.clear(); } void setTime() { bool am = adjustedHour < 12; // work out whether flashing digit is on or off blinkTimer += interval; if (blinkOn) { if (blinkTimer > blinkOnTime) { blinkOn = false; blinkTimer = 0; } } else { if (blinkTimer > blinkOffTime) { blinkOn = true; blinkTimer = 0; } } // display the clock // flash the digits (HH or MM) being changed // display the time lcd.setCursor(0,0); if( !blinkOn && setTimeMode == 1 && !button2Held && ! button2Pressed) { lcd.print("__"); // flash when setting } else { if (hour24) { if ( adjustedHour < 10 ) { lcd.print(" "); } lcd.print(adjustedHour); } else { if (!am) { if ( adjustedHour == 12 ) { lcd.print("12"); } else { if ( adjustedHour -12 < 10 ) { lcd.print(" "); } lcd.print(adjustedHour - 12); } } else { if ( adjustedHour == 0 ) { lcd.print("12"); } else { if ( adjustedHour < 10 ) { lcd.print(" "); } lcd.print(adjustedHour); } } } } lcd.print(":"); if( !blinkOn && setTimeMode == 2 && !button2Held ) { lcd.print("__"); // flash when setting } else { if (adjustedMinute < 10 ) { lcd.print("0"); } lcd.print(adjustedMinute); } // am/pm if( !blinkOn && setTimeMode == 3 && !button2Held ) { lcd.print("__"); // flash when setting } else { if ( hour24 ) { lcd.print(" "); } else { if ( am ) { lcd.print("am"); } else { lcd.print("pm"); } } } // Button 2 Pressed // this increments the hours/minutes if ( button2Held ) { blinkOn = true; blinkTimer = 0; buttonPressedTimer += interval; if (buttonPressedTimer < speed1Max) { delay(speed1Delay); } else if (buttonPressedTimer < speed2Max) { delay(speed2Delay); } else { delay(speed3Delay); } if (setTimeMode == 1) { adjustedHour = adjustedHour + 1; if (adjustedHour == 24) adjustedHour = 0; } else if (setTimeMode == 2 ){ adjustedMinute = adjustedMinute + 1; if (adjustedMinute == 60) adjustedMinute = 0; } } if ( button2Pressed && setTimeMode == 3 ) { blinkOn = true; blinkTimer = 0; hour24 = !hour24; } // Button 1 Pressed // This cycles through Hours / Minutes / Finished if ( button1Pressed ) { blinkOn = false; blinkTimer = 0; setTimeMode = setTimeMode +1; if (setTimeMode == 4) { setTimeMode = 0; millisSinceMidnight = adjustedHour * 3600000 + adjustedMinute * 60000; lcd.clear(); writeTemp(); } } } void setAlarm() { bool am = adjustedHour < 12; // work out whether flashing digit is on or off blinkTimer += interval; if (blinkOn) { if (blinkTimer > blinkOnTime) { blinkOn = false; blinkTimer = 0; } } else { if (blinkTimer > blinkOffTime) { blinkOn = true; blinkTimer = 0; } } // display the clock // flash the digits (HH or MM) being changed // display the time lcd.setCursor(0,0); if( !blinkOn && setAlarmMode == 1 && !button2Held && ! button2Pressed) { lcd.print("__"); // flash when setting } else { if (hour24) { if ( adjustedHour < 10 ) { lcd.print(" "); } lcd.print(adjustedHour); } else { if (!am) { if ( adjustedHour == 12 ) { lcd.print("12"); } else { if ( adjustedHour -12 < 10 ) { lcd.print(" "); } lcd.print(adjustedHour - 12); } } else { if ( adjustedHour == 0 ) { lcd.print("12"); } else { if ( adjustedHour < 10 ) { lcd.print(" "); } lcd.print(adjustedHour); } } } } lcd.print(":"); if( !blinkOn && setAlarmMode == 2 && !button2Held ) { lcd.print("__"); // flash when setting } else { if (adjustedMinute < 10 ) { lcd.print("0"); } lcd.print(adjustedMinute); } // am/pm - not changing here if ( hour24 ) { lcd.print(" "); } else { if ( am ) { lcd.print("am"); } else { lcd.print("pm"); } } if( !blinkOn && setAlarmMode == 3 && !button2Held ) { lcd.print(" ___"); // flash when setting } else { if ( alarmOn ) { lcd.print(" on "); } else { lcd.print(" off"); } } // Button 2 Pressed // this increments the hours/minutes if ( button2Held ) { blinkOn = true; blinkTimer = 0; buttonPressedTimer += interval; if (buttonPressedTimer < speed1Max) { delay(speed1Delay); } else if (buttonPressedTimer < speed2Max) { delay(speed2Delay); } else { delay(speed3Delay); } if (setAlarmMode == 1) { adjustedHour = adjustedHour + 1; if (adjustedHour == 24) adjustedHour = 0; } else if (setAlarmMode == 2 ){ adjustedMinute = adjustedMinute + 1; if ( adjustedMinute == 60 ) adjustedMinute = 0; } } if ( button2Pressed && setAlarmMode == 3 ) { blinkOn = true; blinkTimer = 0; alarmOn = !alarmOn; } // Button 1 Pressed // This cycles through Hours / Minutes / Finished if ( button1Pressed ) { blinkOn = false; blinkTimer = 0; setAlarmMode = setAlarmMode + 1; if (setAlarmMode == 4) { setAlarmMode = 0; alarmHour = adjustedHour; alarmMinute = adjustedMinute; lcd.clear(); writeTemp(); } } } // Set off the alarm, combination of: // - tone // - LED flashing // - note icon on LCD void alarm() { // draw the note icon on the LCD lcd.setCursor(9,0); lcd.write(byte(2)); // play the little tune (uses frequencies in notes[]) // flash the LED at the same time for ( int i = 0 ; i < 4 ; i++ ) { tone(alarmPin,notes[i],200); digitalWrite(alarmLedPin,LOW); delay(200); tone(alarmPin,notes[i+2],200); digitalWrite(alarmLedPin,HIGH); delay(200); } tone(alarmPin,notes[6],600); for (int i = 0 ; i < 6 ; i++ ) { digitalWrite(alarmLedPin,LOW); delay(50); digitalWrite(alarmLedPin,HIGH); delay(50); } for(int i = 3 ; i >= 0 ; i-- ) { tone(alarmPin,notes[i],200); lcd.setCursor(9,0); lcd.write(byte(2)); delay(100); // flash the note icon a little lcd.setCursor(9,0); lcd.write(" "); delay(100); } // turn off alarm, clear LCD, turn off LED alarmOn = false; digitalWrite(alarmLedPin,LOW); lcd.clear(); // write the temp (because there might be a delay) writeTemp(); } // write the temperature on the bottom line of the LCD void writeTemp() { // get the sensor value int tempSensorVal = analogRead(tempPin); // convert the sensor reading to voltage float voltage = (tempSensorVal/1024.0) * 5.0; // convert voltage to temperature float temperature = (voltage - 0.5) * 100; lcd.setCursor(0,1); lcd.print(temperature); lcd.setCursor(4,1); lcd.print((char)223); // degrees symbol lcd.print("C"); }