In der Variante 3 hat die Funkuhr zwei Controller,
einen für die flimmerfreie Anzeige und einen für die störungsfreie Erfassung des DCF Signals. Die Datenübertragung erfolg seriell von TX nach RX
This commit is contained in:
145
Coprozessor_DCF77.ino
Normal file
145
Coprozessor_DCF77.ino
Normal file
@ -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 <util/parity.h> //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));
|
||||||
|
}
|
333
Uhr_DCF77_5Volt_V3.ino
Normal file
333
Uhr_DCF77_5Volt_V3.ino
Normal file
@ -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<<CS12) | (1<<CS10);
|
||||||
|
TIMSK1 = (1<<TOIE1);
|
||||||
|
TCNT1 = 49911;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
ISR(TIMER1_OVF_vect){
|
||||||
|
|
||||||
|
TCNT1 = 49911;
|
||||||
|
offlineCounter++;
|
||||||
|
|
||||||
|
if (offlineCounter > 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
|
||||||
|
|
||||||
|
}
|
Reference in New Issue
Block a user