Encoder/Generator for DCF77 compatible signals


Targets

If you are far away from home your radio-controlled wrist watch still will work precisely for quite a while due to its built-in quartz clock. But what will happen when you have to replace the battery? The received signal will be too weak to enable your watch to syncronize with the transmitter. In this case you would like to have a transmitter of your own just to make your watch usable again, even with some loss of precision.

So, what you need is a small device that gives your radio-controlled watch a chance to synchronize.
 
Pin d11 (OC2A) is oscillating all the time. While d12 is set to INPUT you only get a small signal as the other terminal of the coil is connected to GND via 180 ohms.
When you switch pinMode of d12 to OUTPUT and set it to LOW you get a strong signal as now the end of the coil is grounded via 180 || 18 ohms = 16.36 ohms.


You were right when you noticed that the current through the coil has a DC component. But as Maxwell's equations taught us the DC is not transmitted to the universe.

Implementation details

What you need is a generator for the carrier frequency, either 77,500 Hz for the DCF77 or 60,000 Hz for the MSF signal. This can be done with a timer in CTC mode (Clear Timer on Compare Match) adjusted to the double frequency (thanks to Shannon's theorem) setting your output ports to "0" and "1" alternately. Maybe you have to take care of some unwanted harmonics (just use a capacitor of your choice). The only thing you still have to do is the amplitude modulation. This can be done very easily by just making use of another output pin and connecting it via a resistor to give you the signal modulation your watch requires. The modulation can be controlled by setting the data direction port for this pin either to input or output. As you do not use an ISR you don't need to take care of the amout of code in there which might slow down the desired frequency. This setting of the data direction registers can be done in the loop() section.

The formula to find the OCR2A value is given in the Atmel documentaion:

With a cpu clock of 16 MHz and an OCR2A value of 102 you get 16,000,000/(2*1*(1+102)) = 77,669.9 which is close enough to 77,500 for most of the receivers.
(For MSF you should use OCR2A = 132 to get a frequency of 60,150.38 Hz.)

const byte pin1  =  11;    // goes to antenna. OC2A, pin number cannot be changed
const byte pin2  =  12;    // goes via  18 ohms to antenna. pin number can be changed

void setup() {
  pinMode(pin1, OUTPUT);
  pinMode(pin2, OUTPUT);
  // setup hardware toggle of Arduino-Pin-11 (OC2A, PORT B, bit 3)
  TCCR2B = B00000001;            
  // Bits 2 1 0 = 0 0 1 : no prescaling, divide by 1 (other prescalers: 8, 32, 64, 128, 256, 1024)
  TCCR2A = B01000010;  
  // | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 | 
  // | 0 | 1 | 0 | 0 | - | - | - | - | : Toggle OC2A on Compare Match
  // | - | - | - | - | 0 | 0 | 1 | 0 | : Clear Timer on Compare Match  
  OCR2A  = 102;    // frequency = 16,000,000 / 2 / (OCR2A + 1) = 77,669.9 kHz
  // each time when Timer2 gets 102 the selected output gets inverted
}
void loop(){   }

If you prefer to choose the pins where you connect the coil go for this one:
( see also this page for details )

const byte pin1 = 11; // Port B, Bit 3
const byte pin2 =  8; // Port B, Bit 0
byte tcnt2 = 169;     // 77,348 Hz (with the 3 NOPs before writing to TCNT2) 

void setup() {
  pinMode(pin1, OUTPUT);
  pinMode(pin2, OUTPUT);
  setupTimer2(1);
}

void loop() { }

void setupTimer2(byte index) {
  TCCR2B = 0x00;        // Disable Timer2 while we set it up
  TCNT2  = tcnt2;       // Reset Timer Count 
  TIFR2  = 0x00;        // Timer2 INT Flag Reg: Clear Timer Overflow Flag
  TIMSK2 = 0x01;        // Timer2 INT Reg: Timer2 Overflow Interrupt Enable
  TCCR2A = 0x00;        // Timer2 Control Reg A: Wave Gen Mode normal
  TCCR2B = index;       // Timer2 Control Reg B: Timer Prescaler set 
}

ISR(TIMER2_OVF_vect, ISR_NAKED) {   
  asm("PUSH r24");       // the only register modified in here
  asm("LDS r24, (tcnt2) "); 
  asm("NOP \n\t NOP \n\t NOP");
  //asm("NOP");  // for fine tunig only
  asm("STS %0, r24" : "=m" (TCNT2) ); // TCNT2 = 0xb2
  PINB = B00001001; // with this one you can toggle more than one bit at a time
  asm("POP r24");        
  asm("RETI"); // because we are naked    
};

In the loop-section you can easily handle the modulation. Just copy the protocol defined by the Physikalisch-Technische Bundesanstalt.


As shown in the picture we added two LEDs to indicate whether a "0" or a "1" is being transmitted.


Clearly to be seen there are some harmonics which are not killed by the 220nF capacitor.

Final remark

If you find yourself in the middle of a desert you don't need to take care of any laws regulating the transmission of radio signals. But unfortunately, there you won't find a replacement battery and an Arduino either. And also most probably you don't need to know the exact time.

Otherwise, please respect the laws of the country where you happen to live.

In case your Arduino was shipped with a label please replace it by a sign.



contact: nji(at)gmx.de