Hallo;
ich hab mich mal dran gesetzt und eine Wochenschaltuhr aufbauend auf meiner einfachen Schaltuhr geschrieben.
Die Schaltuhr hat 5x Einschaltzeiten im Format Byte Stunde, Byte Minute + Byte Wochentage
und 5x Ausschaltzeiten im Format Byte Stunde, Byte Minute + Byte Wochentage
FUNCTION_BLOCK HW51
(*
##############################################################
Programmbeschreibung:
Wochenschaltuhr 5 Schaltzeiten, Einkanalig mit kleinster
Schaltzeit 1min
für jede Zeit wird auch eine Tageaktiv Zuordnung per Byte gemacht
Mo=Bit0, Di=Bit1, ... ist das Bit aktiv wird die Schaltzeit an diesem Tag verwendet
Umschaltbarer Modus von ON-OFF Zeit auf Impulsausgang(1 Zykl)
Bei Impulsbetrieb werden nur Einschaltzeiten ausgewertet
Lib: standart, Struct HW51
getestet: Test läuft auf XV100 v3.5.12
##############################################################
Änderungsindex
Name:TL Version:0.1 Datum: 06.09.2023 Grund: neu
##############################################################
*)
VAR_INPUT
Uhrzeit: TOD; (*aktuelle Uhrzeit*)
Wochentag: BYTE; (*aktueller Wochentag, Mo=1 Di=2 ... So=7*)
Zeiten: strHW51; (*Struktur mit Schaltzeiten*)
Mode: BOOL:=0; (*0=on/off, 1=Impulsausgang*)
Hand: BOOL; //Taste Ausgang per Hand umschalten
END_VAR
VAR_OUTPUT
Q1: BOOL;
END_VAR
VAR
Uhrzeit_s: DWORD; (*akt Uhrzeit in Sekunden*)
Uhrzeit_s_alt: DWORD; (*letzte Sekunde*)
Zeit_on: ARRAY [1..5] OF DWORD; //Einschaltzeiten
Zeit_off: ARRAY [1..5] OF DWORD; //Ausschaltzeiten
TagAktivOn: ARRAY [1..5] OF BYTE;
TagAktivOff: ARRAY [1..5] OF BYTE;
Impuls: R_TRIG; (*Flanke*)
Handflanke: R_TRIG; (*Flanke Handbedienung*)
Einschalten: R_TRIG; (*Einschaltflanke*)
Ausschalten: R_TRIG; (*Ausschaltflanke *)
i: INT := 1; (* Laufvariable*)
iTag: INT := 1; (* Laufvariable Wochentag*)
ein: BOOL;(*Hilfsmerker*)
aus: BOOL;(*Hilfsmerker*)
Sekundentrigger: BOOL; //Sekundenflanke
i_sec: INT; (* Laufvariable*)
END_VAR
##############################################
(*Uhrzeit in Sekunden wandeln*)
Uhrzeit_s:= TOD_TO_DWORD(Uhrzeit) / 1000;
IF Uhrzeit_s <> Uhrzeit_s_alt THEN
Sekundentrigger:= true;
Uhrzeit_s_alt:= Uhrzeit_s;
ELSE Sekundentrigger:= false;
END_IF
Handflanke(CLK:= Hand, Q=> );
(*Schaltzeiten begrenzen und in Sekunden ausgeben, nur 1x/min aktualisieren*)
IF Sekundentrigger and (i_sec = 0) THEN //aktualisierung der Sollwerte bei 0sec Flanke
FOR i := 1 TO 5 DO
Zeit_on[i]:=(BYTE_TO_DWORD (LIMIT (0, Zeiten.h_ein[i], 23) )*3600) + (BYTE_TO_DWORD (LIMIT (0, Zeiten.m_ein[i], 59) )*60);
Zeit_off[i]:=(BYTE_TO_DWORD (LIMIT (0, Zeiten.h_aus[i], 23) )*3600) + (BYTE_TO_DWORD (LIMIT (0, Zeiten.m_aus[i], 59) )*60);
TagAktivOn[i]:= Zeiten.Tag_ein[i];
TagAktivOff[i]:= Zeiten.Tag_aus[i];
END_FOR
END_IF
IF Sekundentrigger THEN
i_sec:= i_sec + 1;
IF i_sec >= 60 THEN
i_sec:= 0;
END_IF
END_IF
(*Hilfsmerker Nullsetzen*)
ein:= FALSE;
aus:= FALSE;
IF Mode THEN (*Modus: Schaltimpuls ausgeben*)
IF Sekundentrigger THEN
FOR i := 1 TO 5 DO
IF (Uhrzeit_s = Zeit_on[i]) THEN //ist Schaltzeit erreicht?
CASE Wochentag OF //Wenn ja, ist der Tag auch aktiv?
1: IF TagAktivOn[i].0 THEN ein:= TRUE; END_IF
2: IF TagAktivOn[i].1 THEN ein:= TRUE; END_IF
3: IF TagAktivOn[i].2 THEN ein:= TRUE; END_IF
4: IF TagAktivOn[i].3 THEN ein:= TRUE; END_IF
5: IF TagAktivOn[i].4 THEN ein:= TRUE; END_IF
6: IF TagAktivOn[i].5 THEN ein:= TRUE; END_IF
ELSE ;
END_CASE
EXIT;
END_IF
END_FOR
END_IF
Impuls(CLK:= ein OR Hand, Q=> Q1 ); //Schaltimpuls ausgeben
ELSE (* Modus: EIN-AUS Schalten*)
IF Sekundentrigger THEN
FOR i := 1 TO 5 DO (*Einschaltzeiten mit Uhrzeit vergleichen*)
IF (Uhrzeit_s = Zeit_on[i]) THEN //ist Schaltzeit erreicht?
CASE Wochentag OF //Wenn ja, ist der Tag auch aktiv?
1: IF TagAktivOn[i].0 THEN ein:= TRUE; END_IF
2: IF TagAktivOn[i].1 THEN ein:= TRUE; END_IF
3: IF TagAktivOn[i].2 THEN ein:= TRUE; END_IF
4: IF TagAktivOn[i].3 THEN ein:= TRUE; END_IF
5: IF TagAktivOn[i].4 THEN ein:= TRUE; END_IF
6: IF TagAktivOn[i].5 THEN ein:= TRUE; END_IF
ELSE ;
END_CASE
EXIT;
END_IF
END_FOR
FOR i := 1 TO 5 DO (*Ausschaltzeiten mit Uhrzeit vergleichen*)
IF (Uhrzeit_s = Zeit_off[i]) THEN //ist Schaltzeit erreicht?
CASE Wochentag OF //Wenn ja, ist der Tag auch aktiv?
1: IF TagAktivOff[i].0 THEN aus:= TRUE; END_IF
2: IF TagAktivOff[i].1 THEN aus:= TRUE; END_IF
3: IF TagAktivOff[i].2 THEN aus:= TRUE; END_IF
4: IF TagAktivOff[i].3 THEN aus:= TRUE; END_IF
5: IF TagAktivOff[i].4 THEN aus:= TRUE; END_IF
6: IF TagAktivOff[i].5 THEN aus:= TRUE; END_IF
ELSE ;
END_CASE
EXIT;
END_IF
END_FOR
END_IF
Einschalten(CLK:= ein, Q=> ); //Einschaltflanke erzeugen
Ausschalten(CLK:= aus, Q=> ); //Ausschaltflanke erzeugen
// Ein-Aus_schalten
IF (Ausschalten.Q OR Handflanke.Q) AND Q1 THEN
Q1:= FALSE;
ELSIF (Einschalten.Q OR Handflanke.Q) AND NOT Q1 THEN
Q1:= TRUE;
END_IF
END_IF
Der Baustein wird zusammen mit einer Struktur zur Speicherung der Schaltzeiten eingesetzt. Diesen Datenspeicher kann man in der GVL remanent deklarieren.
zB
VAR_GLOBAL RETAIN
DB_WUhr1: strHW51; //Schaltzeiten für Wochenschaltuhr HW51
END_VAR
TYPE strHW51 :
//Struktur mit Schaltzeiten für Wochenschaltuhr
STRUCT
h_ein: ARRAY[1..5] OF BYTE; (*Einschaltzeiten Stunden*)
m_ein: ARRAY[1..5] OF BYTE; (*Einschaltzeiten Minuten*)
Tag_ein: ARRAY[1..5] OF BYTE; (*Tag aktiv; Mo=Bit0, Di= Bit1...*)
h_aus: ARRAY[1..5] OF BYTE; (*Ausschaltzeiten Stunden*)
m_aus: ARRAY[1..5] OF BYTE; (*Ausschaltzeiten Minuten*)
Tag_aus: ARRAY[1..5] OF BYTE; (*Tag aktiv; Mo=Bit0, Di= Bit1...*)
END_STRUCT
END_TYPE
Have a lot of Fun!