TIA S7 1200 SCL Array of TON

mathiak

Level-1
Beiträge
16
Reaktionspunkte
1
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,

Ich möchte in meinem SPS-Programm Timer in einer Schleife abarbeiten, jedoch funktioniert keiner der Folgenden Aufrufe
Code:
// TimeArr ist ein Array of TON_TIME

#TimeArr[#_I](IN := ..., PT := ...);
#TimeArr[#_I].TON(IN = ..., PT := ...);

Ist das Vorhaben in SCL überhaupt möglich? Ich würde gerne vermeiden alle Timer per Hand einzutragen.

Gruß
Mathias
 
Das Vorhaben ist nicht möglich, da diese Timer auch nur FBs sind.
Und mit FB's kann man bei Siemens generell bis dato weder als Einzel- noch als Multiinstanz Arrays erstellen.
 
Hallo,
du könntest dir die TON-Funktion in deinem Script "nach-programmieren". Dann würde das mit dem Array (mit etwas mehr Aufwand) wieder realisierbar sein ...

Gruß
Larry
 
Hallo Larry,

das klingt gut und würde sicher einiges erleichtern. Bisher habe ich noch nie einen TON selber programmiert. Wie würde sowas aussehen von der Struktur her? Auch bezüglich des Arrays, bleibt der Typ TON_TIME?

Gruß
Mathias
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ja ... so ähnlich ...
Ich würde es so machen :
Eine Variable erschaffen, die die aktuelle Systemzeit (TimeOfDay) beinhaltet.
Ein Array_of_Struct erschaffen in dem du einen Flanken-Bool für die Auslösung deines Timers hast, ein Status-Bool des Timers, die Zeit-Vorgabe als Time für den Timer und die gespeicherte Start-Uhrzeit für den Timer.
Nun kannst du bei "Start_Timer and not FM_Timer" die aktuelle Uhrzeit als Startzeit abspeichern, durch Vergleich "akt_Zeit > gespeicherte + Zeit_Vorgabe" kannst du dann den Status (= Abgelaufen) bilden - und zwar für jedes Array-Element.

ich hoffe, ich habe jetzt nichts vergessen ... 8)

Gruß
Larry
 
Nachtrag (doch etwas vergessen) :
Du mußt den 0:00 Uhr-Überlauf mit berücksichtigen. Also wenn du den Timer z.B. 23:59:55 Uhr startest mit einer Vorgabe von 10 s (z.B.) dann wird es schwierig das Ziel zu erreichen es sei denn du rechnest das mit ein ...
wenn akt_Zeit < Start_Zeit dann Start_Zeit = Start_Zeit - 86400000 (Anzahl der Millisekunden am Tag)

Gruß
Larry
 
Super jetzt hab ichs vertsanden! Bei TOD gefällt mir nur der Tageswechsel nicht, was hälst du davon RD_LOC_T zu nehmen und zu vergleichen?

Gruß
Mathias

// Edit: Zu spät gelesen ;)
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ich stelle mal meine jetzige Lösung hier ein:

Der TON FC-Kopf:
Code:
Input        
  IN    Bool    
  PT    UDInt    
Output        
        
InOut        
  Time    "UDT_TON"    
Temp        
  _CurrentTime    Time_Of_Day    
Return        
  TON    Void
Datentyp UDT_TON:
Code:
ST    UDInt
PT    UDInt
ET    UDInt
RU    Bool
Q     Bool
Der TON FC:
Code:
If #IN Then
  // Get the current TOD
  #_CurrentTime := "MemoryDB".System.TimeOfDay;
  If #Time.RU = False Then
    // Set PT and ST on first start
    #Time.PT := #PT;
    #Time.ST := #_CurrentTime;
    #Time.RU := True;
  Else
    // If ET < PT, then calculate new ET
    If #Time.ET < #Time.PT Then
      // On change of day, CurrentTime is smaller then ST
      If TOD_TO_UDINT(#_CurrentTime) < #Time.ST Then
        #Time.ET := 86400000 + TOD_TO_UDINT(#_CurrentTime) - #Time.ST;
      Else
        #Time.ET := TOD_TO_UDINT(#_CurrentTime) - #Time.ST;
      End_If;
    Else  // If ET >= PT
      #Time.ET := #Time.PT;
      #Time.Q := True;
    End_If;
  End_If;
Else  // #IN = False
  // Reset Timer
  #Time.ET := 0;
  #Time.RU := False;
  #Time.Q := False;
End_If;

Und TimeOfDay wird so generiert:
Code:
....
// Read Local Time
#_I := RD_LOC_T(OUT => "MemoryDB".System.LocalTime);
"MemoryDB".System.TimeOfDay := UDINT_TO_TOD((USINT_TO_UDINT("MemoryDB".System.LocalTime.HOUR) * 3600 +
                                             USINT_TO_UDINT("MemoryDB".System.LocalTime.MINUTE) * 60 +
                                             USINT_TO_UDINT("MemoryDB".System.LocalTime.SECOND)) * 1000 +
                                             ("MemoryDB".System.LocalTime.NANOSECOND / 1000000));
....

Gruß
Mathias
 
Ich habe es mir jetzt nicht im Detail angesehen.
Eins habe ich jedoch noch :
Kannst du dir ein Array_of_FC erstellen ? Wo "merkst" du dir die einzelnen Zustände ? Eigentlich bräuchtest du einen FB, der das Array der benötigten Struktur beinhaltet, in dem du das Alles entsprechend des Array-Index machst.

Gruß
Larry
 
Ich habe ein Array[0..63] of UDT_TON in einem DB gespeichert und im Programm rufe ich die jeweiligen Timer mit
Code:
"TON"(IN := ..., PT := 10000, "Time" := "MemoryDB".ArrayTON[#_I]);
auf.

Gruß
Mathias
 
Ich weiß nicht, ob das Weisheit ist oder Ego / Philosophie ...
Wie schon geschrieben : ich hätte mir einen FB erstellt, der die zugehörigen Daten in seiner Instanz gleich mit verwaltet. Der Vorteil hierbei ist, dass du alles Zusammengehörige auch gleich zusammen hast.

Gruß
Larry
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@mathiak

Darf man fragen, was der ganze hochkompliziert aussehende Aufwand bringen soll, außer das Programm aufzublähen, die Programmfunktion zu verschleiern und das Ego des Programmierers zu stärken?
Ist das jetzt nur um sich die einmalige Arbeit der Deklaration jedes einzelnen Timers zu sparen? Und lästige Symbolik und Kommentare zu jedem Timer gleich mit unmöglich zu machen?

Ich meine, Du wirst wohl tatsächlich keinerlei Programmieraufwand sparen, die IN der Timer müssen ja für jeden Timer separat versorgt werden. Ob Du nun undurchsichtig die Timerbedingungen in ein BOOL-Array oder gar direkt in die Timer-"Instanz" schreibst oder doch besser den übersichtlichen Standard-Timeraufruf ausprogrammierst kommt auf den gleichen Aufwand raus. Ganz abgesehen von der Problematik, daß Du die Timer nicht mehr im selben Programmzyklus starten/stoppen und auswerten kannst.

Überzeuge mich mit einem Beispiel, daß Dein Vorhaben sinnvoll und vorteilhafter als die Standard-Programmierung ist.

Harald
 
Hallo,

natürlich darf man Fragen, aber man muss ja nicht gleich persönlich werden. Ich programmiere weder für mein Ego noch um Programme künstlich aufzublähen. Ich programmiere auch nicht beruflich und bin auch kein Fortgeschrittener SPS Programmierer. Ganz im Gegenteil sogar - dadurch, dass ich den jetzigen Weg gegangen bin spare ich ~ 8% Arbeitsspeicher in der SPS, der bei meinem Programm knapp genug ist. Vorher hatte ich einen Multiinstanz-FB, der alle Unter-FBs aufgerufen hat und darin unter anderem die Timer gespeichert hat. Das war für mich unübersichtlicher und unpraktischer, da ich nicht 128 oder mehr Netzwerke plus FB Instanz Namen eintragen wollte. Vor allem da sich die Anzahl je nach Anwendungsfall auch nachträglich noch leicht ändern lassen soll. Ich hatte es auch schon so, dass ich aus einem FC den FB(der mit den Timern) aufgerufen hab mit jeweils einer InstanzDB, doch das sind auch pro Aufruf in SCL 1 Zeile Code, was bei 128+ sehr viele Zeilen in SCL gibt und wiederum größer und unübersichtlich ist. So wie es jetzt ist, habe ich für alle Aufrufe 1 Zeile im SCL Code, welche eben variabel ist und innerhalb einer Schleife abgearbeitet werden kann.

Ich habe keine Ahnung ob das ansatzweise jemand nachvollziehen kann..

Gruß
Mathias
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@Matthias:
Nicht immer gleich alles persönlich nehmen.

@Harald:
Es gibt durchaus schon Aufgabenstellungen, wo so etwas nicht nur sinnvoll erscheint sondern auch sinnvoll ist.
Ich habe z.B. etwas ähnliches um die Laufzeit aller Stationen eines Rundschalttisches zu messen. Dem Baustein, den ich dafür habe, ist es dabei egal, ob ich 4 Stationen am Tisch habe oder 40. Da habe ich etwas ähnliches umgesetzt - ich denke auch, dass man es verstehen kann wenn man den Baustein durchschaut.

Gruß
Larry
 
Zurück
Oben