/*
* 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
*
* Fixed to avoid millis() rollover causing reset to 0:00
*
* Mark Ruff, Jan 2015
*/
#include <LiquidCrystal.h>
// 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 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;
// 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};
// 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() {
// 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;
if (button1PressedTime == 0) {
button1PressedTime = millis();
}
}
else if (button1State == LOW && prevButton1State == HIGH ) {
button1Pressed = true;
button1Held = false;
button1PressedTime = 0;
}
else {
button1Pressed = false;
button1Held = false;
}
if(button2State == HIGH && prevButton2State == HIGH ) {
button2Held = true;
button2Pressed = false;
if ( button2PressedTime == 0 ) {
button2PressedTime = millis();
}
}
else if (button2State == LOW && prevButton2State == HIGH ) {
button2Pressed = true;
button2Held = false;
button2PressedTime = 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 {
int hours = getHour();
int minutes = getMinute();
int seconds = getSeconds();
// 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
// only refresh every 10s
if ( millis() % 10000 < 200 ) {
writeTemp();
}
// 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 =
(millisSinceMidnight + millis() - prevMillis) % 86400000;
prevMillis = millis();
}
// Calculate hours / minutes / seconds since Arduino reset
// Used to calcuate time
int getHour() {
return (millisSinceMidnight/3600000)%24;
}
int getMinute() {
return (millisSinceMidnight/60000)%60;
}
int getSeconds() {
return (millisSinceMidnight/1000)%60;
}
// 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
if ( seconds % 2 == 0 ) {
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(2500);
lcd.noAutoscroll();
lcd.clear();
}
void setTime() {
bool am = adjustedHour < 12;
bool flash = (millis() % 1500 ) < 250;
// display the clock
// flash the digits (HH or MM) being changed
// display the time
lcd.setCursor(0,0);
if( flash && setTimeMode == 1 && !button2Held && ! button2Pressed) {
lcd.print((char)95);
lcd.print((char)95); // 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( flash && setTimeMode == 2 && !button2Held ) {
lcd.print((char)95);
lcd.print((char)95); // flash when setting
}
else {
if (adjustedMinute < 10 ) {
lcd.print("0");
}
lcd.print(adjustedMinute);
}
// am/pm - don't flash
if( flash && setTimeMode == 3 && !button2Held ) {
lcd.print((char)95);
lcd.print((char)95); // 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 ) {
int delayFactor = millis() - button2PressedTime;
if ( delayFactor < 2000 ) {
delay(200);
}
if (delayFactor < 4000) {
delay(100);
}
delay(50);
if (setTimeMode == 1) {
adjustedHour = ( adjustedHour + 1 ) % 24;
}
else if (setTimeMode == 2 ){
adjustedMinute = ( adjustedMinute + 1 ) % 60;
}
}
if ( button2Pressed && setTimeMode == 3 ) {
hour24 = !hour24;
}
// Button 1 Pressed
// This cycles through Hours / Minutes / Finished
if ( button1Pressed ) {
setTimeMode = (setTimeMode +1 ) % 4;
if (setTimeMode == 0) {
millisSinceMidnight =
adjustedHour * 3600000 + adjustedMinute * 60000;
lcd.clear();
writeTemp();
}
}
}
void setAlarm() {
bool am = adjustedHour < 12;
bool flash = (millis() % 1500 ) < 300;
// display the clock
// flash the digits (HH or MM) being changed
// display the time
lcd.setCursor(0,0);
if( flash && setAlarmMode == 1 && !button2Held && ! button2Pressed) {
lcd.print((char)95);
lcd.print((char)95); // 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( flash && setAlarmMode == 2 && !button2Held ) {
lcd.print((char)95);
lcd.print((char)95); // 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( flash && setAlarmMode == 3 && !button2Held ) {
lcd.print(" ");
lcd.print((char)95);
lcd.print((char)95);
lcd.print((char)95); // flash when setting
}
else {
if ( alarmOn ) {
lcd.print(" on ");
}
else {
lcd.print(" off");
}
}
// Button 2 Pressed
// this increments the hours/minutes
if ( button2Held ) {
int delayFactor = millis() - button2PressedTime;
if ( delayFactor < 2000 ) {
delay(200);
}
if (delayFactor < 4000) {
delay(100);
}
delay(50);
if (setTimeMode == 1) {
adjustedHour = ( adjustedHour + 1 ) % 24;
}
if (setAlarmMode == 1) {
adjustedHour = ( adjustedHour + 1 ) % 24;
}
else if (setAlarmMode == 2 ){
adjustedMinute = ( adjustedMinute + 1 ) % 60;
}
}
if ( button2Pressed && setAlarmMode == 3 ) {
alarmOn = !alarmOn;
}
// Button 1 Pressed
// This cycles through Hours / Minutes / Finished
if ( button1Pressed ) {
setAlarmMode = (setAlarmMode +1 ) % 4;
if (setAlarmMode == 0) {
alarmHour = adjustedHour;
alarmMinute = adjustedMinute;
lcd.clear();
writeTemp();
}
}
delay(100);
}
// 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");
}
Comments