Categories
Statistics
Flag Counter
Since 08.08.2014
Counts only, if "DNT = disabled".

Your IP is 44.213.60.33
ec2-44-213-60-33.compute-1.a
Info
Valid HTML 4.01 Transitional Creative Commons Lizenzvertrag
rss
เราจะทำแบบวิศวกรผู้ยิ่งใหญ่
We love the King
23. July 2024
Your valuable opinion :
4.5 stars

Avg. 4.61 from 23 votes.



Arduino-DCF77.php    20217 Bytes    04-06-2024 19:41:58


Arduino / Genuino DCF-77 Signal Generator


Time machine without the (difficult to obtain) flux capacitor



LASER WARNING : TRANSMITTING YOUR OWN TIME-SIGNAL MAYST CONFUSE OTHER PEOPLE OR SYSTEMS. HANDLE WITH CARE AND INTELLECT.


DCF-77 Signal Generator






✈ Approach




This second version was designed with the scope on easy reproduction. It's portability factor was also optimised. The heart of this circuit is the Real Time Clock DS1307. It is buffered with a huge capacitor. Based on this clock, the Arduino modulates a 77.5 kHz carrier (SiTime 8208 running at 9.92 MHz divided by 128). The modulation is done with 2 AND gates. If the modulation signal is high, both outputs are 5 Vpp and in phase. If the modulation signal is low, the output of the second AND is low and connects the voltage divider to GND. The amplitude at the tap is therefore lowered to 25 %. The lowpass at the output is realised by a Sallen-Key Lowpass, designed for about 100 kHz. An antenna does the rest of filtering (design goal).


DCF-77 Signal Generator


The Modulation signal, created by the Arduino (blue). We can (not) see the missing bit of the 59 th second. This absence is to allow synchronizing the seconds of the clock. Top trace (yellow) is the modulated carrier.


DCF-77 Signal Generator


Digital Modulation : Not only is the carrier a squarewave (rich in harmonics) but also the modulation signal has a high slew rate which is likely to cause unwanted spurii.




✈ Similiar Systems just need a different Oscillator




LOCATION CARRIER OSCILLATOR IN USE
Frankfurt, DL 77.5 kHz SiT8208AC-81-33E-9.920000
Anthorn, UK 60.0 kHz 7.68 MHz
Prangins, HB, offline 75.0 kHz 9.60 MHz


More information can be found here or there or anywhere.


DCF-77 Signal Generator


The carrier, after having been divided by 128




✈ Test Sketch for Arduino/Genuino UNO



Double click on code to select ...

/* ///////////////////////////////////////////////////////////// 
ARDUINO/Genuino (UNO) Test/Demo Sketch for Low Frequency
ASK Synthesizer
Software Version 2.4, 
24.04.2017, Alexander C. Frank
//////////////////////////////////////////////////////////////*/


#include <Wire.h>
#include "TimerOne.h"
#include <LiquidCrystal.h>
LiquidCrystal lcd(6,7,2,3,4,5);  

byte Data[62] ;
volatile unsigned int SekundenZeiger = 0 ;
volatile boolean ModulationNecessary = false ;
const int Modulateur = 9 ;  
const int Illuminateur = 8 ;
const int Correcteur = 10 ;
unsigned int Parity = 0;  // EVEN PARITY IS USED HERE
const int SET = A0 ;
const int PLUS = A1 ;
const int MINUS = A2 ;
const int ENTER = A3 ;

// TIME - DS1307
byte second, minute, hour, dayOfWeek, dayOfMonth, month, year; 
const int DS1307_I2C_ADDRESS = 0x68 ; 

// TIME SUBROUTINES
// Convert normal decimal numbers to binary coded decimal
byte decToBcd(byte val) { return( (val/10*16) + (val%10) ); }
// Convert binary coded decimal to normal decimal numbers
byte bcdToDec(byte val) { return( (val/16*10) + (val%16) ); }

// ///////////////////////////////////////////////////////////// 
// TIME AND CLOCK SUBROUTINES
// ///////////////////////////////////////////////////////////// 
void SetTimeDS1307(byte second, byte minute, byte hour, byte dayOfWeek, byte
dayOfMonth, byte month, byte year)
{
  // sets time and date data to DS3231
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0); // set next input to start at the seconds register
  Wire.write(decToBcd(second)); // set seconds
  Wire.write(decToBcd(minute)); // set minutes
  Wire.write(decToBcd(hour)); // set hours
  Wire.write(decToBcd(dayOfWeek)); // set day of week (1=Monday)
  Wire.write(decToBcd(dayOfMonth)); // set date (1 to 31)
  Wire.write(decToBcd(month)); // set month
  Wire.write(decToBcd(year)); // set year (0 to 99)
  Wire.endTransmission();
}
void readDS1307time(byte *second,
byte *minute,
byte *hour,
byte *dayOfWeek,
byte *dayOfMonth,
byte *month,
byte *year)
{
  Wire.beginTransmission(DS1307_I2C_ADDRESS);
  Wire.write(0); // set DS1307 register pointer to 00h
  Wire.endTransmission();
  Wire.requestFrom(DS1307_I2C_ADDRESS, 7);
  // request seven bytes of data from DS3231 starting from register 00h
  *second = bcdToDec(Wire.read() & 0x7f);
  *minute = bcdToDec(Wire.read());
  *hour = bcdToDec(Wire.read() & 0x3f);
  *dayOfWeek = bcdToDec(Wire.read());
  *dayOfMonth = bcdToDec(Wire.read());
  *month = bcdToDec(Wire.read());
  *year = bcdToDec(Wire.read());
}

void displayTime()
{
  // byte second, minute, hour, dayOfWeek, dayOfMonth, month, year;
  // retrieve data from DS3231
  readDS1307time(&second,&minute,&hour,&dayOfWeek,&dayOfMonth,&month,&year);
  // send it to the lcd
  lcd.setCursor(0,0);
  if (hour<10) lcd.print("0");
  lcd.print(hour);lcd.print(":");
  if (minute<10) lcd.print("0");
  lcd.print(minute);
  lcd.print(":");
  if (second<10) lcd.print("0");
  lcd.print(second);
}

void advance() 
{
  SekundenZeiger += 1;
  if (SekundenZeiger >= 60) SekundenZeiger = 0;
  ModulationNecessary = true ;
}

void setup() 
{
  Timer1.initialize(1000000);
  Timer1.attachInterrupt(advance);
  lcd.begin(8,1);
  Serial.begin(9600);
  Wire.begin();
  pinMode(Modulateur, OUTPUT);
  digitalWrite(Modulateur, LOW);
  pinMode(Illuminateur, OUTPUT);
  // SAVE ENERGY :-)
  digitalWrite(Illuminateur, LOW);
  pinMode(Correcteur, OUTPUT);
  pinMode(SET, INPUT_PULLUP);
  pinMode(PLUS, INPUT_PULLUP);
  pinMode(MINUS, INPUT_PULLUP);
  pinMode(ENTER, INPUT_PULLUP);
  // SET CLOCK - UNCOMMENT IF NECESSARY
  // Sec Min Hour DayOfWeek DayOfMonth Month Year
  // CHECK THAT TIME EXISTS !!!
  // SetTimeDS1307(0, 22, 16, 1, 24, 4, 17);
}

void loop() 
{
if (ModulationNecessary)
{
  switch (Data[SekundenZeiger])
  {
  
  case 0 :
  // NO MODULATION NECESSARY, IT's THE 59th SECOND
  // READ THE TIME AND CALCULATE ARRAY FOR NEXT MINUTE
  ModulationNecessary = false ;
  readDS1307time(&second,&minute,&hour,&dayOfWeek,&dayOfMonth,&month,&year);
  // 0 : UNMODULATED
  // 1 : 100 ms = LOGIC ZERO
  // 2 : 200 ms = LOGIC ONE
  Data[0] = 1 ;   // ALWAYS
  Data[1] = 1 ;   // WEATHER
  Data[2] = 1 ;   // WEATHER
  Data[3] = 1 ;   // WEATHER
  Data[4] = 1 ;   // WEATHER
  Data[5] = 1 ;   // WEATHER
  Data[6] = 1 ;   // WEATHER
  Data[7] = 1 ;   // WEATHER
  Data[8] = 1 ;   // WEATHER
  Data[9] = 1 ;   // WEATHER
  Data[10] = 1 ;   // WEATHER
  Data[11] = 1 ;   // WEATHER
  Data[12] = 1 ;   // WEATHER
  Data[13] = 1 ;   // WEATHER
  Data[14] = 1 ;   // WEATHER
  Data[15] = 1 ;   // ANTENNA (NORMAL)
  Data[16] = 1 ;   // CHANGE SUMMER/WINTERTIME = NO
  Data[17] = 2 ;   // 0 = MEZ, 1 = MESZ
  Data[18] = 1 ;   // 0 = MESZ, 1 = MEZ
  Data[19] = 1 ;   // 0 = NO SECOND TO BE ADDED 
  Data[20] = 2 ;   // ALWAYS = 1, START OF DATA
  
  Parity = 0 ;
  
  Data[27] = 1 ;   // MINUTE 40
  if (minute >39) { Data[27] = 2 ; Parity += 1; minute -= 40 ; }
  Data[26] = 1 ;   // MINUTE 20
  if (minute >19) { Data[26] = 2 ; Parity += 1; minute -= 20 ; }
  Data[25] = 1 ;   // MINUTE 10
  if (minute >9) { Data[25] = 2 ; Parity += 1; minute -= 10 ; }
  Data[24] = 1 ;   // MINUTE 8
  if (minute >7) { Data[24] = 2 ; Parity += 1; minute -= 8 ; }
  Data[23] = 1 ;   // MINUTE 4
  if (minute >3) { Data[23] = 2 ; Parity += 1; minute -= 4 ; }
  Data[22] = 1 ;   // MINUTE 2
  if (minute >1) {Data[22] = 2 ;Parity += 1;minute -= 2 ;}
  Data[21] = 1 ;   // MINUTE 1
  if (minute == 1) { Data[21] = 2 ; Parity += 1; }
  Data[28] = 1 ;   // PARITY BIT MINUTE
  if ((Parity & 0x01) > 0) { Data[28] = 2 ; }
  
  Parity = 0;
  
  Data[34] = 1 ;   // HOUR 20
  if (hour > 19) { Data[34] = 2 ; hour -= 20 ; Parity += 1; }
  Data[33] = 1 ;   // HOUR 10
  if (hour > 9) { Data[33] = 2 ; hour -= 10 ; Parity += 1; }
  Data[32] = 1 ;   // HOUR 8
  if (hour > 7) { Data[32] = 2 ; hour -= 8 ; Parity += 1; }
  Data[31] = 1 ;   // HOUR 4
  if (hour > 3) { Data[31] = 2 ; hour -= 4 ; Parity += 1; }
  Data[30] = 1 ;   // HOUR 2
  if (hour > 1) { Data[30] = 2 ; hour -= 2 ; Parity += 1; }
  Data[29] = 1 ;   // HOUR 1
  if (hour == 1) { Data[29] = 2 ; Parity += 1; }
  Data[35] = 1 ;   // PARITY BIT HOUR
  if ((Parity & 0x01) > 0) { Data[35] = 2 ; }
  
  Parity = 0; 
  
  Data[41] = 1 ;   // DAY OF THE MONTH 20
  if (dayOfMonth > 19) { Data[41] = 2 ; dayOfMonth -= 20 ; Parity += 1; }
  Data[40] = 1 ;   // DAY OF THE MONTH 10
  if (dayOfMonth > 9) { Data[40] = 2 ; dayOfMonth -= 10 ; Parity += 1; }
  Data[39] = 1 ;   // DAY OF THE MONTH 8
  if (dayOfMonth > 7) { Data[39] = 2 ; dayOfMonth -= 8 ; Parity += 1; }
  Data[38] = 1 ;   // DAY OF THE MONTH 4
  if (dayOfMonth > 3) { Data[38] = 2 ; dayOfMonth -= 4 ; Parity += 1; }
  Data[37] = 1 ;   // DAY OF THE MONTH 2
  if (dayOfMonth > 1) { Data[37] = 2 ; dayOfMonth -= 2 ; Parity += 1; }
  Data[36] = 1 ;   // DAY OF THE MONTH 1
  if (dayOfMonth == 1) { Data[36] = 2 ; Parity += 1; }
  Data[44] = 1 ;   // DAY OF THE WEEK 4
  if (dayOfWeek > 3) { Data[44] = 2 ; dayOfWeek -= 4 ; Parity += 1; }
  Data[43] = 1 ;   // DAY OF THE WEEK 2
  if (dayOfWeek > 1) { Data[43] = 2 ; dayOfWeek -= 2 ; Parity += 1; }
  Data[42] = 1 ;   // DAY OF THE WEEK 1
  if (dayOfWeek == 1) { Data[42] = 2 ; Parity += 1; }
  Data[49] = 1 ;   // MONTH 10
  if (month > 9) { Data[49] = 2 ; month -= 10 ; Parity += 1 ; }
  Data[48] = 1 ;   // MONTH 8
  if (month > 7) { Data[48] = 2 ; month -= 8 ; Parity += 1 ; }
  Data[47] = 1 ;   // MONTH 4
  if (month > 3) { Data[47] = 2 ; month -= 4 ; Parity += 1 ; }
  Data[46] = 1 ;   // MONTH 2
  if (month > 1) { Data[46] = 2 ; month -= 2 ; Parity += 1 ; }
  Data[45] = 1 ;   // MONTH 1
  if (month == 1) { Data[45] = 2 ; Parity += 1 ; }
  Data[57] = 1 ;   // YEAR 80
  if (year > 79) { Data[57] = 2 ; year -= 80 ; Parity += 1 ; }
  Data[56] = 1 ;   // YEAR 40
  if (year > 39) { Data[56] = 2 ; year -= 40 ; Parity += 1 ; }
  Data[55] = 1 ;   // YEAR 20
  if (year > 19) { Data[55] = 2 ; year -= 20 ; Parity += 1 ; }
  Data[54] = 1 ;   // YEAR 10
  if (year > 9) { Data[54] = 2 ; year -= 10 ; Parity += 1 ; }
  Data[53] = 1 ;   // YEAR 8
  if (year > 7) { Data[53] = 2 ; year -= 8 ; Parity += 1 ; }
  Data[52] = 1 ;   // YEAR 4
  if (year > 3) { Data[52] = 2 ; year -= 4 ; Parity += 1 ; }
  Data[51] = 1 ;   // YEAR 2
  if (year > 1) { Data[51] = 2 ; year -= 2 ; Parity += 1 ; }
  Data[50] = 1 ;   // YEAR 1
  if (year == 1) { Data[50] = 2 ; Parity += 1 ; }
  Data[58] = 1 ;   // PARITY BIT DATE
  if ((Parity & 0x01) > 0) { Data[58] = 2 ; }
  Data[59] = 0 ;   // ALMOST ALWAYS
  // UPDATE TIME 
  lcd.setCursor(0,0);
  displayTime();
  // DEBUG
  for (int l=0; l<60; l++) 
  {
    if (Data[l] == 0) Serial.print(" ");
    if (Data[l] == 1) Serial.print("0");
    if (Data[l] == 2) Serial.print("1");
    if (l == 0) Serial.print("-");
    if (l == 14) Serial.print("-");
    if (l == 20) Serial.print("-");
    if (l == 28) Serial.print("-");
    if (l == 35) Serial.print("-");
    if (l == 41) Serial.print("-");
    if (l == 44) Serial.print("-");
    if (l == 49) Serial.print("-");
  }
  Serial.print(" ");
  if (hour<10) Serial.print("0");
  Serial.print(hour);Serial.print(":");
  if (minute<10) Serial.print("0");
  Serial.print(minute);
  Serial.print("  ");
  if (dayOfWeek == 1) Serial.print("Monday, ");
  if (dayOfWeek == 2) Serial.print("Tuesday, ");
  if (dayOfWeek == 3) Serial.print("Wednesday, ");
  if (dayOfWeek == 4) Serial.print("Thursday, ");
  if (dayOfWeek == 5) Serial.print("Friday, ");
  if (dayOfWeek == 6) Serial.print("Saturday, ");
  if (dayOfWeek == 7) Serial.print("Sunday, ");
  if (dayOfMonth<10) Serial.print("0");
  Serial.print(dayOfMonth);Serial.print(".");
  if (month<10) Serial.print("0");
  Serial.print(month);Serial.print(".");
  Serial.print((year+2000),DEC);Serial.println(" ");
  break;
  
  case 1 :
  // SHORT PULSE MODULATION: 100 ms 
  // delay(100); // NOT :-) ALIGN PULSES
  digitalWrite(Modulateur, LOW);
  digitalWrite(Correcteur, HIGH) ;
  delay(100);
  digitalWrite(Modulateur, HIGH);
  digitalWrite(Correcteur, LOW) ;
  ModulationNecessary = false ;
  lcd.setCursor(0,0);
  displayTime();
  break;
  
  case 2 :
  // LONG PULSE MODULATION: 200 ms 
  digitalWrite(Modulateur, LOW);
  digitalWrite(Correcteur, HIGH) ;
  delay(200);
  digitalWrite(Modulateur, HIGH);
  digitalWrite(Correcteur, LOW) ;
  ModulationNecessary = false ;
  lcd.setCursor(0,0);
  displayTime();
  break;
         
  }  // END SWITCH      
} // END IF
delay(1);
}

// ///////////////////////////////////////////////////////////// 
// END OF FILE.
// /////////////////////////////////////////////////////////////



DCF-77 Signal Generator


The sketch outputs all data to the serial bus - for easy debugging - e.g. with this website.




✈ Downloads








✈ Notes




The sketch presented above does not make use of the buttons to set the time. Instead it is set by the "setup". Usually such "nice to have" functions are declared as homework. If your lab is veeeeery big, you mayst want to use a power amplifier. The vellemann K8060 (200W amplifier kit) delivers 100 Watts (rms) into a 4 Ω load, up to 200 kHz and seems very promising. And yes, the time on the lcd display is 1 minute in advance, as the sent bitstream is the time of the next minute. Some clocks are very smart. Do not send MEZ (= winter time) in June, this mayst cause them to reject the received information. Some are known to synchronise once a day, at 04:00 (early in the morning :-) so if you want to surprise someone - get up early ...




✈ DISCLAIMER
The board is used to synchronize our experiments (non-radiated, different frequency). This (single) one here has been developped in my free time and is a fully private project. It is not intended to interfer with other countries time standards. But it does well serve to attract trainees and build/test clocks - where the original signal is too weak.




✈ Share your thoughts



The webmaster does not read these comments regularely. Urgent questions should be send via email. Ads or links to completely uncorrelated things will be removed.


Your Browser says that you allow tracking. Mayst we suggest that you check that DNT thing ?

 
t1 = 6585 d

t2 = 279 ms

★ ★ ★  Copyright © 2006 - 2024 by changpuak.ch  ★ ★ ★

Impressum