// Clock Two // tronixstuff.com/projects > Clock Two // John Boxall - February 2012 - March 2013 // Use Arduino v23 | CC by-sa-nc #include "Wire.h" #define DS3231_I2C_ADDRESS 0x68 // the DS3231 RTC is 0x68 int timeDelay(3000); // 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 DS3231 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 DS3231 // 2) Starts the clock // 3) Sets hour mode to 24 hour clock // Assumes you're passing in valid numbers void setDateDS3231(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(DS3231_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 DS3231 void getDateDS3231(byte *second, byte *minute, byte *hour, byte *dayOfWeek, byte *dayOfMonth, byte *month, byte *year) { // Reset the register pointer Wire.beginTransmission(DS3231_I2C_ADDRESS); Wire.write(0); Wire.endTransmission(); Wire.requestFrom(DS3231_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.begin(); //TWI Bus is formed Wire.beginTransmission(DS3231_I2C_ADDRESS); //device address and STSRT command are queued Wire.write(0x0E); //Control Register Address is queued (or Wire.send) Wire.write(0x00); //Data for Control Register is queued (or Wire.send) Wire.endTransmission(); //queued information are transferred under ACK; STOP } // 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 DS3231 hour = (h1*10)+h2; minute = (m1*10)+m2; if (hour<24 && minute <60) // in case user enters invalid time e.g. 2659h { setDateDS3231(second, minute, hour, dayOfWeek, dayOfMonth, month, year); sqwOn(); // turn on blinking decimal point again (setDateDS3231 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; getDateDS3231(&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 }