PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : DCF-77 Empfang zu Fuß



rogerberglen
11.01.2014, 12:09
Ich beschäftige mich gerade mit dem DCF-77 Empfang, den ich zu Fuß erledigen möchte da ich verschiedene Zusatzbits auch mit auswerten will. Ich habe auch viele Beispielprogramme dazu gefunden. Aus einem habe ich die Dekodierung übernommen, da diese recht verständlich aufgebaut ist. Leider wird immer wieder eine 0 (kurzes Signal) als eine 1 dekodiert was dann zu einem Parity-Fehler führt.
Wie kann man das Ganze noch etwas zuverlässiger machen? Denn ich möchte das empfangene Protkoll dann an einen DS1307 übergeben.

Hier mal der Code der das Zeitsingal abtastet:



$regfile = "m32def.dat" 'Vereibarung des Atmel Prozessors, hier: AVR AT Mega32
$crystal = 7372800 ' 7.372.800 Hz-Quarz

On Icp1 On_capture1

Config Timer1 = Timer , Prescale = 1024 , Capture Edge = Falling , Noise Cancel = 1

Enable Icp1 ' Freigabe Timer1
Enable Interrupts ' Freigabe der Interrups allgemein.

On_capture1: ' Wird mit dem Sekunden-Impulse des DCF Empfängers an Port D.6 ausgelöst.
Zaehlerstand = Capture1 ' Aktuellen Zählerstand sofort nach Interrupt fixieren.
Zeitdauer = Zaehlerstand - Zaehlerstand_alt ' Der Wert in der Variablen (Zeitdauer) mit 0,0001388 s multipliziert-
Zaehlerstand_alt = Zaehlerstand ' ergibt die seit dem letzten Interrupt vergangene Zeit in Sek.
Zeiger = Zeiger + 1 ' Laufvariable (Zeiger) um 1 erhöhen.


'Goto Test


Select Case Zeitdauer ' Auswertung der Zeitdauer seit dem letzten Interrupt.
Case Is > 18011 ' <9500> Kein Funk Signal; Weil Impulsabstand größer als 2,5 Sek.
Goto Fehler1
Case Is < 5548 ' <1500> Impuls Störung; Weil Impulsabstand kleiner als 770 ms.
Goto Fehler2
Case Is < 6484 ' <3520> Kurzer regulärer Impulsabstand von ca 900 ms.
Portd.0 = 1 : Bit_old = 0 : Portd.1 = 1 : Sync(zeiger) = 0
Goto Hinter_fehler
Case 6844 To 7493 ' <3422> <3774> Wenn Impulsabstand ca. 1000ms dann war der Bit Wert gleich dem letzten Bit Wert
Portd.0 = 1 : Portd.1 = 1 : Sync(zeiger) = Bit_old ' (950ms - 1.04s)
Goto Hinter_fehler
Case 7750 To 8429 ' <3774> <4200> Langer regulärer Impulsabstand ca. 1100ms.
Portd.1 = 1 : Bit_old = 1 : Portd.0 = 1 : Sync(zeiger) = 1 ' (1.075s - 1.17s)
Goto Hinter_fehler

Case 9006 To 15201 ' <4500> <7600> Ausfall der 59. Sekunde also Pause zwischen 1250 ms - 2111 ms.
' (1.25s - 2.11s)

Besserwessi
11.01.2014, 14:03
So ganz viel kann ich aus dem Codefragment nicht erkennen, da fehlt noch viel. Es wird wohl versucht die Zeit der flanken auszuwerten - im Prinzip kann das gut werden, aber so etwa wie ein ignorieren von Überschwingern kann ich da noch nicht erkennen.

Im Prinzip hat man bei der Auswertung viele Möglichkeiten. Wie man es anstellt hat auch einen Einfluss darauf wie leicht man Fehler erhält bzw. wie gut auch ein leicht gestörtes Signal noch erkannt werden kann.
Das klassische, eher einfache Verfahren ist es jeden Puls einzeln auszuwerten, und dann halt auf 0, 1 oder überlange Pause (= 59.Sekunde) zu entscheiden. Ggf. lohnt es sich die Grenzwerte an die Hardware und ggf. Empfangssituation anzupassen.

Etwas besser kann es werden, wenn man ausnutzt, das die Pulse alle im 1 Sekundentakt beginnen. Also erst einmal den Sekundentakt zu synchronisieren durch so etwas wie einen PLL in Software, und dann nur jeweils das Ende der Pulse bzw. das Signal in der Zeit am Anfang jeder Sekunde auszuwerten. Wenn es sein muss könnte man auch Daten von mehr als 1 Minute zusammenfassen und so ggf. einmal schlecht empfangene "Bits" in der 2./3. Minute besser bestimmen zu können.

ihle
12.01.2014, 19:29
Hallo rogerberglen,

das DCF77 Signal arbeitet mit Absenkungen 100ms Absenkung = logisch 0 und 200ms Absenkung = logisch 1.
ich hab da ein ganz interresantes Pdf

http://www.ihle-elektronik.de/Downloads/DCF77.pdf


mfg ihle

rogerberglen
03.12.2015, 10:25
Ich habe jetzt zur Genüge mit dem DCF-77 Empfang herumexperimentiert. Das mit dem Capturing über einen Timer erscheint mir nicht so das Gelbe vom Ei zu sein.
Jetzt habe ich gelesen, dass es besser ist das Signal zu sampeln.
Sampling habe ich zwar verstanden, lässt sich demnach ohne irgend ein Timer zu benutzen auch bewerkstelligen.
Jetzt habe ich dazu noch Fragen:
Ist es ohne einen Timer möglich alle 10ms den DCF-Eingang zu pollen?
Wie geht es dann weiter? Wird das Sampling dann irgendwann auch angehalten um die gesampelten Bits auch auswerten zu können ?Wie kann man die Abtastung mit dem DCF-Signal syncronisieren?

wkrug
03.12.2015, 16:26
Ganz ohne Timer Unterstützung wird es zwar nicht gehen, weil man ja eine Refernz für die Zeit braucht.

Aber warum machst Du das Ganze nicht über flankengetriggerte Interrupts?
z.B. INT0 auf steigende Flanke. kommt die dann, das Sensig auf fallende Flanke im Interrupt Umstellen.
Fällt die Flanke dann wiede ab, kannst Du den Zeitstempel der ansteigenden Flanke vom aktuellen Wert abziehen.
So bekommst Du die Impulslänge. Umgekehrt gehts natürlich auch und Du bekommst die Pausenlänge.
Die Ist auch wichtig, weil in der 59 Sekunde kein Puls gesendet wird und somit eine Synchronosation stattfinden kann.

Somit wird die Interruptroutine bei jedem Impuls 2x aufgerufen.
Ein Timer - Ich würde einen 16 Bit Timer verwenden - fungiert nur als Zeitbasis zum Bestimmen der Impulslängen.
Timer Interrupts werden keine aufgerufen.

Die ankommenden Bits schiebst Du in entsprechende Variablen und die Paritätsprüfung läuft auch noch nebenher mit.

rogerberglen
04.12.2015, 20:17
Auf dem Weg bin ich gerade. Werde ich Testen wenn ich die Abfragerei zusammen habe.

rogerberglen
05.12.2015, 14:14
Könnte man auch mit Folgendem etwas anfangen. Denn das habe ich momentan in Gebrauch um das DCF-Signal besser kennenzulernen.


Cls 'LCD-Display löschen und Meldung ausgeben.
Locate 3, 1 'Textposition auf LCD-Display festlegen
Lcd "Minutenl{245}cke suchen" 'und Text Minutenlücke suchen ausgeben

signalgap = 0 'Signalbreite löschen
While signalgap < 1700 'Solange empfangen bis Minutenlücke gefun-
'den ist.
' Ende der Sekundenmarke suchen, DCF-Signal wird "0"
While dcf77inp = 1 'Ende der Sekundenmarke suchen, DCF-Signal
Waitms 1 'wird 0. Im ms-Takt abfragen
Wend

' Breite der Lücke messen (Zeit während der das DCF-Signal "0" bleibt)
signalgap = 0 'Signalbreite löschen
While dcf77inp = 0 'Neue Signalbreite messen in dem der Ein-
Incr signalgap 'gang im 1ms-Abstand abgefragt wird.
Waitms 1 'Solange Signal Low ist, Zähler erhöhen
Wend 'Solange wiederholen bis Signal 1 ist.

Locate 3, 1 'Textposition auf LCD-Display festlegen
Lcd " " 'und alten Text löschen.
Locate 3, 1 'Textposition wieder auf Anfang 3. Zeile
Lcd "L{245}cke: "; signalgap; " " 'und Text + Signallänge ausgeben
Wend

' ************************************************** ***************
' * Minutenlücke gefunden (Signalgap >= 1700ms) *
' ************************************************** ***************

Cls 'LCD-Display löschen.
Locate 3, 1 'Textposition auf LCD-Display festlegen.
Lcd "Bits empfangen..." 'Und Text ausgeben.

Reset signalerror 'Fehlerflag für Signalempfang löschen
bitcount = 1 'Bitzähler auf 1 setzen

While BitCount <= 59
If BitCount >= 59 Then BitCount = 0 'Test um die Zeiten auf dem Display zu sehen
' While signalerror = 0 AND bitcount <= 59

' Breite der Sekundenmarke messen: <70ms = Störpuls, 100ms = "0", 200ms = "1"
signalwidth = 0
While dcf77inp = 1
Incr signalwidth
Waitms 1
Wend

' Die erste Sekundenmarke (Minutenanfang) wird immer wesentlich kürzer gemessen.
' Grund unbekannt. Daher wird hier die erste Marke künstlich um 20ms verlängert.

If bitcount = 1 Then signalwidth = signalwidth + 30 '1. Marke verlängern

Locate 2, 1 'Alten Text auf dem LCD-Display
'Lcd " " 'löschen.
'Lowerline
Select Case signalwidth
Case Is < 65: Set signalerror 'Sekundenmarke ist zu schmal
Lcd "error"; signalwidth
Case 65 TO 110: dcfbit(bitcount) = 0 'Signalbreite ergibt "0"
Lcd "(0) "; signalwidth; " "
Case Is > 110: dcfbit(bitcount) = 1 'Signalbreite ergibt "1"
Lcd "(1) "; signalwidth; " "
End Select

Incr bitcount 'read next bit

' Lücke überspringen
signalgap = 0
Locate 2, 12
While dcf77inp = 0
Incr signalgap
Waitms 1
Wend

Lcd SignalGap; " "

Locate 3, 1
I = SignalWidth + SignalGap
LCD I; " "

If signalgap < 700 Then Set signalerror 'Lücke war zu kurz

Wend

Peter(TOO)
05.12.2015, 20:27
Hallo,

Könnte man auch mit Folgendem etwas anfangen. Denn das habe ich momentan in Gebrauch um das DCF-Signal besser kennenzulernen.


' Die erste Sekundenmarke (Minutenanfang) wird immer wesentlich kürzer gemessen.
' Grund unbekannt. Daher wird hier die erste Marke künstlich um 20ms verlängert.
Der Fehler in diesen Programm ist, dass vergessen wurde, dass die LCD-Befehle auch Zeit für die Ausführung benötigen!
Kommt jetzt aber Ganz auf die Bibliothek, das verwendete Interface des LCD und was ausgegeben wird an, wie lange da jeweils gearbeitet wird.

Die gemessenen Zeiten bestehen also aus dem was mit der 1ms Delay gemessen wurde plus dem was die LCD-Befehle dazwischen benötigt haben.

MfG Peter(TOO)

rogerberglen
08.12.2015, 15:14
Zur Zeit läuft die Uhr, aber ich habe da von der DS1307 eine Abweichung innerhalb von 21 Stunden von -7 Sekunden.
Jetzt gerade wird das DCF-77 Signal durch ein nicht Timergestütztes Polling abgefragt. Es wird alle 1ms nachgeschaut was denn der DCF-77 Eingang so macht.
Zu diesem Zweck wird auch der Interrupt INT0 abgeschaltet, solange das DCF-Signal abgetastet wird. Erst nach einer Minute dann wird der Interrupt INT0 wieder freigegeben.
Jede Sekunde wird der RTC ausgelesen und auf dem LCD-Display angezeigt. Der Takt dazu kommt vom DS1307 und löst das Ganze über den INT0-Interrupt aus.
Und jetzt kommt mein dickes Problem:
Wenn ich das DCF-77 nun erneut zum Abgleich einlese, habe ich in dieser Zeit keine LCD-Anzeige der Uhrzeit, da ja der Interrupt INT0 abgeschaltet wird.
Nun fällt mir leider zur Zeit pardout nicht ein wie ich:
1. Das DCF-77 Signal per Interrupt alle 1ms, oder doch besser alle 10ms, sample und auch dann die Zeiten auswerte
2. Der DCF-77 Empfang und Kodierung im Hintergrund abläuft, so dass die Uhrzeit auf dem LCD-Display immer weiterläuft.

Wäre ganz Toll wenn ich in dieser Richtung Unterstützung bekommen könnte.

Eine Lösung für die etwas hinterherhinkende DS1307 wäre die Zeitabweichung festzustellen und einmal (in der Nacht) die DS1307 entsprechend korrigieren.
Noch besser aber ist wenn man das Ganze in der Nacht nach obigen Punkten wieder syncronisert.

Hier der bisher verwendete Code aus dem Internet:

Wie kann ich hier eine Datei bzw. den gesamten Quellcode anhängen ????
Forume meldet, dass der Text zu lang sei.

wkrug
09.12.2015, 16:37
Ich würd die Abfrage der Zeit nicht in ein 1ms Raster legen.
Egal ob nun Timer Interrupts oder Delay's.

Probier doch die Flanken deines DCF Empfängers auszuwerten.
Wenn Du die Sensing Umschalterei im Interrupt nicht magst, kannst Du ebenso 2 Interrupt Eingänge parallel schalten ( z.B. INT0 und INT1 ) und den einen auf steigende Flanke und den anderen auf fallende Flanke programmieren.
Ein Timer läuft frei - Günstig wär ein 16 Bit Timer.
Den Prescaler so einstellen, das 2 Sekunden überbrückt werden können. Eventuell einen Overflow Counter im Timer Overflow mitlaufen lassen.
Der Vorteil ist , das die Interrupts mit 2Hz aufgerufen werden.
Bei deiner Polling Methode läuft das Ganze mit 1000Hz.
Das bedeutet, Du hast keine Probleme um dein Display anzusteuern.

Peter(TOO)
09.12.2015, 17:17
Ich würd die Abfrage der Zeit nicht in ein 1ms Raster legen.
Egal ob nun Timer Interrupts oder Delay's.

Probier doch die Flanken deines DCF Empfängers auszuwerten.
Wenn Du die Sensing Umschalterei im Interrupt nicht magst, kannst Du ebenso 2 Interrupt Eingänge parallel schalten ( z.B. INT0 und INT1 ) und den einen auf steigende Flanke und den anderen auf fallende Flanke programmieren.
Ein Timer läuft frei - Günstig wär ein 16 Bit Timer.
Den Prescaler so einstellen, das 2 Sekunden überbrückt werden können. Eventuell einen Overflow Counter im Timer Overflow mitlaufen lassen.
Der Vorteil ist , das die Interrupts mit 2Hz aufgerufen werden.
Bei deiner Polling Methode läuft das Ganze mit 1000Hz.
Das bedeutet, Du hast keine Probleme um dein Display anzusteuern.
1ms Abtastrate ist übertrieben, 10-50ms reichen.

Das obige Programm ist im Prinzip OK, aber es muss in einem Interrupt abgetastet werden.

Das Abtasten der Flanken macht eine Menge Probleme, das reale Signal des Empfängers sieht eben nicht so schön aus, da hat es eine Menge Störimpulse drauf, besonders bei Gewittern. Mit dem Abtasten, fallen da schon eine Menge der Störimpulse raus.

Wie im obigen Programm, macht man ein Blindfenster von etwa 700ms, in welchem gar nicht abgetastet wird, dann sieht man auch die Störungen nicht und muss diese auch nicht extra behandeln. Das Blindfenster endet etwa 50ms vor der Sekunde. Die Abtastung nimmt man nur während der 300ms vor.
Beim Starten muss man aber zuerst synchronisieren. Da wird dann dauernd abgetastet, bis man einen gültigen 100ms oder 200ms Impuls eingefangen hat.

Ich habe das zu DOS-Zeiten erstmalig für den IBM-PC gemacht. Der Treiber sass da im Timertick von DOS (18.7 Hz, wenn ich mich recht erinnere) und hat dann einfach die System-Uhr korrigiert.

MfG Peter(TOO)

wkrug
09.12.2015, 19:13
Das Abtasten der Flanken macht eine Menge Probleme, das reale Signal des Empfängers sieht eben nicht so schön aus, da hat es eine Menge Störimpulse drauf, besonders bei Gewittern. Mit dem Abtasten, fallen da schon eine Menge der Störimpulse raus.
Mit den Störsignalen hast Du natürlich recht.
Beim AVR ist die Abtasterei in einem Timer Interrupt allerdings auch relativ einfach.
10ms Abtastrate im Prinzip auch kein Problem.

Impulsauswertung müsste man aber trotzdem machen - Liegt die berechnete Impulslänge innerhalb der zulässigen Grenzen?
Wenn nicht handelt es sich um einen Fehlimpuls bzw. Störung.

Bei meiner letzten DCF Steuerung hab ich einfach einen internen Timer als Basis für eine Uhr mitlaufen lassen.
Diese Uhr wird vom DCF Signal beim 30. Impuls einer Minute nachgestellt.
Also in der 30. Sekunde jeder Minute nachgestellt, wenn vorher alle parity Bits des Signals in Ordnung waren.

Die interne Uhr ( Stunden und Minuten ) wurde bei mir erst wieder auf die DCF Zeit nachgestellt, wenn 3 mal eine gültige DCF Zeitinformation ( 3 Minuten ) in Folge empfangen wurde.
Auch Doppelfehler mit gültigem Parity sollten somit keine Chance haben und auch eine automatische Sommer Winterzeit Umstellung ist damit gewährleistet.

Der am Controller verwendete Quarz dürfte so genau sein, das man damit auch mal ne Stunde DCF Ausfall überbrücken kann.
Ein Hardware RTC ist hier natürlich wesentlich genauer.
Gute RTC Chips haben eine Abweichung von 3 Minuten pro Jahr!

DCF hat natürlich den Charme einer Automatischen Sommer / Winterzeit Umstellung, das nicht jeder RTC Chip bietet.

rogerberglen
11.12.2015, 19:55
Ich habe jetzt das Ganze mit 10ms Abtastrate erstellt. Die Uhr läuft jetzt inzwischen unbeirrt und holt sich die Daten aus der RTC. So ganz nebenher wird auch das DCF-77 Signal empfangen und decodiert.
Jetzt muss ich nur noch die Informationen aufbereiten und in die RTC schieben. Dann sollte Alles so funktionieren wie ich mir das vorgestellt hatte.
Wenn Alles funktioniert würde ich gerne den Code komplett zur Verfügung stellen.
Wo kann man in diesem Forum den kompletten Code einstellen?

rogerberglen
14.12.2015, 15:27
Bis jetzt hat die erste Routine (misst den kürzesten DCF-Impuls aus) immer funktioniert. Nach ein paar Änderungen im Programm hat diese plötzlich nicht mehr funktioniert!! Und tut es auch nicht nachdem ich die Änderungen wieder herausgenommen habe.
Auf dem Display erscheint "Sign.Zeit: Messung" und dann nach der Wartezeit gleich "ms 0". Die Schleife wird schlicht ausgelassen
Wenn ich jetzt den Timer1 abschalte dann funktioniert dieser Programmteil. Aber seither hat es immer in Verbindung mit dem Timer1 funktioniert.
Ich kann da kein System erkennen und weis nicht weiter:

Hier mal der betreffende Codeausschnitt:


$regfile = "m32def.dat" 'Atmel Prozessor: AVR AT Mega32
$crystal = 7372800 'Quarz-Frequenz = 7.3728 MHz
$hwstack = 68
$swstack = 68
$framesize = 54
'baud = 19200 'Option für Serielle Schnittstelle
$lib "i2c_twi.lib" 'Hardwaresteuerung für I2C-Bus

------------------------------------------------------------------------------------------------------------------------

Config Lcd = 20x4 'LCD-Display mit 20 Zeichen und 4 Zeilen
Config Lcdbus = 4 '4Bit-Modus für LCD-Daten
Config Lcdmode = PORT 'Betriebsart für LCD-Daten
Config LcdPin = Pin, Db7 =PORTA.7, Db6 =PORTA.6, Db5 =PORTA.5, Db4 =PORTA.4, _
Rs =PORTA.3, E =PORTA.2 'Anschlußbelegung des LCD-Displays

------------------------------------------------------------------------------------------------------------------------

DDRA = DDRA OR &B00000001 'PortA Bit0 ist Ausgang für Beleuchtung
DDRD = &B10110011 'Datenrichtungsregister setzen 1=Ausg.

Config PIND.2 = Input 'INT0-Eingang (Sign. von DS1307 RTC)
Config PIND.6 = Input 'PC0 ist Eingang für DCF-77 Signal

Config TWI = 100000 'I2C-Schnittstelle auf 100 kHz einstellen
TWCR = &B00000100 'I2C-Schnittstelle einschalten

PORTD.7 = 1 'PullUp an Port D7 ein (DCF Ein/Aus)
PORTD.6 = 0 'PullUp an Port D6 aus (DCF-77)
PORTD.5 = 1 'PullUp an Port D5 ein (LED4)
PORTD.4 = 1 'PullUp an Port D4 ein (LED3)
PORTD.3 = 1 'PullUp an Port D3 ein (frei)
PORTD.2 = 0 'PullUp an Port D2 aus (DS1307 int)
PORTD.1 = 1 'PullUp an Port D1 ein (LED2)
PORTD.0 = 1 'PullUp an Port D0 ein (LED1)

DCF77Inp Alias PIND.6 'DCF-77 Eingang Alias

-----------------------------------------------------------------------------------------------------------------------

Config Timer0 = Timer, Prescale = 1024 'Timer für DCF-77 Signalabtastung
Config Timer1 = Timer, Prescale = 1024 'Timer für die Erzeugung eines Sek. Taktes

------------------------------------------------------------------------------------------------------------------------

Const DS1307W = &HD0 'DS1307 RTC schreiben
Const DS1307R = &HD1 'DS1307 RTC lesen

Const Preload0 = 183 'Timer0 Wert für 10ms Impulse
Const Preload1 = 58335 'Timer1 Wert für 1s Impulse

Const DS1307_Sekunden = &H00 'Korrektur bei Zeitübernahme in DS1307
Const Jahrh = &H20 'Start Jahrhundert bei &H20 (2000)

Dim Taste As Byte
Dim RTC_Regs(11) As Byte 'Byte-Array für DS1307 RTC Inhalte
Dim DcfBit(60) As Byte 'Variable für DCF-77 Behandlung
Dim Status As Byte 'Statusregister der Programmteile

Dim Zähler As Word 'Impulslängenmessungen
Dim Fehler As Byte 'Fehlerspeicher für DCF-Routinen
Dim SigZ(10) As Word 'Feldvariable für Unterprogramm

Dim Sek_Hex As Byte 'Sekunden in Hexadezimal
Dim Min_Hex As Byte 'Minuten in Hexadezimal
Dim Std_Hex As Byte 'Stunden in Hexadezimal
Dim Tag_Hex As Byte 'Tage in Hexadezimal
Dim Tag_Str As String * 2 'Tage in Stringform
Dim Mon_Str As String * 2 'Monat in Stringform
Dim Std_Str As String * 2 'Stunden in Stringform
Dim WTag_Hex As Byte 'Wochentag in Hexadezimal 1=Montag
Dim TagNam As String * 10 'Wochentagsname

Dim ZeitZone As String * 4 'Sommer/Winterzeit
Dim ZeitZ_Hex As Byte 'Zeitzone MEZ/MESZ
Dim Mon_Hex As Byte 'Monate in Hexadezimal
Dim Jahr_Hex As Byte 'Jahre in Hexadezimal
Dim JahrH_Hex As Byte 'Jahrhunderte in Hexadezimal
Dim JahrhW As Byte 'Zähler Jahrhundertwechsel seit 2000
Dim JahrhW_EEp As Eram Byte 'Anzahl der Jahrhundertwechsel seit 2000

Dim Dcf_Parity As Single 'Parität bei DCF-77 Auswertung
Dim PBit As Byte 'Variable für Paritätsprüfung

Dim V As Word 'Vergleichswert für Signalzeiten
Dim Z As Byte 'Allgemeine Zählvariable

------------------------------------------------------------------------------------------------------------------------

Declare Function SigDauer() As Word 'DCF-Signallänge ermitteln
Declare Function Syncro() As Byte 'Minutenmarke abwarten
Declare Sub DCFReceive() 'DCF-77 Signalverarbeitung
Declare Sub PTest() 'Paritätstest
Declare Function DelNull(ByVal Var As Byte) As String * 2 'Führende Null unterdrücken
Declare Sub Rtc_Init() 'DS1307 RTC initialisieren
Declare Sub DS1307Set() 'DCF-77 Informationen in RTC schreiben
Declare Function DS1307R_Sekunde() As Byte 'DS1307 Sekundenregister auslesen
Declare Sub DS1307W_Sekunde(ByVal Value As Byte) 'DS1307 Sekundenregister schreiben
Declare Sub DS1307Read() 'DS1307 $00 - $09 auslesen
Declare Sub DS1307Write() 'DS1307 $00 - $09 schreiben

------------------------------------------------------------------------------------------------------------------------

On Timer0 Kurzzeit_isr 'Erzeugung 10ms Takt
On Timer1 Sekundentakt_isr 'Erzeugung 1s Takt

------------------------------------------------------------------------------------------------------------------------

Cls 'LCD-Display löschen
Cursor Off Noblink 'Cursor auf LCD-Display ausblenden
PORTA.0 = 0 'LCD-Hintergrundbeleuchtung einschalten


Timer1 = Preload1 'Timer1 mit Startwert für 1s Takt laden

Call DS1307Read() 'Daten für Lcd-Anzeige aus RTC auslesen

Enable Timer1 'Timer1 für 1s Takt einschalten
Enable Timer0 'Timer0 für 10ms Takt einschalten
Enable Interrupts 'Interrupts global freigeben


PORTD.0 = 0 'Led1 für DCF-Empfang einschalten
PORTD.7 = 0 'DCF77-Empfänger einschalten
Wait 4 '4s warten bis DCF-Empfänger bereit ist

V = SigDauer() 'Durchschnittliche Signaldauer ermitteln

Locate 4, 1 'Textposition auf LCD festlegen.
If V = 0 Then 'Wenn kein Vergleich ermittelt, dann
Lcd "Kein Vergleich gef." 'Fehlermeldung auf LCD ausgeben.
Else 'sonst Vergleichswert auf LCD anzeigen
Lcd "Zeitkonst.: "; V ;" "
End If

------------------------------------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------------------------------

Function SigDauer() As Word

Local Z As Byte 'Allgemeine Zählvariable
Local V As Word 'Variable für Signallängenberechnung

Locate 4, 1 'Text positionieren und ausgeben.
Lcd "Sign.Zeit: Messung"
Wait 2 'Meldung 2s lang anzeigen, dann weiter

While V < 1 'Vergleichswert kleiner 1 ?
For Z = 1 To 10 '10mal Signallänge messen
Do 'Solange warten bis das DCF-Signal 0
Loop Until DCF77Inp = 1 'wird.

Timer0 = Preload0 'Dann Timer für Abtastung vorladen und
Zähler = 0 'Zähler für Signallänge löschen.

Do 'Solange das DCF-Signal 0 ist Signallängen-
Loop Until DCF77Inp = 0 'zähler hochzählen.
SigZ(Z) = Zähler 'Messschritte auf dem Lcd-Display anzeigen
Locate 4, 12
Lcd "("; Z; ") "; SigZ(Z)
Next Z

For Z = 1 To 10 'Nach den 10 Messungen kürzesten Wert fest-
If SigZ(Z) < SigZ(1) Then 'stellen.
Swap SigZ(1), SigZ(Z)
End If
Next Z

If SigZ(1) < 10 Then SigZ(1) = 10 'Sicherheitskorrektur, sonst Fehler mögl.
'Lcd-Ausgabe speichern.
V = SigZ(1) / 2 'Diesen Wert mit Faktor 1.5 multiplizieren
V = V + SigZ(1) 'und als Vergleichswert in Variable able-
Wend 'gen.

SigZ(2) = SigZ(1) * 10 'Wert aufbereiten zur LCD-Anzeige

Locate 4, 12 'Text auf Lcd-Display positionieren und
Lcd SigZ(2); "ms " 'ermittelten Wert anzeigen.
Wait 3 'Text 3s lang anzeigen.

SigDauer = V 'Ermittelten Wert zurückgeben

Return

End Function

fredred
15.12.2015, 11:06
Hallo rogerberglen,

frage:
Warum nutzt du nicht die Lib Dcf77. Da ist doch alles schon drin was du benötigst.
Auch die Abfrage des Dcf_ Status.
Beispiel Ausgabe Terminal::

Print "DCF: " ; Time$ ; " " ; Date$ ; " " ; Time(dcf_sec) ; " " ; Date(dcf_day) ; " " ; Bin(dcf_status) ; " " ; Bin(dcf_parity) ; " " ; Bin(dcf_bits) ; " " ; Bdcf_impuls ; " " ; Bdcf_pause '; " " ; db1 ; " " ; db2

Gruß Fred

rogerberglen
15.12.2015, 11:32
Welche Timer nutzt denn die DCF-77 lib? Gibt diese mir auch wirklich alle Bits 0 - 58 zurück. Denn ich frage da ein paar zusätzliche Sachen ab, nicht nur die Uhrzeit und das Datum.
Wie Zeitkritisch ist diese fertige Lib in Bezug mit anderen Timern und Interrupts?

fredred
15.12.2015, 12:50
Hallo rogerberglen,

Timer1 wird belegt. Stellt aber mit aktiv, [Gosub = Sectic] ein Sekundentakt für Folgeanwendungen zu Verfügung. Persönlich finde ich dies auch sehr hilfreich.
Ja alle Bits können abgefragt werden. Stelle mal ein Printauszug ab welche Infos für mich interessant waren.

31035
Ein zeitkritisches Verhalten mit anderen Timern konnte ich bis dato nicht feststellen. Lib ist ja eine Art Task. Das mit Bit7 an oder ab geschaltet werden kann. Grob gesagt Lib läuft im „Hintergrund“ wenn so eingestellt.

Gruß Fred

P.S ich gehe nicht mehr zu Fuß wenn Bascom ein Auto anbietet von A nach B zukommen.
Ja die Frage bleibt was ist gesünder. Diese muss jeder selber entscheiten.