Three Time Zone Arduino-based Clock

the_eye_of_sauronI’ve been meaning to add a  clock with multiple time zone display to my radio operating position for a while. The time in UTC is displayed on my computer when I’m logging, but it’s small and it disappears when the screen sleeps. Also, I use the same room to take work-related conference calls, and it would be helpful to have a clock that displays the local time in Madagascar and the time on the US East Coast, where most of my overseas calls are scheduled. The fast, reasonable approach would be to wire up a microprocessor, a real-time clock chip, and an I2C-driven LCD display that could show all three zones at once. However, the only LCDs I have on hand have small fonts and aren’t that bright. On the other hand, I have a bunch of 4-digit x 7-segment LED displays that burn as bright as Sauron atop Barad-dûr. I went with those.

The Display

A while back, I had mentioned another project that involved three of these displays. For that project, I whined about how I didn’t want to spend $6 per display to add I2C backpacks. Since then, I did a project that used one of those backpacks, and I have to admit that it was very convenient and shaved off a ton of both wiring and code. But, I only had one of those backpacks on hand, so for this project, I had to drive the displays directly. In the previous three-display project, I chose to drive the digits one at a time, lighting up the entire number, extinguishing it, and then moving to the next number, and repeatedly scanning the display. The microprocessor was fast enough that this scan cycle did not flicker noticeably when supporting the twelve digits in the display.

That worked fine in terms of display brightness and flicker, but I was limited slightly in how much current I could put into the display at once. I limited current to 15mA per segment, so for a given digit position, the maximum current at any time would be 15mA x (7 segments + 1 decimal point) = 120mA. Looking at the ATmega328 datasheet, I confirmed that the chip could supply that current, and I spread the load among different port groups. In that project, each digit was selected by activating a single line on a TPIC6B595 high current shift register. Since I had 12 digits, I needed two of those shift registers (each can sink current for eight control lines).

At two bucks each, those high power shift registers did not break the bank, but when thinking about the clock project, I went with a design that would use two regular SN74HC595 shift registers — three for $2.75!

The revised design was not [entirely] a matter of me being cheap, but wanting to be able to drive the displays at maximum brightness. The new design consists of driving a given position within every digit at once. The top segment, i.e., the one that forms the horizontal bar in the number “7” is designated segment “a”. So, using the shift registers, I am able to set and latch in a bit pattern, where a “1” corresponds to turning on that segment in each of the digits in the display. I can then turn them all on at once, allow some time for the pattern to persist, and then move on to the next segment, cycling through each of the seven segments (not eight because there’s no decimal in the clock display) fast enough that the numbers are evenly lit, without flicker.

Each segment can be lit up at 20mA and that was my goal until I tested it — at that level, my eyeballs just about melted. While I want to be able to see the display from across the room, I do not need to see the shadows of my internal organs projected on the wall by a clock that shines with the intensity of a supernova. Perhaps I exaggerate slightly. The bottom line is that with this configuration I was able to run the display at about half max brightness, but still have a visually bright display. Running the display at lower power should mean longer time to failure as well.

But, had  I wanted to drive the LEDs at higher power — above and beyond what the microprocessor’s outputs could source — this design could handle it because the microprocessor controls the current indirectly. On the high side, microprocessor outputs control current flow to individual segments via PNP-transistors.

driver_obverse IMG_driver_reverse
The display driver board

The microprocessor also controls the shift registers through three lines, a serial line (SER), shift register clock (SRCK), and latch clock (RCK). The shift registers control which digits are selected at any given time. Unlike the TPIC6B595 shift registers, however, the plain vanilla SN74HC595 cannot sink current; instead, I had each line control a 2N7000 N-channel mosfet, which handled the load.

One way that this design is superior to the earlier design is that it is more expandable. The microprocessor controls the shift registers through three lines: serial data (SER), shift register clock (SRCK) and a latch clock (RCK). Since the shift registers are cascaded, two shift registers require no more control lines than one. In the current set up, I am using only 12 of the available 16 shift register outputs, so in principle, I could add a fourth display with no additional hardware. For that matter, I could keep adding displays at the cost of one additional shift register per two displays (i.e., eight digits). The only limiting factor would be that the transistors on the high and low sides would be able to handle the current. A picture will probably make this all clearer:


The code and schematics for this project are archived on github. A significant portion of the code relates to updating the display: defining numbers in terms of which segments get lit up, lighting up the right segment each cycle, blanking the display, and for when the display is being set, blinking one bank of LEDs to indicate that it is being edited.

display_reverse  display_obverse
The front and back of the display board

The Real Time Clock

The clock itself is based around the DS3231 clock, a high precision, temperature-compensated real time clock. One nice feature of the chip is the provision for backup power, in this case a 3V coin cell. If main power fails, the chip won’t forget what time it is. I don’t expect that the clock will ever need to run off its own backup power, but it’s nice to know that it could do so for months since it draws so little current in backup mode.

The chip was available only in SOIC-8 format when I ordered it, so I used an adapter to add it to my perf board. The chip interfaces with the MPU via I2C lines (SCL and SDA) – I did not need to pull them up externally. Aside from that, the chip just connects to power, backup-power, and a common ground.

There are examples about how to control the clock chip directly, writing and reading data via the Wires library. The chip has a few registers that set and report on various features – I am using only a very small subset of this RTC’s capabilities in this project. Some of the example code that I came across on the net is wrong, however, so be careful — the code shows decimal numbers being written/read to the clock. However, hours and minutes are represented internally in binary-coded decimal format, so some utility routines are required to interact with the clock. Rather than write all this from scratch, I used the RTClib from Adafruit, available on github. The library comes with a simple example file that showed me all I needed to set and read times.

The user controls the clock through several small momentary push-buttons mounted out of the way on the side of the clock. To avoid accidentally altering the time by rubbing up against one of these buttons, there is also a slide switch that enables editing mode. When that switch is on, the selected time zone blinks rapidly. To allow the clock to be set to the second, when in edit mode, time does not advance. When exiting edit mode, time is set to zero seconds, so the right way to set the clock is to set it to the next minute, wait for that minute, and quickly exit edit mode.

The top time is the master time — for my purposes, it is set to UTC. The other time zones are derived from that master time zone, with either positive or negative hourly offsets. As written, the software does not handle fractional time zones. For now, I don’t have plans to live in India or South Adelaide or anywhere else with a fractional offset relative to UTC — but if I do, I can always patch the firmware.

There is a button for setting the master hour and another for the minute. Pressing the button just moves the number forward, wrapping after 23 for hours and 59 for minutes, as you’d expect. I did not implement the feature of accelerating the advancement of each unit with prolonged button press because it seemed like a feature that I wouldn’t really need, since I would hope to set the clock only rarely. For the same reason, the units advance in only one direction, rather than forward and backwards. I leave those features for others to implement – programming is by nature social, after all, right?

Since the other time zones are just offset by integer values of hours from the master time zone, each time zone gets a button. When the button is held down, the hour advances. There’s no need to worry about the minutes, since they will just mirror the master clock. So yeah, the minutes display for time zones two and three is redundant, but it looks nice, and maybe someone will implement that fractional time zone feature.

There’s one more button: the sleep display button. I found the display pretty bright, even running at half power. I sometimes have low lighting levels in the radio room and thought that it would be nice to have the option of turning off the display. To remind myself that the clock is still on, when the clock is in “sleep” mode, the colons are lit, but the numbers are dark. Pressing the button again brings the whole display back to life.

On the subject of the DS3231 clock chip, I used one that I had on hand, but was curious how much they would cost to order. Suppliers like Mouser and Digikey had them listed as $7-8 a piece, which seems extraordinarily pricey. Some suppliers like Adafruit and Sparkfun have chronodot boards, which provide a convenient breakout board, but for about twice the cost of the chip itself. However, I came across an almost (?) too-good-to-believe deal on eBay: there are a number of vendors selling a board with a DS3231 and a 32k EEPROM… for $0.85 each. I ordered a few and haven’t seen one with my eyes yet, but Ed Mallon has looked into these boards extensively and they seem to work — read his detailed work on his blog.

The I2C interface is at top; the bottom provides a way to daisy chain other I2C devices. There is a coin-cell battery holder on the reverse side.
The I2C interface is at top; the bottom provides a way to daisy chain other I2C devices. There is a coin-cell battery holder on the reverse side.

The Microprocessor

I prototyped with an Arduino duemilanove based on an ATmega328 running at 16 Mhz, but when it came time to build it up on perf board, I decided to save myself a few parts (to wit: one crystal, two capacitors and some board real estate the near MPU) and use the ATmega328’s internal 8 Mhz clock. While the processor is more than capable of impressing our primate eyes with fast updates to the LED digits, all of the events in the program occur so slowly it doesn’t matter that the MPU is running at “half speed”. The time that is displayed is only updated twice a second, the button presses are only acted upon about every one third of a second, the blink rate is on/off for a tenth of a second. The delay between showing a character and erasing it is faster, 1 millisecond, but no sweat for the microprocessor. I would guess that it could be clocked at 1 Mhz, and would still perform adequately, but I could see no reason to push in that direction, as power consumption is not a strong concern.

I gave myself the option of performing in-system firmware updates by putting an ISP header on the board, and I used that to do the initial programming of the chip after sticking it into a DIP socket. I used a fresh out-of-the-tube ATmega328 with no bootloader for the project. They are shipped with fuses set to work at 8 Mhz — one that had been flashed with a bootloader and configured for 16Mhz or other clock frequency would not have worked.

To program directly from the Arduino IDE, I added files from the file to the hardware directory of the Arduino 1.6 distribution. That file is available from Within the IDE, I then selected the target chip, “Atmega 328 on a breadboard (8 Mhz internal clock), plugged my USBtiny  (with jumper set to power from the USBtiny) into the ISP header on my perf board, and used the IDE’s “upload using programmer” command to flash the target chip.

The Power Supply


I intended to house this clock in the rack with my transceivers and to run it off the station nominal 12V power source, which itself has battery-back up. The MPU, LEDs, and clock run at 5V and I had anticipated driving the LEDs at max current, so a draw of about 360mA all together. For a linear regulator to put out 5V with 13.8V in, would mean that it would need to dissipate up to 4.75W:  (13.8V battery – 0.6V reverse current protection diode drop) * 0.36A.  That’s way above the pay grade for a 78L05 (100 mA max, not even looking at the power), and the LM7805 in a TO-220 case would get pretty hot. I didn’t want that much heat being generated near the clock chip, even if it does have thermal compensation. So, instead of a linear regulator, I used a “drop in replacement” OKI-78SR05.

These are high efficiency three-pin DC/DC converters that can handle an amp and a half (outputting 7.5W), while staying cool. I’m not taking full advantage of the capabilities of this converter since my current needs are relatively low on average. The efficiency of the converter is best when the current draw is above about 200 mA:

Screen Shot 2016-05-20 at 9.53.29 PM

According to the datasheet, these converters do not need external components, but further down, there are suggestions about stability and output that made me think that it would be worth adding 10uF caps on both the input and output. Per the datasheet, I used a multilayer ceramic capacitor with low ESR.

I found the packaging of this module a little difficult to work with. The pins stick straight down from the module, so the package mounts vertically. Since my project consists of stacked boards, I wanted to mount the module flat, but found that I could only push the module forward about half way because the pins are so short.

After hooking everything up, I looked at the power output from the module, and it looked very clean. One concern that I have is that I’m mounting this switching module near my radio equipment. It operates at 500khz, so I’ll have to see if this causes birdies — if so, I’ll try to mitigate it with shielding and post an update.

logic_obverse logic_reverse
The logic board.

I really hadn’t thought that making a clock would be this involved, but I guess if you try hard enough, you can make any project excessively complicated.

I still need to make a faceplate and mount the clock, but as much as I’d like to show the completed clock in this post, I’ve run out of time. I have to travel to the US for meetings (and some Memorial Day camping), so the concluding part of this article will come in about two weeks, plus or minus jet lag.

4 thoughts on “Three Time Zone Arduino-based Clock”

  1. Is there any way to change primary time zone to fractional zone time like Indian Time
    I also want to change second time zone
    if so can you patch the firmware with updated code

  2. Hi Ramesh – Thanks for your comments. I have not had a chance to modify the code for fractional time zones, but realize that this would be a useful addition. I am tied up with business travel for the next few months and have other projects in the queue, so I might not get to this for some time. In the meanwhile, should you or others modify the code to include that functionality, please let me know and I will update the repository.

  3. I didn’t notice any random flickering using the code on the site. Is it possible that there is a transient connection somewhere? – jack

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.