There are some beautiful radio-controlled watches available these days from Citizen, Seiko, Junghans, and even Casio. These timepieces don’t need fiddling every other month, which is great if you have more than one or two and can never remember what comes after “thirty days hath September…”
In the US, these watches work by receiving a 60-bit 1-Hz signal on a 60-kHz carrier wave broadcast from Fort Collins, Colorado called WWVB. The broadcast is quite strong and generally covers the entire continental US, but some areas of the country can have unreliable reception. I live in the SF Bay Area in an area with high RF noise and my reception can be spotty. My watches sync often enough that it’s not an issue 363 days out of the year, but sometimes they can miss DST shifts for a day or two. The east coast is known to be even more challenging.
Wouldn’t it be great if anyone could set up a little repeater to transmit the time so their watches were always in sync?
WWVB has been around awhile and there have been various other projects (1,2) that have demonstrated the feasibility of making your own WWVB transmitter. But these all had very limited range. I wanted to build something that could cover my whole watch stand and be based on a more familiar toolset for the typical hobbyist, namely USB-based 32-bit microcontroller development boards, WiFi, and Arduino. My goal was to make something approachable, reliable, and attractive enough it could sit with my watch collection.
Is this legal?
The FCC requires a license to transmit, but has an exemption for 60 kHz transmitters as long as the field strength is under 40 μV/m40 μV/m at 300 meters. You will definitely not exceed this limit 💪🏼
About WWVB
The classic WWVB transmits one bit of information per second (1Hz) and takes one minute (60 bits) to transmit a full time and date frame.
An example
Here’s an example of one 60 second time encoding:

You can see that the minute of the time is encoded in the first 10 seconds of the window. The hour is in the next 10 seconds, the day is between seconds 22 and 33, etc.
If we wanted to indicate that the time was 30 minutes past the hour, for example, we would set bits 2 and 3 (20 and 10) to “high”.
| Bit | 00 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 |
|---|---|---|---|---|---|---|---|---|---|---|
| Value | 40 | 20 | 10 | 8 | 4 | 2 | 1 | |||
| Example: 30 | 0 | 1 | 1 | 0 | 0 | 0 | 0 |
Similarly, the 7th hour of the day would be 0000111 for bits 12 thru 18.
It’s a trit, not a bit.
How do we represent “high” and “low” for each 1s bit? You might think it would just be a high voltage for high and a low voltage for low, like you would use on a digital arduino pin, but that’s not how it’s done.
WWVB “bits” are actually not just 0 and 1. They’re actually "trits” because they can represent a 0, 1, or a “mark”, and this is one reason why we can’t just use a simple high/low to represent them. The mark is important to allow simple receivers to orient themselves within the signal window. Your watch knows that the last second in the window and the first in the next window are both “marks”, and so it knows to start a new window whenever it sees two marks in a row.
WWVB uses Pulse Width Modulation (PWM) to represent the three possible trit states. In a given 1 second bit, the width of the pulse determines whether the bit is a 0, 1, or mark.
- If power is reduced for one-fifth of a second (0.2 s), this is a data bit with value zero.
- If power is reduced for one-half of a second (0.5 s), this is a data bit with value one.
- If power is reduced for four-fifths of a second (0.8 s), this is a special non-data "mark", used for framing.
| High | Trit value |
|---|---|
| 0.2s | 0 |
| 0.5s | 1 |
| 0.8s | mark |
Coming back to that original example but just focusing on the Minutes section, you can see the trits in the color encoding of the diagram.

Light blue is high and dark blue is low. You can see second 00 is dark blue (low) for 0.8s, which means it’s a “mark”. Second 01 is dark blue for 0.2s, so it’s a 0. Second 02 is dark blue for 0.5s so it’s a 1, and so on.
So now you know how to encode the time and date using WWVB!
The carrier wave
There’s one more part of the signal that needs explanation. While we’re transmitting bits at a frequency of 1 bit per second (1 Hz), we’re actually doing it on top of a 60 kHz carrier wave. The carrier wave isn’t particularly important to the actual encoding of the bits, but it is important because that’s the frequency that’s been allocated for WWVB use and so your watch is looking for a 60 kHz signal using its 60 kHz antenna.
Like we said in the previous section, we represent a high/low/mark trit by the width of our pulse. High for 200ms is a zero, high for 500ms is a 1, high for 800ms is a mark. The way we’ll do that on our 60 kHz carrier wave is by using PWM again, but this time on the 60 kHz signal instead of on the 1 Hz signal. We’ll use a duty cycle of 50% to represent high, which means that half of our 60 kHz pulse is high and half is low. We’ll use a duty cycle of 0% to represent low which effectively means the whole pulse is low.
So what you'll expect to see when you're transmitting a WWVB "mark" is a 1s pulse where half of the pulse is "high" using a 60 kHz signal at 50% duty, and the other half is "low" with a 0% duty (not to scale):

Similarly, a 0 would be a 60 kHz 50% duty cycle for 0.2s, followed by a 0% duty cycle for 0.8s. And a 1 would be the reverse.
The layers of WWVB
In summary, a WWVB date/time is encoded using a few different layers of encoding. At the top is what we think of as a date/time and at the bottom is the 60 kHz carrier wave.
| A date/time is encoded as a… |
| 60-bit frame, using… |
| 1s PWM trits, on top of a… |
| 60 kHz 50% duty cycle carrier wave |
| 🐢🐢🐢 all the way down |
Now that you understand how it works, let’s build the transmitter!
Optional
None of the following is necessary, but some of it might be nice to have.
- Oscilloscope. It can be hard to know if your circuit is doing anything without an oscilloscope. There are some micro DSOs for around $100, and some android-based table DSOs for around $200, but I like the Rigol DHO800 series as an entry-level oscilloscope if your budget can stretch to around $400. A digital multimeter or an individual LED can also be helpful in a pinch.
- 10V power supply. If you need more power you can use an external power supply. I found the signal to be strong enough without it and preferred the convenience of a single USB power supply. If you want to go up to 13V, switch to the TB6612
- 3D printer if you would like to print the tower enclosure for your circuit.
- Permaboard or Perma-proto. After you’ve prototyped your circuit you’ll want to move it to something more permanent. Perma-proto is convenient because it exactly matches your breadboard layout. Permaboard is more configurable but less convenient. Either one can be cut to size.
- Soldering iron. If you’re using permaboard, you’ll need a soldering iron. I love the Pinecil v2, it’s USB-powered, auto-sleep, nearly instant-on, open-source and temperature controlled.
- GPS module. The nice thing about using module development boards like the Feather, Grove, Arduino, etc. is their support for additional modules. The AdaFruit Ultimate GPS FeatherWing pairs well with their Feather boards and includes an accurate RTC. If you go GPS, you don’t necessarily need a microcontroller with WiFi.
- LCD display. This can be a nice touch and can make it easier to tell if your tower is working or not. I like the Adafruit ESP32 TFT Feather or similar. I made an earlier prototype with a screen that displayed the current time, but didn’t like the way the screen lit up my bedroom at night. You can also connect many external displays using the simple I2C connector on many dev boards.
Instructions
Simulator
Before you get started, you might be interested to see a simplified version of the software in action on the Wokwi Arduino online simulator.
https://wokwi.com/projects/431240334467357697
This simulator connects a virtual Arduino to a virtual logic analyser on PIN 4, and lets you download the output of PIN 4 for offline viewing on your computer.
To use it:
- Run the simulator for a few seconds. Notice that D0 is flashing on the logic analyzer. The logs will also show the current date/time (which starts at Jan 1 1970 since we aren't using wifi to initialize it to another value)
- Stop the simulator. The logic analyzer will automatically
download
wokwi-logic.vcdto your computer. - Open
wokwi-logic.vcdin a viewer like PulseView
Software
https://github.com/emmby/WatchTower
Upload the Arduino sketch to your Arduino using the Arduino IDE.
The LED will light up yellow/orange while connecting to WiFi. If you haven’t yet set your SSID, connect your phone to SSID: WWVB and follow the instructions to enter your wifi password.
Once the network is connected and the time has sync’d, the light will turn green briefly and then turn off.
Setup()
The Arduino setup() method does a few things.
Initialize the components we’ll be using, particularly the serial port, LEDs, WiFi, output pins, timezone, and network time sync (NTP). The network time sync will happen automatically in the background every hour. This is important because the realtime clock (RTC) on most microcontrollers are notoriously subject to drift and are rarely accurate for more than a few hours.
Start the 60 kHz carrier wave at a 50% duty cycle.
Loop()
Arduino then moves to the loop(), which continuously performs the following operations:
- Get the current time in UTC
- Convert it to your local timezone to determine DST
- Compute whether the 60 kHz carrier wave should be set to 50% (logical high) or 0% (logical low) for that specific moment in time. Time is always UTC, except for the DST bit which is relative to your local timezone.
- Set the PIN_ANTENNA to high or low based on that value.
- [Optional] you can flash the led for high/low PWM. This is nice for making sure things are working, but it’s grounds for divorce in the bedroom.
Do some other nice-to-haves like logging, setting LEDs and/or rebooting when there are issues.
Verify the microcontroller alone
If you installed and ran your software and you set up the wifi connection, your board should now be outputting a signal on your output pin.
If you have an LED, you can connect the long end (anode) to your output pin and the other end to ground. If everything is working it should flash on/off about once a second.

If you have a digital oscilloscope, you should be able to see a 3V square wave with a periodicity of 16us (1 / 60,000) something like the following:

That’s the 50% duty cycle PWM carrier wave initialized during setup().
If you zoom out to say 1 second per grid square resolution, you’ll be able to see the WWVB signal clearly:

In the 10 seconds shown here, I see a 1, mark, 0, 1, 1, mark, 1, 1, 1, and 1.
Now if you modify the software to hardcode the date to Mar 6, 2008 7:30:00 am and zoom out to see a full 60 seconds, your signal should exactly match the signal in the example we started with:
buf_now_utc.tm_year = buf_now_local.tm_year = 108; // 2008 = 1900 + 108
buf_now_utc.tm_yday = buf_now_local.tm_yday = 65;
buf_now_utc.tm_mon = buf_now_local.tm_mon = 2;
buf_now_utc.tm_mday = buf_now_local.tm_mday = 6;
buf_now_utc.tm_hour = buf_now_local.tm_hour = 7;
buf_now_utc.tm_min = buf_now_local.tm_min = 30;


Looks great! Everything is working as expected.
Electronics assembly
Now that you’ve verified the microcontroller is working, it’s time to put all the components together.
The electronics consist of three basic components: the microcontroller board, the amplifier breakout board, and the antenna.
The connections are quite simple, you can do them on a breadboard or a proto board. I recommend starting with a breadboard, which will look identical to this perma-proto board but without the solder:

Microcontroller board (Adafruit ESP32 QT Py in this photo)
- Connect the ground pin to the ground plane (photo: J2).
- Connect the 5V pin to the power plane (photo: J1).
- Connect your signal pin [M0] to the input pin of your amplifier AIN1.
DRV8833 Amplifier breakout
- Connect the second input pin [AIN2] of your amplifier to ground (photo: J11).
- The Adafruit DRV8833 motor driver board has a sleep pin that needs to be pulled high to enable the breakout, so connect that to power 5v or 3v power, whatever is convenient. We used 5V here. (photo: J12)
- Connect ground to the ground plane. (photo: J16)
- [Optional] Connect the “motor” voltage [VM] to your 5V plane (photo: J17). This is needed if you are powering your amplifier via USB like I have here, but it should not be done if you are planning to use an external power supply on VMotor. The antenna and amplifier circuit can contribute some noise to your 5V line. If you’re worried about it you might use an external power supply instead, but I found for these settings that the noise was negligible (although see Alternatives Considered for some lessons learned).
Antenna
- You can plug your antenna directly into your breadboard, or use a 0.1" Pitch PCB Mount Screw Terminal Block Connector connected to [AOUT1] and AOUT2
Signal Verification
You should be able to do the same LED trick as last time, only this time with the long anode on AOUT1 and the short cathode on AOUT2.
Or with your oscilloscope, you can look at the output of your microcontroller and compare it to the output of your amplifier:

Here the 3V signal on the microcontroller is blue, and you can see that the amplifier is outputting a similar wave but at 5V. If your wave doesn’t look quite like this, check that your antenna is plugged in. The antenna has an impedance that will cause the ringing that you see in the waveform, that’s expected and okay.
The final test is to verify it works with a real watch!

Assembling the enclosure
The enclosure is designed for a 51mm x 63mm perma-proto, which is the size of a half size perma-proto with the excess trimmed. You can trim a proto board by scoring along a straightedge with a utility knife and then bending the board at the score, either by pressing it down on a hard surface at an angle or using a vise grip. Or feel free to modify the Autodesk Fusion file to the size of your own board.

Here I also made a quick and dirty “mount” for the antenna by twisting a couple of loops of wire and soldering them to the perma proto.
Print the enclosure using a 3D printer. I used standard PLA, standard 0.4mm nozzle, and pretty much default slicer settings with no supports.
- STL: The Watch Tower v7.stl
- Autodesk Fusion: The Watch Tower v7.f3d

Once the pieces are printed, insert the circuit board into the bottom and press the lid for a snap fit.
Enjoy!
Plug into USB and you’re done! Your watches should now sync automatically every night.

I reliably get about 8 to 10 inches of signal in a straight line with no obstructions.
If you need more than that, try giving a higher voltage a try using an external power supply. Or you might try a higher duty cycle or doubling up the H-bridges, but see the warnings below!
Alternatives considered
- I wanted to avoid using a separate amplifier breakout board so I tried the Adafruit RP2040 scorpio. It can do 60khz PWM at 5V natively, but it was only able to drive 12mA per channel which wasn’t enough to saturate my ferrite antenna so the square wave collapsed.
- I looked at the Adafruit 8-Channel PWM or Servo FeatherWing because I wanted to take advantage of module stacking, but it can only do 10mA per channel and 1.6khz.
- I looked at Trinket and Itsybitsy ATmega based boards, but they can’t drive much current and they’re not modular with anything and they have no wifi so there’s little advantage over the QT Py.
- I considered driving the DRV8833 with an external power supply. This would have given me higher voltage and likely a stronger signal. But I wanted the convenience of a single usb power supply, and the signal strength was sufficient for my needs.
- ⚠️ WARNING: I tried the linking both the A and B H-bridges of the DRV8833 in parallel, and I also upped the duty cycle to 80%. Totally blew out my microcontroller, presumably with a flyback voltage due to the high inductance antenna. I’m not sure if it was the parallel or the 80% or the combination of the two, it would be worth experimenting further but I haven’t yet.
This page (Watch Tower - Radio controlled watch transmitter) was last updated on August 03, 2025.
Text editor powered by tinymce.