# direkter Lokaldatenzugriff



## sunny22 (10 März 2021)

Hallo Zusammen,

ich hab hier ein S7 Programm und mich würde mal eure Meinung dazu interessieren.
Es wird dort wild über direkte Adressen auf Lokaldaten zugegriffen ohne diese in der Temp-Deklaration zu reservieren.
Kann man das so machen? Sollte man das so machen? Kann sich das auf Lokaldaten anderer Bausteine auswirken?

Grüße Oliver


----------



## Larry Laffer (10 März 2021)

Wie du siehst kann man das so machen ... 8)
Es wird sich so erstmal nicht auf andere Basusteine auswirken ...
Ich persönlich würde es so nicht haben wollen (es strickt verbieten !!!) - es gibt ganz sicher eine Möglichkeit, das Ganze auch "vernünftig" hinzubekommen ...

Gruß
Larry


----------



## PN/DP (10 März 2021)

Wenn der Programmierer schon nicht weiß wie er den TEMP-Speicher symbolisch ansprechen kann (oder keine Lust dazu hat) dann sollte er wenigstens für die Kollegen den verwendeten Speicherbereich irgendwie markieren/reservieren/deklarieren, z.B. als BYTE-Array mit dem Kommentar "Achtung! Nicht verschieben! Wird direkt adressiert!"

Anscheinend hat er sich bei den LB-Zugriffen auch noch verzählt, weil LB8 und LB9 treffen den Speicherbereich der Variable DBZVT. Oder ist da schon jemand unbedarft drauf 'reingefallen und hat die Variable erst nach dem Kunstprojekt angelegt? Oder das Programm soll wirklich so saumäßig im Speicher 'rumschreiben?

Zum Glück geht solches direktes absolut adressiertes 'rumschmieren im TEMP-Speicher nur für Adressen ab dem Beginn des Baustein-eigenen TEMP-Bereiches, so daß kein aktuell belegter Speicher anderer Bausteine damit beeinflusst wird.

Harald


----------



## Banana Joe (11 März 2021)

Was für ein geniales Konstrukt! 

Kann man das so machen? Sicherlich (es scheint ja zu funktionieren).

Sollte man das so machen? Sicherlich nicht.

Jeder der hier noch mal nachträglich was am Lokaldatenbereich ändert und nicht darauf achtet das weiter unten Wild durch die Gegend gev*gelt wird, wird ziemlich ordentlich auf die Schnauze fallen. Wenn man seine Kollegen hasst ist das natürlich ein probates Mittel, um dies zum Ausdruck zu bringen.


----------



## ducati (11 März 2021)

Ja, man kann halt absolut auf alles mögliche zugreifen.

Bei E/As, Merkern und Global-DBs rechnet man damit. Bei Tempvariablen/Lokaldaten eher nicht.

Bei absoluten Zugriffen auf Instanz-DBs ists auch schon unschön, falls mal jemand ne Statische Variable hinzufügt.

Was machen die hier: Die wollen die Bytes in nem Doppelwort drehen. Abgesehn davon, dass es nen AWL-Befehl dafür gibt, gibts auch sonst schönere Varianten, um an die Bytes in nem Doppelwort zuzugreifen...

Und die Überschneidung mit ner deklarierten Variablen ist ganz doof...

Naja, irgendwo kommt der Code her, vermutlich aus nem Forum kopiert 


Ich hab so Code auch schon gesehen... Hab auch schon Rettung von Lokaldaten über den Bausteinaufruf hinaus gesehen, da denkst dann, was treibt der da wenn er Lokaldaten setzt und rücksetzt... 

Also neu würd ich den Zugriff auf Lokaldaten auch sicher nicht mehr machen... Wenn man sich den AWL-Code der aus KOP/FUP/SCL/CFC entsteht mal anschaut, wird da aber auch seeeehr viel mit Lokaldaten hantiert...


----------



## PN/DP (11 März 2021)

ducati schrieb:


> Wenn man sich den AWL-Code der aus KOP/FUP/SCL/CFC entsteht mal anschaut, wird da aber auch seeeehr viel mit Lokaldaten hantiert...


Da macht das aber ein Compiler, der weiß was er tut und die Übersicht behält, welche Adressen er gerade belegt, und das Ganze bei späteren Programmänderungen auch verschieben kann. Wenn ein Programmierer das tut, dann weiß der nach ein paar Wochen nichts mehr wie das zusammenhängt und sein Update/Nachfolger erst recht nicht.

Harald


----------



## NBerger (11 März 2021)

> Zum Glück geht solches direktes absolut adressiertes 'rumschmieren im  TEMP-Speicher nur für Adressen ab dem Beginn des Baustein-eigenen  TEMP-Bereiches, so daß kein aktuell belegter Speicher anderer Bausteine  damit beeinflusst wird.



So ganz stimmt das nicht: Wird dieser Baustein unterbrochen so wird der Tempstack um die bekannten/deklarierten Variablen erhöt, für die Tempvariablen des unterbrechenden Bausteins.
Der kann nun fleißig Werte ändern die nach Rückkehr in diesen Baustein dann verändert/verfälscht sind.

Beim Suchen solcher Fehler kommt freude auf.


----------



## ducati (11 März 2021)

NBerger schrieb:


> So ganz stimmt das nicht: Wird dieser Baustein unterbrochen so wird der Tempstack um die bekannten/deklarierten Variablen erhöt, für die Tempvariablen des unterbrechenden Bausteins.
> Der kann nun fleißig Werte ändern die nach Rückkehr in diesen Baustein dann verändert/verfälscht sind.
> 
> Beim Suchen solcher Fehler kommt freude auf.



Hmm, ich hätt gedacht, alle Interrupt-OBs haben nen eigenen Lokaldatenstack...

Aber gut, so genau hab ich das noch nie ausgetestet...

Oder meinst Du, in nem FC wird nen weiterer FC aufgerufen? Da wüsst ich jetzt auch nicht, wie das gehändelt wird.


----------



## PN/DP (11 März 2021)

NBerger schrieb:


> > Zum Glück geht solches direktes absolut adressiertes 'rumschmieren im TEMP-Speicher nur für Adressen ab dem Beginn des Baustein-eigenen TEMP-Bereiches, so daß kein aktuell belegter Speicher anderer Bausteine damit beeinflusst wird.
> 
> 
> So ganz stimmt das nicht: Wird dieser Baustein unterbrochen so wird der Tempstack um die bekannten/deklarierten Variablen erhöt, für die Tempvariablen des unterbrechenden Bausteins.
> ...


So stimmt das aber nicht. Nach meiner Erfahrung hat jede OB-Ebene (Task) einen ganz eigenen TEMP-Stack, was wie man sieht ganz viel Sinn macht. "Solche" Fehler braucht man nicht suchen, weil die gibt es gar nicht. Versuche doch mal absichtlich, irgendwie versteckt/verpointert in höheren TEMP-Bereich zuzugreifen, und schau, ob Du Rückstände von irgendwelchen unterbrechenden Bausteinen findest  
Oder meinst Du Bausteine, die durch den Baustein selber aufgerufen werden? Direkte Zugriffe ala "T LB nn" werden vom Compiler zuverlässig erkannt und der Stack für den aufgerufenen Baustein beginnt erst hinter diesen Adressen nn, egal wieviel TEMP-Speicher offiziell mit Variablen deklariert oder nicht deklariert ist. (ist zumindest in Step7 classic so, ob TIA auch so schlau ist weiß ich nicht)

Gehört zugreifen in nicht-deklarierten TEMP-Speicher zu Deinem Programmierstil und Du bekommst nun unerklärliche Probleme bei TIA?  Zeig uns doch mal ein Stück Beispielcode, wo das zutrifft, was Du hier verkündest. Sollte ja nicht schwer sein, wo Du doch schon Freude beim Suchen solcher Fehler hattest... 

Harald


----------



## Thomas_v2.1 (11 März 2021)

ducati schrieb:


> Hmm, ich hätt gedacht, alle Interrupt-OBs haben nen eigenen Lokaldatenstack...
> 
> Aber gut, so genau hab ich das noch nie ausgetestet...
> 
> Oder meinst Du, in nem FC wird nen weiterer FC aufgerufen? Da wüsst ich jetzt auch nicht, wie das gehändelt wird.



Weil das was NBerger geschrieben hat auch nicht stimmt. Die SPS prüft am Code beim Hochladen am Code deine Lokaldatenzugriffe und legt den Lokaldatenbereich für den Baustein danach aus, die Deklaration kennt die SPS auch überhaupt nicht.

Das kann man selber überprüfen, indem man versucht einen Baustein mit einem Zugriff auf einen zu großen Lokaldatenbereich (z.B. LW 2050 bei kleinen 300ern) in die SPS hochzuladen, was diese dann ablehnt.
Wenn man die SPS in Stopp schickt, dann kann man sich zudem über den Baugruppenzustand der CPU die L-Stacks der jeweiligen Bausteine anzeigen lassen. Aus der Anzeige ist ersichtlich, dass die Größe des Lokaldatenbereichs eines Bausteins anhand des Codes bestimmt wird. Die dort angezeigten Größen der L-Stacks je Baustein werden von der SPS gemeldet und nicht von Step7 aus dem Code generiert.

Da kommt mir gerade die Idee, dass man evtl. mit etwas indirekter Adressierung unter dem Radar auf den L-Stack von ganz anderen Bausteinen zugreifen könnte, wenn das nicht angefangen wird.


----------



## JSEngineering (11 März 2021)

PN/DP schrieb:


> Da macht das aber ein Compiler, der weiß was er tut und die Übersicht behält, welche Adressen er gerade belegt, und das Ganze bei späteren Programmänderungen auch verschieben kann. Wenn ein Programmierer das tut, dann weiß der nach ein paar Wochen nichts mehr wie das zusammenhängt und sein Update/Nachfolger erst recht nicht.
> 
> Harald




Vielleicht ist das ja mal aus einer CPU "gerettet" worden und ist garnicht von einem Menschen verzapft....


----------



## Oberchefe (12 März 2021)

Ich habe so etwas schon unfreiwillig gesehen. Einer programmiert in FUP und hat die "Typüberprüfung von Operanden" ausgeschaltet und programmiert da etwas, was mit der eingeschaltetet Prüfung nicht erlaubt wäre. Der nächste öffnet den Baustein mit eingeschalteter Überprüfung. Bei ihm wird nun dieses Netzwerk dann als AWL dargestellt, der Rest im FB aber wie gehabt in FUP. Dieses AWL-Netzwerk enthält je nach Programmierung absolute Adressen aus dem Temp-Bereich. Wenn nun der zweite Bearbeiter temporäre Variablen deklariert, sind diese aber auf den selben Adressen wie die vom AWL-Netzwerk, ja nach Programmierreihenfolge der verwendeten Temp-Variablen kommt es jetzt zu ungewollten Ergebnissen. Ich habe mir angewöhnt, die Typprüfung bei eigenen Projekten eingeschaltet zu lassen um "saubereren" Code zu schreiben. Wenn ich fremde Projekte zu bearbeiten habe, gehe ich dann als erstes den kompletten Code durch und prüfe alle Netzwerke ob sie als AWL abgebildet werden, alternativ schalte ich die Typprüfung temporär für das eine Projekt ab.


----------



## Oberchefe (12 März 2021)

Ergänzung: es kommt beim Anlegen der Temp-Variablen zwar eine Warnung, die wird aber erfahrungsgemäß oft überlesen.


----------



## PN/DP (12 März 2021)

Seit Step7 V5.5 SP4 HF? Anfang 2016 ist die "Typüberprüfung von Operanden" in KOP/FUP dauerhaft deaktiviert und kann nicht mehr aktiviert werden. Feld Typprüfung von Operanden ausgegraut.

Harald


----------



## Thomas_v2.1 (12 März 2021)

Thomas_v2.1 schrieb:


> Da kommt mir gerade die Idee, dass man evtl. mit etwas indirekter Adressierung unter dem Radar auf den L-Stack von ganz anderen Bausteinen zugreifen könnte, wenn das nicht angefangen wird.



Das geht übrigens nicht, die SPS geht in Stopp wenn indirekt auf einen Bereich außerhalb der reservierten Lokaldaten zugegriffen wird. Daran kann man auch sehen, dass die SPS den hochgeladenen Code analysiert und danach den Lokaldatenbereich für den Baustein auslegt.

Ein FC ohne Variablendeklaration und mit diesem Code geht in Stopp:

```
L     W#16#AFFE
      T     LW   100

      L     P#104.0
      LAR1  
      L     W#16#BABE
      T     LW [AR1,P#0.0]
```
Mit P#102.0 funktioniert es einwandfrei.


----------



## PN/DP (12 März 2021)

JSEngineering schrieb:


> Vielleicht ist das ja mal aus einer CPU "gerettet" worden und ist garnicht von einem Menschen verzapft....


Glaube ich nicht. So wie der Code aussieht ist der nicht von einem Compiler automatisch erzeugt. So stupider Code wird nur von Menschen verzapft. 
Höchstens daß vielleicht jemand nachträglich die TEMP-Deklarationen gelöscht oder geändert hat - aber auch das hätte ein Mensch gemacht.

Harald


----------



## Thomas_v2.1 (12 März 2021)

Ich würde mich nicht davon freisprechen wollen, dass ich nicht schon einmal so etwas geschrieben hätte ;-)

Vermutlich lief es so ab:
Sauber strukturierter und dokumentierter Code wurde im Büro anhand der Dokumentation vorbereitet.
Bei der Inbetriebnahme war mal wieder alles ganz anders, vermutlich die leidige Endianess.
Es wurde getestet warum die Werte nicht passen, die Bytes wurden beim Herumprobieren an einem Wert so lange gedreht bis sie passen.
Ein funktionierendes Schema wurde gefunden, und des Programmierers flinke Finger haben selbiges gleich auf alle Werte ausgerollt.
Doku und Schick machen kommt später in einer ruhigen Minute...


----------



## PN/DP (12 März 2021)

Thomas_v2.1 schrieb:


> Thomas_v2.1 schrieb:
> 
> 
> > Da kommt mir gerade die Idee, dass man evtl. mit etwas indirekter Adressierung unter dem Radar auf den L-Stack von ganz anderen Bausteinen zugreifen könnte, wenn das nicht angefangen wird.
> ...


Ein kleines bisschen kann man auf Lokaldaten anderer Bausteine zugreifen, nämlich indirekt auf die Lokaldaten des aufrufenden Bausteins (Vorgänger-Lokaldaten), aber auch nur in der Größe wie die da eingestellt sind (wenn ich mich recht erinnere, was ich mal getestet hatte). Da würde ich aber sagen, daß sowas eher nicht aus Versehen passiert.

Harald


----------



## ducati (13 März 2021)

Interessantes Thema 
Das einzige Problem was ich immer wieder mit Lokaldaten an verschiedenen Anlagen habe ist, dass gelesen wird ohne vorher zu schreiben oder dass jemand setzen/rücksetzen will. Manchmal aus Versehen manchmal aus Unwissenheit...
Ob jetzt absolute Adressierung "böse" ist, kann man geteilter Meinung sein.
Man wird sehen, wie in 20 Jahren über die heutigen "Hochsprachenkonstrukte" in der SPS gedacht wird.
Jedenfalls Temp.-Variablen funktionieren in der 300/400er auch mit Interrupt-OBs und FC/FB Aufrufen, seh ich auch so.
Bei 1200/1500 kann mans wenigstens hoffen 

Nichtsdestotrotz versuch ich schon immer symbolisch zu programmieren und so dass man über Querverweise alles findet.

Aber wie Thomas schon schreibt, oft zählt nicht Schönheit auf der Baustelle sondern Zeit und Geld. Und ganz ganz vielen ist Schönheit auch komplett egal...

Achja, hatte da auch schon Kollegen die absolute Adressierung und Pointerrei als Lebenseinstellung gesehen haben, erstens weil der Code kürzer/schneller sei und zweitens weil sie allen anderen Beweisen wollten, dass sie pointern können


----------



## ducati (13 März 2021)

Hmm, da fällt mir nen neuer Programmierwettbewerb ein. Eine Aufgabe, SPS incl. HMI und verschiedene Programmierstile. Am Ende ne Abstimmung, welche Lösung am einfachsten zu verstehen ist und wo an den Lösungen der anderen eine einfache kleine Änderung vorzunehmen ist. 🤔


----------



## Heinileini (13 März 2021)

ducati schrieb:


> Das einzige Problem was ich immer wieder mit Lokaldaten an verschiedenen Anlagen habe ist, dass gelesen wird ohne vorher zu schreiben oder dass jemand setzen/rücksetzen will. Manchmal aus Versehen manchmal aus Unwissenheit...


Mich hat immer am meisten gewurmt, wenn das Lesen von Temps vor dem Definieren selbiger in der Software des SteuerungsHerstellers (Siemens/Fanuc) gut versteckt und durch KnowHowSchutz unsichtbar gemacht war. Bekenne mich schuldig, in solchen Fällen guten Gewissens den Schutz geknackt zu haben - war halt "Notwehr".

Gegen Setzen/Rücksetzen von Temps ist doch nichts einzuwenden. Die Setz-/RücksetzOrgie muss natürlich innerhalb des GeltungsBereichs der Temps und des Zyklus abgeschlossen sein.


----------



## sunny22 (13 März 2021)

Hier mal der komplette Code. Ist für die Kommunikation mit KBR Messgeräten gedacht. 
Vielleicht erkennt es ja jemand wieder 


```
FUNCTION "KOMM_KBR_PB1" : VOID
TITLE =Kommunikationsorganisation mit KBR auf PB1
VERSION : 0.0


VAR_INPUT
  ErstPEW : INT ;    
  ErstPAW : INT ;    
  DBZ : INT ;    
  ErstDBDZ : INT ;    
  WTIME : TIMER ;    
  DBZV : INT ;    
  ErstDBDZV : INT ;    
END_VAR
VAR_IN_OUT
  SCHR : WORD ;    
END_VAR
VAR_TEMP
  SCHRT : WORD ;    
  Adr : DWORD ;    
  DBZT : INT ;    
  DBZVT : INT ;    
END_VAR
BEGIN
NETWORK
TITLE =Takt Timer Sekundenimpuls
//
//
      L     #SCHR; 
      T     #SCHRT; 

      U     #WTIME; //prüfe ob Timer läuft
      SPB   w6; 

      L     0; //Lade null
      ==I   ; 
      S     L      0.0; 
      <>I   ; 
      SPB   w0; 



w0:   UN    L      0.0; //Messwerttyp 1 - Spannung Phase-Null
      SPB   w1; 

      L     #ErstPEW; 
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     PEB [AR1,P#0.0]; //Kennung überprüfen
      L     B#16#6; 
      <>I   ; 
      SPB   x1; 

      L     PEB [AR1,P#1.0]; //Index überprüfen
      L     B#16#1; 
      <>I   ; 
      SPB   x1; 

      ==I   ; 
      SPB   y1; 

x1:   L     #ErstPAW; //schreibe Kennung=6 in erstes PAB
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     B#16#6; 
      T     PAB [AR1,P#0.0]; 

      L     #ErstPAW; //schreiben von Index=1 in zweites PAB
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     B#16#1; 
      T     PAB [AR1,P#1.0]; 
      SPA   w6; //zu Bausteinende

y1:   L     PEB [AR1,P#8.0]; //Umladen Messwert1
      T     LB    11; 
      L     PEB [AR1,P#9.0]; 
      T     LB    10; 
      L     PEB [AR1,P#10.0]; 
      T     LB     9; 
      L     PEB [AR1,P#11.0]; 
      T     LB     8; 

      L     PEB [AR1,P#12.0]; //Umladen Messwert2
      T     LB    15; 
      L     PEB [AR1,P#13.0]; 
      T     LB    14; 
      L     PEB [AR1,P#14.0]; 
      T     LB    13; 
      L     PEB [AR1,P#15.0]; 
      T     LB    12; 

      L     PEB [AR1,P#16.0]; //Umladen Messwert3
      T     LB    19; 
      L     PEB [AR1,P#17.0]; 
      T     LB    18; 
      L     PEB [AR1,P#18.0]; 
      T     LB    17; 
      L     PEB [AR1,P#19.0]; 
      T     LB    16; 

      L     #DBZ; //ZielDB öffnen
      T     #DBZT; 
      AUF   DB [#DBZT]; 
      L     #ErstDBDZ; //Übergabe Momentane EinstiegsAdresse
      SLW   3; //Schiebe Binär m drei Positionen nach links
      LAR1  ; 
      L     LD     8; //schreibe Werte in ZielDB
      T     DBD [AR1,P#0.0]; 
      L     LD    12; 
      T     DBD [AR1,P#4.0]; 
      L     LD    16; //schreibe Werte in ZielDB]
      T     DBD [AR1,P#8.0]; 

      U     L      0.0; 
      R     L      0.0; 
      S     L      0.1; 

      L     #ErstPAW; 
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     B#16#3; 
      T     PAB [AR1,P#1.0]; //schreiben von Index=3 in Ausgang
      SPA   w6; //zu Bausteinende





w1:   UN    L      0.1; //Messewerttyp 2 - Wirkstrom
      SPB   w2; 

      L     #ErstPEW; 
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     PEB [AR1,P#1.0]; //Index überprüfen
      L     B#16#3; 
      <>I   ; 
      SPB   x2; 

      ==I   ; 
      SPB   y2; 

x2:   L     #ErstPAW; //schreibe Kennung=6 in erstes PAB
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     B#16#6; 
      T     PAB [AR1,P#0.0]; 

      L     #ErstPAW; //schreiben von Index=3 in zweites PAB
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     B#16#3; 
      T     PAB [AR1,P#1.0]; 
      SPA   w6; //zu Bausteinende


y2:   L     PEB [AR1,P#8.0]; //Umladen Messwert1
      T     LB    23; 
      L     PEB [AR1,P#9.0]; 
      T     LB    22; 
      L     PEB [AR1,P#10.0]; 
      T     LB    21; 
      L     PEB [AR1,P#11.0]; 
      T     LB    20; 

      L     PEB [AR1,P#12.0]; //Umladen Messwert2
      T     LB    27; 
      L     PEB [AR1,P#13.0]; 
      T     LB    26; 
      L     PEB [AR1,P#14.0]; 
      T     LB    25; 
      L     PEB [AR1,P#15.0]; 
      T     LB    24; 

      L     PEB [AR1,P#16.0]; //Umladen Messwert3
      T     LB    31; 
      L     PEB [AR1,P#17.0]; 
      T     LB    30; 
      L     PEB [AR1,P#18.0]; 
      T     LB    29; 
      L     PEB [AR1,P#19.0]; 
      T     LB    28; 

      L     #DBZ; //ZielDB öffnen
      T     #DBZT; 
      AUF   DB [#DBZT]; 
      L     #ErstDBDZ; //Übergabe Momentane EinstiegsAdresse
      SLW   3; //Schiebe Binär m drei Positionen nach links
      LAR1  ; 
      L     LD    20; //schreibe Werte in ZielDB
      T     DBD [AR1,P#12.0]; 
      L     LD    24; 
      T     DBD [AR1,P#16.0]; 
      L     LD    28; 
      T     DBD [AR1,P#20.0]; 

      U     L      0.1; 
      R     L      0.1; 
      S     L      0.2; 

      L     #ErstPAW; 
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     B#16#8; 
      T     PAB [AR1,P#1.0]; //schreiben vonn Index=3
      SPA   w6; 




w2:   UN    L      0.2; //Messwerttyp 3 cos phi
      SPB   w3; 


      L     #ErstPEW; 
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     PEB [AR1,P#1.0]; //Index überprüfen
      L     B#16#8; 
      <>I   ; 
      SPB   x3; 

      ==I   ; 
      SPB   y3; 

x3:   L     #ErstPAW; //schreibe Kennung=6 in erstes PAB
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     B#16#6; 
      T     PAB [AR1,P#0.0]; 

      L     #ErstPAW; //schreiben von Index=8 in zweites PAB
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     B#16#8; 
      T     PAB [AR1,P#1.0]; 
      SPA   w6; 

y3:   L     PEB [AR1,P#8.0]; //Umladen Messwert1
      T     LB    35; 
      L     PEB [AR1,P#9.0]; 
      T     LB    34; 
      L     PEB [AR1,P#10.0]; 
      T     LB    33; 
      L     PEB [AR1,P#11.0]; 
      T     LB    32; 

      L     PEB [AR1,P#12.0]; //Umladen Messwert2
      T     LB    39; 
      L     PEB [AR1,P#13.0]; 
      T     LB    38; 
      L     PEB [AR1,P#14.0]; 
      T     LB    37; 
      L     PEB [AR1,P#15.0]; 
      T     LB    36; 

      L     PEB [AR1,P#16.0]; //Umladen Messwert3
      T     LB    43; 
      L     PEB [AR1,P#17.0]; 
      T     LB    42; 
      L     PEB [AR1,P#18.0]; 
      T     LB    41; 
      L     PEB [AR1,P#19.0]; 
      T     LB    40; 

      L     #DBZ; //ZielDB öffnen
      T     #DBZT; 
      AUF   DB [#DBZT]; 
      L     #ErstDBDZ; //Übergabe Momentane EinstiegsAdresse
      SLW   3; //Schiebe Binär m drei Positionen nach links
      LAR1  ; 
      L     LD    32; //schreibe Werte in ZielDB
      T     DBD [AR1,P#24.0]; 
      L     LD    36; 
      T     DBD [AR1,P#28.0]; 
      L     LD    40; 
      T     DBD [AR1,P#32.0]; 

      U     L      0.2; 
      R     L      0.2; 
      S     L      0.3; 

      L     #ErstPAW; 
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     B#16#6; 
      T     PAB [AR1,P#1.0]; 
      SPA   w6; //zu Bausteinende




w3:   UN    L      0.3; //Messwerttyp 4 Wirkleistung
      SPB   w4; 

      L     #ErstPEW; 
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     PEB [AR1,P#1.0]; //Index überprüfen
      L     B#16#6; 
      <>I   ; 
      SPB   x4; 

      ==I   ; 
      SPB   y4; 

x4:   L     #ErstPAW; //schreibe Kennung=6 in erstes PAB
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     B#16#6; 
      T     PAB [AR1,P#0.0]; 

      L     #ErstPAW; //schreiben von Index=6 in zweites PAB
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     B#16#6; 
      T     PAB [AR1,P#1.0]; 
      SPA   w6; 

y4:   L     PEB [AR1,P#8.0]; //Umladen Messwert1
      T     LB    47; 
      L     PEB [AR1,P#9.0]; 
      T     LB    46; 
      L     PEB [AR1,P#10.0]; 
      T     LB    45; 
      L     PEB [AR1,P#11.0]; 
      T     LB    44; 

      L     PEB [AR1,P#12.0]; //Umladen Messwert2
      T     LB    51; 
      L     PEB [AR1,P#13.0]; 
      T     LB    50; 
      L     PEB [AR1,P#14.0]; 
      T     LB    49; 
      L     PEB [AR1,P#15.0]; 
      T     LB    48; 

      L     PEB [AR1,P#16.0]; //Umladen Messwert3
      T     LB    55; 
      L     PEB [AR1,P#17.0]; 
      T     LB    54; 
      L     PEB [AR1,P#18.0]; 
      T     LB    53; 
      L     PEB [AR1,P#19.0]; 
      T     LB    52; 

      L     #DBZ; //ZielDB öffnen
      T     #DBZT; 
      AUF   DB [#DBZT]; 
      L     #ErstDBDZ; //Übergabe Momentane EinstiegsAdresse
      SLW   3; //Schiebe Binr m drei Positionen nach links
      LAR1  ; 
      L     LD    44; //schreibe Werte in ZielDB
      L     1.000000e+003; 
      /R    ; 
      T     DBD [AR1,P#36.0]; 
      L     LD    48; 
      L     1.000000e+003; 
      /R    ; 
      T     DBD [AR1,P#40.0]; 
      L     LD    52; 
      L     1.000000e+003; 
      /R    ; 
      T     DBD [AR1,P#44.0]; 

      U     L      0.3; 
      R     L      0.3; 
      S     L      0.4; 

      L     #ErstPAW; 
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     B#16#7; 
      T     PAB [AR1,P#1.0]; //schreiben von Index=6
      SPA   w6; //zu Bausteinende




w4:   UN    L      0.4; //Messwerttyp 5 Blindleistung
      SPB   w5; 

      L     #ErstPEW; 
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     PEB [AR1,P#1.0]; //Index überprüfen
      L     B#16#7; 
      <>I   ; 
      SPB   x5; 

      ==I   ; 
      SPB   y5; 

x5:   L     #ErstPAW; //schreibe Kennung=6 in erstes PAB
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     B#16#6; 
      T     PAB [AR1,P#0.0]; 

      L     #ErstPAW; //schreiben von Index=7 in zweites PAB
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     B#16#7; 
      T     PAB [AR1,P#1.0]; 
      SPA   w6; 

y5:   L     PEB [AR1,P#8.0]; //Umladen Messwert1
      T     LB    59; 
      L     PEB [AR1,P#9.0]; 
      T     LB    58; 
      L     PEB [AR1,P#10.0]; 
      T     LB    57; 
      L     PEB [AR1,P#11.0]; 
      T     LB    56; 

      L     PEB [AR1,P#12.0]; //Umladen Messwert2
      T     LB    63; 
      L     PEB [AR1,P#13.0]; 
      T     LB    62; 
      L     PEB [AR1,P#14.0]; 
      T     LB    61; 
      L     PEB [AR1,P#15.0]; 
      T     LB    60; 

      L     PEB [AR1,P#16.0]; //Umladen Messwert3
      T     LB    67; 
      L     PEB [AR1,P#17.0]; 
      T     LB    66; 
      L     PEB [AR1,P#18.0]; 
      T     LB    65; 
      L     PEB [AR1,P#19.0]; 
      T     LB    64; 

      L     #DBZ; //ZielDB öffnen
      T     #DBZT; 
      AUF   DB [#DBZT]; 
      L     #ErstDBDZ; //Übergabe Momentane EinstiegsAdresse
      SLW   3; //Schiebe Binr m drei Positionen nach links
      LAR1  ; 
      L     LD    56; //schreibe Werte in ZielDB
      L     1.000000e+003; 
      /R    ; 
      T     DBD [AR1,P#48.0]; 
      L     LD    60; 
      L     1.000000e+003; 
      /R    ; 
      T     DBD [AR1,P#52.0]; 
      L     LD    64; 
      L     1.000000e+003; 
      /R    ; 
      T     DBD [AR1,P#56.0]; 

      U     L      0.4; 
      R     L      0.4; 
      S     L      0.5; 

      L     #ErstPAW; //schreibe Kennung=1 in erstes PAB
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     B#16#1; 
      T     PAB [AR1,P#0.0]; 

      L     #ErstPAW; //schreibe Kennung=22 in erstes PAB
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     B#16#50; 
      T     PAB [AR1,P#1.0]; 

//    L     #ErstPAW                    //schreiben von Starttag = 01 in 20. PAB
//  SLW   3
//  T     #Adr
//    LAR1  
//  L     B#16#1
//  T     PAB [AR1,P#20.0]

//     L     #ErstPAW                    //schreiben von Startmonat = 01 in 21. PAB
//   SLW   3
// T     #Adr
//     LAR1  
//   L     B#16#1
//  T     PAB [AR1,P#21.0]

//    L     #ErstPAW                    //schreiben von Endtag = 31 in 22. PAB
//  SLW   3
//     T     #Adr
//   LAR1  
// L     B#16#1F
//   T     PAB [AR1,P#22.0]

//   L     #ErstPAW                    //schreiben von Endmonat = 12 in 23. PAB
// SLW   3
//     T     #Adr
//   LAR1  
// L     B#16#12
//  T     PAB [AR1,P#23.0]

//  SPA   w6                          //zu Bausteinende




w5:   UN    L      0.5; //Messwerttyp 6 - Wirk- und Blindarbeit
      SPB   w6; 

      L     #ErstPEW; //Kennung überprüfen
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     PEB [AR1,P#0.0]; 
      L     B#16#1; 
      <>I   ; 
      SPB   x6; 

      L     #ErstPEW; //Index überprüfen
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     PEB [AR1,P#1.0]; 
      L     50; 
      <>I   ; 
      SPB   x6; 

      ==I   ; 
      SPB   y6; 

x6:   L     #ErstPAW; //schreibe Kennung=1 in erstes PAB
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     B#16#1; 
      T     PAB [AR1,P#0.0]; 

      L     #ErstPAW; //schreiben von Index=22 in zweites PAB
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     B#16#32; 
      T     PAB [AR1,P#1.0]; 

//      L     #ErstPAW                    //schreiben von Starttag = 01 in 20. PAB
//    SLW   3
//  T     #Adr
//   LAR1  
// L     B#16#1
//      T     PAB [AR1,P#20.0]

//    L     #ErstPAW                    //schreiben von Startmonat = 01 in 21. PAB
//  SLW   3
//      T     #Adr
//    LAR1  
//  L     B#16#4
//T     PAB [AR1,P#21.0]

//      L     #ErstPAW                    //schreiben von Endtag = 31 in 22. PAB
//    SLW   3
//  T     #Adr
//LAR1  
//      L     B#16#1A
//    T     PAB [AR1,P#22.0]

//  L     #ErstPAW                    //schreiben von Endmonat = 12 in 23. PAB
//SLW   3
//      T     #Adr
//    LAR1  
//  L     B#16#4
//T     PAB [AR1,P#23.0]

      SPA   w6; 


y6:   L     PEB [AR1,P#20.0]; //Umladen Messwert1
      T     LB    71; 
      L     PEB [AR1,P#21.0]; 
      T     LB    70; 
      L     PEB [AR1,P#22.0]; 
      T     LB    69; 
      L     PEB [AR1,P#23.0]; 
      T     LB    68; 

      L     PEB [AR1,P#24.0]; //Umladen Messwert2
      T     LB    75; 
      L     PEB [AR1,P#25.0]; 
      T     LB    74; 
      L     PEB [AR1,P#26.0]; 
      T     LB    73; 
      L     PEB [AR1,P#27.0]; 
      T     LB    72; 

      L     #DBZV; //ZielDB öffnen
      T     #DBZVT; 
      AUF   DB [#DBZVT]; 
      L     #ErstDBDZV; //Übergabe Momentane EinstiegsAdresse
      SLW   3; //Schiebe Binr m drei Positionen nach links
      LAR1  ; 
      L     LD    68; //schreibe Werte in ZielDB
      L     1.000000e+003; 
      /R    ; 
      T     DBD [AR1,P#0.0]; 
      L     LD    72; 
      L     1.000000e+003; 
      /R    ; 
      T     DBD [AR1,P#4.0]; 

      U     L      0.5; 
      R     L      0.5; 
      S     L      0.0; 

      L     #ErstPAW; //schreibe Kennung=1 in erstes PAB
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     B#16#6; 
      T     PAB [AR1,P#0.0]; 

      L     #ErstPAW; //schreibe Kennung=1 in erstes PAB
      SLW   3; 
      T     #Adr; 
      LAR1  ; 
      L     B#16#1; 
      T     PAB [AR1,P#1.0]; 
      SPB   w6; 


w6:   NOP   0; //Aktualisierung Schieberegister und Wartetimer
      L     #SCHR; 
      L     #SCHRT; 
      <>I   ; 
      L     S5T#1S; // Laufzeit fest eingestellt 30 Sekunden
      SV    #WTIME; // Takt - Timer  Wartezeit lesen
      L     #SCHRT; 
      T     #SCHR; 



END_FUNCTION
```


----------



## Onkel Dagobert (13 März 2021)

Funktioniert dieser Baustein eigentlich wie gewünscht? Harald hatte in #3 ja schon etwas angemerkt.


----------



## ducati (13 März 2021)

Heinileini schrieb:


> Gegen Setzen/Rücksetzen von Temps ist doch nichts einzuwenden. Die Setz-/RücksetzOrgie muss natürlich innerhalb des GeltungsBereichs der Temps und des Zyklus abgeschlossen sein.



Ja klar, dann aber oben drüber 
CLR
= temp_bool01

Nicht vergessen 😂


----------



## sunny22 (13 März 2021)

Onkel Dagobert schrieb:


> Funktioniert dieser Baustein eigentlich wie gewünscht?


Ich denke schon. Die Werte kommen zumindest dort an wo sie sollen. DBZVT wird nur einmal für eine indirekte Adressierung weiter hinten verwendet. Das beißt sich in diesem Fall nicht.


----------



## Onkel Dagobert (13 März 2021)

sunny22 schrieb:


> Ich denke schon. ..


Na fein, dann lass den Baustein in der laufenden Anlage einfach unverändert (never touch ..), oder deklariere den tatsächlich verwendeten Lokaldatenbereich in der Variablendeklaration mittels Symbolen, so wie es schon vorgeschlagen wurde. Damit wäre die schlimmste Sünde behoben. Für neue Anlagen schreibst du diese Funktion nach deinen eigenen Vorstellungen und nach den Vorschlägen, die du hier bekommst komplett neu. Dann würden wir alle mal lernen, wie man so etwas besser macht.


als erstes sollte man die Schnittstellenbeschreibung des Messgerätes analysieren
Vorschläge ?


----------



## sunny22 (13 März 2021)

Um Gottes Willen, ich habe nicht vor das anzufassen. Neue Anlagen würde ich komplett anders aufschalten.
Aktuell läuft es Mess- und Schaltgeräte -> Profibus -> S7 -> Netzwerk -> OPC Server -> BACNet -> Leittechnik
Die neue Variante wäre Mess- und Schaltgeräte -> Modbus -> Koppelcontroller -> BACNet -> Leittechnik


----------

