Frankfurter Funkuhr (DCF 77 Code) (Schleifen)
Unsere Funkuhren werden aus Mainhausen bei Frankfurt mittels DCF77-Code gesteuert. DCF77 steht dabei für "Deutschland (D), Langwelle (C) Frankfurt (F) 77 (genau 77.5kHz)".
Ein Signal von 77.5kHz wird dabei permanent gesendet. Jede Sekunde wird das Signal kurz unterbrochen. Diese Unterbrechungen werden Absenkungen genannt. Es existiert eine kurze Absenkung von 0.1 Sekunden und eine lange Absenkung von 0.2 Sekunden. Nennen wir die beiden Absenkungen K für kurz (K = 0 = Null-Bit) und L für lang (L = 1 = Einsbit). In der 59. Sekunde jeder Minute wird keine Absenkung gemacht; nennen wir die 59. Sekunde "0" (Null Absenkung). Es handelt sich also um einen Code mit drei Symbolen: "K", "L" und "0".
Jede Position in der Minute hat seine eigene Bedeutung. Wie folgt:
0xxxxxxxxxxxxxxrmmms1mmmmmmmMssssssSddddddwwwmmmmmjjjjjjjjDX0
+ Bit 0 ist immer 0
++++++++++++++ Bit 1 - 14 Reserviert. Zur Zeit: Wetterinfo.
Nicht beachten für die Zeit
+ Bit 15: 1 = Alarm
+ Bit 16: 1 = MEZ/MESZ Umstellung in der nächsten Stunde
+ Bit 17: 0 = MEZ 1=MESZ
+ Bit 18: 0 = MESZ 1 = MEZ
+ Bit 19: 1: Am Ende dieser Stunde wird eine
Schaltsekunde eingefügt.
+ Bit 20: Immer 1: Beginn der Minuten
++++++++ Bit 21 - 28: mmmm = Minute Einer,
danach mmm = Minute Zehner,
dann M = Minute Parität
+++++++ Bit 29 - 35:
ssss = Stunde Einer,
danach ss = Stunde Zehner,
dann S = Parität Stunde
++++++++++++++++++++++++ :
Bit 36 - 58:
Tag (dddd,dd),
Wochentag (www),
Monat (mmmm,m),
Jahr (jjjj,jjjj) + Pariät (D)
Bit 59: Keine Marke
(weder 0 noch 1 -> Synchronisation)
Zweistellige Zahlen, wie z. B. die Minute, werden sog. dezimal-binär codiert. Das heißt jede Ziffer wird mit zwei, drei oder vier Bit codiert. In der Regel braucht es vier Bit pro Dezimalziffer. Sind bei einem Zehner die hohen Dezimalstellen nicht möglich, so werden weniger Bit verwendet. Zudem ist es im DCF77 üblich, zuerst die Einer und erst danach die Zehner zu senden. Die Minute 56 wird also KLLK'LKL gesendet (0110 für den Einer und 101 für den Zehner). Speziell ist noch, dass die Bits von links her zu lesen sind. Das erste auftretende Bit in Zahlen sind die Einer, gefolgt von den Zweiern und so fort. Gleich am Beispiel der Minute:
Bit Nr. 21 | Bit für Wert 1 | |
Bit Nr. 22 | Bit für Wert 2 | |
Bit Nr. 23 | Bit für Wert 4 | |
Bit Nr. 24 | Bit für Wert 8 | |
Bit Nr. 25 | Bit für Wert 10 | |
Bit Nr. 26 | Bit für Wert 20 | |
Bit Nr. 27 | Bit für Wert 40 |
Somit liest sich 1010'101 wie 1 + 4 + 10 + 40, also Minute 55.
Beim Wochentag steht 1 für den Montag (LKL ist also der Freitag). Das Paritätsbit bezeichnet hier eine gerade Parität; d. h. für eine ungerade Anzahl 1-Bits, wird ein weiteres 1-Bit gesetzt, sodass die gesamte Anzahl Bits gerade wird.
Was bedeutet nun der folgende Ausschnitt?
KLLKKKKKLL_KLKKLKKLKKLKKLKKKKLKLLKLKLKLKKKKLLKKKKKKLKLLLKKKLKKKLLKKKKKLK_KLKKLK
Schreiben Sie ein Programm, das eine solche Sequenz analysiert und die zugehörige Zeit ausgibt. Dabei ist am einfachsten das Null-Bit (_), also die Startmarke zu suchen.
Schreiben Sie auch die Umkehrung, bei der eine Zeit (yyyy mm. dd. hh:mm www) in das Signal umgewandelt wird. fügen Sie automatisch das Synchronistatios-Bit (0) ein und für die Reservierten Stellen (1-14) erzeugen Sie einfach ein paar Sterne oder eine Zufallsfolge aus "K"s und "L"s.
.
12 Kommentare
3 Lösung(en)
// Autor: Andy Großhennig
// Solution for task: Frankfurter Funkuhr (DCF 77 Code) (Schleifen)
/*
* Jede Sekunde wird das Signal kurz unterbrochen.
* Diese Unterbrechungen werden Absenkungen genannt.
* Es existiert eine kurze Absenkung von 0.1 Sekunden und eine lange Absenkung von 0.2 Sekunden.
* Nennen wir die beiden Absenkungen K für kurz (K = 0 = Null-Bit) und L für lang (L = 1 = Einsbit).
* In der 59. Sekunde jeder Minute wird keine Absenkung gemacht; nennen wir die 59. Sekunde "0" (Null Absenkung).
* Es handelt sich also um einen Code mit drei Symbolen: "K", "L" und "0".
*
* 0 5 10 15 20 25 30 35 40 45 50 55 60 }=> (+1)
* 0|xxxxxxxxxxxxxx|rmmms1|mmmmmmmM|ssssssS|dddddd|www|mmmmm|jjjjjjjjD|X|0
*
* + Bit 0 ist immer 0
* + Bit 1 - 14 Reserviert. Zur Zeit: Wetterinfo. Nicht beachten für die Zeit.
* + Bit 15: 1 = Alarm
* + Bit 16: 1 = MEZ/MESZ Umstellung in der nächsten Stunde
* + Bit 17: 0 = MEZ 1=MESZ
* + Bit 18: 0 = MESZ 1 = MEZ
* + Bit 19: 1: Am Ende dieser Stunde wird eine Schaltsekunde eingefügt.
* + Bit 20: Immer 1: Beginn der Minuten
* + Bit 21 - 28: mmmm = Minute Einer, danach mmm = Minute Zehner, dann M = Minute Parität
* + Bit 29 - 35: ssss = Stunde Einer, danach ss = Stunde Zehner, dann S = Parität Stunde
* + Bit 36 - 58: Tag (dddd,dd), Wochentag (www), Monat (mmmm,m), Jahr (jjjj,jjjj) + Pariät (D)
* + Bit 59: Keine Marke (weder 0 noch 1 -> Synchronisation)
*
* Zweistellige Zahlen, wie z. B. die Minute, werden sog. dezimal-binär codiert.
* Das heißt jede Ziffer wird mit zwei, drei oder vier Bit codiert. In der Regel braucht es vier Bit pro Dezimalziffer.
* Sind bei einem Zehner die hohen Dezimalstellen nicht möglich, so werden weniger Bit verwendet. Zudem ist es im DCF77 üblich, zuerst die Einer und erst danach die Zehner zu senden.
* Die Minute 56 wird also KLLK'LKL gesendet (0110 für den Einer und 101 für den Zehner).
*
* Beim Wochentag steht 1 für den Montag (LKL ist also der Freitag).
* Das Paritätsbit bezeichnet hier eine gerade Parität; d. h. für eine ungerade Anzahl 1-Bits, wird ein weiteres 1-Bit gesetzt, sodass die gesamte Anzahl Bits gerade wird.
*/
#include <iostream>
#include <string>
using namespace std;
string translateIntegertoBinary(string sCode)
{
// If: Translate the day to a binary code
if(sCode == "mo" || sCode == "Mo" || sCode == "MO" || sCode == "montag" || sCode == "Montag")
sCode = "KKL";
else if(sCode == "di" || sCode == "Di" || sCode == "DI" || sCode == "dienstag" || sCode == "Dienstag")
sCode = "KLK";
else if(sCode == "mi" || sCode == "Mi" || sCode == "MI" || sCode == "mittwoch" || sCode == "Mittwoch")
sCode = "KLL";
else if(sCode == "do" || sCode == "Do" || sCode == "DO" || sCode == "donnerstag" || sCode == "Donnerstag")
sCode = "LKK";
else if(sCode == "fr" || sCode == "Fr" || sCode == "FR" || sCode == "freitag" || sCode == "Freitag")
sCode = "LKL";
else if(sCode == "sa" || sCode == "Sa" || sCode == "SA" || sCode == "samstag" || sCode == "Samstag" || sCode == "sonnabend" || sCode == "Sonnabend")
sCode = "LLK";
else if(sCode == "so" || sCode == "So" || sCode == "SO" || sCode == "sonntag" || sCode == "Sonntag")
sCode = "LLL";
return sCode;
}
// Function: Analyze a time
void analyzeTime()
{
string sInput[3] = {"montag", "28.01.1991", "07:00"};
string sCode = "KKKKKKKKKKKKKKKKKKKKL";
string sAdd = "";
short shOneBits = 0;
printf("Geben sie einen Wochentag ein: ");
cin >> sInput[0];
printf("Geben sie ein Datum ein (XX.XX.XXXX): ");
cin >> sInput[1];
printf("Geben sie eine Uhrzeit ein (XX:XX): ");
cin >> sInput[2];
// Switch: One minutes
switch(sInput[2].at(4))
{
case '0': sAdd = "KKKK";
shOneBits = 0;
break;
case '1': sAdd = "KKKL";
shOneBits = 1;
break;
case '2': sAdd = "KKLK";
shOneBits = 1;
break;
case '3': sAdd = "KKLL";
shOneBits = 2;
break;
case '4': sAdd = "KLKK";
shOneBits = 1;
break;
case '5': sAdd = "KLKL";
shOneBits = 2;
break;
case '6': sAdd = "KLLK";
shOneBits = 2;
break;
case '7': sAdd = "KLLL";
shOneBits = 3;
break;
case '8': sAdd = "LKKK";
shOneBits = 1;
break;
case '9': sAdd = "LKKL";
shOneBits = 2;
break;
}
sCode += sAdd;
// Switch: Ten minutes
switch(sInput[2].at(3))
{
case '0': sAdd = "KKK";
shOneBits += 0;
break;
case '1': sAdd = "KKL";
shOneBits += 1;
break;
case '2': sAdd = "KLK";
shOneBits += 1;
break;
case '3': sAdd = "KLL";
shOneBits += 2;
break;
case '4': sAdd = "LKK";
shOneBits += 1;
break;
case '5': sAdd = "LKL";
shOneBits += 2;
break;
}
sCode += sAdd;
// If: Parität minutes
if((shOneBits % 2) == 0)
sCode += "K";
else
sCode += "L";
shOneBits = 0;
// Switch: One hours
switch(sInput[2].at(1))
{
case '0': sAdd = "KKKK";
shOneBits = 0;
break;
case '1': sAdd = "KKKL";
shOneBits = 1;
break;
case '2': sAdd = "KKLK";
shOneBits = 1;
break;
case '3': sAdd = "KKLL";
shOneBits = 2;
break;
case '4': sAdd = "KLKK";
shOneBits = 1;
break;
case '5': sAdd = "KLKL";
shOneBits = 2;
break;
case '6': sAdd = "KLLK";
shOneBits = 2;
break;
case '7': sAdd = "KLLL";
shOneBits = 3;
break;
case '8': sAdd = "LKKK";
shOneBits = 1;
break;
case '9': sAdd = "LKKL";
shOneBits = 2;
break;
}
sCode += sAdd;
// Switch: Ten hours
switch(sInput[2].at(0))
{
case '0': sAdd = "KK";
shOneBits += 0;
break;
case '1': sAdd = "KL";
shOneBits += 1;
break;
case '2': sAdd = "LK";
shOneBits += 1;
break;
}
sCode += sAdd;
// If: Parität hours
if((shOneBits % 2) == 0)
sCode += "K";
else
sCode += "L";
shOneBits = 0;
// Switch: One days
switch(sInput[1].at(1))
{
case '0': sAdd = "KKKK";
shOneBits = 0;
break;
case '1': sAdd = "KKKL";
shOneBits = 1;
break;
case '2': sAdd = "KKLK";
shOneBits = 1;
break;
case '3': sAdd = "KKLL";
shOneBits = 2;
break;
case '4': sAdd = "KLKK";
shOneBits = 1;
break;
case '5': sAdd = "KLKL";
shOneBits = 2;
break;
case '6': sAdd = "KLLK";
shOneBits = 2;
break;
case '7': sAdd = "KLLL";
shOneBits = 3;
break;
case '8': sAdd = "LKKK";
shOneBits = 1;
break;
case '9': sAdd = "LKKL";
shOneBits = 2;
break;
}
sCode += sAdd;
// Switch: Ten days
switch(sInput[1].at(0))
{
case '0': sAdd = "KK";
shOneBits += 0;
break;
case '1': sAdd = "KL";
shOneBits += 1;
break;
case '2': sAdd = "LK";
shOneBits += 1;
break;
case '3': sAdd = "LL";
shOneBits += 2;
break;
}
sCode += sAdd;
sCode += translateIntegertoBinary(sInput[0]);
// Switch: One months
switch(sInput[1].at(4))
{
case '0': sAdd = "KKKK";
shOneBits = 0;
break;
case '1': sAdd = "KKKL";
shOneBits = 1;
break;
case '2': sAdd = "KKLK";
shOneBits = 1;
break;
case '3': sAdd = "KKLL";
shOneBits = 2;
break;
case '4': sAdd = "KLKK";
shOneBits = 1;
break;
case '5': sAdd = "KLKL";
shOneBits = 2;
break;
case '6': sAdd = "KLLK";
shOneBits = 2;
break;
case '7': sAdd = "KLLL";
shOneBits = 3;
break;
case '8': sAdd = "LKKK";
shOneBits = 1;
break;
case '9': sAdd = "LKKL";
shOneBits = 2;
break;
}
sCode += sAdd;
// Switch: Ten months
switch(sInput[1].at(3))
{
case '0': sAdd = "K";
shOneBits += 0;
break;
case '1': sAdd = "L";
shOneBits += 1;
break;
}
sCode += sAdd;
// Switch: One years
switch(sInput[1].at(9))
{
case '0': sAdd = "KKKK";
shOneBits = 0;
break;
case '1': sAdd = "KKKL";
shOneBits = 1;
break;
case '2': sAdd = "KKLK";
shOneBits = 1;
break;
case '3': sAdd = "KKLL";
shOneBits = 2;
break;
case '4': sAdd = "KLKK";
shOneBits = 1;
break;
case '5': sAdd = "KLKL";
shOneBits = 2;
break;
case '6': sAdd = "KLLK";
shOneBits = 2;
break;
case '7': sAdd = "KLLL";
shOneBits = 3;
break;
case '8': sAdd = "LKKK";
shOneBits = 1;
break;
case '9': sAdd = "LKKL";
shOneBits = 2;
break;
}
sCode += sAdd;
// Switch: Ten years
switch(sInput[1].at(8))
{
case '0': sAdd = "KKKK";
shOneBits = 0;
break;
case '1': sAdd = "KKKL";
shOneBits = 1;
break;
case '2': sAdd = "KKLK";
shOneBits = 1;
break;
case '3': sAdd = "KKLL";
shOneBits = 2;
break;
case '4': sAdd = "KLKK";
shOneBits = 1;
break;
case '5': sAdd = "KLKL";
shOneBits = 2;
break;
case '6': sAdd = "KLLK";
shOneBits = 2;
break;
case '7': sAdd = "KLLL";
shOneBits = 3;
break;
case '8': sAdd = "LKKK";
shOneBits = 1;
break;
case '9': sAdd = "LKKL";
shOneBits = 2;
break;
}
sCode += sAdd;
// If: Parität date
if((shOneBits % 2) == 0)
sCode += "K";
else
sCode += "L";
shOneBits = 0;
sCode += "X0";
cout << sCode << "\n\n";
}
// Function: Translate a binary number to the integer counterpart
char translateBinarytoInteger(string sBinary)
{
char cNumber = '0';
// If: Translate a binary code to a integer
if(sBinary == "K" || sBinary == "KK" || sBinary == "KKK" || sBinary == "KKKK")
cNumber = '0';
else if(sBinary == "L" || sBinary == "KL" || sBinary == "KKL" || sBinary == "KKKL")
cNumber = '1';
else if(sBinary == "LK" || sBinary == "KLK" || sBinary == "KKLK")
cNumber = '2';
else if(sBinary == "LL" || sBinary == "KLL" || sBinary == "KKLL")
cNumber = '3';
else if(sBinary == "LKK" || sBinary == "KLKK")
cNumber = '4';
else if(sBinary == "LKL" || sBinary == "KLKL")
cNumber = '5';
else if(sBinary == "LLK" || sBinary == "KLLK")
cNumber = '6';
else if(sBinary == "LLL" || sBinary == "KLLL")
cNumber = '7';
else if(sBinary == "LKKK")
cNumber = '8';
else if(sBinary == "LKKL")
cNumber = '9';
else if(sBinary == "0")
cNumber = '0';
else
printf("Fehler beim Uebersetzen einer Binaeren Zahl!\n");
return cNumber;
}
// Function: If the begin of the code is not '0', remove the first character until the begin is '0'
void trim(string *sCode)
{
// Loop: Delete all charakters until the 0-Bit
for(unsigned short shFirst = 0;shFirst < (*sCode).length();)
{
if((*sCode).at(shFirst) != '0')
(*sCode).erase((*sCode).begin());
else
break;
}
(*sCode).erase((*sCode).begin());
}
// Function: Analyze a code
void analyzeCode()
{
string sCode;
cout << "60 stelligen Zeitcode eingeben (0KLLKLK...)\n";
cin >> sCode;
cout << "\n\n";
char c_arrMinutes[2]; //21-27 -> (E)1234,(Z)567
char c_arrHours[2]; //29-34 -> (E)1234,(Z)56
char c_arrDate[2]; //36-41 -> (E)1234,(Z)56
string sDays; //42-44 -> (1-7 - MO = 1)
char c_arrMonths[5]; //45-49 -> (E)1234,(Z)5
char c_arrYears[8]; //50-57 -> (E)1234,(Z)5678
string sBinary = "";
// If: Check if the first character is '0'
if(sCode.at(0) != 0)
{
trim(&sCode);
}
//*****Analyzing***Minutes*****//
sBinary = sCode[21]; sBinary+= sCode[22]; sBinary += sCode[23]; sBinary += sCode[24];
c_arrMinutes[1] = translateBinarytoInteger(sBinary);
sBinary = sCode[25]; sBinary+= sCode[26]; sBinary += sCode[27];
c_arrMinutes[0] = translateBinarytoInteger(sBinary);
//*****Analyzing***Hours*****//
sBinary = sCode[29]; sBinary+= sCode[30]; sBinary += sCode[31]; sBinary += sCode[32];
c_arrHours[1] = translateBinarytoInteger(sBinary);
sBinary = sCode[33]; sBinary+= sCode[34];
c_arrHours[0] = translateBinarytoInteger(sBinary);
//*****Analyzing***Date*****//
sBinary = sCode[36]; sBinary+= sCode[37]; sBinary += sCode[38]; sBinary += sCode[39];
c_arrDate[1] = translateBinarytoInteger(sBinary);
sBinary = sCode[40]; sBinary+= sCode[41];
c_arrDate[0] = translateBinarytoInteger(sBinary);
//*****Analyzing***Day*****//
sBinary = sCode[42]; sBinary+= sCode[43]; sBinary += sCode[44];
switch(translateBinarytoInteger(sBinary))
{
case '1': sDays = "Montag";
break;
case '2': sDays = "Dienstag";
break;
case '3': sDays = "Mittwoch";
break;
case '4': sDays = "Donnerstag";
break;
case '5': sDays = "Freitag";
break;
case '6': sDays = "Samstag";
break;
case '7': sDays = "Sonntag";
break;
default: sDays = "Fehler!";
}
//*****Analyzing***Month*****//
sBinary = sCode[45]; sBinary+= sCode[46]; sBinary += sCode[47]; sBinary += sCode[48];
c_arrMonths[1] = translateBinarytoInteger(sBinary);
sBinary = sCode[49];
c_arrMonths[0] = translateBinarytoInteger(sBinary);
//*****Analyzing***Years*****//
sBinary = sCode[50]; sBinary+= sCode[51]; sBinary += sCode[52]; sBinary += sCode[53];
c_arrYears[1] = translateBinarytoInteger(sBinary);
sBinary = sCode[54]; sBinary+= sCode[55]; sBinary += sCode[56]; sBinary += sCode[57];
c_arrYears[0] = translateBinarytoInteger(sBinary);
//*****Output*****//
cout << "Tag: " << sDays << endl << "Datum: " << c_arrDate[0] << c_arrDate[1] << "." << c_arrMonths[0] << c_arrMonths[1] << "." << c_arrYears[0] << c_arrYears[1] << endl;
cout << "Uhrzeit: " << c_arrHours[0] << c_arrHours[1] << ":" << c_arrMinutes[0] << c_arrMinutes[1] << endl;
}
// Function: Manage the analyze
void analyze()
{
bool isTimeProvide;
char cOption;
cout << "Wollen sie eine Zeit oder ein Zeitsignal eingeben? (z/s) ";
cin >> cOption;
if(cOption == 'z')
isTimeProvide = true;
else
isTimeProvide = false;
// If: Check whether the input is a time
if(isTimeProvide == true)
analyzeTime();
else
analyzeCode();
}
int main()
{
analyze();
cout << "\n\n";
system("Pause");
return 0;
}
Lösung von: Andy Großhennig (Bundeswehr)
/**
* @author : philipp gressly freimann (phi@gress.ly)
* @date : Feb. 2014
* @copy : philipp gressly freimann, winterthur, switzerland
* @version: 1.1
* @license: http://www.gnu.org/licenses/gpl.txt
*
* Programmiersprache "wiring" (Arduino c++)
*
* Tipp: UBUNTU: Enable serial port as follows
* >sudo chmod a+rw /dev/ttyACM0
* (unfortunately, you have to do this from time to time)
*
* Empfange das DFC77-Signal und leite daraus die Uhrzeit ab.
* Natürlich könnte man die entsprechende Bibliothek verwenden, doch
* genau darum geht es: Lese und parse die Uhrzeit selbst!
*
*/
// Arduino UNO/Leonardo
#define ANALOG_SIGNAL_IN_PIN (A0)
///// AT-Tiny45 (muss beim Hochladen via Arduino berücksichtigt werden):
//#define ANALOG_SIGNAL_IN_PIN (0) // Kontakt 5
// Wenn analog in > 500 change to < 10
#define MINIMAX (500)
#define MINVOLT ( 10)
// Millisekunden für die kurzen und langen Absenkungen im DCF77
#define SHORT_BIT_MIN (75)
#define SHORT_BIT_MAX (155)
#define LONG_BIT_MIN (177)
#define LONG_BIT_MAX (300)
#define ABTASTRATE (20) /* Millisekunden */
// ZEIT, welche gültig gelesen wurde (-1 = ungültig)
boolean datumIstGueltig = false;
int actMinute ;
int actStunde ;
int actTag ;
int actTagImMonat ;
int actWochentag ; // 1 = Montag
int actMonat ;
int actJahrMod100 ; // letzte zwei Ziffern der Jahrzahl
int actSekundenNummer = 0;// 0 .. 58 (59 = lücke)
char time_bits[59]; // '0' or '1'
void setup() {
Serial.begin(9600); // debug only
actSekundenNummer = 0;
pinMode(ANALOG_SIGNAL_IN_PIN, INPUT);
}
// Im ersten Durchgang noch keine Uhrzeit ausgeben: Sie wäre falsch.
boolean ersterDurchgang = true;
long oldOff = 0; // um das 60. Bit (Bit Nr. 59), also die Lücke zu finden
void loop() {
showTime(actSekundenNummer);
long timeStampON;
timeStampON = warteAufStartVonBit();
long timeStampOFF;
timeStampOFF = warteAufEndeBit();
int bitlen = timeStampOFF - timeStampON;
if(timeStampON - oldOff > 1500) {
actSekundenNummer = 0;
showTime(0);
Serial.println("");
Serial.println(">>>>>>>>>>>>>>>>>>>>>>>>> NEXT MINUTE <<<<<<<<<<<<<<<<<<<<<<");
if(! ersterDurchgang) {
berechneZeitvariable();
} else {
ersterDurchgang = false;
}
}
bitlen = bitlen - 20;
if((SHORT_BIT_MIN < bitlen) && (bitlen < SHORT_BIT_MAX)) {
setBit('0');
} else
if((LONG_BIT_MIN < bitlen) && (bitlen < LONG_BIT_MAX)) {
setBit('1');
} else {
// Fehlermeldung für ungültiges Bit.
Serial.write("# (");
Serial.print(bitlen);
Serial.write("ms)");
datumIstGueltig = false;
actSekundenNummer = 0;
}
oldOff = timeStampOFF;
//Serial.write("Bit: ");
//Serial.print(bit);
long nextMinuteTS = timeStampON + 1000;
long jetzt = millis();
long wieLangeNoch = nextMinuteTS - jetzt;
// Nicht bis unmittelbar vor das nächste Siglan warten, da
// a eine Ungenauigkeit existiert und b die Zeit ja noch
// ausgegeben werden muss.
// Hier 50 millisekunden für die Ausgabe
//Serial.write("delay");
// Nachdem die debug info weg ist, kann 50 durch 1-2 ms ersetzt werden
// max, damit sicher nicht weniger als 1 ms gewartet wird.
delay(max(1, wieLangeNoch - ABTASTRATE - 50));
}
// Ausgabe der Zeit hier auf der Seriellen Schnittstelle
// Später im DIGITAL-Display
void showTime(int actSekundenNummer) {
//Serial.write("debug start show time");
//Serial.println();
korrektheitPruefen();
if(! datumIstGueltig) {
Serial.write(".");
return;
}
//Am rechnen:
if(0 == actMonat) {
Serial.write("_");
return;
}
// Wochentag
if(1 == actWochentag) {Serial.write(" Montag, ");}
if(2 == actWochentag) {Serial.write(" Dienstag, ");}
if(3 == actWochentag) {Serial.write(" Mittwoch, ");}
if(4 == actWochentag) {Serial.write("Donnerstag, ");}
if(5 == actWochentag) {Serial.write(" Freitag, ");}
if(6 == actWochentag) {Serial.write(" Samstag, ");}
if(7 == actWochentag) {Serial.write(" Sonntag, ");}
// Tag und Monat
Serial.print(actTagImMonat);
Serial.write(". ");
Serial.print(actMonat);
Serial.write(". ");
// jahr
Serial.write("20"); // Akt Jahrhundert - 1
if(actJahrMod100 < 10) {Serial.write("0");}
Serial.print(actJahrMod100);
Serial.write(" ");
// Stunde Minute Sekunde
if(actStunde < 10) {Serial.write("0");}
Serial.print(actStunde);
Serial.write(":");
if(actMinute < 10) {Serial.write("0");}
Serial.print(actMinute);
if(0 != actSekundenNummer) {
Serial.write(" und ");
if(actSekundenNummer < 10) {
Serial.write(" "); // ausrichten
}
Serial.print(actSekundenNummer);
if(1 != actSekundenNummer) {
Serial.println(" Sekunden.");
} else {
Serial.println(" Sekunde.");
}
}
}
/**
* Prüfe, ob alle Zahlen möglich sind, und ob die
* Paritätsbits stimmen.
* Diese Prüfung wird immer erst vollzogen, wenn alle Bits der
* gesuchten Zeitangabe übermittelt wurden.
* Beispiel: aktSekundenNummer = 29 jetzt Minuten und Parität prüfen
*/
void korrektheitPruefen() {
datumIstGueltig = false;
/* Prüfe Minute */
if(invalid(actMinute, 0, 59, 21, 27, 28)) {
return;
}
/* Stunde */
if(invalid(actStunde, 0, 24, 29, 34, 35)) {
return;
}
/* Einzelne Einträge noch nicht prüfen, sondern nur die Parität: */
if(invalid(0, 0, 0, 36, 57, 58)) {
return;
}
/* Prüfe Gültigkeit, aber keine Parität */
if(59 == actSekundenNummer) {
if(0 >= actTagImMonat || actTagImMonat > 31) {
datumIstGueltig = false;
return;
}
if(actWochentag < 1) {
datumIstGueltig = false;
return;
}
if(0 >= actMonat || actMonat > 12) {
datumIstGueltig = false;
return;
}
if(0 > actJahrMod100 || actJahrMod100 > 99) {
datumIstGueltig = false;
return;
}
}
datumIstGueltig = true;
}
boolean invalid(int wert, int minWert, int maxWert, int b1, int bn, int pb) {
// Nix prüfen, wenn noch nicht da. Erst, wenn Prüfbit gelesen, dann testen.
if(pb == actSekundenNummer - 1) {
/* Existiert? */
if(wert < minWert || wert > maxWert) {
datumIstGueltig = false;
return true; //IN-valid
}
// Prüfe, ob die gelesene Parität (bit bp) mit der berechneten übereinstimmt
if(('1' == time_bits[pb]) ^ (1 == berechneParitaet(b1, bn))) {
return true; // IN-valid
}
}
return false; // not IN-valid
}
int berechneParitaet(int erstesBit, int letztesBit) {
int paritaet = 0;
int idx;
for(idx = erstesBit; idx <= letztesBit; idx++) {
if('1' == time_bits[idx]) {
paritaet ++;
}
}
return paritaet % 2;
}
void berechneZeitvariable() {
datumIstGueltig = true;
int hh = 0; // hh of next Minute
if('1' == time_bits[34]) { hh = hh + 20;}
if('1' == time_bits[33]) { hh = hh + 10;}
if('1' == time_bits[32]) { hh = hh + 8;}
if('1' == time_bits[31]) { hh = hh + 4;}
if('1' == time_bits[30]) { hh = hh + 2;}
if('1' == time_bits[29]) { hh = hh + 1;}
actStunde = hh;
int mm = 0; // next Minute
if('1' == time_bits[27]) { mm = mm + 40;}
if('1' == time_bits[26]) { mm = mm + 20;}
if('1' == time_bits[25]) { mm = mm + 10;}
if('1' == time_bits[24]) { mm = mm + 8;}
if('1' == time_bits[23]) { mm = mm + 4;}
if('1' == time_bits[22]) { mm = mm + 2;}
if('1' == time_bits[21]) { mm = mm + 1;}
actMinute = mm;
int dd = 0; // Tag im Monat
if('1' == time_bits[41]) { dd = dd + 20;}
if('1' == time_bits[40]) { dd = dd + 10;}
if('1' == time_bits[39]) { dd = dd + 8;}
if('1' == time_bits[38]) { dd = dd + 4;}
if('1' == time_bits[37]) { dd = dd + 2;}
if('1' == time_bits[36]) { dd = dd + 1;}
actTagImMonat = dd;
int mon = 0; // Monatsnummer
if('1' == time_bits[49]) { mon = mon + 10;}
if('1' == time_bits[48]) { mon = mon + 8;}
if('1' == time_bits[47]) { mon = mon + 4;}
if('1' == time_bits[46]) { mon = mon + 2;}
if('1' == time_bits[45]) { mon = mon + 1;}
actMonat = mon;
int wot = 0; // Wochentagsnummer 1=Mo.
if('1' == time_bits[44]) { wot = wot + 4;}
if('1' == time_bits[43]) { wot = wot + 2;}
if('1' == time_bits[42]) { wot = wot + 1;}
actWochentag = wot;
int jj = 0; // Jahr modulo 100 (Einer- und Zehnerstelle)
if('1' == time_bits[57]) { jj = jj + 80;}
if('1' == time_bits[56]) { jj = jj + 40;}
if('1' == time_bits[55]) { jj = jj + 20;}
if('1' == time_bits[54]) { jj = jj + 10;}
if('1' == time_bits[53]) { jj = jj + 8;}
if('1' == time_bits[52]) { jj = jj + 4;}
if('1' == time_bits[51]) { jj = jj + 2;}
if('1' == time_bits[50]) { jj = jj + 1;}
actJahrMod100 = jj;
// BIT 0 ist immer 0
if(time_bits[0] != '0') {
datumIstGueltig = false;
return;
}
// BIT 20 (beginn Zeitinfo ist immer 1)
if(time_bits[20] != '1') {
datumIstGueltig = false;
return;
}
}
void setBit(char actBit) {
time_bits[actSekundenNummer] = actBit;
actSekundenNummer = actSekundenNummer + 1;
if(actSekundenNummer > 58) {
actSekundenNummer = 0;
datumIstGueltig = false;
}
}
long warteAufStartVonBit() {
int summe = 0;
while(true) {
int in = analogRead(ANALOG_SIGNAL_IN_PIN);
if(in < MINVOLT) {summe = summe + 1;}
if(in > MINIMAX) {summe = 0 ;} // RESET
if(summe > 2) {return millis() - 3*ABTASTRATE/2;}
delay(ABTASTRATE);
}
return 0;
}
long warteAufEndeBit() {
int summe = 0;
while(true) {
int in = analogRead(ANALOG_SIGNAL_IN_PIN);
if(in > MINIMAX) { summe = summe + 1;}
if(in < MINVOLT) { summe = 0; } // RESET
if(summe > 2) {return millis() - 3*ABTASTRATE/2;}
delay(ABTASTRATE);
}
}
// END DFC77
Lösung von: Philipp G. Freimann (BBW (Berufsbildungsschule Winterthur) https://www.bbw.ch)
function encodeDCF77(d) {
var output, temp;
function castBits(num, len) {
num = num.toString(2); // in binär umwandeln
while (num.length < len) num = "0" + num; // führende nullen einfügen
return num.split("").reverse().join(""); // ausgabe rückwärts
}
function getParityBit(str) { // gerade parität
if (eval(str.split("").join("+") % 2) == 0) return "1";
return "0";
}
// [00] startbit (1 bit)
output = "0";
// [01] diverses (19 bits)
for (temp = 1; temp <= 19; temp++) output += "•";
// [20] beginn der zeitangabe (1 bit)
output += "1";
// [21] einerstelle minuten (4 bits)
temp = d.getMinutes();
while (temp > 10) temp -= 10;
output += castBits(temp, 4);
// [25] zehnerstellte minuten (3 bits)
temp = Math.floor(d.getMinutes() / 10);
output += castBits(temp, 3);
// [28] minuten paritätsbit
output += getParityBit(output.substring(21));
// [29] einerstelle stunden (4 bits)
temp = d.getHours();
while (temp > 10) temp -= 10;
output += castBits(temp, 4);
// [33] zehnerstelle stunden (2 bits)
temp = Math.floor(d.getHours() / 10);
output += castBits(temp, 2);
// [35] stunden paritätsbit
output += getParityBit(output.substring(29));
// [36] einerstelle kalendertag (4 bits)
temp = d.getDate();
while (temp > 10) temp -= 10;
output += castBits(temp, 4);
// [40] zehnerstelle kalendertag (2 bits)
temp = Math.floor(d.getDate() / 10);
output += castBits(temp, 2);
// [42] wochentag; montag = 1, sonntag = 7 (3 bits)
temp = d.getDay() + 1;
output += castBits(temp, 3);
// [45] einerstelle monat; januar = 1 (4 bits)
temp = d.getMonth() - 1;
while (temp > 10) temp -= 10;
output += castBits(temp, 4);
// [49] zehnerstelle monat (1 bit)
temp = Math.floor(d.getMonth() / 10);
output += castBits(temp, 1);
// [50] einerstelle jahr (4 bits)
temp = d.getFullYear().toString();
temp = parseInt(temp.charAt(temp.length - 1));
output += castBits(temp, 4);
// [54] zehnerstelle jahr (4 bits)
temp = d.getFullYear().toString();
temp = parseInt(temp.charAt(temp.length - 2));
output += castBits(temp, 4);
// [58] zeitangabe paritätsbit
output += getParityBit(output.substring(36));
return output;
}
function decodeDCF77time(str) {
var d = new Date(0, 0, 0, 0, 0, 0, 0),
temp1, temp2;
function readBits(str) {
str = str.split("").reverse().join(""); // bits umkehren
return parseInt(str, 2); // rückgabe als integer
}
// jahr
temp1 = str.substr(50, 4); temp2 = str.substr(54, 4);
temp1 = readBits(temp1) + readBits(temp2) * 10;
temp2 = new Date();
if (temp1 + 2000 > temp2.getFullYear()) temp1 + 1900;
else temp1 += 2000;
d.setFullYear(temp1);
// monat
temp1 = str.substr(45, 4); temp2 = str.substr(49, 1);
d.setMonth((readBits(temp1) + 1) + readBits(temp2) * 10);
// kalendertag
temp1 = str.substr(36, 4); temp2 = str.substr(40, 2);
d.setDate((readBits(temp1)) + readBits(temp2) * 10);
// stunde
temp1 = str.substr(29, 4); temp2 = str.substr(33, 2);
d.setHours(readBits(temp1) + readBits(temp2) * 10);
// minuten
temp1 = str.substr(21, 4); temp2 = str.substr(25, 3);
d.setMinutes(readBits(temp1) + readBits(temp2) * 10);
return d;
}
// test
var test = new Date(),
testDCF77 = encodeDCF77(test);
console.log(testDCF77);
console.log(decodeDCF77time(testDCF77).toString());
/*----------------------*\
| das _/K/L-ding |
\*----------------------*/
var klStr = "KLLKKKKKLL_KLKKLKKLKKLKKLKKKKLKLLKLKLKLKKKKLLKKKKKKLKLLLKKKLKKKLLKKKKKLK_KLKKLK";
// sequenz zwischen _ suchen
klStr = klStr.substring(klStr.indexOf("_") + 1);
klStr = klStr.substring(0, klStr.indexOf("_"));
// umformung in bits
klStr = klStr.replace(/K/g, "0");
klStr = klStr.replace(/L/g, "1");
console.log(decodeDCF77time(klStr).toString()); // lissalanda@gmx.at
Lösung von: Lisa Salander (Heidi-Klum-Gymnasium Bottrop)
Verifikation/Checksumme:
Bei der angegebenen Zeit handelt es sich um 21:58 am So. 20. Jan. im Jahr '13.
Aktionen
Neue Lösung hinzufügen
Bewertung
Durchschnittliche Bewertung:
Meta
Zeit: | 4 |
Schwierigkeit: | Mittel |
Webcode: | hf0f-bm7t |
Autor: | Philipp G. Freimann (BBW (Berufsbildungsschule Winterthur) https://www.bbw.ch) |
Kommentare (12)
Wie soll man mit einer Bitfolge KLKK… (Länge = 61) auf ein UTF77-Signal (Länge = 58) kommen, wenn Fehlerbits nie extra hinterhergesendet werden?
Desto länger ich mich mit diesem Problem befasse, umso mehr komme ich zu der Annahme, dass der Ersteller seine eigene Aufgabe nicht verstanden hat.
Meine Lösung (JavaScript) läuft eigentlich tadellos — wäre da nicht diese kuriose Aufgabenstellung und die arbiträr scheindende Checksumme. (Januar 2013?! Niemals!)
Viele liebe Grüße, Lisa.
Das "umgekehrte" Zweiersystem liest sich wie folgt:
0000 = 0
1000 = 1
0100 = 2 (0 Einer, 1 Zweier)
1100 = 3 (1 Einer, 1 Zweier)
0010 = 4 (0 Einer, 0 Zweier, 1 Vierer)
1010 = 5 (1 Einer, 0 Zweier, 1 Vierer)
0110 = 6 (0 Einer, 1 Zweier, 1 Vierer)
...
1101 = 11 (1 Einer, 1 Zweier, 0 Vierer, 1 Achter)
...
Genau das Binärsystem nur dass diesmal die Einer zuerst geschickt werden.
Ah darum hab ich so lange für den Code gebraucht ^^ Dann hoffen wir mal das alle Fehler raus sind =).
Also sind bei den Minuten Einern garnicht die 4 Bits der Wert für den Einer, sondern man muss die 4 Bits anders Lesen. Kannst du evtl nochmal genauer Erläutern wie das Prinzip ist?
Also bei dem Zehner ist ja klar: 101 = 5 nur versteh ich grad nicht wie man da auf 1+4 kommt und auch nich bei den Einern wie man von 1010 auf 1+4 kommt
Sorry Sorry,
Ich vergaß zu erwähnen, dass die Bitfolge im DCF 77 von links her aufsteigend ist. Ganz links stehen die Einer, dann die Zweier, dann die Achter.
Ich habe das in der Aufgabenstellung korrigiert.
Danke für den Hinweis.
Die Wiki-Seite gibts übrigens auch noch als Hilfe:
http://de.wikipedia.org/wiki/DCF77
Ah ok - wäre vllt anschaulicher im Beispiel bei Bit 0 anstatt 0 ein K zu schreiben.
Ich habe mein Programm soweit berichtigt, jedoch bekomme ich jetz bei den Einer Minuten den Code "LKLK" (1010) was eine 10 wäre und nicht geht
Kommentar-Editier Funktion nehme ich gerne in die Wish-List auf. Danke für den Hinweis
Danke, da hab ich mich vertan.
Ich habe den Monat dahingehend korrigiert, dass er in der Erklärung nur die geforderten 5 Bit benötigt.
Im angegeben (zu durchsuchenden) String kommt eine "0" vor. Dies ist aber keine Null im Binären Sinne, sondern die "nicht gesendete Absenkung". Damit handelt es sich dabei um Bit Nr. 59. Die zählung mit Bit Position 0 beginnt eine Stelle Rechts von Bit Nr. 59.
Zusatz: Da ja erst die Einerstellen gesendet werden, funktioniert die Erklärung weder so: mmmm,mm (zu lang) noch so: mmm,mm (man braucht 4 Bits um die Einer darzustellen), sodass man hier das Komma verschieben muss: mmmm,m
// Ne Kommentar editieren funktion wäre nicht schlecht
Desweiteren ist in der Legende die Monatsdarstellung mit 6 Bit erklärt, im Beispiel jedoch stehen für die Monate nur 5 Bits. Damit das System am Ende aufgeht dürfte es aber nur die Variante mit 5 Bits sein. Für den Zehner in den Monaten bräuchte man ja eh nur 1 Bit