# Beautiful Arduino Binary Clock

22,288

105

34

## Introduction: Beautiful Arduino Binary Clock

In this Instructable I'll be showing how to make a Aduino Binary Clock. Starting with this you can make a binary clock with any design and format as you like, just like any other clock.

## Step 1: What Is a Binary Clock?

A Binary number is a number expressed in the binary numeral system or base-2 numeral system which represents numeric values using two different symbols: typically 0 (zero) and 1 (one). Because of its straightforward implementation in digital electronic circuitry using logic gates, the binary system is used internally by almost all modern computers and computer-based devices. Counting in binary is similar to counting in any other number system. Beginning with a single digit, counting proceeds through each symbol, in increasing order:

DecimalBinary 00 11 210 311 4100 5101 6110 7111 81000 91001 101010 111011 121100 131101 141110 151111

A binary clock is a clock that displays the time of day in a binary format. This projects aproach is the same as binary-coded decimal clocks, where is used six columns of LEDs to represent zeros and ones. Each column represents a single decimal digit, a format known as binary-coded decimal (BCD). Each row represents powers of two, from 2^0 (or 1), up to 2^3 (or 8). So all you have to do when reading the clock is to sum the value of the row if the LED is on. For instance, the first column from the right to the left of the image above have the 8-LED and the 1-LED turned on, adding 8 with 1 you get 9, so the ones of the seconds is 9, next column is the tens of the seconds, and the only turned on is the 4-LED, so you end up with a total value of 49 seconds, and the same for minutes and hours. Please note that here the hour is shown in the 24-h format.

## Step 2: Materials

1. Arduino Pro Mini 328 5V (I used this one, but virtually any other Arduino will suit, and if you have never used the Pro Mini you will probably need the CP2102 to connect to the computer, you can buy the two together in this link)
2. DS1302 (I bought this one before I read that the use of DS3231 is advised, please note that the programming is made for the DS1302 module)

3. 20x 10mm Diffused Warm LEDs (buying spare parts is recommended)

4. 20x 10Ω resistors (you can find this easily at a local store, again, buying spare parts is recommended)

5. 2x simple push buttons (again, you can find this easily at a local store and buying spare parts is recommended)

6. 2x 10kΩ resistors (used here as Pull-up Resistors, easily found at a local store, buying spare parts is recommended)

## Step 3: Prototype

I started making a prototype in the protoboard. Note that it is not needed for the final project, I just wanted to see how the LED matrix, the Arduino and the clock module could work together. For this part I used the Arduino Mega and simple red LEDs. It all worked well and as expected.

## Step 4: Box

I wanted it to be at the same time futuristic (because it's a binary clock) and natural. The way was to make a wooden box with 10mm warm-colored LEDs on the front, the wood would be a contrast to the binary clock and give it a more retro look. I lack both ability and tools for woodworking, so I drew what I wanted and explained it to a local woodworker who makes handmade furniture, then he made the box. It is composed of two halves, that open to access the inside.

## Step 5: Circuit

The LEDs are arranged in a matrix, so it use less arduino pins and still don't make use of a separate controller. This way 9 pins are used for the matrix. If you don't know what a LED matrix is, it is recommended that you read more about it (there is a great explanation in this link). After making the LED matrix like the image above, I soldered the connections to arduino, then the clock module, the buttons for the time adjustment, and at last the power supply. There is still some work to do in that part, but it's just finishing.

## Step 6: Code

The code is based in the example of the Arduino Playgroud post about the DS1302 clock module. With the modifications to show the time on the LED matrix.

```// Binary Clock v0.2
// Gabriel J. Pensky

// DS1302 ----------------------------------------------------------------------------------------------------
// Set your own pins with these defines !
#define DS1302_SCLK_PIN   13    // Arduino pin for the Serial Clock
#define DS1302_IO_PIN     12    // Arduino pin for the Data I/O
#define DS1302_CE_PIN     11    // Arduino pin for the Chip Enable

// Macros to convert the bcd values of the registers to normal
// integer variables.
// The code uses separate variables for the high byte and the low byte
// of the bcd, so these macros handle both bytes separately.
#define bcd2bin(h,l)    (((h)*10) + (l))
#define bin2bcd_h(x)   ((x)/10)
#define bin2bcd_l(x)    ((x)%10)

// Register names.
// Since the highest bit is always '1',
// the registers start at 0x80
// If the register is read, the lowest bit should be '1'.
#define DS1302_SECONDS           0x80
#define DS1302_MINUTES           0x82
#define DS1302_HOURS             0x84
#define DS1302_DATE              0x86
#define DS1302_MONTH             0x88
#define DS1302_DAY               0x8A
#define DS1302_YEAR              0x8C
#define DS1302_ENABLE            0x8E
#define DS1302_TRICKLE           0x90
#define DS1302_CLOCK_BURST       0xBE
#define DS1302_CLOCK_BURST_WRITE 0xBE
#define DS1302_RAMSTART          0xC0
#define DS1302_RAMEND            0xFC
#define DS1302_RAM_BURST         0xFE
#define DS1302_RAM_BURST_WRITE   0xFE

// Defines for the bits, to be able to change
// between bit number and binary definition.
// By using the bit number, using the DS1302
// is like programming an AVR microcontroller.
// But instead of using "(1<<X)", or "_BV(X)",
// the Arduino "bit(X)" is used.
#define DS1302_D0 0
#define DS1302_D1 1
#define DS1302_D2 2
#define DS1302_D3 3
#define DS1302_D4 4
#define DS1302_D5 5
#define DS1302_D6 6
#define DS1302_D7 7

// Bit for clock (0) or ram (1) area,
// called R/C-bit (bit in address)
#define DS1302_RC DS1302_D6

// Seconds Register
#define DS1302_CH DS1302_D7   // 1 = Clock Halt, 0 = start

// Hour Register
#define DS1302_AM_PM DS1302_D5 // 0 = AM, 1 = PM
#define DS1302_12_24 DS1302_D7 // 0 = 24 hour, 1 = 12 hour

// Enable Register
#define DS1302_WP DS1302_D7   // 1 = Write Protect, 0 = enabled

// Trickle Register
#define DS1302_ROUT0 DS1302_D0
#define DS1302_ROUT1 DS1302_D1
#define DS1302_DS0   DS1302_D2
#define DS1302_DS1   DS1302_D2
#define DS1302_TCS0  DS1302_D4
#define DS1302_TCS1  DS1302_D5
#define DS1302_TCS2  DS1302_D6
#define DS1302_TCS3  DS1302_D7

// Structure for the first 8 registers.
// These 8 bytes can be read at once with
// the 'clock burst' command.
// Note that this structure contains an anonymous union.
// It might cause a problem on other compilers.
typedef struct ds1302_struct
{
uint8_t Seconds:4;      // low decimal digit 0-9
uint8_t Seconds10:3;    // high decimal digit 0-5
uint8_t CH:1;           // CH = Clock Halt
uint8_t Minutes:4;
uint8_t Minutes10:3;
uint8_t reserved1:1;
union
{
struct
{
uint8_t Hour:4;
uint8_t Hour10:2;
uint8_t reserved2:1;
uint8_t hour_12_24:1; // 0 for 24 hour format
} h24;
struct
{
uint8_t Hour:4;
uint8_t Hour10:1;
uint8_t AM_PM:1;      // 0 for AM, 1 for PM
uint8_t reserved2:1;
uint8_t hour_12_24:1; // 1 for 12 hour format
} h12;
};
uint8_t Date:4;           // Day of month, 1 = first day
uint8_t Date10:2;
uint8_t reserved3:2;
uint8_t Month:4;          // Month, 1 = January
uint8_t Month10:1;
uint8_t reserved4:3;
uint8_t Day:3;            // Day of week, 1 = first day (any day)
uint8_t reserved5:5;
uint8_t Year:4;           // Year, 0 = year 2000
uint8_t Year10:4;
uint8_t reserved6:7;
uint8_t WP:1;             // WP = Write Protect
};

// Variables -----------------------------------------------------------------------------------------------------------
unsigned long timen = 0;
unsigned long timeb = 0;
byte s0 = B00000000;
byte s1 = B00000000;
byte m0 = B00000000;
byte m1 = B00000000;
byte h0 = B00000000;
byte h1 = B00000000;
boolean button1State = LOW;
boolean lastButton1State = LOW;
boolean b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0;

// Setup -----------------------------------------------------------------------------------------------------------------
void setup()
{
for (int i=2; i<=11; i++)
{ pinMode(i, OUTPUT);
digitalWrite(i, HIGH);}

ds1302_struct rtc;

Serial.begin(9600);

// Start by clearing the Write Protect bit
// Otherwise the clock data cannot be written
// The whole register is written,
// but the WP-bit is the only bit in that register.
DS1302_write (DS1302_ENABLE, 0);

// Disable Trickle Charger.
DS1302_write (DS1302_TRICKLE, 0x00);

// Remove the next define,
// after the right date and time are set.
//#define SET_DATE_TIME_JUST_ONCE
#ifdef SET_DATE_TIME_JUST_ONCE

// Fill these variables with the date and time.
int seconds, minutes, hours, dayofweek, dayofmonth, month, year;

// Example for april 15, 2013, 10:08, monday is 2nd day of Week.
// Set your own time and date in these variables.
seconds    = 0;
minutes    = 48;
hours      = 8;
dayofweek  = 1;  // Day of week, any day can be first, counts 1...7
dayofmonth = 19; // Day of month, 1...31
month      = 2;  // month 1...12
year       = 2017;

// Set a time and date
// This also clears the CH (Clock Halt) bit,
// to start the clock.

// Fill the structure with zeros to make
// any unused bits zero
memset ((char *) &rtc, 0, sizeof(rtc));

rtc.Seconds    = bin2bcd_l( seconds);
rtc.Seconds10  = bin2bcd_h( seconds);
rtc.CH         = 0;      // 1 for Clock Halt, 0 to run;
rtc.Minutes    = bin2bcd_l( minutes);
rtc.Minutes10  = bin2bcd_h( minutes);
// To use the 12 hour format,
// use it like these four lines:
//    rtc.h12.Hour   = bin2bcd_l( hours);
//    rtc.h12.Hour10 = bin2bcd_h( hours);
//    rtc.h12.AM_PM  = 0;     // AM = 0
//    rtc.h12.hour_12_24 = 1; // 1 for 24 hour format
rtc.h24.Hour   = bin2bcd_l( hours);
rtc.h24.Hour10 = bin2bcd_h( hours);
rtc.h24.hour_12_24 = 0; // 0 for 24 hour format
rtc.Date       = bin2bcd_l( dayofmonth);
rtc.Date10     = bin2bcd_h( dayofmonth);
rtc.Month      = bin2bcd_l( month);
rtc.Month10    = bin2bcd_h( month);
rtc.Day        = dayofweek;
rtc.Year       = bin2bcd_l( year - 2000);
rtc.Year10     = bin2bcd_h( year - 2000);
rtc.WP = 0;

// Write all clock data at once (burst mode).
DS1302_clock_burst_write( (uint8_t *) &rtc);
#endif
}

// Loop ----------------------------------------------------------------------------------------------------------
void loop()
{ ds1302_struct rtc;

for(int coln = 0; coln <=4; coln++){
digitalWrite(coln+6, HIGH);
switch (coln){
case 0:
for (int rown = 0; rown <=3; rown++){
digitalWrite(rown+2, LOW);
delayMicroseconds(100);
digitalWrite(rown+2, HIGH);
}
}break;
case 1:
for (int rown = 0; rown <=3; rown++){
digitalWrite(rown+2, LOW);
delayMicroseconds(100);
digitalWrite(rown+2, HIGH);
}
}
digitalWrite(5, LOW);
delayMicroseconds(100);
digitalWrite(5, HIGH);
}break;
case 2:
for (int rown = 0; rown <=3; rown++){
digitalWrite(rown+2, LOW);
delayMicroseconds(100);
digitalWrite(rown+2, HIGH);
}
}break;
case 3:
for (int rown = 0; rown <=3; rown++){
digitalWrite(rown+2, LOW);
delayMicroseconds(100);
digitalWrite(rown+2, HIGH);
}
}
digitalWrite(5, LOW);
delayMicroseconds(100);
digitalWrite(5, HIGH);
}break;
case 4:
for (int rown = 0; rown <=3; rown++){
digitalWrite(rown+2, LOW);
delayMicroseconds(100);
digitalWrite(rown+2, HIGH);
}
}break;

}
digitalWrite(coln+6, LOW);
}

timeb++;
}else{
timeb = 0;
}

if (timeb > 2000){
timeb = 0;
digitalWrite(5, LOW);
digitalWrite(7, HIGH);
digitalWrite(9, HIGH);
}else{
digitalWrite(2, LOW);
digitalWrite(3, LOW);
digitalWrite(4, LOW);
digitalWrite(5, LOW);
}
}
delay (500);
digitalWrite(5, HIGH);
digitalWrite(7, LOW);
digitalWrite(9, LOW);
}else{
digitalWrite(2, HIGH);
digitalWrite(3, HIGH);
digitalWrite(4, HIGH);
digitalWrite(5, HIGH);
}
}
}

case 0:
break;
case 1:
if (b1 == 0){
s0++;
if (s0 > 9){s0 = 0;}
}
}
break;
case 2:
if (b2 == 0){
s1++;
if (s1 > 5){s1 = 0;}
}
}
break;
case 3:
if (b3 ==0){
m0++;
if (m0 > 9){m0 = 0;}
}
}
break;
case 4:
if (b4 == 0){
m1++;
if (m1 > 5){m1 = 0;}
}
}
break;
case 5:
if (b5 == 0){
h0++;
if (h0 > 9){h0 = 0;}
}
}
break;
case 6:
if (b6 == 0){
h1++;
if (h0 > 3){
if (h1 > 2){h1 = 0;}
}else{
if (h1 > 1){h1 = 0;}
}
}
}
break;
case 7:
// Fill the structure with zeros to make
// any unused bits zero
memset ((char *) &rtc, 0, sizeof(rtc));

rtc.Seconds    = s0;
rtc.Seconds10  = s1;
rtc.CH         = 0;      // 1 for Clock Halt, 0 to run;
rtc.Minutes    = m0;
rtc.Minutes10  = m1;
rtc.h24.Hour   = h0;
rtc.h24.Hour10 = h1;
rtc.h24.hour_12_24 = 0; // 0 for 24 hour format
rtc.Date       = 0;
rtc.Date10     = 0;
rtc.Month      = 0;
rtc.Month10    = 0;
rtc.Day        = 0;
rtc.Year       = 0;
rtc.Year10     = 0;
rtc.WP = 0;

// Write all clock data at once (burst mode).
DS1302_clock_burst_write( (uint8_t *) &rtc);

break;
}

if (timen <= millis()-1000 && adjustStep == 0){
char buffer[80];     // the code uses 70 characters.
// Read all clock data at once (burst mode).
s0 = rtc.Seconds;
s1 = rtc.Seconds10;
m0 = rtc.Minutes;
m1 = rtc.Minutes10;
h0 = rtc.h24.Hour;
h1 = rtc.h24.Hour10;
timen = millis();
//Serial.print(h1);
//Serial.print(h0);
//Serial.print(m1);
//Serial.print(m0);
//Serial.print(s1);
//Serial.println(s0);
//Serial.println(timen);
}
}

// -------------------------------------------------------------------------------------------------------------
//
// This function reads 8 bytes clock data in burst mode
// from the DS1302.
//
// This function may be called as the first function,
// also the pinMode is set.
//
{
int i;

_DS1302_start();

// the CLOCK_BURST_READ command is issued
// the I/O-line is released for the data

for( i=0; i<8; i++)
{
}
_DS1302_stop();
}

// ---------------------------------------------------------------------------------------------------------------
// DS1302_clock_burst_write
//
// This function writes 8 bytes clock data in burst mode
// to the DS1302.
//
// This function may be called as the first function,
// also the pinMode is set.
//
void DS1302_clock_burst_write( uint8_t *p)
{
int i;

_DS1302_start();

// the CLOCK_BURST_WRITE command is issued.
// the I/O-line is not released
_DS1302_togglewrite( DS1302_CLOCK_BURST_WRITE, false);

for( i=0; i<8; i++)
{
// the I/O-line is not released
_DS1302_togglewrite( *p++, false);
}
_DS1302_stop();
}

// -----------------------------------------------------------------------------------------------------------------------
//
// This function reads a byte from the DS1302
// (clock or ram).
//
// The address could be like "0x80" or "0x81",
// the lowest bit is set anyway.
//
// This function may be called as the first function,
// also the pinMode is set.
//
{
uint8_t data;

_DS1302_start();
// the I/O-line is released for the data
_DS1302_stop();

return (data);
}

// ------------------------------------------------------------------------------------------------------------------
// DS1302_write
//
// This function writes a byte to the DS1302 (clock or ram).
//
// The address could be like "0x80" or "0x81",
// the lowest bit is cleared anyway.
//
// This function may be called as the first function,
// also the pinMode is set.
//
void DS1302_write( int address, uint8_t data)
{

_DS1302_start();
// don't release the I/O-line
// don't release the I/O-line
_DS1302_togglewrite( data, false);
_DS1302_stop();
}

// --------------------------------------------------------------------------------------------------------------------
// _DS1302_start
//
// A helper function to setup the start condition.
//
// An 'init' function is not used.
// But now the pinMode is set every time.
// That's not a big deal, and it's valid.
// At startup, the pins of the Arduino are high impedance.
// Since the DS1302 has pull-down resistors,
// the signals are low (inactive) until the DS1302 is used.
void _DS1302_start( void)
{
digitalWrite( DS1302_CE_PIN, LOW); // default, not enabled
pinMode( DS1302_CE_PIN, OUTPUT);

digitalWrite( DS1302_SCLK_PIN, LOW); // default, clock low
pinMode( DS1302_SCLK_PIN, OUTPUT);

pinMode( DS1302_IO_PIN, OUTPUT);

digitalWrite( DS1302_CE_PIN, HIGH); // start the session
delayMicroseconds( 4);           // tCC = 4us
}

// ------------------------------------------------------------------------------------------------------------------------
// _DS1302_stop
//
// A helper function to finish the communication.
//
void _DS1302_stop(void)
{
// Set CE low
digitalWrite( DS1302_CE_PIN, LOW);

delayMicroseconds( 4);           // tCWH = 4us
}

// -------------------------------------------------------------------------------------------------------------------------
//
// A helper function for reading a byte with bit toggle
//
// This function assumes that the SCLK is still high.
//
{
uint8_t i, data;

data = 0;
for( i = 0; i <= 7; i++)
{
// Issue a clock pulse for the next databit.
// If the 'togglewrite' function was used before
// this function, the SCLK is already high.
digitalWrite( DS1302_SCLK_PIN, HIGH);
delayMicroseconds( 1);

// Clock down, data is ready after some time.
digitalWrite( DS1302_SCLK_PIN, LOW);
delayMicroseconds( 1);        // tCL=1000ns, tCDD=800ns

// read bit, and set it in place in 'data' variable
}
return( data);
}

// -----------------------------------------------------------------------------------------------------------------------
// _DS1302_togglewrite
//
// A helper function for writing a byte with bit toggle
//
// The 'release' parameter is for a read after this write.
// It will release the I/O-line and will keep the SCLK high.
//
void _DS1302_togglewrite( uint8_t data, uint8_t release)
{
int i;

for( i = 0; i <= 7; i++)
{
// set a bit of the data on the I/O-line
delayMicroseconds( 1);     // tDC = 200ns

// clock up, data is read by DS1302
digitalWrite( DS1302_SCLK_PIN, HIGH);
delayMicroseconds( 1);     // tCH = 1000ns, tCDH = 800ns

if( release && i == 7)
{
// If this write is followed by a read,
// the I/O-line should be released after
// the last bit, before the clock line is made low.
// This is according the datasheet.
// I have seen other programs that don't release
// the I/O-line at this moment,
// and that could cause a shortcut spike
// on the I/O-line.
pinMode( DS1302_IO_PIN, INPUT);

// For Arduino 1.0.3, removing the pull-up is no longer needed.
// Setting the pin as 'INPUT' will already remove the pull-up.
// digitalWrite (DS1302_IO, LOW); // remove any pull-up
}
else
{
digitalWrite( DS1302_SCLK_PIN, LOW);
delayMicroseconds( 1);       // tCL=1000ns, tCDD=800ns
}
}
}
```

Runner Up in the
Lights Contest 2017

Runner Up in the
Microcontroller Contest 2017

## Recommendations

31 4.5K
1 76 9.6K
227 14K
168 14K

• ### Make It Bridge

Could someone write this for the RTC I2C DS1307 AT24C32 Real Time Clock Module?
And/or clean up the comments in this code..... they are somewhat vague or confusing for a noob like me.

How can we connect female micro usb port to the circuit. Plz anyone reply

Same here. Cannot find the issue

Hello, the code uploads to the Arduino and is verified, but the LEDs seem to flash incorrectly (from side to side instead of up and down), I have checked my circuit and it all checks out. I was just wondering if anyone else has had this problem?

Hello I dont have the ds1302 neither the cp2102, Can I make it on the protoboard without problems or I need them?

Hi friend...can you help me.
How to build arduino binary clock using dmd p10..

why doesn't it work on proteus simulation? can you help me?

Updated code with exact same wiring diagram to work with DS3231. Changed remaining parts for readability. Also changed button mode, no longer need to hold 2 seconds to change min or hour, an instant press/release will change and press plus hold will change every half second. Hope this helps someone.

https://github.com/shmoesolid/DS3231_Binary_Clock

Updated to version v0.2.s.2 which fixes the LED flicker/dimming by stabilizing the refresh rate of the LEDs to a constant rate. The same wiring diagram still applies.

Hi. Perhaps you know what the problem is? I make a clock on ds3231 with your code, in general everything works, but after turning off the power, the time is reset and when I turn it on again, I have to reinstall the time.
A battery is installed in the RTC module, and the time should be saved! But this does not happen ...

When you set your time on the first run, that time is then stored in the chip and the battery should maintain that time. If you're rerunning the code every time you start it up, then you need to comment out the rtc.SetTime() method after the first run as you're just going to keep resetting your time with that method, once commented out the time should be pulled from the chip instead. That or maybe the battery is not so great. Hopefully that helped, if not let me know.

"When you set your time on the first run, that time is then stored in the chip and the battery should maintain that time."
Exactly! But this does not happen. The battery is 3.3 volts, I checked.
I did not restart the code, I just unplugged the power supply from the outlet to transfer the clock to another room, and when I turned on the time started to go from the first second, the minutes and hours were not saved ...
Maybe a problem in the RTC module? But unfortunately I have no other right now to check

Upload code with time set in setup, comment out time set and reupload with it commented out, if that's not working then definitely something else is up. Or can try to upload code with time set already commented then set time manually with the buttons, should save like that as well. Not sure what else could be wrong, maybe bad chip like you said.

Thanx!!! It worked!

How to manage the daily time savings? is it managed by a function or by the RTC DS1302 with the parameter ?

Great project, I have to build a big clock.

I had problems with the binary led's not working correctly. After much twiddling about with the code, I found it was a small formatting error in " if(bitRead(s0,rown) == 1){" it needed the space after the comma e.g. if(bitRead(s0, rown) == 1){". There were a couple that just needed a space inserting. Then it worked fine!

Thank You!!!!Thank YOU!!! thank you so much for sharing the code so everybody can see it!!!! Great project Im also going to build one.

Thank you for sharing your project, I am building the clock but I have a doubt. How do you regulate the time for you to dial the time correctly?
What are the two pushbuttons used for?
Thank you

Hi gpensky! Great binary clock! Can you point me to where in the code you declare the pins you are using for anode / cathode wires? I get that there's 9 pins: 4 cathode & 5 anode. And i see where you declare pins 11,12,13 for the clock. But how do you identify which anode column to turn HIGH or LOW? Sorry for my ignorance and thanks for your time!

Hi! Oye possible yo use the ds1307 no replacement for ds1302?