Published © GPL3+

# DIY 3D Printed Single Digit Arduino Clock

One big digit, fully functional Arduino Nano clock.

IntermediateFull instructions provided3,286

## Things used in this project

### Hardware components

 Arduino Nano R3
×1
 Maxim Integrated DS3231M - ±5ppm, I2C Real-Time Clock
×1
 General Purpose Transistor NPN
×8
 Resistor 1k ohm
×8
 LED Strip, 500 mm
×1

### Software apps and online services

 Arduino IDE

### Hand tools and fabrication machines

 Soldering iron (generic)

Read more

## Code

### Code

C/C++
```// 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
}
```

## Credits

### Mirko Pavleski

10 projects • 354 followers