DS3231 real-time clock/calendar IC is based on a temperature
KHz crystal oscillator, with a claimed accuracy of ±2 parts per million
at ordinary temperatures (± 2 minutes per year). This little clock IC
all the features that a worthy clock should have, and it includes an
interface! The module pictured on the left was
purchased from Amazon Prime for $5.99, battery included! To get started
with it, I downloaded an RTC library from Adafruit, and ran their
simple and instructive demo from this page. Using a 16 x 2 LCD that
was on hand, I put together a simple clock display (photo right), which
amounted to little more than substituting LCD for Serial as the output
channel in the Adafruit example. In the back of my mind, or maybe
somewhere in the middle, was the thought of interfacing the WWVB receiver. This was not a
particularly compelling idea. Similar interfaces have been done
countless times, and in better ways. On the other hand, I had only a
murky idea how the clock and receiver/decoder could be made to work
together within a single control program. It
seemed, for example, that
the WWVB signal decoding part, which involves timing of level
durations, might complicate updating the clock display. The appeal of
the undertaking was the near certainty of learning something.
In the vein of keeping my options open,
I ordered a 4-line LCD. There
could be no harm in throwing something together on a breadboard, and
fiddling with a few possibilities. Meanwhile, I thought that a timed
interrupt might work for updating the real-time clock display without
interfering with WWVB decoding. Googling this idea led to another fine
instructional example: http://www.instructables.com/id/Arduino-Timer-Interrupts/.
—Interrupt service routines should be sparse. My thought was that the
ISR would not actually update the display, but rather signal when to
Most physical clocks have a convenient
way to adjust the time, such as pushing buttons or turning a knob.
Perhaps I should have taken time to do this. Things did not go smoothly
at first. Once the WWVB simulator was connected, the clock would get
synched to an old (simulated) date/time. Not only that, but due to
coding errors, the wrong year was being set, and Daylight Savings Time
was in effect in January! Those were my errors—nothing wrong with
signal decoding, or with the clock.
When the 4-line LCD came, I added WWVB data to the bottom line of the
display. This brought up an interesting sub-problem, namely how to save
WWVB data when power was removed from the microcontroller. The clock
has a battery and continues to run and keep time whether it is
connected externally or not. However, the Nano does not have a battery.
That is when I learned about Arduino’s EEPROM: https://www.arduino.cc/en/Tutorial/EEPROMWrite.
The complete Arduino (Nano) sketch is here: wwvb-RTC.ino.
When dealing with more than one time source it would be easy to lose
track of which source is responsible for a variable named ‘hour’ or
‘minute’. To help make their meaning clearer, I substituted names like
‘rtcNow’ and ‘wwvbSecond’, where normally simpler names would suffice.
While the display update is interrupt driven, the
internal clock update is not. Whenever a valid decode of WWVB data
occurs, the clock gets updated at that moment. Essentially all decodes
of simulated data are valid. However, as previously discussed, only a
fraction of real WWVB decodes are valid. In the first overnight period
of testing with the real receiver, 37 decodes were valid, the last at
07:26 UTC (2:26 AM Eastern Time). The antenna was the
loopstick-in-the-window setup, same as pictured in the WWVB paragraphs.
By the time the above LCD screen photo
was taken, I had transferred the circuit from breadboard to a generic
circuit board. This phase of the project did not proceed smoothly
either. I had intended to socket each of the IC-form components, but
decided for expediency to solder the level converter directly to the
board. This was a mistake. At first it appeared that the receiver had
stopped working, but on investigating I found the trouble was not with
the receiver but the level converter. To correct the problem I socketed
a second converter on a small accessory board and fastened the pieces
together, leaving the original level changer soldered in place, but not
The two I²C devices are wired side-by-side at one corner of the circuit board. The real-time
clock plugs in battery side up and the 4-wire cable next to it runs to the
LCD. A couple of jumper-header combinations serve as switches. For
example to turn off the LCD backlight, the jumper from D2 is moved to
ground. To run the simulator, the yellow jumper from D3 is moved from
the level converter to the output of an off-board TTL inverter, as indicated in the
testing, no WWVB decodes were classified as valid that were not
actually valid. Therefore it is unlikely that an invalid decode might
misadjust the clock. [This problem was observed subsequently, however.] Nevertheless, the validity checker could be made
stronger. For example, the decoded year should agree with the
clock year ± 1.
moment when seconds tick on the display is
not generally the same instant that the real-time clock increments
seconds internally. Moreover, the WWVB seconds counter can only be
trusted when there has been a valid decode. A shorter update interrupt
interval, say half a second, might improve display accuracy, but that
hardly matters. I even considered using two Arduinos, one dedicated to
the clock and the other to WWVB.
Two issues remain unresolved at this writing. The LCD occasionally
blinks dark-light for a fractional second—I don’t know why. Of more
practical consequence, the clock stops or freezes from time to time,
maybe when processing an invalid sync. Pressing the Arduino reset
button resumes processing, with correct time display and without loss
of WWVB data. If I figure out what causes the interrupts or processing to stop I will post an addendum or revised sketch. While
this narrative does not cover all of the project’s
travails, the diagram together with the sketch basically tell
the story, at least to the present point. [To be continued ...]
Project descriptions on this page are intended for entertainment only.
The author makes no claim as to the accuracy or completeness of the
information presented. In no event will the author be liable for any
damages, lost effort, inability to carry out a similar project, or to
reproduce a claimed result, or anything else relating to a decision to
use the information on this page.