TIA VB-Skript für Rezept-Datenbank

Zuviel Werbung?
-> Hier kostenlos registrieren
@faust : das könnt ihr natürlich machen - ich denke aber mal, dass dieses Thema schon zum allemeinen Interesse geworden ist zumal sich ja schon einige hier engagieren ... Ich würde es hier halten ... aber das ist natürlich eure Entscheidung ...
Wie schon geschrieben soll die hoffentlich gefundene Lösung dann ja auch hier veröffentlicht bzw. weiterbehandelt werden. Es soll damit keiner abgehängt o.ä. werden.

Wir sehen aber beispielhaft in diesem Thread, wie lange man sich im Kreis drehen kann, wenn bestimmte (wichtige) Informationen entweder falsch oder ungenau formuliert werden (z.B. Stichwort "Überlast": viele sind zuerst von "Script-Überlast" ausgegangen, dabei war es eine variablenwertbezogene Überlast). Diese Dinge kann man m.M.n. besser (und vor allem schneller) in einem direkten Gespräch bzw. Videocall auflösen.

Im übrigen scheinen wir (siehe hucki's letzte Beiträge) jetzt ja "auf dem richtigen Dampfer zu sein".


Gruß, Fred
 
Wow.....grad mega Input hier.....bin noch am studieren was diese Function überhaupt so tut :rolleyes:

Versuch das Ganze mal in einem Post niederzulegen:

Betreffend den Fragen zu den PLC-Variablen:
- Die "DB600_HMI" sind nur in der PLC, damit ich überhaupt sehe was das Script so treibt. Die kann ich als interne HMI-Variablen umdeklarieren.
- Beim Erfassungszyklus hab ich alles durchprobiert. Standartmässig sind sie aber auf "Zyklisch im Betrieb - 1sec" eingestellt
- Die "DB820" sind meine projektierten bzw. der Rezeptur zugewiesenen Rezeptvariablen. Das müssen ja PLC-Variablen sein zwecks der Synchronisierung. Oder habe ich das falsch verstanden. Zudem verwende ich aus dieser "DB820" ja auch die "DataNumber", mithilfe ich derer ja dann dem HMI auch sage "LadeDatensatz", um mir diesen dann auch in meinem Rezepturbild anzuzeigen. Daher weise ich dieser Variable in meinem Script ja auch den entsprechenden Wert zu. Kann ich diese Zuweisung auch mit einer Variablen machen, die NICHT Bestandteil meiner Rezepturvariablen ist??
-> Gibt es hierzu meinerseits Fehl-Überlegungen???

Betreffend den Anworten:

- Was ist der Unterschied zwischen der "Funktion" und der "Sub"? (Also Funktion verstehe ich glaubs soweit...aber den Unterschied nicht)
- @hucki : Was genau macht diese Zuweisung: "vbRecordNext = StartNr". "vbRecordNext" ist ja der Funktionsname. Wieso kriegt der einen Variablenwert zugewiesen. Ist das nur, damit ein Rückgabewert der Funktion gegeben ist, falls sie sonst keine Einträge findet?

Sorry für meine Verständnis-Demenz. Mein Wissen ist da noch nicht auf Profiniveau :rolleyes:
MEGA vielen Dank. Werde das aber am Montag direkt mal in die Tastatur hauen und ausprobieren. Wäre ja mega wenn das gehen würde :cool:
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@markus.dietschi : eine Function unterscheidet sich von einer SUB (Prozedur) nur insofern als das diese einen direkten Rückgabewert hat. Dieser wird im Script von @hucki unter der Überschrift "evaluation" geschrieben und dann an die aufrufende Routine zurückgegeben.
Ablauftechnisch hat FUNCTION gegenüber SUB sonst keinen Vorteil ...
 
Betreffend den Anworten:

- Was ist der Unterschied zwischen der "Funktion" und der "Sub"? (Also Funktion verstehe ich glaubs soweit...aber den Unterschied nicht)
Ein Sub-Prozedur ist eine Ansammlung von Anweisungen, die "nur" ausgeführt werden sollen.
Eine Funktion liefert zusätzlich noch ein Ergebnis an den Aufruf zurück, den Rückgabewert.

Ich programmiere gerne so, dass ich die Scripte nicht nur für genau einen Anwendungsfall nutzen kann, sondern versuche eher alles ein wenig universell zu halten.
In diesem Fall habe ich in meinem HMI nicht nur ein Rezept, sondern 4 von denen.
Also wollte ich das Script:
a) nicht auf ein bestimmtes sondern alle 4 Rezepte nutzen können
b) den Startwert universell und nicht von nur einer bestimmten Variablen haben
c) die Suche in beide Richtungen ermöglichen
und
d) das Ergebnis individuell für alle 4 Rezepte verarbeiten können.

Für a) bis c) habe ich daher dem Script 3 Eingangsvariablen verpasst und kann diese so für jeden Scriptaufruf individuell vorgeben
und für d) das Script als Funktion, weil ich so das Suchergebnis wieder nicht nur einer bestimmten Variablen sondern als Rückgabewert bei jedem Scriptaufruf einer individuellen Variablen zuweisen kann.


- @hucki : Was genau macht diese Zuweisung: "vbRecordNext = StartNr". "vbRecordNext" ist ja der Funktionsname. Wieso kriegt der einen Variablenwert zugewiesen. Ist das nur, damit ein Rückgabewert der Funktion gegeben ist, falls sie sonst keine Einträge findet?
Da das Script als Funktion deklariert ist, gibt diese über ihren Namen ein Ergebnis an den Scriptaufruf zurück.
Und Du hast genau richtig erkannt, dass mit dieser Zuweisung dafür gesorgt wird, dass in jedem Fall auch ein Ergebnis vorhanden ist.
Funktion ohne Rückgabewert = Fehler


Zwischen "Loop While..." und "ResetBit..." würde ich als Nächstes noch eine Abfrage einfügen, ob "vbRecordNext = StartNr" und ggf. für den Benutzer eine Meldung ausgeben, dass kein weiterer Datensatz vorhanden ist.
Das habe ich mittlerweile auch noch umgesetzt.
Auch wenn es Dir im konkreten Fall nicht wirklich weiter hilft, weil Dir mein Info-Popup fehlt, so hilft es vielleicht zumindest als Anregung:
Code:
Function vbRecordNext(ByVal RecipeNr, ByVal StartNr, ByVal Dir)
'
'Script:            vbRecordNext
'Version:           1.00
'Author:            hucki
'issue Date:        09.02.2024
'last modified:     10.02.2024
'State:             draft
'
'Function:          determines the next existing data record in order to select it (to skip gaps in the data storage)
'                   -> function is controlled using the status value of the query
'                   Ermittelt den naechst vorhandenen Datensatz, um diesen anzuwaehlen (um Luecken im Datenspeicher zu ueberspringen)
'                   -> Funktion wird mittels des Statuswertes der Abfrage gesteuert
'                  
'changes:            . Dir-Limits
'                   - no further record
'

    Const RECORD_MN = 1, RECORD_MX = 500                                                                ' query limits
    Const QUERY_RUN = 2, QUERY_FINISHED = 4, QUERY_ERROR = 12                                            ' query status
    Const MSG_NO_RECORD = 6                                                                                ' info message number in tlInformation
   
    Dim DataRecordNr, Add                                                                                ' needed vars


    Dim X_POS, Y_POS                                                                                     ' Position PopUp
   
    X_POS = PopupPosNormal_X
    Y_POS = PopupPosNormal_Y
   
   
    If Dir > 0 Then
        Add = 1
    Else
        Add = -1
    End If
   
   
    SetBit "QueryRunning"
   
   
    vbRecordNext = StartNr
    DataRecordNr = StartNr
   
    Do
       
        ' next record number
        DataRecordNr = DataRecordNr + Add
        If DataRecordNr < RECORD_MN Or DataRecordNr > RECORD_MX Then Exit Do
       
        ' query
        GetDataRecordName RecipeNr, DataRecordNr, "RecipeName", "DataRecordName", "QueryStatus"
   
        ' wait for execution
        Do
        Loop Until QueryStatus > QUERY_RUN
       
        ' evaluation
        If QueryStatus = QUERY_FINISHED Then vbRecordNext = DataRecordNr  

    Loop While QueryStatus = QUERY_ERROR
   
   
    ' no further record
    If vbRecordNext = StartNr Then
        SetTag "gdbHmi.Info.Hardware.HMI.Message", MSG_NO_RECORD                                        '     set Msg: no further record available
        ShowPopupScreen "Information", X_POS, Y_POS, hmiOn, hmiAnimationOff, hmiFast                    '    show popup
    End If
   
   
    ResetBit "QueryRunning"

End Function
 
@markus.dietschi : eine Function unterscheidet sich von einer SUB (Prozedur) nur insofern als das diese einen direkten Rückgabewert hat. Dieser wird im Script von @hucki unter der Überschrift "evaluation" geschrieben und dann an die aufrufende Routine zurückgegeben.
Ablauftechnisch hat FUNCTION gegenüber SUB sonst keinen Vorteil ...
Genau.
1707608273284.png
Ich kann dem Script für meine 4 Rezepte unterschiedliche Startwerte für die Suche vorgeben und kann das Ergebnis der Suche über den Rückgabewert auch 4 unterschiedlichen Variablen zuweisen.


4 Anwendungen, 2 Suchrichtungen, ein gleiches Script.
Ist vor allem bei Script-Änderungen von Vorteil, wenn man (ich) nicht alles doppelt und dreifach kopieren muss.
 
Hallo hucki,

ist offtopic, aber eine Gelegenheit:
Gibt es einen Grund, warum du "SetBit QueryRunning" bzw. "ResetBit QueryRunning" anstatt "QueryRunning = true" bzw "QueryRunning = false" einsetzt?


Gruß, Fred
 
Hallo hucki,

Gibt es einen Grund, warum du "SetBit QueryRunning" bzw. "ResetBit QueryRunning" anstatt "QueryRunning = true" bzw "QueryRunning = false" einsetzt?
Ja, gibt es: Faulheit beim Tippen. 🫣🤭


Ursprünglich wollte ich dieses Bit nicht im Script setzen, weil es explizit genannt wird.
Widerspricht doch eigentlich der gewünschten universalen Verwendung des Scriptes. Daher habe ich das Setzen zuerst in der Funktionsliste des Button vor dem eigentlichen Scriptaufruf ausgeführt.

Da es aber Sinn hat, die Aufrufbutton des Scriptes auch bei den verschiedenen Rezepten über das gleiche Flag alle gegenseitig zu sperren, habe ich es doch mit ins Script hinein genommen.
Daher habe ich den kompletten Befehl einfach aus der Funktionsliste kopiert (bzw. ausgeschnitten), am Anfang und am Ende des Scriptes eingefügt und bei Letzterem nur noch das "Re" davor geschrieben.
😁

PS:
Die Frage ist mittlerweile, ob man die Sperrung überhaupt braucht?!
Mit den HMI-internen Variablen ist das Durchsuchen der ca. 500 Datensätze gefühlt unter 1s:
Um diese Inhalte anzuzeigen, benötigen wir die Zustimmung zum Setzen von Drittanbieter-Cookies.
Für weitere Informationen siehe die Seite Verwendung von Cookies.
Da muss man sich sputen, wenn man währenddessen zu 'ner 2. Rezeptverwaltung wechseln möchte.
🤷‍♂️
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo hucki.

Ich habe deshalb gefragt, weil ich bei mir mit Skripten ähnlich, aber wirklich generell so verfahre, um die Aktivität anzuzeigen (Eieruhr-Grafik) bzw. Doppelausführungen zu verhindern.

Gerade Letzteres habe ich bei Comfort-Panels häufig (quasi Prellen der Schaltfläche) und mit der auch von dir eingesetzten Verfahrensweise dieses Verhalten ein wenig eindämmen können.

Die Betonung liegt dabei auf "ein wenig", denn wer über zittrige;) Finger verfügt, der schafft eine zweite Betätigung der Schaltfläche, BEVOR im aufgerufenen Skript die "Eieruhr"-Hilfsvariable gesetzt und die Grafik angezeigt wird!
Vielleicht ist deine Variante des Setzens/Rücksetzens ja schneller ...


Gruß, Fred
 
Hallo zusammen
Wollte nun noch mein offizielles Feedback abgeben, nachdem ich diese Tage den Code entsprechend einpflegen und das Ganze durchtesten konnte.........UND ES FUNKTIONIERT (y)(y)(y)(y)

Ein herzliches Dankeschön an alle.....ihr seid echt Helden. Vielen Dank für die megamässige Unterstützung. Hoffe das ich das eines Tages auch so weitergeben kann.
@hucki Vielen Dank für deine Mühe mit deiner eigenen Simulation. Deine Codevorschläge samt deinen Pictures haben echt geholfen.

Ihr habe mir echt das Projekt gerettet :cool:. Danke vielmals liebe Leute
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Einen kleinen Nachtrag hätte ich noch (falls jemdanden doch noch langweilig sein sollte :) )

Ich habe das gleiche Skript genommen und einfach die unteresten Einträge "QUERY_FINISHED" & "QUERY_RUN" getauscht (und einige Kleinigkeiten), um nicht nach dem nächsten Eintrag, sondern nach dem nächst freien Platz zu suchen, um einen neuen Datensatz entsprechend speichern zu können. Im Anschluss an das Skript wird unter dem gleichen E/A-Button-Befehl, die Funktion "Speicher Datensatz" ausgeführt.
Jetzt kann ja der Fall eintretten, das die DB voll ist, und kein Platz gefunden wird. Dann gibt mir die Funktion ja sinngemäss der Codezeile 42 "vbRecordNext = StartNr" ja wieder den Anfangswert zurück. Was ja Bullshit ist, und mir dann quasi der Startwert (also erster Datensatz, oder welcher auch immer) überschrieben wird.

Wie kann ich das noch elegant abfangen? Kann ich gemäss dem letzten Code von @hucki eine PLCI-Variable im Skript setzen lassen, und dann mit dieser (anstatt durch den betätigten E/A-Button) bei Wertänderung die Funktion "SpeicherDatensatz" durchführen? Und wenn ja, wie und wo setze ich dann diese PLC-Variable wieder zurück? Muss ich damit ich diesen Fehlerfall abfangen kann ein eigenes Skript schreiben, oder geht das doch einfacher?
 
Was würdest du denn dann gerne machen voll ?
Dein Fehlerfall wäre in dem Fall ja, eben genau das Neuer_Wert = Alter_Wert ist - tritt dieser Fall ein dann solltest du das dann anzeigen ...
 
@hucki Vielen Dank für deine Mühe mit deiner eigenen Simulation.
Danke für die Blumen.
Ich tüftle da allerdings mehr in meinem eigenen als in Deinem Interesse...
😁


Ich habe das gleiche Skript genommen und einfach die unteresten Einträge "QUERY_FINISHED" & "QUERY_RUN" getauscht (und einige Kleinigkeiten), um nicht nach dem nächsten Eintrag, sondern nach dem nächst freien Platz zu suchen, um einen neuen Datensatz entsprechend speichern zu können.
Ein 2. Script oder das jetzige Script nur abgewandelt, so dass man beides suchen lassen kann?

Bei mir ist es Letzteres und so sieht meine momentane Abwandlung dafür aus:
Code:
Function vbRecordSearch(ByVal RecipeNr, ByVal StartNr, ByVal Dir)
'
'Script:            vbRecordSearch
'Version:           1.00
'Author:            hucki
'issue Date:        09.02.2024
'last modified:     14.02.2024
'State:             draft
'
'Function:          determines the next (not) existing data record in the specified recipe
'                      (to fill/skip gaps in the data storage)
'                   -> function is controlled using the status value of the query
'                   Ermittelt den naechsten (nicht) vorhandenen Datensatz im angegebenen Rezept
'                      (um Luecken im Datenspeicher zu fuellen/ueberspringen)
'                   -> Funktion wird mittels des Statuswertes der Abfrage gesteuert
'               
'changes:           - Dir-Limits
'                   - no further record
'                   - StartNr = 0 -> search the first free spot
'

 
    SetBit "QueryRunning"                                                                               ' set the running flag
 
 

    Const RECORD_MN = 1, RECORD_MX = 500                                                                ' query limits
    Const QUERY_RUN = 2, QUERY_FINISHED = 4, QUERY_ERROR = 12                                           ' query status
    Const MSG_NO_RECORD = 6                                                                             ' info message number in tlInformation
 
    Dim DataRecordNr, Add, Match, Miss                                                                  ' needed vars
 
    Dim X_POS, Y_POS                                                                                    ' popup position vars

    X_POS = PopupPosNormal_X                                                                            ' get the global position
    Y_POS = PopupPosNormal_Y                                                                            ' get the global position
 
 
    If StartNr = 0 Or Dir > 0 Then                                                                      ' free spot or forward search?
        Add = 1                                                                                         '    increment
    Else
        Add = -1                                                                                        '    decrement
    End If
 
    If StartNr = 0 Then                                                                                 ' free spot search?
        Match = QUERY_ERROR
        Miss  = QUERY_FINISHED
    Else
        Match = QUERY_FINISHED
        Miss  = QUERY_ERROR
    End If
 
 
    vbRecordSearch = StartNr                                                                            ' initialize the return value
    DataRecordNr = StartNr                                                                              ' initialize the loop var
 
    Do                                                                                                  ' loop start
   
        ' next record number
        DataRecordNr = DataRecordNr + Add                                                               '   in-/decrease the loop var
        If DataRecordNr < RECORD_MN Or DataRecordNr > RECORD_MX Then Exit Do                            '   limit check of the loop var
   
        ' query
        GetDataRecordName RecipeNr, DataRecordNr, "RecipeName", "DataRecordName", "QueryStatus"         '   recipe query
 
        ' wait for execution
        Do                                                                                              '   loop start
        Loop Until QueryStatus > QUERY_RUN                                                              '   loop when query still running
   
        ' evaluation
        If QueryStatus = Match Then vbRecordSearch = DataRecordNr                                       '   record founded? -> set a new return value

    Loop While QueryStatus = Miss                                                                       ' loop without a record founded
 
 
    ' no further record
    If vbRecordSearch = StartNr Then                                                                    ' no record founded?
        SetTag "gdbHmi.Info.Hardware.HMI.Message", MSG_NO_RECORD                                        '   set Msg: no further record available
        ShowPopupScreen "Information", X_POS, Y_POS, hmiOn, hmiAnimationOff, hmiFast                    '   show the popup
    End If
 
 
    ResetBit "QueryRunning"                                                                             ' reset the running flag

End Function



Im Anschluss an das Skript wird unter dem gleichen E/A-Button-Befehl, die Funktion "Speicher Datensatz" ausgeführt.
Da ist der Fehler. In der Funktionsliste hast Du keine Möglichkeit auf das Suchergebnis zu reagieren.
Und das ist auch ein Grund, warum ich obiges Script als Funktion ausgeführt habe.


Leg' Dir für "SpeichereDatensatz" ein eigenes Script an (und lass in der Funktionsliste des Button die Suche vorher weg).
In diesem Script rufst Du als erstes das/dein obige(s) Such-Script auf und verwendest dabei die StartNr= 0 (und Dir = 1 bzw. dies automatisch festlegen lassen).

Jetzt kommt auch ein Vorteil einer Funktion für diesen Anwendungsfall -> das 2. Script bekommt vom obigen Script direkt einen Rückgabewert (ohne notwendigen Zwischenspeicher), den Du dann im 2. Script auswerten kannst.
Ist der Rückgabewert = 0 (= Speicher voll), überspringst Du im Speicher-Script das "SpeichereDatensatz".

z.B.:
Code:
Sub vbRecordSave(ByVal RecipeNr)
'
'Script:            vbRecordSave
'Version:           1.00
'Author:            hucki
'issue Date:        14.02.2024
'last modified:     14.02.2024
'State:             draft
'
'Function:          Saves a new data record in the specified recipe
'                   Speichert einen neuen Datensatz im angegebenen Rezept
'               
'changes:           .
'              

    Const START_NR = 0, DIR = 1                                                         ' search const
 
    Dim SpotNr                                                                          ' needed vars
 
 
 
    SpotNr = vbRecordSearch (RecipeNr, START_NR, DIR)                                   ' free spot search
 
    If SpotNr > 0 Then
        SaveDataRecord RecipeNr, SpotNr, hmiOverwriteWithConfirmation, hmiOn, Null      ' record save
    End If
 
End Sub
 
Zuletzt bearbeitet:
Zuviel Werbung?
-> Hier kostenlos registrieren
@hucki
Vielen Dank für dein Eigenintresse :cool: . Dein erweiterter Code sieht mega aus. Von alleine würd ich never ever auf sowas kommen. Bin schon glücklich dass ich verstehe wie das Ding funktioniert.
Ich habe momentan 2 Scripts im Einsatz. Eines für die Leersuche "vbNextFreePlace" und eines für das Vorhandensein "vbNextRecord". Hab dein Codevorschlag leider erst zu spät gesehen. Aber vielleicht setze ich das auch noch so um. Da ich die Rezept-DB für den Betrieb in eine Betriebs-DB in der PLC übergeben muss, und ich auch von der PLC her ein aktuelles Betriebs-Rezept wieder in die Rezept-DB rückspeisen möchte, musste ich ohnehin auf der PLC einen Code schreiben, um das zu bewerkstelligen. Daher habe ich das gleich ausgeweitet, und auch sämtliche Rezeptbuttons-Befehle wie "Speichern/Aktualisieren/Default-Rezept/etc." direkt seitens PLC angestossen. Dann ist programmiertechnisch alles am gleichen Ort.
Hab deinen Code verwendet, und dabei noch zwei Variablen gesetzt, damit ich auf der PLC mitbekomme, wann das Skript völlig durch ist, und ob für die Speicherung überhaupt ein Leerplatz gefunden wurde. Damit weiss ich ab wann und ob überhaupt, ich in der PLC den Code für das Schreiben anstossen darf. Somit bin ich auch nicht mehr an die Lesegeschwindigkeit des Skripts gebunden, ober an die Synchronisationszeit der Variablen zwischen HMI<->PLC.
Und auch die Messagebox funktioniert :) GEILE SACHE.....macht echt Freude wenn man sieht wie es läuft.
Code:
Function vbNextFreePlace(ByVal RecipeNr)
'
    Const RECORD_MN = 1, RECORD_MX = 500            ' 
    Const QUERY_RUN = 2, QUERY_FINISHED = 4, QUERY_ERROR = 12
    Const MSG_NO_PLACE = 12    
    
    Dim DataRecordNr, StartNr, DirValue
    Dim X_Pos, Y_Pos
    

    DB600_HMI_Recipe_xDatabaseSkriptRun = True                                        'Externe Variable "Script laeuft" setzen
    StartNr = 0                                                                        'Startwert der Loop-Schlaufe setzen
    DirValue = 1                                                                    'Zaehlrichtung definieren
    X_Pos = INTERN_PopUpPosX                                                        'Position fuer PopUp-Meldung
    Y_Pos = INTERN_PopUpPosY                                                        'Position fuer PopUp-Meldung
        

    vbNextFreePlace = StartNr                                                        'Definierter Rueckgabewert der Funktion bei "Fehler"
    DataRecordNr = StartNr                                                            'Startwert der Loop-Schlaufe setzen
    
    
    Do
        
        ' next record number
        DataRecordNr = DataRecordNr + DirValue
        If DataRecordNr < RECORD_MN Or DataRecordNr > RECORD_MX Then Exit Do
        
        ' query
        GetDataRecordName RecipeNr, DataRecordNr, "Database_RecipeName", "Database_DataRecordName", "Database_ScriptStatus"
    
        ' wait for execution
        Do
        Loop Until Database_ScriptStatus > QUERY_RUN
        
        ' evaluation
        If Database_ScriptStatus = QUERY_ERROR Then vbNextFreePlace = DataRecordNr    

    Loop While Database_ScriptStatus = QUERY_FINISHED
    
    
    If vbNextFreePlace = StartNr Then                                                'Wenn kein Speicherplatz mehr verfuegbar, dann...
        INTERN_PopUpMessage = MSG_NO_PLACE                                            'Message-Typ vorgeben
        ShowPopupScreen "PopUp_Message", X_Pos, Y_Pos, hmiOn, hmiAnimationOff, hmiMedium
        vbNextFreePlace = vbNextRecord(RecipeNr,0,1)                                'gueltige Datensatznummer fuer Anzeige suchen
        DB600_HMI_Recipe_xDatabaseFreePlace = False                                    'PLC-Variable ruecksetzen
    Else
        DB600_HMI_Recipe_xDatabaseFreePlace = True
    End If
   
    DB600_HMI_Recipe_xDatabaseSkriptRun = False                                        'Externe Variable "Script laeuft" ruecksetzen

End Function
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Frag wegen des Überlast-Problems auch mal den Siemens Support. Mir scheint das Verhalten nicht normal.
Die Support-Anfrage ist doch nicht nötig, das Verhalten ist normal.
Das hatte ich geschrieben, weil ich am Freitag mit Fieber krank war und den Thread nur mit einem halben Auge am Smartphone verfolgt hatte ;) und leider mal keinen Faktencheck durchgeführt hatte ... :(

Die Fehlernummer "$190010 Überlast, Werte gehen verloren" bedeutet NICHT "Skript-Überlauf", sondern "Variablen-Schreibaufträge-Überlast", wie ein schneller Blick in die TIA-Hilfe oder ins TIA-Handbuch zeigt:

NummerWirkung/Ursachen
190010

Die Variable wird zu oft mit Werten beschrieben (z. B. in einer Schleife von einem Skript aus).
Es gehen Werte verloren, da maximal 100 Vorgänge zwischengespeichert werden.

Im Grunde braucht nun keine besonders komplizierte oder trickreiche Programmierung des Skriptes gesucht werden, sondern in den Skripten in #17 oder #21 bei GetDataRecordName braucht man eigentlich nur die als Parameter verwendeten HMI-Variablen durch HMI-<interne Variable> ersetzen - bei denen tritt keine Überlast auf. Allerdings muss dann im Skript auf die Wertänderung der Statusvariable am Ende von GetDataRecordName gewartet werden. Man kann da nicht das Skript nach dem Anstossen von GetDataRecordName beenden und bei einer Wertänderung der HMI-internen Statusvariable ein weiteres Skript aufrufen, weil HMI-interne Variablen keine Ereignisse bei Wertänderung auslösen.
Alternative: die HMI-Variable für den Bearbeitungsstatus in eine deaktivierte HMI-Verbindung ohne Steuerungsanbindung legen, dann löst sie Ereignisse bei Wertänderung aus. Das hat schon in WinCC flexible 2008 funktioniert und sollte auch in TIA funktionieren.

Das suchen eines Datensatzes im HMI sollte m.M. ohne verbundene SPS funktionieren, damit das HMI-Projekt bedienbar/testbar/simulierbar bleibt.
 
Vielen Dank @PN/DP für deine Ausführung. Mittlerweile habe ich das Skript auch so umgesetzt, das die Variablen nur HMI intern sind, und damit scheint es auch zu funktionieren. Übergebe lediglich den Schlusswert "DataRecordNr" als Rückgabewert zur Funktion. Und den Rückgabewert der Funktion übergebe ich dann im HMI einer PLC-Variable, welche ich somit auf Änderung überprüfen kann. Somit weiss diese neue Variable wegen ihrer Wertänderung, ob sie automatisch eine neue Rezeptbild-Auffrischung durchführen muss oder nicht.
Läuft :cool:
 
Ich fand' vom Such-Script diesen Teil hier:
Code:
...
    If StartNr = 0 Or Dir > 0 Then                                                                      ' free spot or forward search?
        Add = 1                                                                                         '    increment
    Else
        Add = -1                                                                                        '    decrement
    End If
 
    If StartNr = 0 Then                                                                                 ' free spot search?
        Match = QUERY_ERROR
        Miss  = QUERY_FINISHED
    Else
        Match = QUERY_FINISHED
        Miss  = QUERY_ERROR
    End If
...
irgendwie doppelt gemoppelt,

da habe ich ihn noch etwas umformuliert:
Code:
...
    Add = CInt(Dir < 0) - CInt(Dir => 0)                                                                ' set add to -1 or +1 (TRUE = -1!)
   
    If StartNr = 0 Then                                                                                 ' free spot search?
        Add   = 1
        Match = QUERY_ERROR
        Miss  = QUERY_FINISHED
    Else
        Match = QUERY_FINISHED
        Miss  = QUERY_ERROR
    End If
...

:coffee:
 
Zurück
Oben