// Clock Two
// tronixstuff.com/projects > Clock Two
// John Boxall - February 2012 - March 2013
// Use Arduino v23 | CC by-sa-nc
#include "Wire.h"
#define DS1307_I2C_ADDRESS 0x68 // the DS1307 RTC is 0x68
int timeDelay(15000); // duration in ms between displaying time
// digits' PORTD representation. 0~9, A~F, "-"
byte segments[]={
B00111111,B00000110,B01011011,B01001111,B01100110,B01101101,B01111101,B00000111,B01111111,B01100111,B01110111,B01111100,B00111001,B01011110,B01111001,B01110001, B01000000};
// usual DS1307 time functions
// See tronixstuff.com/tutorials > chapter twenty for more information
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val)
{
return ( (val/10*16) + (val%10) );
}
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val)
{
return ( (val/16*10) + (val%16) );
}
// 1) Sets the date and time on the ds1307
// 2) Starts the clock
// 3) Sets hour mode to 24 hour clock
// Assumes you're passing in valid numbers
void setDateDs1307(byte second, // 0-59
byte minute, // 0-59
byte hour, // 1-23
byte dayOfWeek, // 1-7
byte dayOfMonth, // 1-28/29/30/31
byte month, // 1-12
byte year) // 0-99
{
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(0);
Wire.write(decToBcd(second)); // 0 to bit 7 starts the clock
Wire.write(decToBcd(minute));
Wire.write(decToBcd(hour));
Wire.write(decToBcd(dayOfWeek));
Wire.write(decToBcd(dayOfMonth));
Wire.write(decToBcd(month));
Wire.write(decToBcd(year));
Wire.write(00010000); // sends 0x10 (hex) 00010000 (binary) to control register - turns on square wave
Wire.endTransmission();
}
// Gets the date and time from the ds1307
void getDateDs1307(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
// Reset the register pointer
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(0);
Wire.endTransmission();
Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
// A few of these need masks because certain bits are control bits
*second = bcdToDec(Wire.read() & 0x7f);
*minute = bcdToDec(Wire.read());
*hour = bcdToDec(Wire.read() & 0x3f); // Need to change this if 12 hour am/pm
*dayOfWeek = bcdToDec(Wire.read());
*dayOfMonth = bcdToDec(Wire.read());
*month = bcdToDec(Wire.read());
*year = bcdToDec(Wire.read());
}
void sqwOn() // turns on 1Hz output for decimal point blinking
{
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(0x07); // move pointer to SQW address
Wire.write(0x10); // sends 0x10 (hex) 00010000 (binary)
Wire.endTransmission();
}
void sqwOff()
// turns off decimal point blinking
{
Wire.beginTransmission(DS1307_I2C_ADDRESS);
Wire.write(0x07); // move pointer to SQW address
Wire.write(0x00); // turns the SQW pin off
Wire.endTransmission();
}
// for information on "PORTD" etc see tronixstuff.com/tutorials > chapter 43
void loopNumbers() // for testing
{
for (int a=0; a<16; a++)
{
PORTD = segments[a]; // digital 4~7 HIGH, digital 3~0 LOW
delay(100);
}
}
void blankLED()
// blanks LED display by setting all pins LOW
{
PORTD = B00000000;
}
void displayTime1(int a, int b, int c, int d)
{
int del=750; // delay between digits
int bdel=100;
PORTD = segments[a];
delay(del);
blankLED();
delay(bdel);
PORTD = segments[b];
delay(del);
PORTD = segments[16]; // display hyphen
delay(del);
PORTD = segments[c];
delay(del);
blankLED();
delay(bdel);
PORTD = segments[d];
delay(del);
blankLED(); // clear display
}
void setTime()
// user presses button A (digital 8) to enter 'set time' mode while time being displayed
// then user presses A to advance value, B to lock in. Repeat for four digits of time
{
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
int h1=0;
int h2=0;
int m1=0;
int m2=0;
boolean set=false;
blankLED();
int debounce=200;
do // get first digit of hours from user
// press digital 8 button to change from 0>1>2>0>1...
// press digital 9 to set value
{
PORTD = segments[h1];
if (digitalRead(8)==HIGH)
{
delay(debounce);
h1++;
if (h1>2)
{
h1=0;
}
PORTD = segments[h1];
}
if (digitalRead(9)==HIGH)
{
delay(debounce);
set=true;
}
}
while (set!=true);
blankLED();
set=false;
delay(500);
do // get second digit of hours from user
// press digital 8 button to change from 0>1>2>...9>0...
// press digital 9 to set value
{
PORTD = segments[h2];
if (digitalRead(8)==HIGH)
{
delay(debounce);
h2++;
if (h2>9)
{
h2=0;
}
PORTD = segments[h2];
}
if (digitalRead(9)==HIGH)
{
delay(debounce);
set=true;
}
}
while (set!=true);
blankLED();
set=false;
delay(500);
do // get first digit of minutes from user
// press digital 8 button to change from 0>1>..5>0..
// press digital 9 to set value
{
PORTD = segments[m1];
if (digitalRead(8)==HIGH)
{
delay(debounce);
m1++;
if (m1>5)
{
m1=0;
}
PORTD = segments[m1];
}
if (digitalRead(9)==HIGH)
{
set=true;
delay(debounce);
}
}
while (set!=true);
blankLED();
set=false;
delay(500);
do // get second digit of minutes from user
// press digital 8 button to change from 0>1>..9>0..
// press digital 9 to set value
{
PORTD = segments[m2];
if (digitalRead(8)==HIGH)
{
delay(debounce);
m2++;
if (m2>9)
{
m2=0;
}
PORTD = segments[m2];
}
if (digitalRead(9)==HIGH)
{
set=true;
delay(debounce);
}
}
while (set!=true);
blankLED();
set=false;
delay(500);
// now convert the user time data to variables to write to DS1307
hour = (h1*10)+h2;
minute = (m1*10)+m2;
if (hour<24 && minute <60) // in case user enters invalid time e.g. 2659h
{
setDateDs1307(second, minute, hour, dayOfWeek, dayOfMonth, month, year);
sqwOn(); // turn on blinking decimal point again (setDateDs1307 seems to turn it off...
PORTD = segments[16]; // display hyphen
delay(500);
blankLED();
delay(500);
PORTD = segments[16]; // display hyphen
delay(500);
blankLED();
}
}
void setup()
{
DDRB = B00000000; // set d13~d8 as inputs for buttons
DDRD = B11111111; // set d7~d0 as outputs for LED display
Wire.begin(); // fire up I2C bus
blankLED(); // blanks display.
sqwOn(); // turn on blinking decimal point
}
void loop()
{
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
int h1, h2, m1, m2;
getDateDs1307(&second, &minute, &hour, &dayOfWeek, &dayOfMonth, &month, &year);
h1=int(hour/10);
h2=hour%10;
m1=int(minute/10);
m2=minute%10;
displayTime1(h1,h2,m1,m2); // displays the time on the display
if (digitalRead(8)==HIGH)
{
setTime();
}
delay(timeDelay); // arbitrary delay until next time display
}
Comments