## Introduction: One Component Radio Clock Time Transmitter

Believe it or not, you can generate a time signal to set your WWVB controlled radio clocks with just an attiny45, wire antenna, and a battery. Upload the code to an attiny45, put a 20" or so wire on pin 6 and power with 5v.  You'll need to put your radio clock close to pick up the signal best.

## Step 1: The WWVB Time Signal and 60Khz Carrier

The WWVB time signal is a 60khz carrier modulated by reducing the carrier in a particular sequence to encode the time.  Wikipedia has a good article which I used to design this project: https://en.wikipedia.org/wiki/WWVB

The attiny45/85 has a fast timer that can be set to generate a square wave at 60khz like this:

/* Initalize Fast PWM on OCR1A*/
DDRB |= _BV(PB1); // Set PWM pin as output
PLLCSR |= _BV(PLLE); // Start PLL
_delay_us(100);      // Wait till PLL stablizes p. 9
PLLCSR |= _BV(PCKE); // Set Clock source to PLL
OCR1C = 132; // Set OCR1C to top p. 91 (60kkHz)
OCR1A = 66;  // Set beginning OCR1A value (50% duty cycle)
TCCR1  |= _BV(CS12);   /* Set clock prescaler to 8   */
TCCR1 |= _BV(PWM1A)   /* Enable PWM based on OCR1A  */ \
|  _BV(COM1A0)   /* Set PWM compare mode p. 89 */ \
;

## Step 2: Modulating the 60khz Carrier

To modulated the carrier, just reduce the duty cycle of the wave by changing OCR1A to less than 66.  I set the other timer on the attiny45 to fire an interrupt 61 times a second like this:

/* Initalize CTC interupt on timer0 at 61hz */
TCCR0A  |= _BV(WGM01); //pg. 82  Mode 2 CTC OCR0A TOP
OCR0A |= 127;   // 8mhz / ((127+1) * 1024 prescale) = 61hz
TCCR0B |= _BV(CS00) | _BV(CS02);  // set prescaler to 1024
TIMSK |= _BV(OCIE0A);// enable compare match interrupt
sei(); // Enable interupts

This gives 61 times slices in each second to reduce the power of the carrier for modulation.

## Step 3: Encoding the Modulation With a Time Signal

Next I wrote a routine which would keep track of the 61 time slices of each second and change to duty cycle of the carrier to encode the time signal.  Each case represents a second of the minute long time signal.  Each parameter can be set.  I have a few defines that can be used to easily change the hour and minutes.  You can add other defines too.

ISR(TIMER0_COMPA_vect){

switch (slot) {

case 0 : { signal = 2;break;}

case 1 : { signal = ((minute_tens >> 2) & 1);break;} // min 40
case 2 : { signal = ((minute_tens >> 1) & 1);break;} // min 20
case 3 : { signal = ((minute_tens >> 0) & 1);break;} // min 10

case 5 : { signal = ((minute_ones >> 4) & 1);break;} // min 8
case 6 : { signal = ((minute_ones >> 2) & 1);break;} // min 4
case 7 : { signal = ((minute_ones >> 1) & 1);break;} // min 2
case 8 : { signal = (minute_ones & 1);break;}   // min 1

case 9 : { signal = 2;break;}

case 12 : { signal = ((hour_tens >> 1) & 1);break;} // hour 20
case 13 : { signal = ((hour_tens >> 0) & 1);break;} // hour 10

case 15 : { signal = ((hour_ones >> 4) & 1);break;} // hour 8
case 16 : { signal = ((hour_ones >> 2) & 1);break;} // hour 4
case 17 : { signal = ((hour_ones >> 1) & 1);break;} // hour 2
case 18 : { signal = (hour_ones & 1);break;}  // hour 1

case 19: { signal = 2;break;}

case 26: { signal = 1;break;}  //
case 27: { signal = 1;break;}  // Day of year 60
case 29: { signal = 2;break;}  //

case 31: { signal = 1;break;}  //
case 32: { signal = 1;break;}  // Day of year 6
case 37: { signal = 1;break;}  //
case 39: { signal = 2;break;}

case 42: { signal = 1;break;}  //
case 43: { signal = 1;break;}  // DUT1 = 0.3
case 49: { signal = 2;break;}

case 50: { signal = 1;break;}  // Year = 08
case 55: { signal = 1;break;}  // Leap year = True
case 59: { signal = 2;break;}

default: { signal = 0;break;}
}

switch (signal) {

case 0: {
// 0 (0.2s reduced power)
if (timer < 12) {OCR1A = 6;}
else {OCR1A = 66;}
} break;
case 1: {
// 1 (0.5s reduced power)
if (timer < 30) {OCR1A = 6;}
else {OCR1A = 66;}
} break;
case 2: {
// Marker (0.8s reduced power)
if (timer < 48) {OCR1A = 6;}
else {OCR1A = 66;}
} break;
}

if (timer == 61) { // Check to see if at end of second
timer = 0;   // If so reset timer
slot++;   // Advance data slot in minute data packet
if (slot == 60) {
slot = 0; // Reset slot to 0 if at 60 seconds