Electronics Projects

Receiving WWVB time signal with CME6005

This projects is rather an experiment on how to build hardware for receiving the WWVB time signal and process it. The WWVB radio station located by Fort Collins in Colorado transmits atomic clock signal every minute by using a 60 kHz carrier (check here for the time code format). The strength and readability of the signal is monitored on the above website in four US cities located in four time zones: PST, MST, CST, EST. Although the closest to us monitoring city (La Crosse, WI) is about 200 miles away, the signal strength reported there matches our local conditions pretty well. Both cities are about the same distance away from Fort Collins (ca. 750 miles).

Hardware

The schematic is extremely simple and is based on CME6005 receiver chip manufactured by C-MAX. The chip includes a very sensitive receiver, a crystal bandpass filter, and a comparator that outputs receiving bits. The antenna I used is winded on a 24-mm ferrite rod and is also manufactured by C-MAX. Unfortunately, compared to other C-MAX clock antennas, this one is not factory pre-tuned, so I had to figure out the tank capacitors to tune it to 60 kHz by myself. It turns out that a pretty good tuning can be established by connecting 3 capacitors in parallel: 6800pF, and two of 330pF. Longer C-MAX antennas (60 mm and 100 mm) are already equipped with tank capacitors, which makes using them a bit simpler.

Schematic Prototype

The output of the receiver is connected to the microcontroller for processing. I put microcontroller as far away from the receiver as I could in order to reduce its influence on the receiver, so it is located on the far right on the protoboard. The microcontroller measures the duration of received signals to qualify them as a 0, or 1, or sync, or noise. The received bits are accumulated in CPU registers and are used later for time and date decoding. An 8-pin chip close to the receiver board on the image is an op-amp, which is used as a buffer for monitoring the receiver's output at pin 15, which determines the AGC level (automatic gain control). The voltage at this pin changes between 0.43V and 0.48V. I hoped to use this voltage to retrieve some info on the signal strength, but postponed these experiments to a later time. So, no op-amp is shown on the schematic.

The received is assembled on a small PCB shown below. All capacitors are in 0603 package, and the crystal is in CM250S one. The antenna is fixed on the PCB with two short pieces of a heat shrink tube. For this PCB has short cuts shown in white on the layout image. The coil should be placed in the center of the rod. The 330pF caps are mounted one on a top of the other. It would be a good idea to use a two-sided PCB and use the foil on its back side as ground level.

Receiver board Board layout

The time and date is displayed on an LCD module with a serial interface. The green and red LEDs indicate the received bits. If the green LED is on then 0 is received, if the red one is on then 1 is received. Lighting both LEDs corresponds to receiving a sync signal. The LEDs are turned on for 0.1 sec right after receiving a bit before a new one will be transmitted. According to the WWVB standard, there is at leat 0.2 sec interval for this between the end of one pulse and beginning of the next one. The LCD is also updated during this time. This is done again to minimize the interference between the receiver and fast microcontroller. A logic 0 at pin 11 corresponds to reducing the carrier level on 10 db, so at this time the receiver is particularly vulnerable. It turns out that most of the interference is caused by the wires connecting the microcontroller with the LED module. According to the control LEDs on the protoboard, disconnection of the LCD module leads to a much more reliable reception.

In order to measure the received pulse duration at pin 11 of the receiver I use timer TMR1 of the microcontroller. The timer runs at FOSC/4 frequency with a 1:8 input divider. Since FOSC is 2 MHz, the timer overflows in about 1.048 sec, which is sufficient to measure the 0.8 sec sync pulses, which have longest duration in the WWVB signal. The received pulses arrive to the timer gate logic at pin T1G and request an interrupt at each signal level change at this pin. The timer counts only when the T1G input is low, so it starts and stops automatically, while the interrupt on change is used to do the processing as described in the next section.

It should be noted that the receiver is unable to provide a reliable reception at any time during the day. The signal becomes stronger and weaker periodically, but there are long enough intervals of signal stability. The best time to get the time settings is at night, when the signal is strongest. The worst time is generally at sunset and sunrise. During these periods the atmosphere levels that reflect certain wavelengths are repositioning up and down due to temperature changes and other factors. Since there is 1 hour time difference between our local time and the sender's one, it gets dark earlier on our side, which blocks reception for about 1.5 hours. Otherwise, the signal is pretty strong and stable with some short interruptions.

Software

The microcontroller algorithm is written in assembly language and implemented as a finite state machine (FSM) with 3 states. After initializing the CPU registers the program enters an infinite loop and the time signal processing is entirely provided by the interrupt service routine (ISR). There is just one CPU interrupt source enabled, which requests an interrupt whenever the signal at the timer gate pin T1G is changed. If the signal changes from logical 1 to 0, then a pulse is receiving. The timer starts to count automatically, thus measuring the pulse duration. In this case we know that a new second is just started and update the seconds counter. Besides of that one or both LEDs are lighted up for 100 msec to indicate previously received pulse.

If the signal at pin T1G changes from logical 0 to 1, the transmitted pulse is over. In this case the timer counter has an information on its duration. If the timer overflow was detected, this means that the pulse was too long and, thus, is invalid. Otherwise, we check the pulse duration to be in one of intervals (given values are in milliseconds) [150,250], [450,550], or [750,850] corresponding to the duration of 0, 1, and sync, respectively. The nominal values for these durations are 200, 500, and 800 msec, respectively, but since CPU is clocked from internal RC-oscillator, I allowed some tolerance for the pulse length.

Once the received pulse width is validated and measured, the control is given to processPulse() method that implements the above mentioned FSM. State 0 of this FSM is devoted to waiting for the sync signal (the one with duration 800 msec). Once such signal is received, the FSM enters state 1, in which it checks if the next received pulse is a sync or not. If it is not the case, the FSM returns back to state 0. Otherwise, according to the WWVB encoding, the transmitter just started to transmit a new frame, so FSM enters state 2.

State 2 is devoted to receiving 6 bytes of time/date data. If you take a look on the WWVB Time Code Format, it becomes apparent that the frame consists of 6 parts separated by a sync pulses P0 - P6. The sync pulses do not carry any information and do not need to be stored. Also, bit #5 is always 0 in each of 6 parts, so it does not need to be stored as well. Hence, each of 6 groups in a frame carries just up to 8 information bits, so each group can be stored in a byte. I maintain a variable pulseNo that changes from 10 down to 0 within a group indicating the received pulse number. Upon receiving a valid bit in state 2, it is shifted into the received byte. As soon as a sync bit is received and the pulseNo is 0 (so the sync comes as expected) the obtained byte is stored in one of 6 variables specified above. In any other case, the received frame prefix is ignored and the FSM rolls back into state 0.

Processing of time/date data can be done right upon receiving the corresponding part of the frame. For this I maintain a variable that counts which part of the frame is currently received. Processing of minutes and hours is trivial. The only thing to worry about is that the transmitted time in UTC and should be converted into your local time. For this I just add a constant tZone to hours, which is set to -6 for CST. To convert the days count into month/day format a few more steps are needed, which is done around the label computeDate in the code. First, the days count is converted from BCD into binary. Note that the day count is also relative to UTC, so it should be adjusted to your local time. Once a part of the time/date frame is received and decoded, it is forwarded to the LCD for displaying.

Running this prototype circuit for several days as a clock demonstrated a high efficiency and reliability of the used algorithm. I am going to use it in one of my next projects involving radio-controlled clock.

Downloads


Last modified:Mon, Jan 23, 2023.

12974