Project tutorial
Arduino Astronomical Clock

Arduino Astronomical Clock

Use this astronomical clock to automatically control light fixtures.

  • 5,886 views
  • 3 comments
  • 6 respects

Components and supplies

A000066 iso both
Arduino UNO & Genuino UNO
×1
I2C DS1307 AT24C32 Real Time Clock Module
×1
Omron 5V Relay
×1
2N2222 transistor
×1
1N4001 diode
×1
1KOhm base resistor
×1
Sparkfun 4-Digit 7-Segment Display
×1
100 Ohm Resistors
×4
150Ohm resistors
×4
2N3905 PNP transistors
×4
Fuse
×1
Metal Oxide Varistor (MOV)
×1

About this project

About this project

This product allows you to set separate turn-on and turn-off times and those repeat every day. The disadvantage of this product is that, as the seasons change, you need to constantly adjust the turn-on and turn-off times. As illustrated in Figure 1, the variation over the year (in sunset time in this example) is very significant even at my Northern California latitude, with almost three hours difference between the earlier and latest sunset times!

-

Another approach to this problem, and one that you often find in many beginner elecronics projects, is to turn the lights ON/OFF based on some photo-sensitive device; a LDR or a photo-transistor for example. While this approach can be made to work reasonably well, it's not without its issues. It's hard to choose a threshold that won't either turn the lights ON too late or turn them OFF too early. In very cloudy days, you run the risk that the system will turn on unnecessarily. Furthermore, if a leave or some other object obstructs the light sensor, the device won't work properly. It's not a very robust approach.

My objective with this project was to build a system that, given my latitude and longitude coordinates and the current time/day of the year, automatically calculates the sunrise and sunset times, controlling the lights accordingly. There are of course commercial products that do this, but it is so much more fun to build one:)

So here are the features/objectives for this project:

- Automatic sunrise and sunset relay control to turn lights (or some other AC load) on/off respectively

- 7-segment display continuously shows time, estimated sunrise and sunset time

- Simple Plus/Minus push buttons to adjust time manually (i.e, without a PC)

- Automatic Daylight Savings Time (DST) adjustments

- Battery backed time (restores correct time following a power-failure).

- USB port access for software debug and upgrade

I've been looking for an excuse to get myself into the "Arduino" world and this project seemed like a good candidate. In-fact, one can learn quite a bit about Arduino programming by implementing a system like this. And so was born the "Arduino Astronomical Clock for Automatic Light Control". Let's jump-in.

See more on my website.

Part 2 - Theory of Operation

As shown in Figure 1, the sunset (and sunrise) times follow an almost sinusoidal pattern over the year. The actual formula is a little more complicated than that, and for those curious about these things, there is an excellent resource at this website with more details:
http://williams.best.vwh.net/sunrise_sunset_algorithm.htm

The beauty of the Arduino open-source community is that you'll often find someone already implemented code to do something similar to what you are intending to do. This project is no exception (see "Credits" section at the end for more info), and fortunately for me, the good folks at swfltek.com produced the "Timelord" library:

http://www.swfltek.com/arduino/timelord.html

The "Timelord" library does a great job of calculating sunrise and sunset times for a given latitude/longitude and present time. The library also includes a handy automatic DST time conversion method that I used as well in this project.

The code must also take care of determining current time, driving the 7-segment display, and handle the time adjustment buttons. For the time-keeping function, I decided to use an inexpensive DS1307 Real Time clock (RTC) from ebay. The great thing about this item is that it is battery backed, so once time is set for the first time, it remains (relatively) accurate even if there's a power failure. Some drift is expected over time with such a budget oscillator, but the time adjustment buttons should enable us to compensate that should it be needed. So far, it has proven quite accurate. There are also equivalent modules from Adafruit or Sparkfun that you could use.

The 4-digit seven segment display is driven in the common time-multiplexed way . For the manual (button driven) time adjustment, I chose a PLUS/MINUS three-speed button arrangement. This is my favorite (arguably most elegant) clock time adjustment method. My car uses it, and I liked it so much that I decided to replicate it in software. Basically the PLUS button increments the time whereas the MINUS decrements it. If you hold any of these buttons for longer than 4s, then it enters a second speed, and later on a third speed where the increment (decrement) is faster. It's intuitive, simple, and works quite well.

So without further ado, let's look at the implementation.

Images (Figures)

Part 3 - Hardware

The Arduino is the "brains" of the project. The Arduino Uno board is considered the 'reference' platform in the Arduino family, and it's the one I used (also because I had one just laying around). I reckon you could also use an Arduino Nano for a smaller footprint. Most of the I/Os were used in this project, so I wouldn't recommend a limited I/O version. See Figure 2 for a block diagram.

The Uno's digital I/O #13 (configured as output) controls the LED on-board and also turns ON the external relay that controls AC power. I could have used a "relay shield", but my philosophy is to use first what I already have on the shop, so I built one around an Omron 5V relay and a 2N2222 transistor with 1KOhm base resistor (see Figure 3). A 1N4001 diode protects the transistor from over-voltage when the relay switches state. As an added convenience, the switch S allows the user to force the relay ON (manual override) or put it into normal "AUTO" mode, controlled by the Arduino. I recommend addin a fuse to the AC circuit for protection as shown in the figure. The AC adpater also connects 'downstream' from the fuse so it is also protected.

In keeping with my re-use philosophy, I built my 7-segment display from individual segments I already owned (Figure 5). It's a lot of soldering work and you may save yourself some work by buying a pre-assembled module. These were common-anode type displays, so I used 2N3905 PNP transistors for the multiplexing and as a consequence the Arduino outputs are active Low. This can easily be changed in the code in case of common-cathode displays, NPN transistors and active High outputs. Google around for more info if you are not familiar with this driving arrangement. Series 150Ohm resistors (in this case resistor array) limits the I/O current through the ATmega pins. Notice that I don't drive the decimal points in the segments so only 7 segment connections are needed (plus 4 multiplexing enables). See Figure 5 and the circuit in Figure 6.

The time-adjustment push-buttons are connected to A0 and A1 inputs (configured as digital Inputs) and must include pull-up resistors. Figure 7 shows the simple circuit.

The RTC module connects through I2C to the A4 and A5 Arduino I/Os. Finally, the 5V power supply (Figure 8) is provided from a re-purposed cell-phone wall wart. This supply is rated at 5.2V 400 mA. Following some measurements, I figured it's an unregulated design, so with 100 mA load it actually outputs in the range of 7 to 8V. This is perfectly fine since the Arduino DC input includes a 5V regulator. The project consumes less than 100 mA in normal operation. 

Code

Astronomical_Night_Lamp.inoC/C++
Turns a relay driven through LED I/O #13 ON/OFF at sunset/sunrise according to the current
/* Astronomical Night Lamp by Paulo Oliveira. www.paulorenato.com
 * Turns a relay driven through LED I/O #13 ON/OFF at sunset/sunrise according to the current
 * date andthe user's Lattitude and Longitude. Uses ad DS1307 RTC for time and battery backup.
 * Displays time, sunrise and sunset on a 4x 7-segment display. Full article at:
 * http://paulorenato.com/joomla/index.php?option=com_content&view=article&id=125&Itemid=4
 */

/******************* CONSTANTS AND VARIABLES *******************
****************************************************************/
#include <Time.h>  
#include <TimeLord.h>
#include <Wire.h>       // Needed for I2C communication
#include <DS1307RTC.h>  // a basic DS1307 library that returns time as a time_t

#define DS1307_ADDRESS 0x68
#define LED 13 //LED night light (or Relay control). Default in Arduino for test
#define SUNS 1
#define SUNR 2
#define TEMPO 3
#define DEBUG 1  // Set to 1 to enable debug messages through serial port monitor
#define FAST_THRESHOLD 50 // Button thresholds. Controls timing. Makes code pretty.
#define SUPER_FAST_THRESHOLD 150
#define SUPER_FAST_DIVIDER 1
#define FAST_DIVIDER 4
#define SLOW_DIVIDER 25

const int TIMEZONE = -8; //PST
const float LATITUDE = 38.65, LONGITUDE = -121.15; // set your position here

TimeLord myLord; // TimeLord Object, Global variable
byte sunTime[]  = {0, 0, 0, 1, 1, 13}; // 17 Oct 2013
int minNow, minLast = -1, hourNow, hourLast = -1, minOfDay; //time parts to trigger various actions.                               // -1 init so hour/min last inequality is triggered the first time around
int mSunrise, mSunset; //sunrise and sunset expressed as minute of day (0-1439)
// Need to adapt this according to the actual physical connections:
int digit1 = 12; //PWM Display 
int digit2 = 11; //PWM Display
int digit3 = 10; //PWM Display 
int digit4 = 9; //PWM Display

//Pin mapping for seven-segment drive
int segG = 8; //digG
int segF = 7; //digF
int segC = 6; //digC
int segA = 5; //digA
int segB = 4; //digB
int segD = 3; //digD
int segE = 2; //digE

//Push Buttons for time adjust. Note Analog A0-A5 => [14 ... 19]
int BTN_PLUS = 14; //A0
int BTN_MINUS = 15; //A1


/************************ ARDUINO SETUP  ***********************
****************************************************************/
void setup()  {
  Serial.begin(9600);
  while (!Serial) ; // Needed for Leonardo only
  /* Set Pin Modes Appropriately */
  pinMode(LED, OUTPUT);
  pinMode(segA, OUTPUT);
  pinMode(segB, OUTPUT);
  pinMode(segC, OUTPUT);
  pinMode(segD, OUTPUT);
  pinMode(segE, OUTPUT);
  pinMode(segF, OUTPUT);
  pinMode(segG, OUTPUT);
  pinMode(digit1, OUTPUT);
  pinMode(digit2, OUTPUT);
  pinMode(digit3, OUTPUT);
  pinMode(digit4, OUTPUT);
  
  pinMode(BTN_PLUS, INPUT);
  pinMode(BTN_MINUS, INPUT);
  
  /* TimeLord Object Initialization */
  myLord.TimeZone(TIMEZONE * 60);
  myLord.Position(LATITUDE, LONGITUDE);
  myLord.DstRules(3,2,11,1,60); // DST Rules for USA
  
  setSyncProvider(RTC.get);   // the function to get the time from the RTC
  if(timeStatus()!= timeSet) 
     Serial.println("Unable to sync with the RTC");
  else
     Serial.println("RTC has set the system time");  
 
}

/******************** MAIN LOOP STARTS HERE  *******************
****************************************************************/
void loop(){   
  if (timeStatus()!= timeNotSet) {
    digitalClockDisplay();  
    check_buttons();
    minNow = minute();
    if (minNow != minLast) {
        minLast = minNow;
        hourNow = hour();
        minOfDay = hourNow * 60 + minNow; //minute of day will be in the range 0-1439
        #if DEBUG == 1
          Serial.print(" hourNow");
          Serial.print(hourNow);
          Serial.print(" minNow");
          Serial.print(minNow);
          Serial.print("  minOfDay:");
          Serial.print(minOfDay);
          Serial.print("  minLast:");
          Serial.print(minLast);
          Serial.print("  hourLast:");
          Serial.print(hourLast);
          Serial.println();
        #endif
        if (hourNow != hourLast) { // Noting that the Sunrise/Sunset is only calculated every hour => less power. 
      /* Sunrise: */
      sunTime[3] = day(); // Uses the Time library to give Timelord the current date
      sunTime[4] = month();
            sunTime[5] = year();
      myLord.SunRise(sunTime); // Computes Sun Rise. Prints:
      mSunrise = sunTime[2] * 60 + sunTime[1];
      #if DEBUG == 1
                          Serial.print("SUNRISE:");
          DisplayTime(sunTime);
                        #endif
      /* Sunset: */
      sunTime[3] = day(); // Uses the Time library to give Timelord the current date
      sunTime[4] = month();
            sunTime[5] = year();
      myLord.SunSet(sunTime); // Computes Sun Set. Prints:
      mSunset = sunTime[2] * 60 + sunTime[1];
            #if DEBUG == 1
              Serial.print("SUNSET:");
              DisplayTime(sunTime);
            #endif
            hourLast = hourNow;
       }
        digitalWrite(LED, minOfDay < mSunrise || minOfDay >= mSunset);
        #if DEBUG == 1
          Serial.print("  mSunrise:");
          Serial.print(mSunrise);
          Serial.print("  mSunset:");
          Serial.print(mSunset);
          Serial.print("  LED:");
          Serial.print(minOfDay < mSunrise || minOfDay >= mSunset);
          Serial.println();
        #endif
        
        // if (minOfDay == mSunrise || minOfDay == mSunset) whistle(); Maybe cute to add sound later
    } // End: if (minNow != minLast)
  } // End:  if (timeStatus()!= timeNotSet)
} // End loop()

/************************* FUNCTIONS  **************************
****************************************************************/

void digitalClockDisplay(){
// digital clock display of the time. 
// It cycles through time->sunrise->sunset
  int secondsNow; 
  int offset;
  byte DisplayTime[] = {0, 0, 0, 1, 1, 13};; // The time to display on 7-segment
  byte SunriseTime[] = {0, 0, 0, 1, 1, 13};; // The sunrise time to display on 7-segment
  byte SunsetTime[] = {0, 0, 0, 1, 1, 13};; // The sunset time to display on 7-segment
  
  #if DEBUG == 1 // Serial still displays actual time; not display time.
    Serial.print(hour());
    printDigits(minute());
    printDigits(second());
    Serial.print(" ");
    Serial.print(day());
    Serial.print(" ");
    Serial.print(month());
    Serial.print(" ");
    Serial.print(year()); 
    Serial.println(); 
  #endif
  
  secondsNow = second();
  DisplayTime[5] = year();
  DisplayTime[4] = month();
  DisplayTime[3] = day();
  DisplayTime[2] = hour();
  DisplayTime[1] = minute();
  DisplayTime[0] = second();
  myLord.DST(DisplayTime); // Adjust for DST for 7-segment display 
  // Sunrise
  SunriseTime[5] = year();
  SunriseTime[4] = month();
  SunriseTime[3] = day();
  SunriseTime[2] = int(mSunrise/60);
  SunriseTime[1] = mSunrise % 60;
  SunriseTime[0] = second();
  myLord.DST(SunriseTime); // Adjust for DST for 7-segment display 
  // Sunset
  SunsetTime[5] = year();
  SunsetTime[4] = month();
  SunsetTime[3] = day();
  SunsetTime[2] = int(mSunset/60);
  SunsetTime[1] = mSunset % 60;
  SunsetTime[0] = second();
  myLord.DST(SunsetTime); // Adjust for DST for 7-segment display 
  
  // Change the display depending on seconds() so it cycles time->sunrise->sunset
  // 0-2 Display "T"
  // 2 - 20 Display Actual Time
  // 20 - 22 Display SS
  // 22 - 40 Display Sunset Time
  // 40 - 42 Display SR
  // 42 - 60 Display Sunrise Time
  if (secondsNow <= 2)
        displayNumber(0, TEMPO);
  else if ((secondsNow > 2) && (secondsNow <= 20))
        displayHourMinute(DisplayTime[2], DisplayTime[1]);
  else if ((secondsNow > 20) && (secondsNow <= 22))
        displayNumber(0, SUNS);
  else if ((secondsNow > 22) && (secondsNow <= 40))
        displayHourMinute(SunsetTime[2], SunsetTime[1]);
  else if ((secondsNow > 40) && (secondsNow <= 42))
        displayNumber(0, SUNR);
  else if ((secondsNow > 42) && (secondsNow <= 60))
        displayHourMinute(SunriseTime[2], SunriseTime[1]);
  else
        Serial.print("FAILED");  
}

void printDigits(int digits){
  // utility function for digital clock display: prints preceding colon and leading 0
  Serial.print(":");
  if(digits < 10)
    Serial.print('0');
  Serial.print(digits);
}

void DisplayTime(uint8_t * when)
{
Serial.print(when[2]);
printDigits(when[1]);
printDigits(when[0]);
Serial.print(" ");
Serial.print(when[4]);
Serial.print("/");
Serial.print(when[3]);
Serial.print("/");
Serial.print(when[5]); 
Serial.println(); 
}

//Given a number, we display 10:22
//After running through the 4 numbers, the display is left turned off

//Display brightness
//Each digit is on for a certain amount of microseconds
//Then it is off until we have reached a total of 20ms for the function call
//Let's assume each digit is on for 1000us
//Each digit is on for 1ms, there are 4 digits, so the display is off for 16ms.
//That's a ratio of 1ms to 16ms or 6.25% on time (PWM).
//Let's define a variable called brightness that varies from:
//5000 blindingly bright (15.7mA current draw per digit)
//2000 shockingly bright (11.4mA current draw per digit)
//1000 pretty bright (5.9mA)
//500 normal (3mA)
//200 dim but readable (1.4mA)
//50 dim but readable (0.56mA)
//5 dim but readable (0.31mA)
//1 dim but readable in dark (0.28mA)

void displayNumber(int toDisplay, int character) {
#define DISPLAY_BRIGHTNESS  3000

// toDisplay is the number to display if character == 0
// if character is not 0, then a special character (SUNR/SUNS/TEMPO) is displayed instead

// These would be used for common anode displays
// #define DIGIT_ON  HIGH
// #define DIGIT_OFF  LOW

// Common Cathode diplay:
#define DIGIT_ON  LOW
#define DIGIT_OFF  HIGH

  long beginTime = millis();

  for(int digit = 4 ; digit > 0 ; digit--) {

    //Turn on a digit for a short amount of time
    switch(digit) {
    case 1:
      digitalWrite(digit1, DIGIT_ON);
      break;
    case 2:
      digitalWrite(digit2, DIGIT_ON);
      break;
    case 3:
      digitalWrite(digit3, DIGIT_ON);
      break;
    case 4:
      digitalWrite(digit4, DIGIT_ON);
      break;
    }

    if (character == 0) {
    //Turn on the right segments for this digit
    lightNumber(toDisplay % 10);
    toDisplay /= 10;
    }
    else {
      switch ( character ) {
      case SUNS:
      lightNumber(11); // Sunset Character
      break;
      case SUNR:
      lightNumber(12); // Sunrise Character
      break;
      case TEMPO:
      lightNumber(13); // Time Character
      break;
      }
    }
      

    delayMicroseconds(DISPLAY_BRIGHTNESS); 
    //Display digit for fraction of a second (1us to 5000us)

    //Turn off all segments
    lightNumber(10); 

    //Turn off all digits
    digitalWrite(digit1, DIGIT_OFF);
    digitalWrite(digit2, DIGIT_OFF);
    digitalWrite(digit3, DIGIT_OFF);
    digitalWrite(digit4, DIGIT_OFF);
  }

  // while( (millis() - beginTime) < 10) ; TEST TO INCREMENT BRIGHTNESS
  while( (millis() - beginTime) < 5) ; 
  //Wait for time to pass before we paint the display again
}

//Given a number, turns on those segments
//If number == 10, then turn off number
void lightNumber(int numberToDisplay) {

#define SEGMENT_ON  LOW
#define SEGMENT_OFF HIGH

  switch (numberToDisplay){

  case 0:
    digitalWrite(segA, SEGMENT_ON);
    digitalWrite(segB, SEGMENT_ON);
    digitalWrite(segC, SEGMENT_ON);
    digitalWrite(segD, SEGMENT_ON);
    digitalWrite(segE, SEGMENT_ON);
    digitalWrite(segF, SEGMENT_ON);
    digitalWrite(segG, SEGMENT_OFF);
    break;

  case 1:
    digitalWrite(segA, SEGMENT_OFF);
    digitalWrite(segB, SEGMENT_ON);
    digitalWrite(segC, SEGMENT_ON);
    digitalWrite(segD, SEGMENT_OFF);
    digitalWrite(segE, SEGMENT_OFF);
    digitalWrite(segF, SEGMENT_OFF);
    digitalWrite(segG, SEGMENT_OFF);
    break;

  case 2:
    digitalWrite(segA, SEGMENT_ON);
    digitalWrite(segB, SEGMENT_ON);
    digitalWrite(segC, SEGMENT_OFF);
    digitalWrite(segD, SEGMENT_ON);
    digitalWrite(segE, SEGMENT_ON);
    digitalWrite(segF, SEGMENT_OFF);
    digitalWrite(segG, SEGMENT_ON);
    break;

  case 3:
    digitalWrite(segA, SEGMENT_ON);
    digitalWrite(segB, SEGMENT_ON);
    digitalWrite(segC, SEGMENT_ON);
    digitalWrite(segD, SEGMENT_ON);
    digitalWrite(segE, SEGMENT_OFF);
    digitalWrite(segF, SEGMENT_OFF);
    digitalWrite(segG, SEGMENT_ON);
    break;

  case 4:
    digitalWrite(segA, SEGMENT_OFF);
    digitalWrite(segB, SEGMENT_ON);
    digitalWrite(segC, SEGMENT_ON);
    digitalWrite(segD, SEGMENT_OFF);
    digitalWrite(segE, SEGMENT_OFF);
    digitalWrite(segF, SEGMENT_ON);
    digitalWrite(segG, SEGMENT_ON);
    break;

  case 5:
    digitalWrite(segA, SEGMENT_ON);
    digitalWrite(segB, SEGMENT_OFF);
    digitalWrite(segC, SEGMENT_ON);
    digitalWrite(segD, SEGMENT_ON);
    digitalWrite(segE, SEGMENT_OFF);
    digitalWrite(segF, SEGMENT_ON);
    digitalWrite(segG, SEGMENT_ON);
    break;

  case 6:
    digitalWrite(segA, SEGMENT_ON);
    digitalWrite(segB, SEGMENT_OFF);
    digitalWrite(segC, SEGMENT_ON);
    digitalWrite(segD, SEGMENT_ON);
    digitalWrite(segE, SEGMENT_ON);
    digitalWrite(segF, SEGMENT_ON);
    digitalWrite(segG, SEGMENT_ON);
    break;

  case 7:
    digitalWrite(segA, SEGMENT_ON);
    digitalWrite(segB, SEGMENT_ON);
    digitalWrite(segC, SEGMENT_ON);
    digitalWrite(segD, SEGMENT_OFF);
    digitalWrite(segE, SEGMENT_OFF);
    digitalWrite(segF, SEGMENT_OFF);
    digitalWrite(segG, SEGMENT_OFF);
    break;

  case 8:
    digitalWrite(segA, SEGMENT_ON);
    digitalWrite(segB, SEGMENT_ON);
    digitalWrite(segC, SEGMENT_ON);
    digitalWrite(segD, SEGMENT_ON);
    digitalWrite(segE, SEGMENT_ON);
    digitalWrite(segF, SEGMENT_ON);
    digitalWrite(segG, SEGMENT_ON);
    break;

  case 9:
    digitalWrite(segA, SEGMENT_ON);
    digitalWrite(segB, SEGMENT_ON);
    digitalWrite(segC, SEGMENT_ON);
    digitalWrite(segD, SEGMENT_ON);
    digitalWrite(segE, SEGMENT_OFF);
    digitalWrite(segF, SEGMENT_ON);
    digitalWrite(segG, SEGMENT_ON);
    break;

  case 10:
    digitalWrite(segA, SEGMENT_OFF);
    digitalWrite(segB, SEGMENT_OFF);
    digitalWrite(segC, SEGMENT_OFF);
    digitalWrite(segD, SEGMENT_OFF);
    digitalWrite(segE, SEGMENT_OFF);
    digitalWrite(segF, SEGMENT_OFF);
    digitalWrite(segG, SEGMENT_OFF);
    break;
    
   case 11: // S Character
    digitalWrite(segA, SEGMENT_ON);
    digitalWrite(segB, SEGMENT_OFF);
    digitalWrite(segC, SEGMENT_ON);
    digitalWrite(segD, SEGMENT_ON);
    digitalWrite(segE, SEGMENT_OFF);
    digitalWrite(segF, SEGMENT_ON);
    digitalWrite(segG, SEGMENT_ON);
    break;
    
    case 12: // R Character
    digitalWrite(segA, SEGMENT_ON);
    digitalWrite(segB, SEGMENT_ON);
    digitalWrite(segC, SEGMENT_ON);
    digitalWrite(segD, SEGMENT_OFF);
    digitalWrite(segE, SEGMENT_ON);
    digitalWrite(segF, SEGMENT_ON);
    digitalWrite(segG, SEGMENT_ON);
    break;
        
    case 13: // T Character
    digitalWrite(segA, SEGMENT_ON);
    digitalWrite(segB, SEGMENT_OFF);
    digitalWrite(segC, SEGMENT_OFF);
    digitalWrite(segD, SEGMENT_OFF);
    digitalWrite(segE, SEGMENT_ON);
    digitalWrite(segF, SEGMENT_ON);
    digitalWrite(segG, SEGMENT_OFF);
    break;
  }
}


void displayHourMinute(int Disphour, int Dispminute) {

  int NumberToDisplay;
  NumberToDisplay = Disphour*100 + Dispminute;
  displayNumber(NumberToDisplay, 0);

}

void check_buttons() {
// Implements Plus/Minus time adjustment with three-speeds
byte minutes;
byte hours;
int count = 0;
int divider = SLOW_DIVIDER;

//Retrieve current time:
minutes = minute();
hours = hour();
if (!digitalRead(BTN_PLUS) || !digitalRead(BTN_MINUS)) { // only executes if one of the buttons was pressed
Serial.println("After the if any button");

  while (!digitalRead(BTN_PLUS)) {
        Serial.println("After the while() PLUS");
      if ((count % divider) == 0) {
         IncrementTime(hours, minutes);
         if ((count >= FAST_THRESHOLD) && (count < SUPER_FAST_THRESHOLD) ) divider = FAST_DIVIDER; // Speeds-up after a few seconds
         if (count > SUPER_FAST_THRESHOLD ) divider = SUPER_FAST_DIVIDER;
         }
    displayHourMinute(hours, minutes);
                count++;
  }

  while (!digitalRead(BTN_MINUS)) {
        Serial.println("After the while() MINUS");
      if ((count % divider) == 0) {
         DecrementTime(hours, minutes);
         if ((count >= FAST_THRESHOLD) && (count < SUPER_FAST_THRESHOLD) ) divider = FAST_DIVIDER; // Speeds-up after a few seconds
         if (count > SUPER_FAST_THRESHOLD ) divider = SUPER_FAST_DIVIDER;
         }
    displayHourMinute(hours, minutes);
                count++;
  }

  // SET the RTC once button is released
  Wire.beginTransmission(DS1307_ADDRESS);
  Wire.write(0x00); //stop Oscillator

  Wire.write(decToBcd(3)); // seconds = 3 so it moves to clock display on return
  Wire.write(decToBcd(minutes));
  Wire.write(decToBcd(hours));
  // Retains current day/week/moth/year settings
  Wire.write(decToBcd(weekday()));
  Wire.write(decToBcd(day()));
  Wire.write(decToBcd(month()));
  Wire.write(decToBcd(year()));
  Wire.write(0x00); //re-start 
  Wire.endTransmission();
  setSyncProvider(RTC.get); // Need to re-sync Time with the RTC
  Serial.println("After the Wire.endTransmission()");
  } // End if  
}

void IncrementTime(byte &hours, byte &minutes) {
  // Increment minutes and hours
  minutes++;
  if ( minutes > 59) {
    minutes = 0;
    hours++;
    }
  if ( hours > 23 ) hours = 0;
}

void DecrementTime(byte &hours, byte &minutes) {
  // Decrement minutes and hours
  if ( minutes != 0) {
    minutes = minutes - 1;
  }
  else {
    minutes = 59;
    if ( hours > 0 ) {
      hours = hours - 1 ;
      }
    else {
      hours = 23;
      }
  }
}

byte decToBcd(byte val){
// Convert normal decimal numbers to binary coded decimal
  return ( (val/10*16) + (val%10) );
}

Comments

Author

Default
paulo
  • 1 project
  • 0 followers

Additional contributors

Published on

February 3, 2014

Members who respect this project

16089940DefaultDefaultPhoto

and 2 others

Project replicated by

16089940
See similar projects
you might like

Similar projects you might like

Master Clock

Project tutorial by Jed Hodson

  • 8,497 views
  • 4 comments
  • 12 respects

Arduino Clock

Project tutorial by Arduino_Scuola

  • 26,780 views
  • 0 comments
  • 12 respects

Clock Set Date Time

Project tutorial by Tittiamo

  • 34,199 views
  • 26 comments
  • 43 respects

Digital Clock with Arduino, RTC and Shift Register 74HC595

Project tutorial by LAGSILVA

  • 20,727 views
  • 16 comments
  • 46 respects

Enigma QR Clock

Project tutorial by Arduino Enigma

  • 6,075 views
  • 0 comments
  • 13 respects

Arduino "Atomic" Grandfather Clock

Project tutorial by oliverb

  • 5,851 views
  • 1 comment
  • 7 respects
Add projectSign up / Login