// - D C F - 7 7 - F u n k u h r - Version: 1.1 - 4/2008
// Autor: Holger Reither
// ( http://olbnet.selfhost.eu/reither/ )
// Einbinden des FB
// ================
// Dieser Funktionsbaustein muß zyklisch im Intervall von 100ms
// ausgeführt werden!
// Sinnvoller Weise nutzt man den OB35, da dessen Aufrufintervall
// 100ms (Grundeinstellung) ist.
// Dieser FB kann die Systemuhr direkt stellen (1 am Eingang
// "DCFStellen")
// Weiterhin kann die zuletzt ermittelte DCF-Zeit am Ausgang "DCFZeit"
// gelesen werden.
// Eine positive Flanke am Ausgang "DCFOK" signalisiert die Gültigkeit
// des Ausganges "DCFZeit".
// Zum stellen der Systemuhr wird die SFC0 benötigt !!
// Diagnose
// ========
// Die Out-Variable DCFLastPegel muß mit geringer Verzögerung der
// In-Variable DCFSignal folgen. Ist dies nicht der Fall, ist die CPU
// temporär stark beschäftigt oder generell zu langsam. Ein erkennen
// der aktuellen DCF-Zeit ist somit nicht möglich.
// Die Variable DCFStatus enthält den aktuellen Empfangsstatus der
// aktuellen Minute (siehe unten).
// DCFFehlerZaehler zählt die "fehlerhaften Minuten" seit dem letzten
// gültigen und verifizierten Zeitzeichenempfang (gezählt wird nicht
// die Zeit, sondern die erkannten vollen Minuten/ Impulslücken!!).
// SFC0Fehler
// Trat beim Versuch die Systemuhr zu stellen ein Fehler auf, so wird
// diese Variable für die nächsten 15 Takte (Sekunden) auf 1 gesetzt
// SFC0Fehlercode
// Trat beim Versuch die Systemuhr zu stellen ein Fehler auf, so wird
// diese Variable mit dem Systemfehlercode der SFC0 geladen.
// (0000 Kein Fehler/ 8080 Fehler im Datum/ 8081 Fehler in der Uhrzeit/
// 8xyy allgemeine Fehlerinformation/ siehe Hilfe zum SFC0)
// Internes / Infos
// ================
// Datenstruktur:
// -mit jeder Sekunde wird ein Bit übertragen,
// -der Impuls für die 59. Sekunde fällt aus, und dient zur
// Synchronisation,
// -ein kurzer Impuls entspricht einer 0 ein langer entspricht einer 1,
// -die Übertragung erfolgt Ziffernweise,
// -das erste Bit einer Ziffer ist immer das niederwertigste,
// DCF-
// Status: Sekunden-Bit: Bedeutung:
// -1 Synchronbit erkannt (Lücke in 59.Sekunde)
// 0.. 0..17 0 leer
// 18 1 Startbit ?? oder SZ
// 19 0 Startbit ?? oder SZ
// 20 1 Startbit ?? oder SZ
// 21..24 Minute / Einer-Stelle
// 25..27 Minute / Zehner-Stelle
// 28 1. Paritätsbit
// 29..32 Stunde / Einer-Stelle
// 33..34 Stunde / Zehner-Stelle
// 35 2. Paritätsbit
// 36..39 Tag / Einer-Stelle
// 40,41 Tag / Zehner
// 42 ? ev.Wochentag
// 43 Wochentag
// 44 Wochentag ???011-Samstag 111-So 100-Mo
// 45..48 Monat / Einer
// 49 Monat / Zehner
// 50..53 Jahr / Einer
// 54..57 Jahr / Zehner
// 58 Paritätsbit (oder Stopbit ??)
// ..59 59 Synchronisation ->Impuls fällt aus
// Status 59: bereit zum stellen / keine Fehler erkannt
// 118 Fehler: Startbitkombination ungültig
// (Bit 18,19,20/ 4..Sommerzeit, 5..Winterzeit )
// 128 Fehler: Prüfbit 28
// 135 Fehler: Prüfbit 35
// 158 Fehler: Prüfbit 58
// 180 Fehler: vorige Minute+1 <> aktuelle Minute
// Codierung des Wochentages:
// So Mo Di Mi Do Fr Sa So
// DCF : 7 1 2 3 4 5 6 7
// S7-Data_and_Time: 1 2 3 4 5 6 7 1
// CPU-Belastung
// =============
// Berechnungen werden über den Zeitraum einer Minute aufgeteilt.
// - Begin erste Sekunde: Stellen, evtl. positive Flanke an "DCFOk",
// - 15.Sekund: Löschen rücksetzen/ initialisieren Zeitzeichenempfang,
// negative Flanke an "DCFOk",
// - Sekunde 18..58: Empfan der Zeit-Innformation
// - Sekund 58: Auswertung, vorbereiten zum Stellen
// - erhöhe Interuptzähler -----------------------------------------------
L #Interruptzaehler
L 1
+I
T #Interruptzaehler
// - Pegeländerung ? -----------------------------------------------------
CLR
X #DiagLastPegel
X #DCFSignal
SPBN ENDE
// - Impulslänge auswerten -----------------------------------------------
UN #DCFSignal // Impulsende ?
SPB _IE // Ja auswerten
L #Interruptzaehler // lange Pause ?
L 10
>I
SPB _S10 // Stellen ...
SPA _QIT // war nur normale Lücke
// - DCFStatus erhöhen ---------------------------------------------------
_IE: L #DiagDCFStatus
L 58
>=I
SPB _IEX
L #DiagDCFStatus // Next Status
L 1
+I
T #DiagDCFStatus
_IEX: NOP 0
// - Bit aus Impulslänge erkennen ----------------------------------------
L #Interruptzaehler // Impulslänge ?
L 1
>I
SPB _H
SET // kurzer Impuls
R #DiagDCFBit
SPA _xxx
_H: NOP 0 // Langer Impuls
SET
S #DiagDCFBit
UN #PruefBit
= #PruefBit
_xxx: NOP 0
// - R E S E T -----------------------------------------------------------
// - Lösche alte Bytes in 5. Sekunde / Ende des DCFOK-Impulses -----------
L 15
L #DiagDCFStatus
==I
SPBN _100
L 0
T #ZStartBitKombination
T #ZMinuteEiner
T #ZMinuteZehner
T #ZStundeEiner
T #ZStundeZehner
T #ZTagEiner
T #ZTagZehner
T #ZMonatEiner
T #ZMonatZehner
T #ZWochenTag
T #ZJahrEiner
T #ZJahrZehner
T #DiagSFC0Fehlercode // Systemuhr
CLR
= #DCFVerglFehler
= #DiagSFC0Fehler
= #DCFOK //Ende des evtl. DCFOK - Impulses
_100: NOP 0
// überpringe "leere Sekunden"
L 17
L #DiagDCFStatus
<I
SPBN _QIT
// - mitlaufendes Prüfbit rücksetzen -------------------------------------
L #DiagDCFStatus // Sekunde 21 ?
L 21
==I
SPBN _PB1
CLR
= #PruefBit
_PB1: NOP 0
// Srungleiste
L #DiagDCFStatus
L 18
-I
SPL _E_L
SPA _STB //18
SPA _STB //19
SPA _STB //20
SPA _MiE //21
SPA _MiE //22
SPA _MiE //23
SPA _MiE //24
SPA _MiZ //25
SPA _MiZ //26
SPA _MiZ //27
SPA _S28 //28
SPA _StE //29
SPA _StE //30
SPA _StE //31
SPA _StE //32
SPA _StZ //33
SPA _StZ //34
SPA _S35 //35
SPA _TgE //36
SPA _TgE //37
SPA _TgE //38
SPA _TgE //39
SPA _TgZ //40
SPA _TgZ //41
SPA _WTE //42
SPA _WTE //43
SPA _WTE //44
SPA _MoE //45
SPA _MoE //46
SPA _MoE //47
SPA _MoE //48
SPA _MoZ //49
SPA _JrE //50
SPA _JrE //51
SPA _JrE //52
SPA _JrE //53
SPA _JrZ //54
SPA _JrZ //55
SPA _JrZ //56
SPA _JrZ //57
SPA _S58 //58
_E_L: SPA _QIT
//---------------------------
_STB: L #ZStartBitKombination
U #DiagDCFBit
SPBN _x99
L 8
OW
_x99: SRW 1
T #ZStartBitKombination
L #DiagDCFStatus
L 20 // aktuelles StatusBit=20 ?
==I
SPBN _QIT
L #ZStartBitKombination
L 5
==I
R #ZSommerzeit
SPB _QIT
L #ZStartBitKombination
L 4
==I
S #ZSommerzeit
SPB _QIT
L 118 // Fehlerstatus
T #DiagDCFStatus
SPA _QIT
//---------------------------
_MiE: L #ZMinuteEiner
U #DiagDCFBit
SPBN _x10
L 16
OW
_x10: SRW 1
T #ZMinuteEiner
SPA _QIT
//---------------------------
_MiZ: L #ZMinuteZehner
U #DiagDCFBit
SPBN _x11
L 8
OW
_x11: SRW 1
T #ZMinuteZehner
SPA _QIT
//---------------------------
_S28: NOP 0
X #PruefBit
X #DiagDCFBit
SPB _QIT
L 128
T #DiagDCFStatus
SPA _QIT
//---------------------------
_StE: L #ZStundeEiner
U #DiagDCFBit
SPBN _x12
L 16
OW
_x12: SRW 1
T #ZStundeEiner
SPA _QIT
//---------------------------
_StZ: L #ZStundeZehner
U #DiagDCFBit
SPBN _x13
L 4
OW
_x13: SRW 1
T #ZStundeZehner
SPA _QIT
//---------------------------
_S35: NOP 0
X #PruefBit
X #DiagDCFBit
SPB _QIT
L 135
T #DiagDCFStatus
SPA _QIT
//---------------------------
_TgE: L #ZTagEiner
U #DiagDCFBit
SPBN _x14
L 16
OW
_x14: SRW 1
T #ZTagEiner
SPA _QIT
//---------------------------
_TgZ: L #ZTagZehner
U #DiagDCFBit
SPBN _x15
L 4
OW
_x15: SRW 1
T #ZTagZehner
SPA _QIT
//---------------------------
_WTE: L #ZWochenTag
U #DiagDCFBit
SPBN _x16
L 8
OW
_x16: SRW 1
T #ZWochenTag
SPA _QIT
//---------------------------
_MoE: L #ZMonatEiner
U #DiagDCFBit
SPBN _x17
L 16
OW
_x17: SRW 1
T #ZMonatEiner
SPA _QIT
//---------------------------
_MoZ: L 0
U #DiagDCFBit
SPBN _x18
L 1
_x18: T #ZMonatZehner
SPA _QIT
//---------------------------
_JrE: L #ZJahrEiner
U #DiagDCFBit
SPBN _x19
L 16
OW
_x19: SRW 1
T #ZJahrEiner
SPA _QIT
//---------------------------
_JrZ: L #ZJahrZehner
U #DiagDCFBit
SPBN _x20
L 16
OW
_x20: SRW 1
T #ZJahrZehner
SPA _QIT
// - Auswertung ----------------------------------------------------------
_S58: NOP 0
X #PruefBit
X #DiagDCFBit
SPB _POK
L 158
T #DiagDCFStatus
SPA _QIT
_POK: NOP 0
// - Vergleiche Aktuelle Minute mit vorheriger Minute
L #OldMinuteZehner
SLW 8
L #OldMinuteEiner
OW
BTI
L 1
+I
T #TmpMinute
L #ZMinuteZehner
SLW 8
L #ZMinuteEiner
OW
BTI
L #TmpMinute
==I
SPB _MV1
SET
= #DCFVerglFehler // Fehler nur merken!!
_MV1: NOP 0
// ----------
L #ZStundeEiner
L #OldStundeEiner
==I
SPBN _ung
L #OldStundeZehner
L #ZStundeZehner
==I
SPBN _ung
L #OldTagEiner
L #ZTagEiner
==I
SPBN _ung
L #OldTagZehner
L #ZTagZehner
==I
SPBN _ung
L #ZMonatEiner
L #OldMonatEiner
==I
SPBN _ung
L #ZMonatZehner
L #OldMonatZehner
==I
SPBN _ung
L #OldWochenTag
L #ZWochenTag
==I
SPBN _ung
L #OldJahrEiner
L #ZJahrEiner
==I
SPBN _ung
L #OldJahrZehner
L #ZJahrZehner
==I
SPBN _ung
L #OldStartBitKombination
L #ZStartBitKombination
==I
SPBN _ung
// - Zeitformat erstellen ------------------------------------------------
L 0 // Fehlerzähler auf 0
T #DiagFehlerZaehler
L 59 // Info für DcfOk-Impuls
T #DiagDCFStatus
// - Formatiere #DCFZeitTemp ====>>>> Date_And_Time ----------------------
L #ZJahrZehner
SLD 4
L #ZJahrEiner
OD
SLD 4
L #ZMonatZehner
OD
SLD 4
L #ZMonatEiner
OD
SLD 4
L #ZTagZehner
OD
SLD 4
L #ZTagEiner
OD
SLD 4
L #ZStundeZehner
OD
SLD 4
L #ZStundeEiner
OD
T DB35.DBD 28 // D! >>>> Adresse im DB: #DCFZeitTemp + 0 <<<<
T DB35.DBD 2 // D! >>>> Adresse im DB: #DCFZeit + 0 <<<<
L #ZMinuteZehner
SLW 4
L #ZMinuteEiner
OW
T DB35.DBB 32 // B! >>>> Adresse im DB: #DCFZeitTemp + 4 <<<<
T DB35.DBB 6 // B! >>>> Adresse im DB: #DCFZeit + 4 <<<<
L 0
T DB35.DBW 33 // W! >>>> Adresse im DB: #DCFZeitTemp + 5 <<<<
T DB35.DBW 7 // W! >>>> Adresse im DB: #DCFZeit + 5 <<<<
L #ZWochenTag
L 1 // Wochentag +1
+I // weil Versatz im Format
L 8
>=I
SPBN _WT
L 1 // 1 f. Sonntag
_WT: T DB35.DBB 35 // B! >>>> Adresse im DB: #DCFZeitTemp + 7 <<<<
T DB35.DBB 9 // B! >>>> Adresse im DB: #DCFZeit + 7 <<<<
//--------------------------------------------
_ung: NOP 0 // der Vergleich der letzten Minuten ergab fehler
// Speichere letzte Minute für weitere Gültigkeitsprüfung
L #ZMinuteEiner
T #OldMinuteEiner
L #ZMinuteZehner
T #OldMinuteZehner
L #ZStundeEiner
T #OldStundeEiner
L #ZStundeZehner
T #OldStundeZehner
L #ZTagEiner
T #OldTagEiner
L #ZTagZehner
T #OldTagZehner
L #ZMonatEiner
T #OldMonatEiner
L #ZMonatZehner
T #OldMonatZehner
L #ZWochenTag
T #OldWochenTag
L #ZJahrEiner
T #OldJahrEiner
L #ZJahrZehner
T #OldJahrZehner
L #ZStartBitKombination
T #OldStartBitKombination
CLR // Vergleich der letzten beiden Minuten durchführen?
U #DCFVerify
SPBN _QIT // nein
CLR // Passen die letzten beitden Minuten zusammen?
U #DCFVerglFehler
SPBN _QIT // ja
L 180
T #DiagDCFStatus
SPA _QIT
// -----------------------------------------------------------------------
// - Flanke f. Synchronisation, Stellen ... ------------------------------
_S10: NOP 0
L #DiagDCFStatus // letzte Minute vollständig ?
L 59
==I
SPB _S15
L #DiagFehlerZaehler // Nein war nicht vollständig
L 1
+I
T #DiagFehlerZaehler
SPA _S99
_S15: NOP 0 // letzte Minute war vollständig
SET // Impuls "gültige Zeit steht bereit"
= #DCFOK
U #ZSommerzeit // Ausgang Sommerzeit setzen
= #DCFSommerZeit
U #DCFStelleSystemZeit
SPBN _S99
CALL "SET_CLK"
PDT :=#DCFZeitTemp
RET_VAL:=#DiagSFC0Fehlercode
_S99: L #DiagDCFStatus // merke evtl. fehlerstatus
L 59
>I
SPBN _S9A
L #DiagDCFStatus
T #OldFehlerstatus
_S9A: L -1 // Status zurück setzen
T #DiagDCFStatus
SET
SPA _QIT
// -----------------------------------------------------------------------
// - Quittieren ----------------------------------------------------------
// Zähler auf 0
_QIT: L 0 // Interruptzähler auf 0
T #Interruptzaehler
CLR
U #DCFSignal // merke Pegel
= #DiagLastPegel
// -----------------------------------------------------------------------
ENDE: NOP 0
// -----------------------------------------------------------------------
|