diff --git a/Coprozessor_DCF77.ino b/Coprozessor_DCF77.ino new file mode 100644 index 0000000..a6f6550 --- /dev/null +++ b/Coprozessor_DCF77.ino @@ -0,0 +1,145 @@ +/* Das Programm dekodiert die DCF77 Zeit, + macht die Paritätsprüfung und + schickt die vier benötigten Ziffern für die Zeitanzeige + als serielle Daten über den TX Pin 1 an den Anzeigecontroller. + Datengeschwindigkeit: 9600 Baud + Wenn ein gültiges Signal gesendet wurde, gibt es eine Pause von 30 Minuten, + in dieser Zeit wird der DCF Empfänger an Pin 6 abgeschaltet. + mit Hilfe von: https://wolles-elektronikkiste.de/dcf77-funkuhr + 30.04.2025 +*/ + +#include //comment out if you don't use an AVR MCU + +#define dcfOnOut 6 +int interruptPin = 2; + +volatile unsigned long lastInt = 0; +volatile unsigned long long currentBuf = 0; +volatile byte bufCounter; +volatile bool parityStat = 0; +volatile byte dcf77MinuteEiner = 0; +volatile byte dcf77MinuteZehner = 0; +volatile byte dcf77HourEiner = 0; +volatile byte dcf77HourZehner = 0; + + +void setup() { + Serial.begin(9600); + pinMode(dcfOnOut, OUTPUT); + digitalWrite(dcfOnOut, HIGH); + pinMode(interruptPin, INPUT); + attachInterrupt(digitalPinToInterrupt(interruptPin), DCF77_ISR, CHANGE); +} + +void loop() { + if (parityStat == 1) { + delay(100); + Serial.print(dcf77HourZehner); + Serial.print(","); + Serial.print(dcf77HourEiner); + Serial.print(","); + Serial.print(dcf77MinuteZehner); + Serial.print(","); + Serial.print(dcf77MinuteEiner); + delay(100); + + digitalWrite(dcfOnOut, LOW); + + parityStat = 0; + delay(1800000); // 30 Minuten, 15 Minuten Wartezeit: 900000 + digitalWrite(dcfOnOut, HIGH); + } +} + +/************************************************************************* + + lesen des dcf Signals am Pin 2 + +**************************************************************************/ + +void DCF77_ISR() { // + unsigned int dur = 0; + dur = millis() - lastInt; + + if (digitalRead(interruptPin)) { + + if (dur > 1500) { + unsigned long highBuf = (currentBuf >> 32) & 0x7FFFFFF; + unsigned long lowBuf = (currentBuf & 0xFFFFFFFF); + bufCounter = 0; + + evaluateSequence(); + currentBuf = 0; + } + } + else { + if (dur > 150) { + currentBuf |= ((unsigned long long)1 << bufCounter); + } + bufCounter++; + } + lastInt = millis(); +} + +/************************************************************************** + + Umwandlung Binärcode in Ziffern + + *************************************************************************/ + + +void evaluateSequence() { + parityStat = 1; + byte dcf77Year = (currentBuf >> 50) & 0xFF; // year = bit 50-57 + byte dcf77Month = (currentBuf >> 45) & 0x1F; // month = bit 45-49 + byte dcf77DayOfWeek = (currentBuf >> 42) & 0x07; // day of the week = bit 42-44 + byte dcf77DayOfMonth = (currentBuf >> 36) & 0x3F; // day of the month = bit 36-41 + byte dcf77Hour = (currentBuf >> 29) & 0x3F; + dcf77HourEiner = (currentBuf >> 29) & 0xF; // hour = bit 29-34, 6 bit + dcf77HourZehner = (currentBuf >> 33) & 0x3; // hour = bit 29-34, 6 bit + byte dcf77Minute = (currentBuf >> 21) & 0x7F; + dcf77MinuteEiner = (currentBuf >> 21) & 0xF; // minute = 21-27, 7 bit + dcf77MinuteZehner = (currentBuf >> 25) & 0x7; // minute = 21-27, 7 bit + + bool parityBitMinute = (currentBuf >> 28) & 1; + bool parityBitHour = (currentBuf >> 35) & 1; + bool parityBitDate = (currentBuf >> 58) & 1; + + /*************************************************************************** + Paritätsprüfung + + ***************************************************************************/ + + if ((parity_even_bit(dcf77Minute)) != parityBitMinute) { + parityStat = 0; + } + if ((parity_even_bit(dcf77Hour)) != parityBitHour) { + parityStat = 0; + } + if (((parity_even_bit(dcf77DayOfMonth) + parity_even_bit(dcf77DayOfWeek) + + parity_even_bit(dcf77Month) + parity_even_bit(dcf77Year)) % 2) != parityBitDate) + { + parityStat = 0; + } + if (dcf77MinuteEiner > 9) { + parityStat = 0; + } + if (dcf77MinuteZehner > 5) { + parityStat = 0; + } + if (dcf77HourEiner > 9) { + parityStat = 0; + } + if (dcf77HourZehner > 2) { + parityStat = 0; + } + if (dcf77Hour == 0 && dcf77Minute == 0) { + parityStat = 0; + } + +} + +unsigned int rawByteToInt(byte raw) { + return ((raw >> 4) * 10 + (raw & 0x0F)); +} diff --git a/Uhr_DCF77_5Volt_V3.ino b/Uhr_DCF77_5Volt_V3.ino new file mode 100644 index 0000000..a783a6b --- /dev/null +++ b/Uhr_DCF77_5Volt_V3.ino @@ -0,0 +1,333 @@ +/* Programm zum DCF77 Empfang für atmega 328p + Sekunden Timer ISR + 5 Volt Variante für Peripherie + Datenempfang vom Coprozessor + 03.05.2025 +*/ + +#define bcdA 5 // D5 +#define bcdB 6 // D6 +#define bcdC 7 // D7 +#define bcdD 8 // D8 +#define displayPosition1 9 // D9 +#define displayPosition2 10 // D10 +#define displayPosition3 3 // D3 +#define displayPosition4 4 // D4 + +byte selectZiffer = 0; +byte displayPosition = 0; +volatile int dcf77MinuteEiner = 0; +volatile int dcf77MinuteZehner = 0; +volatile int dcf77HourEiner = 0; +volatile int dcf77HourZehner = 0; +volatile byte noSignalMinutenCounter = 0; +volatile byte noSignalStundenCounter = 0; +volatile byte einerStunden = 7; +volatile byte zehnerStunden = 1; +volatile byte einerMinuten = 0; +volatile byte zehnerMinuten = 1; +volatile byte offlineCounter = 0; +volatile bool parityStat = 0; + +void setup() { + pinMode(bcdA, OUTPUT); + pinMode(bcdB, OUTPUT); + pinMode(bcdC, OUTPUT); + pinMode(bcdD, OUTPUT); + pinMode(displayPosition1, OUTPUT); + pinMode(displayPosition2, OUTPUT); + pinMode(displayPosition3, OUTPUT); + pinMode(displayPosition4, OUTPUT); + + + digitalWrite(bcdA, HIGH); + digitalWrite(bcdB, HIGH); + digitalWrite(bcdC, HIGH); + digitalWrite(bcdD, HIGH); + digitalWrite(displayPosition1, HIGH); + digitalWrite(displayPosition2, HIGH); + digitalWrite(displayPosition3, HIGH); + digitalWrite(displayPosition4, HIGH); + + Serial.begin(9600); + + // Timer1 setzen (1 Sekunde = 49911, zwei Sekunden = 34286) + TCCR1A = 0x00; + TCCR1B = (1< 59){ + + offlineCounter = 0; + + if (parityStat == 0) { + byte m = zehnerMinuten * 10; + noSignalMinutenCounter = m + einerMinuten; + byte s = zehnerStunden * 10; + noSignalStundenCounter = s + einerStunden; + + noSignalMinutenCounter++; + + if (noSignalMinutenCounter > 59) { + noSignalMinutenCounter = 0; + noSignalStundenCounter++; + if (noSignalStundenCounter > 23) { + noSignalStundenCounter = 0; + } + } + einerStunden = noSignalStundenCounter % 10; // zerlegt die Zahl in Einer + zehnerStunden = (noSignalStundenCounter / 10) % 10; // und Zehner + einerMinuten = noSignalMinutenCounter % 10; + zehnerMinuten = (noSignalMinutenCounter / 10) % 10; + } + + else { + einerMinuten = dcf77MinuteEiner; + zehnerMinuten = dcf77MinuteZehner; + einerStunden = dcf77HourEiner; + zehnerStunden = dcf77HourZehner; + parityStat = 0; + } + } +} + +void initDisplay() { + + // Die Schleife ruft nacheinander die Anzeigestellen auf und übergibt die Ziffern + + for (displayPosition = 1; displayPosition <= 4; displayPosition++) { + + if (displayPosition == 1) { + digitalWrite(displayPosition1, HIGH); + digitalWrite(displayPosition2, LOW); + digitalWrite(displayPosition3, LOW); + digitalWrite(displayPosition4, LOW); + + if (zehnerStunden == 0) { + selectZiffer = 0; + } + if (zehnerStunden == 1) { + selectZiffer = 1; + } + if (zehnerStunden == 2) { + selectZiffer = 2; + } + } + + if (displayPosition == 2) { + digitalWrite(displayPosition1, LOW); + digitalWrite(displayPosition2, HIGH); + digitalWrite(displayPosition3, LOW); + digitalWrite(displayPosition4, LOW); + + if (einerStunden == 0) { + selectZiffer = 0; + } + if (einerStunden == 1) { + selectZiffer = 1; + } + if (einerStunden == 2) { + selectZiffer = 2; + } + if (einerStunden == 3) { + selectZiffer = 3; + } + if (einerStunden == 4) { + selectZiffer = 4; + } + if (einerStunden == 5) { + selectZiffer = 5; + } + if (einerStunden == 6) { + selectZiffer = 6; + } + if (einerStunden == 7) { + selectZiffer = 7; + } + if (einerStunden == 8) { + selectZiffer = 8; + } + if (einerStunden == 9) { + selectZiffer = 9; + } + } + + if (displayPosition == 3) { + digitalWrite(displayPosition1, LOW); + digitalWrite(displayPosition2, LOW); + digitalWrite(displayPosition3, HIGH); + digitalWrite(displayPosition4, LOW); + + + if (zehnerMinuten == 0) { + selectZiffer = 0; + } + if (zehnerMinuten == 1) { + selectZiffer = 1; + } + if (zehnerMinuten == 2) { + selectZiffer = 2; + } + if (zehnerMinuten == 3) { + selectZiffer = 3; + } + if (zehnerMinuten == 4) { + selectZiffer = 4; + } + if (zehnerMinuten == 5) { + selectZiffer = 5; + } + + } + + if (displayPosition == 4) { + digitalWrite(displayPosition1, LOW); + digitalWrite(displayPosition2, LOW); + digitalWrite(displayPosition3, LOW); + digitalWrite(displayPosition4, HIGH); + + + if (einerMinuten == 0) { + selectZiffer = 0; + } + if (einerMinuten == 1) { + selectZiffer = 1; + } + if (einerMinuten == 2) { + selectZiffer = 2; + } + if (einerMinuten == 3) { + selectZiffer = 3; + } + if (einerMinuten == 4) { + selectZiffer = 4; + } + if (einerMinuten == 5) { + selectZiffer = 5; + } + if (einerMinuten == 6) { + selectZiffer = 6; + } + if (einerMinuten == 7) { + selectZiffer = 7; + } + if (einerMinuten == 8) { + selectZiffer = 8; + } + if (einerMinuten == 9) { + selectZiffer = 9; + } + } + + // BCD Zifferncode + + switch (selectZiffer) { + case 0: + digitalWrite(bcdA, LOW); + digitalWrite(bcdB, LOW); + digitalWrite(bcdC, LOW); + digitalWrite(bcdD, LOW); + break; + + case 1: + digitalWrite(bcdA, HIGH); + digitalWrite(bcdB, LOW); + digitalWrite(bcdC, LOW); + digitalWrite(bcdD, LOW); + break; + + case 2: + digitalWrite(bcdA, LOW); + digitalWrite(bcdB, HIGH); + digitalWrite(bcdC, LOW); + digitalWrite(bcdD, LOW); + break; + + case 3: + digitalWrite(bcdA, HIGH); + digitalWrite(bcdB, HIGH); + digitalWrite(bcdC, LOW); + digitalWrite(bcdD, LOW); + break; + + case 4: + digitalWrite(bcdA, LOW); + digitalWrite(bcdB, LOW); + digitalWrite(bcdC, HIGH); + digitalWrite(bcdD, LOW); + break; + + case 5: + digitalWrite(bcdA, HIGH); + digitalWrite(bcdB, LOW); + digitalWrite(bcdC, HIGH); + digitalWrite(bcdD, LOW); + break; + + case 6: + digitalWrite(bcdA, LOW); + digitalWrite(bcdB, HIGH); + digitalWrite(bcdC, HIGH); + digitalWrite(bcdD, LOW); + break; + + case 7: + digitalWrite(bcdA, HIGH); + digitalWrite(bcdB, HIGH); + digitalWrite(bcdC, HIGH); + digitalWrite(bcdD, LOW); + break; + + case 8: + digitalWrite(bcdA, LOW); + digitalWrite(bcdB, LOW); + digitalWrite(bcdC, LOW); + digitalWrite(bcdD, HIGH); + break; + + case 9: + digitalWrite(bcdA, HIGH); + digitalWrite(bcdB, LOW); + digitalWrite(bcdC, LOW); + digitalWrite(bcdD, HIGH); + break; + + } + + // Unterdrueckung der fuehrenden Null + + if (displayPosition == 1) { + if (selectZiffer == 0) { + goto noTime; + } + } + + delayMicroseconds(2500); //Anschaltzeit der Ziffern + +noTime: {} + + } +} + +void loop() { + if (Serial.available()){ + dcf77HourZehner = Serial.parseInt(); + dcf77HourEiner = Serial.parseInt(); + dcf77MinuteZehner = Serial.parseInt(); + dcf77MinuteEiner = Serial.parseInt(); + String(DCFzeit) = Serial.readString(); + + parityStat = 1; + } + + initDisplay(); // zeigt die Uhrzeit an + +}