Überprüfen: Programm mit Schleife zum Vergleich eines Werts mit Werten in DB

ibanesch

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

ich möchte einen Wert derüber eine Schnittstelle eingelesen wird mit Werten die in einem DB hinterlegt sind Vergleichen. Wenn ein Positiver Vergleich erfolgt, soll ein Bit gesetzt werden und der entsprechende Wert gespeichert werden.
Dazu habe ich folgendes Programm geschrieben, bin mir aber vorallem bei der indirekten Adressierung nicht sicher, könnte bitte jemand mal drüber schaun,mir fehlt momentan leider jede testmöglichkeit.

Code:
 L     P#0.0
      LAR1  
      AUF   #DB_nummer
      L     0
M001: T     #S_ZAE
      L     DBW [AR1,P#0.0]
      L     #Can_msg
      ==I   
      SPB   M002
      +AR1  P#2.0
      L     #S_ZAE
      L     DBLG
      ==I   
      BEB   
      L     #S_ZAE
      L     2
      +I    
      LOOP  M001
 
M002: S     #treffer
      L     DBW [AR1,P#0.0]
      T     #code

S_ZAE (INT)ist der Schleifenzähler, treffer das bit das gesetzt werden soll und in code(WORD) soll der wert gespeichert werden im fall eines treffers.
Can_msg(WORD) enthält den wert auf den der Verglech erfolgen soll.
 
Auf den ersten Blick sieht alles gut aus, allerdings finde ich Deine Schleife etwas eigenwillig programmiert.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo,
dein Schleifenzähler muß meiner meinung nach am Anfang mit der Anzahl der Worte die verglichen Werden soll gefüttert werden, dann vorm Loop aufgerufen werden, da das Loop ihn dann um einen verringert

Code:
L 10 // Beispiel für 10 Durchläufe
next: T #Schleifenzähler
.
.Programm
.
L #Schleifenzähler
LOOP next
 
Danke für eure schnellen Antworten.
Bei dem Teil:
Code:
 +AR1  P#2.0
und bei dem

Code:
L     DBW [AR1,P#0.0]

kann mir einer erklären ob ich da dann immer im DB um 1 Word weiter springe, bzw warum das so funktioniert.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ja ... du erhöhst den AR1 mt den Befehl um 2 Byte (= 1 Wort) und du liest das durch das AR1 adressierte Wort. Das ",P#0.0" ist als zusätzliches Offset zu stehen - manchmal kam man das auch ganz gut gebrauchen.

Beispiel :
Code:
L     DBW [AR1,P#0.0]
T     DBW [AR1,P#2.0]
lädt das Wort, das über AR1 adressiert wird und speichert es im nächsten Wort ab.

Gruß
Larry
 
Auf den ersten Blick sieht alles gut aus, allerdings finde ich Deine Schleife etwas eigenwillig programmiert.
@online
So, wie ibanesch es programmiert hat, ist es zwar sehr ungewöhnlich, müsste aber funktionieren.
Mein lieber Michael - für eine fundierte Aussage reicht es nicht, nur einen Blick auf den Code zu werfen.
Man muß schon den Code verstehen und ggf. testen. Dazu braucht man nicht unbedingt einen Simulator,
das kann man notfalls auch mit Zettel und Stift am Schreibtisch tun.

Die Antwort an ibanesch mit 'drüber Nachdenken lautet: der Code funktioniert leider NICHT wie gewünscht!

An dem ungetesteten Programmentwurf ist doch so einiges anzumerken und zu ändern:
Code:
      L     P#0.0
      LAR1  
      AUF   #DB_nummer
      [COLOR="Red"]L     0[/COLOR]
M001: T     #S_ZAE
      L     DBW [AR1,P#0.0]
      L     #Can_msg
      ==I   
      SPB   M002
      +AR1  P#2.0
      L     #S_ZAE
      L     DBLG
      [COLOR="red"]==I   
      BEB[/COLOR]   
      L     #S_ZAE
      [COLOR="red"]L     2[/COLOR]
      +I    
      [COLOR="red"]LOOP  M001[/COLOR]
 
M002: S     #treffer
      [COLOR="Blue"]L     DBW [AR1,P#0.0][/COLOR]
      T     #code

So wie online in #3 schon andeutete, muß die Besonderheit beachtet werden, daß LOOP den Akku1 decrementiert.
Der Schleifenzähler #S_ZAE wird als Vorwärts-Word-Zähler (+2) benutzt, LOOP decrementiert aber den Schleifenzähler um 1.
Im Programmentwurf erhöht sich #S_ZAE tatsächlich nur um 1 je Schleifen-Durchlauf.
Also entweder SPA M001 statt LOOP M001 oder vor dem LOOP S_ZAE + 3 rechnen. (LOOP liest sich aber besser)
Den Schleifenzähler #S_ZAE könnte man auch ganz weglassen und stattdessen prüfen: AR1 > (DBLG * 8 - Zugriffsbreite)

Der Vergleich mit DBLG verhindert nicht, daß über die DB-Länge hinaus gelesen wird, weil zuerst auf das nicht mehr vorhandene
DBW zugegriffen wird und erst danach geprüft wird.
Außerdem beachtet der Vergleich nicht, daß höchstens auf die Adresse DBLG-2 (DBLG - Zugriffsbreite) zugegriffen werden kann.
Und Schleifenzähler prüft man sicherheitshalber auf >= max statt auf == max.

Wenn keine Übereinstimmung mit #Can_msg gefunden wird, dann sind #treffer und #code unbestimmt (keine Zuweisungen).
Wenn eine Übereinstimmung gefunden wurde, dann wird immer #code = #Can_msg zurückgegeben.
Das nochmalige L DBW [AR1,P#0.0] nach M002 ist überflüssig.

Wenn DBLG = 64kB ist und #Can_msg nicht gefunden wird, dann endet die Schleife und geht zu M002, was als #treffer=true gewertet wird!
(sofern die CPU dann noch nicht wegen Zykluszeitüberschreitung in Stop gegangen ist).
Wenn DBLG > 64kB ist wird die Schleife nur höchstens DBLG-64k mal durchlaufen.

Ich habe das Programm mal so geändert, daß der Entwurf noch zu erkennen ist, es aber nun funktionieren sollte (nicht getestet):
Code:
      L     P#0.0
      LAR1  
      AUF   #DB_nummer
      L     2           // 2 = wg. Word-Zugriffsbreite, max.Adr.: DBLG-2
M001: T     #S_ZAE
      L     DBLG
      >D
      SPB   M003

      L     #Can_msg
      L     DBW [AR1,P#0.0]
      ==I   
      S     #treffer
      SPB   M002

      +AR1  P#2.0
      L     #S_ZAE
      L     3           // 3 = 2 (wg. Word!) + 1 (wg. LOOP!)
      +I    
      LOOP  M001

M003: R     #treffer
      L     0           // Ersatzwert bei nicht gefunden
 
M002: T     #code

Harald
 
[IRONIE]
Ich gelobe, nie wieder in diesem Forum Code zu beurteilen, den ich nicht verstanden und in ausführlichen Tests und Prüfungen verifiziert und validiert habe!
[/IRONIE]
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wirklich vielen Dank, das bei Loop wusste ich nicht, aber schon wieder was gelernt.

Alerdings eine Sache versteh ich noch nicht

Wenn DBLG = 64kB ist und #Can_msg nicht gefunden wird, dann endet die Schleife und geht zu M002, was als #treffer=true gewertet wird!

Wenn DBLG > 64kB ist wird die Schleife nur höchstens DBLG-64k mal durchlaufen.

Warum währe das bei einer DB Länge > 64kB so?
Liegt das an der Funktion von DBLG?
(Der DB in meinem Programm enthält nur 92 Werte)
 
Als Dummer Prog hab ich da noch ne Frage:
bei Loop wird da wirklich in der Schleige gsprungen und der Zyklus nicht weiter bearbeitet, warum nicht was das im Zyklus Arbeitet und bei jedem Zyklus den nächsten Datensatz abfragt?
 
Meines wissens nach wird die Schleife in vorgebener Anzahl innerhalb des Zyklus durchgearbeitet. Du hast sicherlich recht damit das es möglich wäre das Ganze zyklisch durchzuarbeiten.
Allerdings würde das Erkennen je nach Länge des Bereichs + der Zykluszeit ggf. viele Sekunden dauern, und das ist nicht immer schön...;)
(IMHO)

Gruß
Toki
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Als Dummer Prog hab ich da noch ne Frage:
bei Loop wird da wirklich in der Schleige gsprungen und der Zyklus nicht weiter bearbeitet, warum nicht was das im Zyklus Arbeitet und bei jedem Zyklus den nächsten Datensatz abfragt?
Weil man manchmal das Ergebnis genau in diesem Zyklus braucht.
Wenn zum Beispiel 5 Wörter durchsucht werden sollen, kann sich im zweiten Zyklus das erste Wort ja schon wieder geändert haben.
 
alles Klar, denke wohl immer noch in der weise, möglichst Zykluszeit zu sparen und alles am Zyklus "aufzuhängen"
*ACK*
 
Noch als Nachschlag:
Ein typisches Beispiel ist der SFC20 Blockmove von Siemens.
Der überträgt den kompletten Bereich von Quelle zum Ziel in einem Zyklus, Stichwort: Konsistent.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Ihr habt recht, ich komm aus Bereichen bei denen das in einem Zyklus eher unwahrscheinlich ist. Kann mich aber in solche Bereiche reindenken.

schönen Abend

Winnman
 
Alerdings eine Sache versteh ich noch nicht

Wenn DBLG = 64kB ist und #Can_msg nicht gefunden wird, dann endet die Schleife und geht zu M002, was als #treffer=true gewertet wird!

Wenn DBLG > 64kB ist wird die Schleife nur höchstens DBLG-64k mal durchlaufen.
= 64kB: Weil #S_ZAE ein 16Bit-Wert ist und nach 65536 Durchläufen beim LOOP dann 0 wird.
> 64kB: Weil der Vergleich #S_ZAE mit DBLG ==I ist und deshalb nur die unteren 16 Bit verglichen werden.

Harald
 
Ein DB kann doch nur max 64kB groß sein, oder???

Es scheint tatsächlich noch keine S7-CPU zu geben, die DB > 64kB kann.
PLCSIM V5.4.3 meldet in den Leistungsdaten für alle Bausteinarten
(OB, FC, FB und DB): max Länge 65570 (Byte), das wären 64kB + 34Byte.
Allerdings ist da wohl der Arbeitsspeicherbedarf :confused: gemeint und nicht
die Datenlänge (Größe) des DB.

Tatsächlich ist es (noch) nicht möglich, DB > 64kB zu erzeugen.
Die maximal mögliche Datenlänge eines DB ist 65534Byte, dementsprechend
kann auch DBLG nur 0..65534 liefern.

Harald
 
Zurück
Oben