clock-share.pde
/*
Fancy clock version 1.1
Eric Ayars
Arduino-based clock with:
2-line backlit LCD
Time, Date, Temperature
Date-dependent event notification
Automatic daylight-savings time adjustment
(possibly) automatic backlight adjustment for ambient conditions
Alarm
USB port for setting clock to computer time
Based on:
1307 real-time clock (I2C interface)
LM35 thermometer
Arduino 328 (enough memory that way for event storage!)
*/
#include <avr/pgmspace.h>
#include <Wire.h>
#include <LiquidCrystal.h>
#define CLOCK_ADDRESS 0x68
#define TEMPERATURE_PIN 0
#define BACKLIGHT 3
#define MIN_BACKLIGHT 50
#define MAX_BACKLIGHT 255
#define MESSAGE_LENGTH 17
#define DEBOUNCE 50
#define MAX_ALARM 7
#define BUZZER 13
boolean DaylightSavings = false;
char Message[MESSAGE_LENGTH] = " ";
char TopLine[MESSAGE_LENGTH] = " ";
char BottomLine[MESSAGE_LENGTH] = " ";
char SetMessage[] = " Clock Set ";
char AlarmMessage[] = " Alarm Set ";
byte Temp1;
byte Year = 9;
byte Month = 12;
byte Day = 26;
byte DoW = 8;
byte Hour = 3;
byte Minute = 41;
byte Second = 30;
byte oldHour = 255; // These three are set to absurd values to trigger
byte oldMinute = 255; // the change-sensitive bits in loop().
byte oldSecond = 255; //
byte oldDay = 255; //
boolean OldButtonState = false;
boolean NewButtonState = false;
volatile byte Rotor = 0;
byte UIDelay=100;
// Button/rotary switch connections
byte Button = 10;
byte A = 2;
byte B = 11;
byte AlarmOn = 0; // lowest bits are flags indicating which alarms are on.
byte AlarmMinute[MAX_ALARM]; // Array of alarm minutes...
byte AlarmHour[MAX_ALARM]; // ...hours...
byte AlarmDays[MAX_ALARM]; // ...and days.
char OnAlarms[8] = "SMTWHFS"; // Indicators for alarm on these days...
char OffAlarms[8] = "smtwhfs"; // ...and off.
boolean AlarmRinging = false; // Is the alarm sounding?
boolean BuzzerState = false; // Is the alarm (while sounding) currently on or off?
char *WeekDay[7] = {
"Sunday ",
"Monday ",
"Tuesday ",
"Wednesday ",
"Thursday ",
"Friday ",
"Saturday "};
LiquidCrystal lcd(8,9,7,6,5,4);
float tconvert = 500.0/1024.0; // converts A/D value to temperature.
void SetClock() {
// This is the user interface routine for setting the clock.
// The 1307 chip is actually set using SetTime().
UpdateTimeDisplayPlus(Hour, Minute, Year, DaylightSavings);
SetBottomLine(DoW, Month, Day);
writeLCD(0,TopLine);
writeLCD(1,BottomLine);
// Here's where we set the hour
Rotor = Hour + 48; // The extra value on rotor allows easier turn-back.
while (!ButtonPressed()) {
delay(UIDelay);
Hour = Rotor % 24;
UpdateTimeDisplayPlus(Hour, Minute, Year, DaylightSavings);
writeLCD(0,TopLine);
lcd.setCursor(0,0);
lcd.cursor();
}
// Here we set the minute
Rotor = Minute + 120; // The extra value on rotor allows easier turn-back.
while (!ButtonPressed()) {
delay(UIDelay);
Minute = Rotor % 60;
UpdateTimeDisplayPlus(Hour, Minute, Year, DaylightSavings);
writeLCD(0,TopLine);
lcd.setCursor(3,0);
lcd.cursor();
}
// Here we set the year
Rotor = Year;
while (!ButtonPressed()) {
delay(UIDelay);
Year = Rotor;
UpdateTimeDisplayPlus(Hour, Minute, Year, DaylightSavings);
writeLCD(0,TopLine);
lcd.setCursor(10,0);
lcd.cursor();
}
// Here we set the Daylight Savings status
// I set the initial value of the rotor to 127 or 128: odd is
// true, even is false.
if (DaylightSavings) {
Rotor = 127;
} else {
Rotor = 128;
}
while (!ButtonPressed()) {
delay(UIDelay);
DaylightSavings = (boolean)(Rotor%2);
UpdateTimeDisplayPlus(Hour, Minute, Year, DaylightSavings);
writeLCD(0,TopLine);
lcd.setCursor(13,0);
lcd.cursor();
}
// Set the day of the week
Rotor = DoW + 16; // The extra value on rotor allows easier turn-back.
while (!ButtonPressed()) {
delay(UIDelay);
DoW = constrain((Rotor % 8), 1, 7);
SetBottomLine(DoW, Month, Day);
writeLCD(1, BottomLine);
lcd.setCursor(0,1);
lcd.cursor();
}
// Set the Month
Rotor = Month + 26; // The extra value on rotor allows easier turn-back.
while (!ButtonPressed()) {
delay(UIDelay);
Month = constrain((Rotor % 13),1,12);
SetBottomLine(DoW, Month, Day);
writeLCD(1, BottomLine);
lcd.setCursor(11,1);
lcd.cursor();
}
// Set the Date
Rotor = Day;
while (!ButtonPressed()) {
delay(UIDelay);
switch (Month) {
// Thirty days hath November,
// All the rest I can't remember.
case 1:
case 3:
case 5:
case 7:
case 8:
case 10:
case 12:
Day = Rotor % 32;
break;
case 4:
case 6:
case 9:
case 11:
Day = Rotor % 31;
break;
case 2:
Day = Rotor % 30;
break;
}
if (Day==0) {
Day++;
}
SetBottomLine(DoW, Month, Day);
writeLCD(1, BottomLine);
lcd.setCursor(14,1);
lcd.cursor();
}
// Turn cursor off
lcd.noCursor();
// Save the new stuff, with second set to zero
setTime(Year, Month, Day, DoW, Hour, Minute, 0x00);
// Mark that things have changed so the next loop() does
// what is needed, if needed.
oldSecond = 255;
oldMinute = 255;
oldHour = 255;
oldDay = 255;
}
void setTime(byte Year, byte Month, byte Day, byte DoW, byte Hour, byte Minute, byte Second) {
// 1) Sets the date and time on the ds1307
// 2) Starts the clock
// 3) Sets hour mode to 24 hour clock
// 4) Assumes you're passing in valid numbers
Wire.beginTransmission(CLOCK_ADDRESS);
Wire.send(0);
Wire.send(decToBcd(Second));
Wire.send(decToBcd(Minute));
Wire.send(decToBcd(Hour));
Wire.send(decToBcd(DoW));
Wire.send(decToBcd(Day));
Wire.send(decToBcd(Month));
Wire.send(decToBcd(Year));
Wire.endTransmission();
}
void DisplayAlarmInfo(byte Alarm) {
// This function sets the bottom line to be useful information for setting
// the alarm(s).
// Convert from 24-hour internal to 12-hour display
Temp1 = (AlarmHour[Alarm]) % (byte)12;
if (Temp1 == 0) {
Temp1 = 12;
}
if (Temp1 / 10) {
// write the 1 in this case.
BottomLine[0] = '1';
} else {
BottomLine[0] = ' ';
}
// Second digit of hour:
BottomLine[1] = (char)(Temp1 % 10 + 48);
// minutes
BottomLine[2] = ':';
BottomLine[3] = (char)(AlarmMinute[Alarm] / 10 + 48);
BottomLine[4] = (char)(AlarmMinute[Alarm] % 10 + 48);
// Take care of am/pm
if (AlarmHour[Alarm] > 11) {
BottomLine[5] = 'p';
} else {
BottomLine[5] = 'a';
}
BottomLine[6] = ' ';
// Is this alarm on?
if ((AlarmOn >> Alarm) & 1) { // Clever, here. :-( This checks the alarm bit for this alarm.
BottomLine[7] = '!';
} else {
BottomLine[7] = '-';
}
BottomLine[8] = ' ';
// List status for each day
for (byte j=0;j<7;j++) {
if ((AlarmDays[Alarm] >> j) & 1) { // Check which days things are on using bit-shift.
BottomLine[9+j] = OnAlarms[j]; // Capital letters for "on this day".
} else {
BottomLine[9+j] = OffAlarms[j]; // lower-case letters for "not on this day".
}
}
// Update display
writeLCD(1,BottomLine);
}
void SetAlarm() {
// Picks an alarm number, sets it.
byte ThisAlarm = 0;
const char *M = PSTR(" Set Alarm # 0 ");
for (byte j=0;j<MESSAGE_LENGTH-1;j++) {
TopLine[j] = (char)pgm_read_byte(M++);
}
// First select which alarm to set
Rotor = 3*MAX_ALARM;
while (!ButtonPressed()) {
ThisAlarm = Rotor % MAX_ALARM;
TopLine[13] = (char)ThisAlarm + 49;
// (Add 49 instead of 48 so that the alarm counts 1-7 rather than 0-6.)
writeLCD(0,TopLine);
// Depending on which alarm is selected, display info on second line.
DisplayAlarmInfo(ThisAlarm);
// Mark what is being changed
lcd.setCursor(13,0);
lcd.cursor();
delay(UIDelay);
}
// Now an alarm number has been selected, so set it.
// Set the hour
Rotor = AlarmHour[ThisAlarm] + (byte)48;
while (!ButtonPressed()) {
AlarmHour[ThisAlarm] = Rotor % (byte)24;
DisplayAlarmInfo(ThisAlarm);
lcd.setCursor(1,1);
lcd.cursor();
delay(UIDelay);
}
// Set the Minute
Rotor = AlarmMinute[ThisAlarm] + (byte)120;
while (!ButtonPressed()) {
AlarmMinute[ThisAlarm] = Rotor % (byte)60;
DisplayAlarmInfo(ThisAlarm);
lcd.setCursor(3,1);
lcd.cursor();
delay(UIDelay);
}
// Set the activity
if ((AlarmOn >> ThisAlarm) & 1) { // Check this alarm's on-status-bit.
Rotor = (byte)127;
} else {
Rotor = (byte)128;
}
while (!ButtonPressed()) {
if (Rotor % 2) {
AlarmOn = AlarmOn | ((byte)1 << ThisAlarm); // Turn on this alarm's on-status-bit.
} else {
AlarmOn = AlarmOn & ((byte)255 - ((byte)1<<ThisAlarm)); // Turn off this on-status-bit.
}
DisplayAlarmInfo(ThisAlarm);
lcd.setCursor(7,1);
lcd.cursor();
delay(UIDelay);
}
// Set the days it should ring
for (byte j=0;j<MAX_ALARM;j++) {
if (AlarmDays[ThisAlarm] & ((byte)1<<j)) {
// On this day
Rotor = (byte)127;
} else {
Rotor = (byte)128;
}
while (!ButtonPressed()) {
if (Rotor % 2) {
// Turn this day's bit on
AlarmDays[ThisAlarm] = AlarmDays[ThisAlarm] | ((byte)1<<j);
} else {
// Turn this day's bit off
AlarmDays[ThisAlarm] = AlarmDays[ThisAlarm] & ((byte)255-((byte)1<<j));
}
DisplayAlarmInfo(ThisAlarm);
lcd.setCursor((9+j),1);
lcd.cursor();
delay(UIDelay);
}
}
// Save alarm status to EEPROM
SaveStatus();
// Set oldDay to invalid value so that the bottom line gets set back to normal.
oldDay = 255;
// Clear the cursor
lcd.noCursor();
}
void UpdateTimeDisplayPlus(byte Hour, byte Minute, byte Year, boolean DaylightSavings) {
// Updates TopLine to reflect current time, with addition of
// year and daylight savings time status.
UpdateTimeDisplay(Hour, Minute);
TopLine[8] = '2';
TopLine[9] = '0';
TopLine[10] = (char)(Year/10) + 48;
TopLine[11] = (char)(Year%10) + 48;
TopLine[12] = ' ';
if (DaylightSavings) {
TopLine[13] = 'D';
} else {
TopLine[13] = ' ';
}
TopLine[14] = 'S';
TopLine[15] = 'T';
}
void UpdateRotation() {
// This is the subroutine that runs every time pin 2
// goes low.
if (digitalRead(B)) {
Rotor++;
} else {
Rotor--;
}
}
boolean ButtonPressed() {
// I'm using the internal pull-up resistors on the Arduino, so
// logic is inverted. LOW means the button is pressed.
// This routine, however, returns true if button has been pressed and false
// otherwise. It's sensitive to the transition between unpressed and pressed.
boolean WasIt; // as in, "Was It pressed?"
NewButtonState = !digitalRead(Button);
if ((!OldButtonState) && (NewButtonState)) {
// Button was unpressed and is now pressed
WasIt = true;
} else {
WasIt = false;
}
OldButtonState = NewButtonState;
return(WasIt);
}
void DealWithButton() {
// Function to deal with button presses.
// If the alarm is beeping it turns the beep off and returns.
// Otherwise, it starts the whole "set time/date/alarm" routine.
byte Next=0; // flag to keep track of next action.
if (AlarmRinging) {
// Alarm is ringing, so turn it off and return.
AlarmRinging = false;
BuzzerState = false;
digitalWrite(BUZZER, LOW);
} else {
// User must be trying to set the clock or the alarm.
for (byte j=0;j<MESSAGE_LENGTH;j++) {
TopLine[j] = SetMessage[j];
BottomLine[j] = AlarmMessage[j];
}
Rotor=0;
TopLine[0] = '*';
writeLCD(0,TopLine);
writeLCD(1,BottomLine);
// Now wait for selection.
unsigned long StartTimeOut = millis();
while (!ButtonPressed()) {
delay(UIDelay); // user interface delay
Rotor = Rotor % 2;
// move selection display according to current rotor position.
if (Rotor == 1) {
TopLine[0] = ' ';
BottomLine[0] = '*';
Next = 1;
} else {
TopLine[0] = '*';
BottomLine[0] = ' ';
Next = 0;
}
writeLCD(0,TopLine);
writeLCD(1,BottomLine);
// Check for time-out
if ((millis()-StartTimeOut) > (unsigned long)30000) {
// No buttonpress for 30 seconds, go back to keeping time.
Next = 2;
// Since it skips SetClock() or SetAlarm() here, we need
// to reset the bottom line display.
oldDay = 255;
break;
}
}
if (Next == 0) {
// Set clock
SetClock();
} else if (Next == 1) {
// Set alarm
SetAlarm();
}
}
}
void writeLCD(int lineNum, char* contents) {
lcd.setCursor(0,lineNum);
lcd.print(contents);
}
void Retrieve(const char *M) {
// Retrieves a string from PROGMEM, puts it into BottomLine.
for (byte j=0;j<MESSAGE_LENGTH-1;j++) {
BottomLine[j] = (char)pgm_read_byte(M++);
}
}
void GetMessage(byte Year, byte Month, byte Day, byte DoW) {
// There's no way to store all the necessary strings in
// RAM on an ATMega168, or even ATMega328. Instead, I'm
// storing the strings in PROGMEM. The PSTR() designation
// stores the indicated string in program memory, then
// the Retrieve() function pulls it out (temporarily)
// for use by the program.
// At the very least, the Message should be the day/date,
// which has been calculated prior to this.
strcpy(Message, BottomLine);
// Now look for special cases.
switch (Month) {
case 1:
// Martin Luther King, Jr. Day
if ((DoW==2) && (Day>14) && (Day<22)) {
// Third Monday of January.
Retrieve(PSTR("MLK Jr. Day "));
}
switch (Day) {
case 1:
Retrieve(PSTR("Happy New Year! "));
break;
case 5:
Retrieve(PSTR("Nat'l Bird Day "));
break;
case 18:
Retrieve(PSTR("Pooh Day "));
break;
case 20:
Retrieve(PSTR("Inauguration Day"));
break;
case 23:
Retrieve(PSTR("Cheryl's B-day "));
break;
}
break;
case 2:
//President's day
if ((DoW==2) && (Day>14) && (Day<22)) {
// Third Monday of Feb.
Retrieve(PSTR("President's Day "));
}
//Super Bowl (or Paskenta Road Race)
if ((DoW==1) && (Day<8)) {
// First Sunday of Feb.
Retrieve(PSTR("Super Bowl "));
}
switch (Day) {
case 2:
Retrieve(PSTR("Groundhog Day "));
break;
case 14:
Retrieve(PSTR("Valentine's Day "));
break;
case 29:
Retrieve(PSTR("Leap Day "));
break;
}
break;
// This sort of thing continues for each month of the year.
// I currently have about 150 of these "specials", and on a
// 328 there's room for one each day of the year.
case 11:
if (DoW==5) {
// Deal with Thanksgiving.
if ((Day > 21) && (Day < 29)) {
// This is the fourth Thursday of November
Retrieve(PSTR("Thanksgiving! "));
break;
}
}
switch (Day) {
// Here's an example of how to do another type of special.
// This one not only announces the birthday but displays the age.
case 19: {
byte dt, tdt, odt;
char Temp[MESSAGE_LENGTH] = "Eric is xx! ";
dt = Year + 32;
tdt = dt / 10;
odt = dt % 10;
Temp[8] = (char)tdt+48;
Temp[9] = (char)odt+48;
strcpy(Message, Temp);
break;
}
}
break;
}
}
int GetTemperature() {
////Serial.println("GetTemperature()");
// Centigrade
//return (int)(analogRead(TEMPERATURE_PIN)*tconvert);
// Fahrenheit
return (int)((analogRead(TEMPERATURE_PIN)*tconvert)*1.8 + 32);
}
void SaveStatus() {
// Saves permanent information in 1307 EEPROM.
// Information saved consists of the following bytes
// 8: Daylight Savings state
// 9: AlarmOn byte
// 10-30: sequential elements of AlarmHour array, AlarmMinute array, and AlarmDays array.
// The order is
// AlarmHour[0], AlarmMinute[0], AlarmDays[0],
// AlarmHour[1], AlarmMinute[1], AlarmDays[1],
// etc.
Wire.beginTransmission(CLOCK_ADDRESS);
// Start with memory location 8 (the first 7 are time).
Wire.send(0x08);
// Write the Daylight Savings flag.
Wire.send((byte)DaylightSavings);
// Write the AlarmOn byte.
Wire.send(AlarmOn);
// Write the array data.
for (byte j=0;j<MAX_ALARM;j++) {
Wire.send(AlarmHour[j]);
Wire.send(AlarmMinute[j]);
Wire.send(AlarmDays[j]);
}
// And done...
Wire.endTransmission();
}
void LoadStatus() {
// Recalls data from 1307 EEPROM on powerup.
// Start by pointing to the data we want
Wire.beginTransmission(CLOCK_ADDRESS);
Wire.send(0x08);
Wire.endTransmission();
// now get data bytes
Wire.requestFrom(CLOCK_ADDRESS, 2+(MAX_ALARM*3));
DaylightSavings = Wire.receive();
AlarmOn = Wire.receive();
for (byte j=0;j<MAX_ALARM;j++) {
AlarmHour[j] = Wire.receive();
AlarmMinute[j] = Wire.receive();
AlarmDays[j] = Wire.receive();
}
}
byte decToBcd(byte val) {
// Convert normal decimal numbers to binary coded decimal
return ( (val/10*16) + (val%10) );
}
byte bcdToDec(byte val) {
// Convert binary coded decimal to normal decimal numbers
return ( (val/16*10) + (val%16) );
}
void getTime(byte *Year, byte *Month, byte *Day, byte *DoW, byte *Hour, byte *Minute, byte *Second) {
// Gets the date and time from the ds1307
// Reset the register pointer
Wire.beginTransmission(CLOCK_ADDRESS);
Wire.send(0);
Wire.endTransmission();
Wire.requestFrom(CLOCK_ADDRESS, 7);
// A few of these need masks because certain bits are control bits
*Second = bcdToDec(Wire.receive() & 0x7f); // second
*Minute = bcdToDec(Wire.receive()); // minute
*Hour = bcdToDec(Wire.receive() & 0x3f); // hour, change for 12 hour am/pm
*DoW = bcdToDec(Wire.receive()); // Day of week
*Day = bcdToDec(Wire.receive()); // Day of month
*Month = bcdToDec(Wire.receive()); // month
*Year = bcdToDec(Wire.receive()); // year
}
void UpdateTimeDisplay(byte Hour, byte Minute) {
// Updates TopLine, characters 0-10, with time and alarm info.
Temp1 = Hour % 12; // Convert 24h clock to 12h
if (Temp1==0) { // 00 is actually 12 on am/pm clock.
Temp1 = 12;
}
if (Temp1 / 10) {
// write the 1 in this case.
TopLine[0] = '1';
} else {
TopLine[0] = ' ';
}
// Second digit of hour:
TopLine[1] = (char)(Temp1 % 10 + 48);
// minutes
TopLine[2] = ':';
TopLine[3] = (char)(Minute / 10 + 48);
TopLine[4] = (char)(Minute % 10 + 48);
// Take care of am/pm
if (Hour > 11) {
TopLine[5] = 'p';
} else {
TopLine[5] = 'a';
}
TopLine[6] = 'm';
TopLine[7] = ' ';
// Alarm indicator at [10] and [11]
if (AlarmOn) {
TopLine[8] = 'o';
TopLine[9] = 'n';
} else {
TopLine[8] = '-';
TopLine[9] = '-';
}
TopLine[10] = ' ';
}
void SetBottomLine(byte DoW, byte Month, byte Day) {
// Loads the day/date information into the second line of the display.
for (byte j=0;j<MESSAGE_LENGTH;j++) {
BottomLine[j] = WeekDay[DoW-1][j];
}
// Update date display
if (Month<10) {
BottomLine[11] = ' ';
} else {
BottomLine[11] = '1';
}
BottomLine[12] = (char)(Month%10)+48;
BottomLine[13] = '/';
if (Day<10) {
BottomLine[14] = (char)Day+48;
BottomLine[15] = ' ';
} else {
BottomLine[14] = (char)(Day/10)+48;
BottomLine[15] = (char)(Day%10)+48;
}
}
void UpdateTemperatureDisplay() {
// Updates TopLine, characters 12-15, with temperature.
int Temp = GetTemperature();
TopLine[11] = (char)Temp/10 + 48;
TopLine[12] = (char)Temp%10 + 48;
TopLine[13] = (char)223;
TopLine[14] = 'F';
TopLine[15] = ' ';
}
void setup() {
// Configure the switch, button, and buzzer.
pinMode(Button, INPUT);
pinMode(A, INPUT);
pinMode(B, INPUT);
pinMode(BUZZER, OUTPUT);
// Start the I2C interface to the 1307 clock
Wire.begin();
// Start the LCD
lcd.begin(2,16);
lcd.clear();
// Attach interrupt to pin A of the rotary switch
attachInterrupt(0, UpdateRotation, FALLING);
// Get things from the eeprom
LoadStatus();
// Set old information to absurd values to trigger new second/minute/hour/day actions
oldHour = 255; // These three are set to absurd values to trigger
oldMinute = 255; // the change-sensitive bits in loop().
oldSecond = 255; //
oldDay = 255; //
}
void loop() {
/* In this main loop, several things should happen.
Every quarter second:
Check the time.
Check to see if the button is pressed.
If so, handle it and come back when finished.
If an alarm is ringing, toggle the buzzer on/off.
Every second:
Update the time display.
Update temperature display.
If it's an even second, swap message/date info on line 2.
Every minute:
Check to see if an alarm should be ringing.
Turn it on or off as necessary.
Every hour:
Check for daylight savings time shifts and other specials.
Adjust backlight for daylight/evening conditions.
Every day:
Check for a message to put on line 2.
Update the display of line 2
*/
// These are the things that happen every cycle.
getTime(&Year, &Month, &Day, &DoW, &Hour, &Minute, &Second);
if (ButtonPressed()) {
DealWithButton();
}
if (AlarmRinging) {
// Toggle buzzer on/off
BuzzerState = !BuzzerState;
digitalWrite(BUZZER, BuzzerState);
}
// These are the things that happen every second:
if (Second != oldSecond) {
oldSecond = Second;
UpdateTimeDisplay(Hour, Minute);
UpdateTemperatureDisplay();
// Write to the LCD
writeLCD(0, TopLine);
if (Second%4<2) {
// Display this for 2 seconds
writeLCD(1, Message);
} else {
// Display that for 2 seconds
writeLCD(1, BottomLine);
}
}
// These are the things that happen every minute:
if (Minute != oldMinute) {
oldMinute = Minute;
// Deal with alarms
// Assume that nothing is happening.
AlarmRinging = false;
// Now check to see if anything IS happening.
if (AlarmOn) {
// Loop through the set of alarms, check which is on
for (byte j=0;j<MAX_ALARM;j++) {
if ((AlarmOn >> j) & 1) { // Check each AlarmOn bit
// alarm j is on, check time for alarm j.
if ((AlarmHour[j]==Hour) && (AlarmMinute[j]==Minute)) {
// Check day for alarm j
if ((AlarmDays[j]>>(Day-1)) & 1) {
// Alarm j should be ringing.
AlarmRinging = true;
}
}
}
}
}
}
// These are the hourly events:
if (Hour != oldHour) {
oldHour = Hour;
// Adjust backlight level
if ((Hour>20) || (Hour<6)) {
// Nighttime, so dim the lights.
analogWrite(BACKLIGHT, MIN_BACKLIGHT);
} else {
analogWrite(BACKLIGHT, MAX_BACKLIGHT);
}
// Check for time changes every Sunday
if (DoW==1) {
// It's Sunday. Check the rest of the requirements
if ((Month==3) && (Day>7) && (Day<15) && (!DaylightSavings)) {
// This is the day to "Spring Forward"
if ((Hour==2) && (Minute==0) && (Second==0)) {
// set reminder
Retrieve(PSTR("Set clocks ++ "));
// Set hour up by one.
Hour++;
setTime(Year, Month, Day, DoW, Hour, Minute, Second);
// Set DaylightSavings flag
DaylightSavings = true;
// Save DS flag to EEPROM
SaveStatus();
}
}
if ((Month==11) && (Day<8) && (DaylightSavings)) {
// This is the day to "Fall Back", and we haven't fallen back yet.
if ((Hour==2) && (Minute==0) && (Second==0)) {
// Remind people
Retrieve(PSTR("Set clocks back "));
// Decrement hour
Hour--;
setTime(Year, Month, Day, DoW, Hour, Minute, Second);
// Clear DS flag
DaylightSavings = false;
// Save DS flag to EEPROM
SaveStatus();
}
}
}
}
// These are the daily events:
if (Day != oldDay) {
oldDay = Day;
SetBottomLine(DoW, Month, Day);
// Update the day's special message
GetMessage(Year, Month, Day, DoW);
}
// Wait around a bit before repeating.
delay(250);
}
Generated by GNU enscript 1.6.4.