# Uhrzeit- und Pausensteuerung Beckhoff



## MichiJa (16 Juli 2021)

Hallo Zusammen, 
ich hänge gerade an einer Aufgabe fest. Ich möchte gerne mithilfe einer Beckhoff Steuerung (TwinCat 3) mehrere Uhren synchronisieren und an bestimmten Tagen zu bestimmten Uhrzeiten eine Pausensirene für eine bestimmte Zeit ertönen lassen.
- Die Uhren werden über einen Minutenimpuls angesteuert
- Mo. bis Fr. ertönt die Sirene jeweils 10 mal (Uhrzeiten sind für jeden Wochentag identisch) für 3 Sekunden. 
- Sa. ertönt die Sirene 5 mal ebenfalls für 3 Sekunden
- So. ist Ruhetag 
Bezüglich der Uhrzeitsynchronisation bin ich wie folgt vorgegangen: Mithilfe des FB NT_GetTime gekoppelt an einem TON lese ich die Systemzeit aus. Anschließend werden die aktuellen Minuten mit denen aus dem vorherigen Zyklus verglichen. Bei Ungleichheit wird der Output auf True gesetzt und der Minutenzeiger angesteuert. Ich hoffe/denke, dass das soweit in Ordnung ist.

Mein Problem ist nun die Programmierung der Sirenen. Ich habe mich bereits im Forum umgeschaut, finde aber nicht die richtigen Ansatz für mein Problem.
Prinzipiell würde ich die Zeiten in ein Array packen und über eine Schleife mit der Systemzeit vergleichen und im Anschluss mit einem TP für 3 Sekunden auf True setzen. Doch wie binde ich die Wochentage am Besten ein? Ein weiteres Array oder Struct?
Zusatz: Über die Struktur TIMESTRUCT des FB's NT_GetTime können unter anderem die Wochentage, das Datum ,die Uhrzeit usw. herausgefiltert werden.

Sind meine Gedankengänge einigermaßen plausibel? Über Anregungen und Hilfestellungen zur Umsetzung würde ich mich freuen 

Vielen Dank

Gruß 
Michi


----------



## Mrtain (16 Juli 2021)

Ich würde ein Struct erstelle, wo die Wochentage Mo - So enthalten ist.
Für jden Tag gibt es  dann ein enable Feld ( bool) und weitere Felder für die Startzeit und Dauer.
Die Struktur brauchst du dann für jede Sirene. 
Ob du die in Array packst oder einzeln pro Sirene anlegst, ist geschmackssache.

In etwa so. Die einstellungen müssten natürlich remanent sein.


```
stSireneZeiten :struct
    Startzeit  :#Startzeit;
    Dauer :#Dauer;
end_struct;

stSireneTag :struct
   Enable :bool;
   Zeiten :array[#n] of stSireneZeiten;
end_struct;

stSirene :struct
    Mo,Die,Mi,Do,Fr,Sa,So :stSireneTag;
end_struct

Sirene01 :stSirene;
```


----------



## MichiJa (16 Juli 2021)

@Mrtain vielen Dank für die schnelle Rückmeldung. Ich werde mir diesen Ansatz mal zu Gemüte führen


----------



## Matze001 (16 Juli 2021)

Blöde Frage. Die Uhren werden über einen Minutenimpuls angesteuert.
Das heißt bei jedem Impuls tickern sie eine Minute weiter? 
Was machst Du dann wenn mal eine (warum auch immer) davon läuft.
(z.B. Stromausfall in dem Bereich)

Grüße

Marcel


----------



## Mrtain (16 Juli 2021)

Ist ja im Prinzip nichts anderes als eine Nebenuhr-Steuerung. Wenn man herkömmliche Nebenuhren eine Stunde vor oder zurück stellen will, gibt man 60 Impulse an die Nebenuhr. Theoretisch müsste man die Anzahl der fehlenden Impulse für ermitteln und an die Nebenuhr schicken.


----------



## MichiJa (16 Juli 2021)

Matze001 schrieb:


> Blöde Frage. Die Uhren werden über einen Minutenimpuls angesteuert.
> Das heißt bei jedem Impuls tickern sie eine Minute weiter?
> Was machst Du dann wenn mal eine (warum auch immer) davon läuft.
> (z.B. Stromausfall in dem Bereich)
> ...


Genau, bei jedem Impuls tickern sie eine Minute weiter.

Mrtain hats im Prinzip schon erklärt - das ganze ähnelt einer Nebenuhr-Steuerung.
Die Frage kam intern aber auch schon bezüglich des Wechsel von der Sommer- zur Winterzeit und umgekehrt auf. Die optimale Lösung für dieses Problem steht noch aus.

Gruß
Michi


----------



## holgermaik (16 Juli 2021)

Matze001 schrieb:


> Was machst Du dann wenn mal eine (warum auch immer) davon läuft.


Normalerweise werden die Impulse von der Mutteruhr gesendet. Die "Slave" Uhren brauchen keine Spannung oder sonstiges.
Zur Umstellung Winter -> Sommer kommen einfach 60 Impulse in schneller Folge. Bei Sommer -> Winter passiert 60 Minuten lang nichts.


----------



## MichiJa (22 Juli 2021)

Mrtain schrieb:


> Ich würde ein Struct erstelle, wo die Wochentage Mo - So enthalten ist.
> Für jden Tag gibt es  dann ein enable Feld ( bool) und weitere Felder für die Startzeit und Dauer.
> Die Struktur brauchst du dann für jede Sirene.
> Ob du die in Array packst oder einzeln pro Sirene anlegst, ist geschmackssache.
> ...





Mrtain schrieb:


> Ist ja im Prinzip nichts anderes als eine Nebenuhr-Steuerung. Wenn man herkömmliche Nebenuhren eine Stunde vor oder zurück stellen will, gibt man 60 Impulse an die Nebenuhr. Theoretisch müsste man die Anzahl der fehlenden Impulse für ermitteln und an die Nebenuhr schicken.


Hallo,
ich habe die Sirenensteuerung jetzt etwas anders gelöst, beziehungsweise auf "eigenes" Programmieren verzichtet. Die Beckhoff Bib bietet einen Funktionsbaustein namens FB_WeeklyTimeSwitch an, mit dem man das Signal für eine bestimmte Zeit an ausgewählten Wochentagen erzeugen kann. Ich versuche nun die Sommer- & Winterzeit in mein Programm einzubeziehen. Kannst du mir/ Könnt ihr mir bitte weitere Denkanstöße geben wie ich dies umgesetzt bekomme? Muss ich mir das Datum und die Uhrzeit für die Uhrumstellungen holen und im Anschluss eine Schleife mit 60 Impulsen (Winter -> Sommer) ausgeben oder denke ich zu einfach?

Gruß
Michi


----------



## asci25 (22 Juli 2021)

MichiJa schrieb:


> Muss ich mir das Datum und die Uhrzeit für die Uhrumstellungen holen und im Anschluss eine Schleife mit 60 Impulsen (Winter -> Sommer) ausgeben oder denke ich zu einfach?


Ich hätte da noch einen einfacheren Gedanken: Die EU schafft die Uhrzeitumstellung einfach mal ab - das wird so langsam mal Zeit.


----------



## MichiJa (23 Juli 2021)

asci25 schrieb:


> Ich hätte da noch einen einfacheren Gedanken: Die EU schafft die Uhrzeitumstellung einfach mal ab - das wird so langsam mal Zeit.


Gut, dann werde ich dies einfach mal in die Wege leiten.


----------



## jensemann (23 Juli 2021)

Du könntest auch aus der TC2_Utillities den FB_LocalSystemTime benutzen.


			FB_LocalSystemTime


----------



## MichiJa (23 Juli 2021)

jensemann schrieb:


> Du könntest auch aus der TC2_Utillities den FB_LocalSystemTime benutzen.
> 
> 
> FB_LocalSystemTime


Vielen Dank. Also den hatte ich auch schon im Visier und würde ihn auch gerne verwenden, jedoch weiß ich nicht, wie ich nach der Zeitumstellung meine 60 Impulse an die Uhren bringen kann. Kann mir da bitte jemand auf die Sprünge helfen? Aktuell verfolge ich noch den Ansatz mir die Tage der Umstellungen selbst zu errechnen und diese mit dem aktuellen Datum zu vergleichen.

Ach, eine Frage hätte ich auch noch in Bezug auf die Zeitumstellung von Winter zu Sommer: Was ergibt mehr Sinn? Die Uhren eine Stunde "warten" lassen oder den Zeiger um elf Stunden verschieben, wodurch man zumindest sieht, dass die Uhren "arbeiten"? 

Gruß
Michi


----------



## jensemann (23 Juli 2021)

Du brauchst ja nur die Minutenzeiger/-Anzeige laufen lassen, lass die Stunden aussen vor und aktualisiere die einfach alle 60 Minuten.


----------



## Heinileini (23 Juli 2021)

MichiJa schrieb:


> Was ergibt mehr Sinn? Die Uhren eine Stunde "warten" lassen oder den Zeiger um elf Stunden verschieben, wodurch man zumindest sieht, dass die Uhren "arbeiten"?


Das ist ja ein ganz neuer Aspekt. Bisher hiess es ...


MichiJa schrieb:


> - Die Uhren werden über einen Minutenimpuls angesteuert


Keine Rede davon, dass Du den StundenZeiger separat ansteuern kannst bzw. musst?
Oder meinst Du mit "arbeiten", dass Du dies durch 660 Minuten-Impulse bewerkstelligen müsstest? Wie lange benötigst Du für einen solchen MarathonLauf, ohne dass die Uhren anfangen, einzelne MinutenImpulse zu schlabbern?


----------



## MichiJa (23 Juli 2021)

Heinileini schrieb:


> Das ist ja ein ganz neuer Aspekt. Bisher hiess es ...
> 
> Keine Rede davon, dass Du den StundenZeiger separat ansteuern kannst bzw. musst?
> Oder meinst Du mit "arbeiten", dass Du dies durch 660 Minuten-Impulse bewerkstelligen müsstest? Wie lange benötigst Du für einen solchen MarathonLauf, ohne dass die Uhren anfangen, einzelne MinutenImpulse zu schlabbern?


Die Stundenzeiger muss ich nicht separat ansteuern, mit denen habe ich im Grunde nichts am Hut. 
Genau, mit "arbeiten" meine ich die 660 Minuten-Impulse. Dieser Marathon-Lauf wird vermutlich länger als eine Minute dauern, wodurch sich denke ich die Antwort von alleine ergibt. Danke.


----------



## Heinileini (23 Juli 2021)

MichiJa schrieb:


> Dieser Marathon-Lauf wird vermutlich länger als eine Minute dauern, wodurch sich denke ich die Antwort von alleine ergibt.


Länger als 1 Minute. Das habe ich befürchtet. 
Zum Trost: eine (Zeiger-)Uhr, die steht, zeigt zweimal am Tag die richtige Zeit an. Und an dem Tag, an dem sie 1 Stunde zurück gestellt werden muss, sogar dreimal!
Aber dieses "Argument" soll bitte nicht als Rechtfertigung missverstanden werden, die Uhrzeitumstellung nicht abzuschaffen!   
Die Zeitumstellung als "ArbeitsBeschaffungsMaßnahme" zu rechtfertigen, finde ich auch nicht wirklich überzeugend.
Ist doch eher eine ProgrammiererKopfschmerzenBeschaffungsMaßnahme.
Also ...


asci25 schrieb:


> Die EU schafft die Uhrzeitumstellung einfach mal ab - das wird so langsam mal Zeit.


Häwenaissuiikend!


----------



## PN/DP (23 Juli 2021)

Wenn die Uhrzeitumstellung abgeschafft wird, dann muß an vielen vielen Altanlagen die vom jeweiligen Programmierer oft irgendwie mehr schlecht als recht realisierte Uhrzeitumstellung entfernt werden - das wird auch eine Arbeitsbeschaffungsmaßnahme. 

Harald


----------



## Heinileini (23 Juli 2021)

Und das Schlimmste daran: man kann sich nicht darauf verlassen, dass dieser alte Zopf dann auch abgeschnitten bleibt.
Sooo überwältigend sind die MehrheitsVerhältnisse pro und contra wohl doch nicht, sonst wär's längst passiert ...


----------



## DeltaMikeAir (24 Juli 2021)

PN/DP schrieb:


> Wenn die Uhrzeitumstellung abgeschafft wird, dann muß an vielen vielen Altanlagen die vom jeweiligen Programmierer oft irgendwie mehr schlecht als recht realisierte Uhrzeitumstellung entfernt werden - das wird auch eine Arbeitsbeschaffungsmaßnahme.
> 
> Harald


Oh ja, viel Spaß.


----------



## MichiJa (27 Juli 2021)

So, ich habe mein Glück versucht. In der Simulation klappt es recht gut, obwohl der Code mit Sicherheit noch Luft nach oben hat. Falls jemandem mögliche Problematiken, Fehler oder auch Verbesserungen einfallen, bitte ich diese einmal zu äußern. Vielen Dank und beste Grüße 


//-------------Minutenimpuls an die Uhr--------------


wMin_akt := GVL.stSystemTime.wMinute; 

IF (wMin_alt <> wMin_akt) AND (NOT bWinter AND NOT bSummer) 
THEN                                                    
    bClock1 := TRUE;                                            
END_IF

wMin_alt := wMin_akt;                                        

tpDurationSignal(IN := bClock1, PT := T#2S);                                
IF NOT tpDurationSignal.Q 
THEN
    bClock1 := FALSE;
END_IF


//-------------Zeitumstellung--------------


// Berechnung des Tages für die Zeitumstellung der Sommerzeit 
// Die Berechnung des Datums für die Zeitumstellung des aktuellen Jahres ist Abhängig vom Vorjahr -> "GVL.stSystemTime.wYear -1"

tsTimeChangeSum.wYear := GVL.stSystemTime.wYear;
wDaySum := 31 - (((GVL.stSystemTime.wYear - 1) + 5 +( (GVL.stSystemTime.wYear - 1) / 4 )) MOD 7);
tsTimeChangeSum.wDay := wDaySum; 
dtTimeChangeSum := SYSTEMTIME_TO_DT(tsTimeChangeSum);


//Vergleich des Tages der Zeitumstellung mit der Systemzeit
rTSummer(CLK := ((GVL.dtSystemTime >= dtTimeChangeSum) AND (GVL.dtSystemTime < dtTimeChangeSum + T#1S))

IF rTSummer.Q THEN
    bSummer := TRUE;    
END_IF

// Taktgeber
IF bSummer = TRUE THEN
    tonTest1 (IN := NOT tonTest2.Q, PT := T#500MS);
    tonTest2 (IN := tonTest1.Q, PT := T#2S);
    IF tonTest1.Q = TRUE THEN
        bClock2:= TRUE; 
    ELSE 
        bClock2 := FALSE;
    END_IF    
ELSE
    bClock2 := FALSE;
END_IF


// Impulse werden im Zeitraum von 157,5 Sekunden (63 Impulse) gesendet // 60 Impulse für das Vorstellen der Uhr + 3 weitere für die Minutenimpulse 
tpSummer2min(IN := bSummer, PT := T#157.5S);                                
IF NOT tpSummer2min.Q 
THEN
    bSummer := FALSE;
END_IF


// Berechnung des Tages für die Zeitumstellung der Winterzeit
// Die Berechnung des Datums für die Zeitumstellung des aktuellen Jahres ist Abhängig vom Vorjahr -> "GVL.stSystemTime.wYear -1"

tsTimeChangeWin.wYear := GVL.stSystemTime.wYear;
wDayWin := 31 - (((GVL.stSystemTime.wYear - 1) + 2 +( (GVL.stSystemTime.wYear - 1) / 4 )) MOD 7);
tsTimeChangeWin.wDay := wDayWin; 
dtTimeChangeWin := SYSTEMTIME_TO_DT(tsTimeChangeWin);


// Vergleich des Tages der Zeitumstellung mit der Systemzeit
rTWinter(CLK := ((GVL.dtSystemTime >= dtTimeChangeWin) AND (GVL.dtSystemTime < dtTimeChangeWin + T#1S))             
IF rTWinter.Q THEN 
    bWinter := TRUE; 
END_IF

// Der Impuls "bClock" wird für eine Stunde unterdrückt -> siehe oben: "AND NOT bWinter" 
tpWinter1h(IN := bWinter, PT := T#61M);                                
IF NOT tpWinter1h.Q 
THEN
    bWinter := FALSE;
END_IF

bClock := bClock1 OR bClock2;


----------



## PN/DP (27 Juli 2021)

MichiJa schrieb:


> // Die Berechnung des Datums für die Zeitumstellung des aktuellen Jahres ist Abhängig vom Vorjahr -> "GVL.stSystemTime.wYear -1"


Wieso ist das Datum der Zeitumstellung vom Vorjahr abhängig??? Die Umstellungen sind immer am letzten Sonntag im März und am letzten Sonntag im Oktober.

Es ist ungünstig, die Systemuhr zu verstellen. Denn dann muß man sich zusätzlich zuverlässig merken ob schon umgestellt wurde und weitere Umstellungen unterdrücken. Üblicherweise läßt man die Systemuhr einfach immer in Winterzeit (oder noch besser: in UTC) laufen und rechnet dann die Systemzeit in die aktuell richtige Lokalzeit um (je nach Zeitpunkt 0 oder 1 oder 2 Stunden addieren). 
Wenn man die Systemuhr mit einem NTP-Server synchronisieren will, dann muß bzw. wird sogar die Systemuhr immer in UTC laufen. Zusätzliches Verstellen der Systemuhr hat dann keinen Bestand und wird immer wieder rückgängig gemacht.

Harald


----------



## jensemann (27 Juli 2021)

Du holst dir die Minuten aus dem Struct der Systemzeit, warum nicht auch die Stunden? Windows kennt von Kindesbeinen an die Zeitumstellung, da braucht man sich eigentlich nicht drum kümmern.
Deine Minutenpulse kannst du immer schicken.


----------



## Heinileini (27 Juli 2021)

PN/DP schrieb:


> Wieso ist das Datum der Zeitumstellung vom Vorjahr abhängig???


Sie ist vom aktuellen Jahr abhängig (und damit "indirekt" natürlich auch vom Vorjahr).


PN/DP schrieb:


> Die Umstellungen sind immer am letzten Sonntag im März und am letzten Sonntag im Oktober.


Mein Ansatz, müsste ich auf irgendwelche Hilfen vom "SystemFunktionen" verzichten, wäre genau durch den WochenTag Sonntag inspiriert, nämlich einen speziellen, den OsterSonntag. Dafür gibt es Formeln/Lösungswege - habe ich vor Jahrenden schonmal in Excel durchexerziert, habe die Lösung aber jetzt nicht parat *). Auf dem Umwege über OsterSonntag dürfte sich relativ leicht das Datum des letzten Sonntags im März und Oktober ermitteln lassen.
Ich vermute mal, dass die Formeln entweder zur Ermittlung des Wochentages bzw. zur Ermittlung des OsterSonntags vielleicht irgendwo "aktuelle JahresZahl minus eins" enthalten.


jensemann schrieb:


> Deine Minutenpulse kannst du immer schicken.


Das hatten wir eigentlich schon geklärt, dass nur "fast immer" richtig ist. Aber nicht in der Stunde, nach der die Uhr 1 Stunde zurückgestellt werden soll.

PS:
*) Doch, in einem geordneten Haushalt geht nix verloren. Konnte die VBA-Routine tatsächlich wiederfinden:

```
Function Ostern(ByVal Jahr As Integer) As Date
    Dim ZR1, ZR2, ZR3, ZR4, ZR5, ZR6, ZR7 As Integer
    ZR1 = Jahr Mod 19 + 1: ZR2 = Int(Jahr / 100) + 1
    ZR3 = Int(3 * ZR2 / 4) - 12: ZR4 = Int((8 * ZR2 + 5) / 25) - 5
    ZR5 = Int(5 * Jahr / 4) - ZR3 - 10: ZR6 = (11 * ZR1 + 20 + ZR4 - ZR3) Mod 30
    If (ZR6 = 25 And ZR1 > 11) Or ZR6 = 24 Then ZR6 = ZR6 + 1
    ZR7 = 44 - ZR6
    If ZR7 < 21 Then ZR7 = ZR7 + 30
      ZR7 = ZR7 + 7
    ZR7 = ZR7 - (ZR5 + ZR7) Mod 7
    If ZR7 <= 31 Then
      Ostern = DateSerial(Jahr, 3, ZR7)
    Else
      Ostern = DateSerial(Jahr, 4, ZR7 - 31)
    End If
End Function
```


----------



## PN/DP (27 Juli 2021)

Hmm, der Ostersonntag liegt meistens nach dem letzten Sonntag im März, manchmal aber auch davor - und trotzdem kann man vom Ostersonntag ausgehend den letzten Sonntag im März berechnen??? 

Harald


----------



## MichiJa (27 Juli 2021)

PN/DP schrieb:


> Wieso ist das Datum der Zeitumstellung vom Vorjahr abhängig??? Die Umstellungen sind immer am letzten Sonntag im März und am letzten Sonntag im Oktober.


Mit der angewendeten Formel und dem aktuellen Jahr berechne ich mir den Tag (27., 28.,...) für die Zeitumstellung des darauffolgenden Jahres. Demnach nutze ich das Vorjahr um den Tag der Zeitumstellung für das aktuelle Jahr zu berechnen. Deswegen auch Aktuelles Jahr -1. 


PN/DP schrieb:


> Es ist ungünstig, die Systemuhr zu verstellen.


Kann natürlich sein, dass ich gerade gewaltig auf dem Schlauch stehe, aber eigentlich verstelle ich die Systemzeit gar nicht, sondern filtere mir nur daraus das aktuelle Jahr um die Daten für die Zeitumstellungen zu ermitteln. Diese vergleiche ich mit der Systemzeit und reagiere je nach Umstellung entsprechend. 


jensemann schrieb:


> Du holst dir die Minuten aus dem Struct der Systemzeit, warum nicht auch die Stunden? Windows kennt von Kindesbeinen an die Zeitumstellung, da braucht man sich eigentlich nicht drum kümmern.


Da ich nur Minutenimpulse benötige sind für mich die Stunden doch uninteressant, oder sehe ich das falsch?


jensemann schrieb:


> Das hatten wir eigentlich schon geklärt, dass nur "fast immer" richtig ist. Aber nicht in der Stunde, nach der die Uhr 1 Stunde zurückgestellt werden soll.


Genau. 


Vielen lieben Dank für eure Unterstützung.
Gruß
Michi


----------



## Heinileini (27 Juli 2021)

PN/DP schrieb:


> Hmm, der Ostersonntag liegt meistens nach dem letzten Sonntag im März, manchmal aber auch davor - und trotzdem kann man vom Ostersonntag ausgehend den letzten Sonntag im März berechnen???


Ja, sicher. Und solange sowohl der OsterSonntag als auch der letzte Sonntag im März *nach* dem potenziellen Störer (Schaltag, 29. Februar) stattfinden, muss man sich nicht einmal um das Thema SchaltJahr kümmern - das tut schon die Berechnung des OsterSonntags! 

Nachtrag:

```
dws = OsterSo + INT((31_Mrz - OsterSo) / 7) * 7 ' WxlTag (Winter->Sommer)

dsw = OsterSo + INT((31_Okt - OsterSo) / 7) * 7 ' WxlTag (Sommer->Winter)

' Wobei ...
' OsterSo : Datum des OsterSonntags im aktuellen Jahr (s. 'PS' in Beitrag #23)
' 31_Mrz  : Datum des 31. Mrz im aktuellen Jahr
' 31_Okt  : Datum des 31. Okt im aktuellen Jahr

' Gilt auch für das 'PS' in Beitrag #23:
' In SCL und ST dürfte das INT überflüssig sein, da ein INT-Ergebnis einer Division immer nur ab- und nie aufgerundet wird.
' Aber: Vorsicht, der Compiler könnte/dürfte die Division durch 7 mit der anschliessenden Multiplikation mit 7 "zusammenfassen" (= schlabbern)!
' Vorsichtshalber das DivisionsErgebnis einer INT-HilfsVariable zuweisen und mit dieser HilfsVariable weiterrechnen.
```


----------



## jensemann (27 Juli 2021)

Die Minuten ticken doch sowohl in der Stunde vor der Zeitumstellung, als auch danach. Wenn sich der Wert der Stunde alle 60 Minuten ändert, kannst du ihn übernehmen. Zum Zeitpunkt der Zeitumstellung im März ändert sich der Wert der Stunde von 1 auf 3 -> 1:59 ..3:00, und im Oktober schaltet die Uhr von 2:59 auf 2:00, also ändert sich dort der Wert der Stunde nicht. 
Wenn du also immer dann, wenn die Minute auf 00 steht, den Stundenwert übernimmst, hast du nie ein Problem mit der Zeitumstellung und du kannst diesen Wert auch an alle nachgeordneten Clients weitergeben. 
Nochmal: Solange die Systemzeit korrekt ist, brauchst du dir um die Zeitumstellung in TwinCat keine Sorgen machen.


----------



## Heinileini (27 Juli 2021)

jensemann schrieb:


> Nochmal: Solange die Systemzeit korrekt ist, brauchst du dir um die Zeitumstellung in TwinCat keine Sorgen machen.


Die empfangenden Uhren werden aber allein durch den Minuten-Impuls gesteuert/weitergeschaltet. Einen entsprechenden Impuls für den StundenZeiger gibt es nicht - wär' ja auch zu einfach!


----------



## PN/DP (27 Juli 2021)

MichiJa schrieb:


> PN/DP schrieb:
> 
> 
> > Wieso ist das Datum der Zeitumstellung vom Vorjahr abhängig??? Die Umstellungen sind immer am letzten Sonntag im März und am letzten Sonntag im Oktober.
> ...


Ich glaube nicht, daß in der Formel der Ausdruck "Jahr - 1" das Vorjahr meint, sondern einfach für die Verschiebung des Ergebnisses der Division und des (0-basierten) MOD um 1 Tag nötig ist. Genauso, wie wenn man ein 0-basiertes Array [0..30] für jeden Tag eines Monats hat und den Index in das Array aus "Tag - 1" berechnet. Da meint "Tag - 1" auch nicht "Gestern" oder einen Tag des Vormonats.




MichiJa schrieb:


> eigentlich verstelle ich die Systemzeit gar nicht


OK, ich hatte den Code nur oberflächlich überflogen und fälschlicherweise angenommen, daß da die Uhr verstellt wird. Vor allem, weil beim Rückstellen zur Winterzeit etwas extra für 1 Stunde unterdrückt wird, was bei Berechnung aus einer nicht verstellten Uhr eigentlich nicht nötig sein sollte.

Harald


----------



## MichiJa (28 Juli 2021)

Vielen Dank für euer Feedback. Ich werde versuchen den Code anzupassen und zu verbessern. 

Vielleicht ist es dennoch sinnvoll meine Gedankengänge noch einmal kurz aufzuführen:

Minutenimpulse:

Mithilfe des von Beckhoff gestellten Funktionsbausteins FB_LocalSystemTime (Link) hole ich mir die lokale Windows-Systemzeit
Aus dieser filtere ich die Minuten heraus und vergleiche die "aktuellen" Minuten mit den "alten" Minuten. Daraus ergeben sich die benötigten Minutenimpulse für die Uhren
Zeitumstellung: 

Berechnung des Datums der Zeitumstellung für das aktuelle Jahr
Vergleich des berechneten Datums mit der Systemzeit. Salopp gesagt: Damit die Uhren wissen, wann eine Zeitumstellung stattfindet
Je nach Umstellung werden entweder zusätzlich 60 Impulse an die Uhren weitergegeben (W -> S) oder das Weitergeben der Minutenimpulse für eine Stunde unterbunden (S -> W)

Gruß
Michi


----------



## Heinileini (28 Juli 2021)

Habe in meine Beiträge #23 und #26 "aufgebohrt" (s. PS bzw. Nachtrag).


----------



## MichiJa (2 August 2021)

Hallo zusammen,
im Falle eines Stromausfalls sollen die Uhren nachgetaktet werden. Dazu muss man natürlich wissen wie lange ein Stromausfall vorlag. Wie geht man mit diesem Problem am Besten um? 
Ich habe mir dazu folgende Gedanken gemacht: 

Ich speichere die Systemzeit persistent in einer Variable ab
Nach dem Stromausfall und dem Neustart wird diese dann mit der aktuellen Systemzeit verglichen 
Aus der sich ergebenden Differenz werden die fehlenden Impulse berechnet und in eine Variable gespeichert
Diese werden dann über einen Abwärtszähler abgefrühstückt
Geht der Grundgedanke schon in die richtige Richtung oder wird dies in der Regel anders umgesetzt?

Wie kann die konkrete Uhrzeit und das Datum unmittelbar nach dem Neustart aus der Systemzeit entnommen werden? Die Uhr läuft nun mal weiter, wodurch auch die Differenz ständig größer wird. 
Ein weiteres Problem womit ich zu kämpfen habe, ist das Konvertieren vom Format Date and Time zum Word für den Zähler des CTD. Ergibt es eventuell mehr Sinn, das in eine anderes Format zu überführen?  

Vorab vielen Dank.

Gruß
Michi


----------



## Heinileini (2 August 2021)

In dieser Richtung, einen "Zähler" zu verwenden, hatte ich auch schon tendiert - jedenfalls um die Phänomene beim Wechsel von W->S bzw. S->W aufzufangen bzw. zu "puffern". Ein weiteres Phänomen, nämlich ein StromAusfall - so finde ich - lässt sich gut in dieses Konzept integrieren.
Der Aufwand hierfür beschränkt sich eigentlich darauf, zu ermitteln, wie viele Impulse nachzuliefern sind. Die Abarbeitung der Impulse wäre, dann schon erledigt, weil identisch mit dem Vorstellen der Uhr beim Wechsel W->S. 
Das Unterdrücken der Impulse beim Wechsel S->W hatte ich mir so vorgestellt, dass der Zähler im negativen Bereich arbeitet.
D.h., der Zähler wird statt beim "normalen" Minuten-Impuls um 1 erhöht und statt beim Wxl S->W um 61 erhöht zu werden, beim Wxl W->S um 59 vermindert. 
Die Auswertung des Zählers und die (Nicht-)Umsetzung in reale Impulse an die Uhren sieht dann so aus:
- ist der Zählerstand <= 0, so passiert nichts
- ist der Zählerstand > 0, so wird 1 Impuls ausgegeben und der Zähler um 1 dekrementiert.
Für den Fall, dass der Zählerstand > 1 ist, muss natürlich dafür gesorgt werden, dass die ImpulsFolge entspechend einem "speziellen" Takt erfolgt.

Allerdings neige ich dazu, weder CTU noch CTD zu verwenden, sondern eine "stinknormale", aber statische INT-Variable.

D&T? Weiss ich nicht. Stelle mir vor, dass die "Datümer" (letzter Sonntag im Mrz und Okt) nicht in jedem Zyklus berechnet werden, aber natürlich ständig zum Vergleich mit dem aktuellen Datum zur Verfügung stehen müssen. Ferner denke ich, dass die Zeit in einer Form zur Verfügung steht, die ein Vielfaches von s oder ms oder µs oder ns darstellt. 
Du benötigst 
- die Stunde 2 für die Wxl W->S und S->W
- die Minute bei jedem Wxl der Minute
- z.B. einen 0,5 Hz Takt zum Aufholen der "geschlabberten" Minuten-Impulse.
Die Stunden, Minuten und Sekunden lassen sich Leicht per Division und MOD aus z.B. einem Vielfachen von ms isolieren.

So in etwa hatte ich mir das gedacht (noch recht rudimentär, gänzlich ungetestet und ohne StromAusfallBerücksichtigung):

```
// Pulse vorbereiten
tbSecond0 := tiSecond = 0 ;
tbHour2 := tiHour = 2 ;
IF sbSecond0Prev OR NOT tbSecond0 THEN
    ; // wenn nicht positive Flanke der Sekunde: nichts tun
ELSIF sbHour2Prev OR NOT tbHour2 THEN
    PulseCounter := PulseCounter + 1 ;  // 1 min vor, normaler Impuls, wenn nicht Beginn der "magischen" Stunde
ELSIF tdateChgWin2Sum = actualDate THEN
    PulseCounter := PulseCounter + 61 ; // 1 min vor und 1 h vor
ELSIF tdateChgSum2Win = actualDate THEN
    PulseCounter := PulseCounter - 59 ; // 1 min vor und 1 h zurück
ELSE
    PulseCounter := PulseCounter + 1 ;  // 1 min vor, normaler Impuls, wenn Beginn der "magische" Stunde, aber kein Wxl-Datum
END_IF ;
sbSecond0Prev := tbSecond0 ; // für FlankenErkennung
sbHour2Prev := tbHour2 ; // für FlankenErkennung

// Pulse ausgeben bzw. unterdrücken
tbClock := ( tiSecond MOD 2 ) = 0 ; // für z.B. tbClock 0,5 Hz

output_pulse := output_pulse AND tbClock ; // Rücksetzen des Ausgabe-Impulses
IF sbClockPrev OR NOT tbClock THEN
    ; // wenn nicht positive Flanke des AusgabeTaktes: nichts tun
ELSIF PulseCounter <= 0 THEN
    ; // wenn ZählerStand <= 0: nichts tun
ELSE                                             
    output_pulse = TRUE ; // wenn Zählerstand > 0: Impuls setzen und Zähler dekrementieren
    PulseCounter := PulseCounter - 1 ;
ENDIF ;
sbClockPrev := tbClock ; // für FlankenErkennung
```


----------



## MichiJa (3 August 2021)

Vielen Dank für die ausführliche Erläuterung!


Heinileini schrieb:


> Der Aufwand hierfür beschränkt sich eigentlich darauf, zu ermitteln, wie viele Impulse nachzuliefern sind.


Aber genau hier liegt auch mein Problem. Wie kann man die exakte Uhrzeit unmittelbar nach dem Einschalten festhalten, um die zeitliche Differenz zu ermitteln? Im Grunde muss ich ja wissen wann die Steuerung ausgefallen ist und wann sie wieder gestartet wurde.


----------



## PN/DP (3 August 2021)

Könnte man nicht ab Mitternacht mitzählen, wieviele Minutenimpulse tatsächlich ausgegeben wurden, und mit der aktuellen Uhrzeit vergleichen, wieviele es hätten sein müssen?
Haben Deine Nebenuhren irgendeine Rückmeldung, wo ein oder beide Zeiger stehen?

Harald


----------



## Heinileini (3 August 2021)

MichiJa schrieb:


> Wie kann man die exakte Uhrzeit unmittelbar nach dem Einschalten festhalten, um die zeitliche Differenz zu ermitteln?


Du benötigst nicht die "die genaue Uhrzeit unmittelbar nach dem Einschalten", sondern die aktuelle Uhrzeit, zu der Du beginnst, die ImpulsAusgabe wieder aufzunehmen. Und natürlich auch bzw. insbesondere, die aktuelle Uhrzeit und den Zählerstand zu dem Zeitpunkt, zu dem Du den letzten Impuls ausgegeben bzw. unterdrückt hast. Die aktuelle Uhrzeit kannst Du in "aller Ruhe" - wie gewohnt - einlesen.

Tja, das bedeutet eigentlich, dass man jeden Impuls nicht mehr stur aus irgendwelchen Wechseln/Flanken von irgendwelchen Teilen der Uhrzeit ableitet, sondern grundsätzlich jedesmal davon ausgeht, dass die Zeitspanne seit der letzten Ausgabe eines Impulses unbekannt ist und berechnet werden muss. Werde noch ein Bisschen darüber nachdenken. Immerhin könnte ja während des Stromausfalls ein Wechsel von Winter-/Sommerzeit stattgefunden haben und man muss sich deshalb nicht nur die Uhrzeit, sondern auch das Datum des zuletzt ausgegebenen Impulses merken.

Wichtig ist, dass Du die Uhrzeit (und das Datum), die Du Dir bei der Ausgabe des (jeweils) letzten Impulses gemerkt hast, nicht mit "Schrott" überspeicherst, wenn die PLC neu hochfährt.

Die Unsicherheit, die bleibt, ist, ob alle Uhren geschaltet haben, wenn der StromAusfall einsetzte, während Du einen Impuls ausgegeben hast.
Also, war der Impuls, der bei den Uhren angekommen ist, lang genug, um auch bei allen wirksam zu werden. Dagegen weiss ich kein Rezept, wenn es keine Rückmeldungen der Uhren gibt.


----------



## MichiJa (3 August 2021)

PN/DP schrieb:


> Haben Deine Nebenuhren irgendeine Rückmeldung, wo ein oder beide Zeiger stehen?


Nein, die Uhren geben leider keine Rückmeldung. 



Heinileini schrieb:


> Immerhin könnte ja während des Stromausfalls ein Wechsel von Winter-/Sommerzeit stattgefunden haben und man muss sich deshalb nicht nur die Uhrzeit, sondern auch das Datum des zuletzt ausgegebenen Impulses merken.


Unabhängig vom Wechsel der Sommer-/Winterzeit muss das Datum sowieso einbezogen werden, falls sich der Stromausfall über mehrere Tage erstrecken sollte, oder nicht? Das war zumindest mein Gedanke und der Grund dafür warum ich vom Datentyp Date and Time gesprochen habe.

Gruß
Michi


----------



## Heinileini (3 August 2021)

MichiJa schrieb:


> Unabhängig vom Wechsel der Sommer-/Winterzeit muss das Datum sowieso einbezogen werden, falls sich der Stromausfall über mehrere Tage erstrecken sollte, oder nicht? Das war zumindest mein Gedanke und der Grund dafür warum ich vom Datentyp Date and Time gesprochen habe.


Hmmm, jain. Du musst doch "normalerweise" (wenn kein Wechsel zwischen Sommer- und Winterzeit während des StromAusfalls stattfindet) "nur" den MinutenZeiger und "indirekt" auch den StundenZeiger synchronisieren. Oder haben Deine Uhren auch eine DatumsAnzeige, die über den Minuten-Impuls gesteuert wird?
Uhrzeit *und Datum* sind zu berücksichtigen *wegen* der Umstellungen zwischen Sommer- und Winterzeit.
Um die beiden Zeiger (Stunde und Minute) zu synchronisieren, kann Dir egal sein, wie viele (halbe!?) Tage zwischen Beginn und Ende des StromAusfalls vergangen sind.
Du musst nur die Differenz zwischen Soll und Ist der Zeiger ausgleichen und die ist maximal 12 Stunden.
Frage am Rande: die StundenZeiger machen doch pro 24 Stunden 2 Umdrehungen?

Ich würde "intern" doch lieber mit 1 Variablen für das Datum und einer weiteren Variablen für die Zeit arbeiten wollen.
Datum: Anzahl der Tage seit einem bestimmten "Basis"-Datum.
Zeit: Anzahl der Sekunden (oder ms oder µs oder ...) seit 00:00.000..... Uhr.
Damit Datum und Zeit konsistent sind (zueinander passen), würde ich auch aktuelles Datum und aktuelle Zeit in der "gemeinsamen" Form DAT einlesen, diese dann in die 2 genannten Teile aufspalten, einfach, weil ich's übersichtlicher finde.


----------



## MichiJa (3 August 2021)

Heinileini schrieb:


> Hmmm, jain. Du musst doch "normalerweise" (wenn kein Wechsel zwischen Sommer- und Winterzeit während des StromAusfalls stattfindet) "nur" den MinutenZeiger und "indirekt" auch den StundenZeiger synchronisieren. Oder haben Deine Uhren auch eine DatumsAnzeige, die über den Minuten-Impuls gesteuert wird?
> Uhrzeit *und Datum* sind zu berücksichtigen *wegen* der Umstellungen zwischen Sommer- und Winterzeit.
> Um die beiden Zeiger (Stunde und Minute) zu synchronisieren, kann Dir egal sein, wie viele (halbe!?) Tage zwischen Beginn und Ende des StromAusfalls vergangen sind.


Ja guck, da hatte ich wohl einen Denkfehler🤔. Nein nein, die Uhren haben keine Datumsanzeige.


PN/DP schrieb:


> Könnte man nicht ab Mitternacht mitzählen, wieviele Minutenimpulse tatsächlich ausgegeben wurden, und mit der aktuellen Uhrzeit vergleichen, wieviele es hätten sein müssen?


Jetzt leuchtet mir auch der Ansatz von PN/DP ein.


Heinileini schrieb:


> Du musst nur die Differenz zwischen Soll und Ist der Zeiger ausgleichen und die ist maximal 12 Stunden.
> Frage am Rande: die StundenZeiger machen doch pro 24 Stunden 2 Umdrehungen?


Zur Frage: Genau, 2 Umdrehungen pro 24 Stunden.


----------



## Heinileini (3 August 2021)

PN/DP schrieb:


> Könnte man nicht ab Mitternacht mitzählen, wieviele Minutenimpulse tatsächlich ausgegeben wurden, und mit der aktuellen Uhrzeit vergleichen, wieviele es hätten sein müssen?


Ja. Und zwar separat für jede einzelne, angeschlossene Uhr.
Warum so kompliziert? Ich gehe mal davon aus, dass die Synchronität einzelner Uhren verloren gehen kann (z.B. durch einen Defekt) oder von vornherein (noch) nicht gegeben ist. Also für jede Uhr ein eigenes Eingabefeld vorsehen, in dem die tatsächliche, aktuelle Anzeige der jeweiligen Uhr eingegeben werden kann, um jegliche Manipulationen an den Uhren vor Ort zu vermeiden.
Praktisch dürfte es sinnvoll sein, in der Zeitspanne vom Ablesen der ersten Uhr bis zur Eingabe des letzten AnzeigeWertes, die ImpulsAusgabe zumindest für die zu stellenden Uhren, anzuhalten.
Die internen Zähler der Uhren würde ich tatsächlich bei 12 h "überlaufen" lassen, also - wenn man so will - die Minuten-Impulse ab Mitternacht bzw. ab Mittag zählen lassen.
Um die "magische" Stunde (2 Uhr an den Tagen der Wechsel zwischen Sommer- und Winterzeit) richtig zu dekodieren ist ein 24-h-Turnus nur bei der "Master-Uhr" (bei der eingelesenen Zeit) erforderlich, nicht bei den angeschlossenen ZeigerUhren.


----------



## MichiJa (4 August 2021)

Heinileini schrieb:


> Die internen Zähler der Uhren würde ich tatsächlich bei 12 h "überlaufen" lassen, also - wenn man so will - die Minuten-Impulse ab Mitternacht bzw. ab Mittag zählen lassen.


Die Anzahl der Impulse ab Mitternacht, die persistent gespeichert werden, lassen sich relativ leicht ermitteln. 
Aber wie kann ich die Anzahl der Impulse aus der aktuellen Zeit ermitteln, um im Anschluss die Differenz bilden zu können? 

Gruß
Michi


----------



## Windoze (4 August 2021)

"Aktuelle Stunde * 60 + Aktuelle Minute" oder?


----------



## MichiJa (4 August 2021)

Windoze schrieb:


> "Aktuelle Stunde * 60 + Aktuelle Minute" oder?


Jap, bin gerade auch auf den Trichter gekommen. Habe mir die Stunden und Minuten aus dem TIMESTRUCT der Systemzeit geholt.


----------



## Heinileini (5 August 2021)

MichiJa schrieb:


> Jap, bin gerade auch auf den Trichter gekommen. Habe mir die Stunden und Minuten aus dem TIMESTRUCT der Systemzeit geholt.


Dein TIMESTRUCT gibt welche Zeit wieder? Die aktuelle OrtsZeit ohne Berücksichtigung einer Sommerzeit, also quasi eine ganzjährige Winterzeit?


----------



## MichiJa (5 August 2021)

Heinileini schrieb:


> Dein TIMESTRUCT gibt welche Zeit wieder? Die aktuelle OrtsZeit ohne Berücksichtigung einer Sommerzeit, also quasi eine ganzjährige Winterzeit?


Der Funktionsbaustein den ich dafür verwende berücksichtigt die Sommer-und Winterzeit -> FB_LocalSystemTime


----------



## Heinileini (5 August 2021)

MichiJa schrieb:


> Der Funktionsbaustein den ich dafür verwende berücksichtigt die Sommer-und Winterzeit


Hmmm, dann hätten wir uns den Umweg über Winter-/Sommer-Zeit-Umschaltung eigentlich schenken können/müssen.
Wenn ich die Beschreibung richtig deute, kann ein "Jitter", also ein Schwanken um den tatsächlichen Wert herum, auftreten.
Um wie viel kann die gelieferte Zeit normalerweise nachgehen bzw. vorgehen?
Wahrscheinlich sollten wir die Weitergabe von Minuten-Impulsen ein wenig "abkoppeln". Immerhin können wir die Uhren nicht rückwärts laufen lassen, sondern müssen uns mit u.U. sehr vielen "EhrenRunden" behelfen, die aber nicht unnötig durch kleine, kurzzeitige Abweichungen angeleiert werden sollten.


----------



## MichiJa (6 August 2021)

Heinileini schrieb:


> Hmmm, dann hätten wir uns den Umweg über Winter-/Sommer-Zeit-Umschaltung eigentlich schenken können/müssen.


Die Impulse müssen doch trotzdem gesetzt werden, oder nicht? Ich vergleiche lediglich mein errechnetes mit dem aktuellen Datum und gebe dann die Impulse/ keine Impulse an die Uhren weiter. 


Heinileini schrieb:


> Um wie viel kann die gelieferte Zeit normalerweise nachgehen bzw. vorgehen?


Diese Frage kann ich dir jetzt nicht beantworten.


----------



## Heinileini (8 August 2021)

Moin MichiJa,

habe nochmal "gebastelt". Aber - wie immer - nicht getestet:


```
//-> TYPE Uhr :
//->     STRUCT
//->         iAnzg         : INT  ; // für aUhr[iIdx].iAnzg
//->         iDiff         : INT  ; // für aUhr[iIdx].iDiff
//->         bPuls         : BOOL ; // für aUhr[iIdx].bPuls
//->     END_STRUCT
//-> END_TYPE

VAR_OUTPUT
    obUhr01Step  : BOOL ;
    obUhr02Step  : BOOL ;
//  u.s.w. ...
    obUhr19Step  : BOOL ;
    obUhr20Step  : BOOL ;
END_VAR

VAR
    aiAnzg           : ARRAY[1..20] OF INT  ; // "Ersatz" für aUhr[iIdx].iAnzg [min]
    aiDiff           : ARRAY[1..20] OF INT  ; // "Ersatz" für aUhr[iIdx].iDiff -60..659 [min]
    abPuls           : ARRAY[1..20] OF BOOL ; // "Ersatz" für aUhr[iIdx].bPuls
//->     aUhr             : ARRAY[0..20] OF Uhr ; // ersetzt aiAnzg[] und aiDiff[] und abPuls[]

    tbAusgTakt       : BOOL ; // 0,5 Hz-Takt für Ansteuerung der Uhren

    dtSollAnzgSec    : DT   ; // HilfsVariable für den eingelesenen Datums+Zeit-Wert [s]

    iAnfMin          : INT  := -60 ; // "Konstante" max. 60 Minuten-Impulse unterdrücken
    iIdxMaxUhr       : INT  :=  20 ; // "Konstante" Index letzte Uhr
    iIdxMinUhr       : INT  :=   1 ; // "Konstante" Index erste Uhr
    iSollAnzg        : INT  ; // aus DATE_AND_TIME extrahierte Zeit "00:00" .. "11:59" [min]
    iIdx             : INT  ; // LaufVariable (Array-Index)

    sbAusgTaktZuvo   : BOOL ; // static, für FlankenErkennung AusgabeTakt
    siSollAnzgZuvo   : INT  ; // static, für FlankenErkennung Zeit (hh:mm)
END_VAR

dtSollAnzgSec := ??? ; // <===<<< eingelesene Zeit mit Datum [s] (DT, DATE and TIME)

iIdxMinUhr :=   1 ; // Index für erste Uhr
iIdxMaxUhr :=  20 ; // Index für letzte Uhr

iAnfMin    := -60 ; // AnfangsWert für iDiff z.B. -60..659, d.h. max 60 min warten statt Ehrenrunden ausgeben

iSollAnzg  := DT_TO_INT ( ( dtSollAnzgSec / 60 ) MOD 720 ) ; // [min] begrenzt auf "00:00" .. "11:59"

// - - - < im MinutenTakt Abweichungen ermitteln und weitergeben > - - -
IF NOT siSollAnzgZuvo AND iSollAnzg THEN
    FOR iIdx := iIdxMinUhr TO iIdxMaxUhr DO
        IF NOT bPuls[iIdx] THEN // Anzahl Minuten-Impulse -60..659
//->         IF NOT aUhr[iIdx].bPuls THEN // Anzahl Minuten-Impulse -60..659                   // ersetzt vorherige Zeile
            iDiff[iIdx] := ( iSollAnzg - iAnzg[iIdx] - iAnfMin ) MOD 720 + iAnfMin ;
//->             aUhr[iIdx].iDiff := ( iSollAnzg - iAnzg[iIdx] - iAnfMin ) MOD 720 + iAnfMin ; // ersetzt vorherige Zeile
        END_IF ;
    END_FOR ;
END_IF ;
siSollAnzgZuvo := iSollAnzg ; // FlankenVariable aktualisieren

// - - - < im BlinkTakt (0,5 Hz) Pulse ausgeben > - - -
tbAusgTakt := ( dtSollAnzgSec MOD 2 ) = 0 ;
IF NOT sbAusgTaktZuvo XOR tbAusgTakt THEN // keine AusgTaktFlanke
    ; // nix
ELSIF tbAusgTakt THEN // pos. AusgTaktFlanke
    FOR iIdx := iIdxMinUhr TO iIdxMaxUhr DO
        IF iDiff[iIdx] > 0 THEN
//->         IF aUhr[iIdx].iDiff > 0 THEN                       // ersetzt vorherige Zeile
            bPuls[iIdx] := TRUE ; // Puls starten
//->             aUhr[iIdx].bPuls := TRUE ; // Puls starten     // ersetzt vorherige Zeile
        END_IF ;
    END_FOR ;
    sbAusgTaktZuvo := tbAusgTakt ; // Flanken-"Merker" aktualisieren
ELSE // neg. AusgTaktFlanke
    FOR iIdx := iIdxMinUhr TO iIdxMaxUhr DO
        IF bPuls[iIdx] THEN // wenn PulsAusgabe für diese Uhr aktiv ist, dann ...
//->         IF aUhr[iIdx].bPuls THEN // wenn PulsAusgabe für diese Uhr aktiv ist, dann ...          // ersetzt vorherige Zeile
            iDiff[iIdx] := iDiff[iIdx] - 1 ; // Soll-Impulse dekrementieren
//->             aUhr[iIdx].iDiff := aUhr[iIdx].iDiff - 1 ; // Soll-Impulse dekrementieren           // ersetzt vorherige Zeile
            iAnzg[iIdx] := ( iAnzg[iIdx] + 1 ) MOD 720 ; // AnzeigeWert aktualisieren
//->             aUhr[iIdx].iAnzg := ( aUhr[iIdx].iAnzg + 1 ) MOD 720 ; // AnzeigeWert aktualisieren // ersetzt vorherige Zeile
            bPuls[iIdx] := FALSE ; // und Puls beenden
//->             aUhr[iIdx].bPuls := FALSE ; // und Puls beenden                                     // ersetzt vorherige Zeile
        END_IF ;
    END_FOR ;
    sbAusgTaktZuvo := tbAusgTakt ; // Flanken-"Merker" aktualisieren
END_IF ;

// - - - < Ausgabe der Minuten-Impulse an die Peripherie > - - -
obUhr01Step := bPuls[1] ;
//-> obUhr01Step := aUhr[1].bPuls ;  // ersetzt vorherige Zeile
obUhr02Step := bPuls[2] ;
//-> obUhr02Step := aUhr[2].bPuls ;  // ersetzt vorherige Zeile
//
// u.s.w. ...
//
obUhr19Step := bPuls[19] ;
//-> obUhr19Step := aUhr[19].bPuls ; // ersetzt vorherige Zeile
obUhr20Step := bPuls[20] ;
//-> obUhr20Step := aUhr[20].bPuls ; // ersetzt vorherige Zeile
```

Habe für die n Uhren ein Array of Struct bzw. wahlweise drei Arrays (2x INT und 1x BOOL) angedacht mit den "Zeilen" 1..n (konkret 1..20) eingeführt, damit jede angeschlossene Uhr "individuell" angesteuert werden kann.
Die Zeilen, die für die Version "Array of Struct" gemeint sind, sind allesamt "auskommentiert" und beginnen mit "//->".
Werden diese aktiviert, dann muss normalerweise die Zeile direkt davor entfallen bzw. auskommentiert werden.
Ausnahmen:
Bei der TypDefinition (ganz am Anfang) entfällt nichts.
Bei der Deklaration der "normalen" Arrays entfallen alle drei, wenn die Deklaration von aUhr[] aktiviert wird.

Häwenaissuiikend! Gruss, Heinileini

PS:
Wie steht es eigentlich mit ...


MichiJa schrieb:


> Mein Problem ist nun die Programmierung der Sirenen.


Ist das noch akut/aktuell?


----------



## MichiJa (9 August 2021)

Vielen Dank Heinileini und auch vielen Dank an alle anderen die geholfen haben. Ein super Forum mit einer sehr hilfsbereiten Community - Top! 


Heinileini schrieb:


> Ist das noch akut/aktuell?


Nein, das Thema ist nicht mehr akut. 

Gruß
Michi


----------

