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