Step 7 AWL Bits in einen Byte schreiben

mC_fAkEr

Level-1
Beiträge
1
Reaktionspunkte
0
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo Leute,
ich möchte gerne in einen separaten FC Bits in ein Byte schreiben.
Schnittstelle ist folgendermaßen Eingerichtet:

IN:
I0 BOOL
I1 BOOL
I2 BOOL
I3 BOOL
I4 BOOL
I5 BOOL
I6 BOOL
I7 BOOL

OUT:
Out_Byte Byte

Code:
L #Out_Byte
LAR1

U #I0
= DBX [AR1,P#0.0]

usw....

Liege ich hiermit richtig oder bin ich total auf einen falschen Weg?

Danke und Gruß
Stefan
 
Hallo Stefan,

ein Fehler: Du mußt nicht den Inhalt der Variable in AR1 laden sondern die Adresse --> also "L P##Out_Byte"
noch ein Fehler: das DBX hat beim Schreiben auf den Ausgang nichts zu suchen, #Out_Byte liegt nicht in einem DB
Hinweis: das Byte sollte in TEMP zusammengesetzt werden und erst am Ende auf das Ausgangsbyte der FC kopiert werden.

Besserer Lösungsweg, Du erstellst in TEMP eine Struktur aus Bits, kopierst die 8 Eingangsbits einzeln (!) nacheinander in die TEMP-Bits und kopierst danach das Byte aus der Struktur in das Ausgangsbyte. Dann brauchst Du nur einmal indirekte Adressierung mit AR1:
Code:
FUNCTION FCxxx : BYTE

VAR_INPUT
  I0  : BOOL ;
  I1  : BOOL ;
  I2  : BOOL ;    
  I3  : BOOL ;    
  I4  : BOOL ;    
  I5  : BOOL ;    
  I6  : BOOL ;    
  I7  : BOOL ;    
END_VAR

VAR_TEMP
  tempWord : STRUCT
   Bit_08 : BOOL ;
   Bit_09 : BOOL ;
   Bit_10 : BOOL ;
   Bit_11 : BOOL ;
   Bit_12 : BOOL ;
   Bit_13 : BOOL ;
   Bit_14 : BOOL ;
   Bit_15 : BOOL ;
   Bit_00 : BOOL ;
   Bit_01 : BOOL ;
   Bit_02 : BOOL ;
   Bit_03 : BOOL ;
   Bit_04 : BOOL ;
   Bit_05 : BOOL ;
   Bit_06 : BOOL ;
   Bit_07 : BOOL ;
  END_STRUCT ;
END_VAR

BEGIN
NETWORK
      U     #I0 ;
      =     #tempWord.Bit_00 ;

      ...

      U     #I7 ;
      =     #tempWord.Bit_07 ;

      LAR1  P##tempWord ;
      L     LW [AR1,P#0.0] ;
      T     #RET_VAL ;

Für welche CPU mit welchem Step7 programmierst Du eigentlich? In SCL könnte man das ganze sehr schön per AT lösen, bei S7-1200/S7-1500 geht die indirekte Adressierung sowie AT allerdings nicht bei "optimierten" Bausteinen, dafür aber mit dem Slice-Zugriff.

Verschiedene Lösungen und Irrwege mit old classic Step7 findest Du z.B. hier, den Programmcode für den von Dir angedachten Lösungsweg findest Du da im Beitrag #6

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Für solche Zwecke definier ich mir in der Symboltabelle so etwas:


"XWORD ","MW 90 ","WORD","Zur Umsetzung WORD BYTE BIT "
"XBYTEL ","MB 91 ","BYTE","Low Byte von XWORD "
"XBYTEH ","MB 90 ","BYTE","High Byte von XWORD "
"XBit0 ","M 91.0 ","BOOL","Bit 0 von XWORD "
"XBit1 ","M 91.1 ","BOOL","Bit 1 von XWORD "
"XBit2 ","M 91.2 ","BOOL","Bit 2 von XWORD "
"XBit3 ","M 91.3 ","BOOL","Bit 3 von XWORD "
"XBit4 ","M 91.4 ","BOOL","Bit 4 von XWORD "
"XBit5 ","M 91.5 ","BOOL","Bit 5 von XWORD "
"XBit6 ","M 91.6 ","BOOL","Bit 6 von XWORD "
"XBit7 ","M 91.7 ","BOOL","Bit 7 von XWORD "
"XBit8 ","M 90.0 ","BOOL","Bit 8 von XWORD "
"XBit9 ","M 90.1 ","BOOL","Bit 9 von XWORD "
"XBit10 ","M 90.2 ","BOOL","Bit 10 von XWORD "
"XBit11 ","M 90.3 ","BOOL","Bit 11 von XWORD "
"XBit12 ","M 90.4 ","BOOL","Bit 12 von XWORD "
"XBit13 ","M 90.5 ","BOOL","Bit 13 von XWORD "
"XBit14 ","M 90.6 ","BOOL","Bit 14 von XWORD "
"XBit15 ","M 90.7 ","BOOL","Bit 15 von XWORD "
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Für solche Zwecke definier ich mir in der Symboltabelle so etwas:


"XWORD ","MW 90 ","WORD","Zur Umsetzung WORD BYTE BIT "
"XBYTEL ","MB 91 ","BYTE","Low Byte von XWORD "
"XBYTEH ","MB 90 ","BYTE","High Byte von XWORD "
"XBit0 ","M 91.0 ","BOOL","Bit 0 von XWORD "
...
Statt froh zu sein, dass dank lokaler Variablen sowas inzwischen frei von Seiteneffekten relativ einfach programmiert werden kann, werden einem Anfänger Steinzeitmethoden empfohlen, die vielleicht Jahre spater zu Fehlern führen. Toll!
Gruß
Erich
 
Zuletzt bearbeitet:
Wenn man schon unbedingt im Stil der ollen Schmiermerker absolut adressiert programmieren will, dann sollte man für das Byte-Zusammenbasteln wenigstens den Lokaldatenbereich (TEMP) nehmen. Bei Verwendung globaler Merker ist das Bit-Gebastel nicht Task-safe, d.h. jede OB-Ebene müsste seinen eigenen Schmiermerkerbereich bzw. eine eigene Bit-Bastel-Function haben.

Byte-Zusammenbasteln in TEMP ohne Pointer (daß die Bit- und Byte-Zugriffe die richtigen Adressen treffen muß man selber drauf achten!):
Code:
      U     #I0 ;
      =     #temp_Bit_00 ; //muß an L0.0 liegen

      ...

      U     #I7 ;
      =     #temp_Bit_07 ; //muß an L0.7 liegen

      L     LB 0 ;
      T     #RET_VAL ;

Harald
 
Statt froh zu sein, dass dank lokaler Variablen sowas inzwischen frei von Seiteneffekten relativ einfach programmiert werden kann, werden einem Anfänger Steinzeitmethoden empfohlen, die vielleicht Jahre spater zu Fehlern führen. Toll!
Gruß
Erich

Ich habe es vorher mit Lokalvariablen gemacht, aber da diese auch mit temporären Variablen belegt werden, sind feste Merker gerade in Bezug auf Seiteneffekte sicherer.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Die alten Römer konnten das auch ohne Schmiermerker, Adressregister oder Absolutzugriffe auf Lokaldaten. :ROFLMAO:

Code:
L	0
T	Temp_Byte


//---------------------- Bit 0
	U	I0
	SPBN	Bit1


	L	TempByte
	OW	W#16#01
	T	TempByte


//---------------------- Bit 1
Bit1:	U	I1
	SPBN	Bit2


	L	TempByte
	OW	W#16#02
	T	TempByte


//---------------------- Bit 2-6
...
...


//---------------------- Bit 7
Bit7:	U	I7
	SPBN	MEnd


	L	TempByte
	OW	W#16#80
	T	TempByte




//---------------------- Ausgangswert übertragen
	L	TempByte
	T	RET_VAL
 
Ich habe es vorher mit Lokalvariablen gemacht, aber da diese auch mit temporären Variablen belegt werden, sind feste Merker gerade in Bezug auf Seiteneffekte sicherer.
Also ich würde ein solches Szenario absolut nicht als "sicherer" bezeichnen:
- im OB1 wird in M90.0-M90.7 ein Byte zusammengebastelt
- dabei wird es vom OB35 oder OB40 unterbrochen, welcher ebenfalls in M90.0-M90.7 ein Byte zusammenbastelt
- nachdem OB35/OB40 abgearbeitet wurde kehrt das Programm zum OB1 zurück, wo die angefangene Bastelei vollendet wird und der nun in M90.0-M90.7 vorhandene Inhalt weiterverarbeitet wird

Mit Basteln in TEMP würde es nicht zu diesem Seiteneffekt kommen.

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
d.h. jede OB-Ebene müsste seinen eigenen Schmiermerkerbereich bzw. eine eigene Bit-Bastel-Function haben.
Was ist daran ein Problem? Der Merkerbereich ist doch groß genug im Verhältnis zur Zahl der möglichen DB's
Wenn Du (wie hier eigentlich angefragt wurde) einen FC zur Kapselung der Aufgabe schreiben sollst, dann brauchst Du für jeden OB eine andere Version des FC. Mit Verwendung von Lokaldaten reicht nur eine Version.

Harald
 
Die alten Römer konnten das auch ohne Schmiermerker, Adressregister oder Absolutzugriffe auf Lokaldaten. :ROFLMAO:
Bei den alten Römern gab es noch keine Lokaldaten (deshalb hat Siemens die Schmiermerker erfunden), die alten Römer mußten ganz ohne Lokaldaten auskommen:
Code:
      L     0

      U     #I0
      SPBN  Bit1
      OW    W#16#01

Bit1: U     #I1
      SPBN  Bit2
      OW    W#16#02
...

Bit7: U     #I7
      SPBN  OutB
      OW    W#16#80
OutB: T     #RET_VAL


Falls es bei den alten Römern eine Anweisung gab, wie man einfach das VKE ins A1 bekommt :confused:, dann könnten sie sich das Byte auch zusammen-rotiert haben ganz ohne Sprünge.

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Wenn Du (wie hier eigentlich angefragt wurde) einen FC zur Kapselung der Aufgabe schreiben sollst, dann brauchst Du für jeden OB eine andere Version des FC. Mit Verwendung von Lokaldaten reicht nur eine Version.

Harald

Da haben wir uns missverstanden. Für einen solchen FC würde ich natürlich auch Lokalvariablen verwenden. Nur halte ich einen solchen FC selten für sinnvoll. Wenn man ein Programm selbst konzipiert, ist ein STRUCT bzw UDT aus BOOLs da die bessere Wahl. Oder ein ARRAY von BOOLs, wenn es um eine größere Anzahl ähnlicher Signale geht.

Mir ging es eher darum, in einem größeren FC oder FB einfach auf Bits einer Variablen zuzugreifen, die als BYTE oder WORD deklariert ist. AWL ist in dieser Hinsicht ja ziemlich ärmlich, so etwas wie unions oder casts in C gibt es ja leider nicht, man kann nichtmal ein INT als WORD lesen oder umgekehrt. Ich brauchte das für die Erweiterung eines Fremdprogramms, in dem Fehler von Messungen jeweils in einer WORD-Variablen gespeichert waren, von denen ich aber nur ein Bit für Störmeldungen brauchte. Erst hatte ich das mit Lokalvariablen gelöst:
Code:
L "DB_Mess_Err".XXX; T LW 8 ;U L 9.7; = Stoerbit[21];

In anderen Bausteinen waren aber mehr temporäre Variablen, so dass Kollisionen damit möglich wären. Man müsste jedesmal ausrechnen, wo noch freie Lokalmerker sind. Deshalb bin ich umgestiegen auf die Merker.
Code:
L "DB_Mess_Err".XXX; T "XWORD" ;U "XBit7"; = Stoerbit[21];

Außerdem ist damit klarer, dass es sich um Bit 7 des WORDs handelt. Bei der Lokaldatenversion muss man aufpassen, dass man nicht L 8.7 , also Bit15 abfragt.

Die Bausteine werden nur von OB1 aufgerufen, dass man in anderen OB-Tasks nur andere Schmiermerker verwenden darf, ist mir klar.
 
man kann nichtmal ein INT als WORD lesen oder umgekehrt.
?
Alles was du in die Akkus beförderst ist dort WORD/DWORD. AWL interessiert sich sowieso nicht für Datentypen.

Code:
L "DB_Mess_Err".XXX; T "XWORD" ;U "XBit7"; = Stoerbit[21];
Code:
L "DB_Mess_Err".XXX; T LW 8 ;U L 9.7; = Stoerbit[21];
Genau was PN/DP meinte. Wenn du die erste Variante in verschiedenen Tasks laufen lässt hast du Brösel.

Die zweite Variante ist halt auch die denkbar schlechteste Variante die man in AWL machen kann.
Die Verwendung von absoluten L-Adressen ist genauso wenig schlau wie absolute M-Adressen.
Bei beiden Datenbereichen hast du die Möglichkeit von Kollisionen wenn das Restprogramm drauf zugreift.

Wie wäre es mit...
Code:
//Wie die alten Römer
      L     "DB_Mess_Err".XXX
      UW    W#16#8000
      U     >0
      =     Stoerbit[21]


//Lokal mit AR-Zugriff
      L     "DB_Mess_Err".XXX
      T     #TEMP_WORD
      LAR1  P#TEMP_WORD
      U     [AR1,P#0.7]
      =     Stoerbit[21] 

//Oder separat gekapselt - Schönste Lösung, vor allem wenn du es sowieso mehrfach brauchst.
      CALL  "GetBitfromWORD"
       IN:="DB_Mess_Err".XXX
       n :=7
       Q :=Stoerbit[21]
Alles Möglichkeiten ohne Absolutzugriffe.

Die Bausteine werden nur von OB1 aufgerufen, dass man in anderen OB-Tasks nur andere Schmiermerker verwenden darf, ist mir klar.
Gut, ist auch deinem Nachfolger/Kollegen klar wenn der irgendwann man dran muss?
Funktionieren tut es schon sofern mann sich an die Rahmenbedingungen hält. Sauber ist es halt nicht.
Weiterempfehlen würde ich es halt nicht.
 
Zuletzt bearbeitet:
Wenn man ein Programm selbst konzipiert, ist ein STRUCT bzw UDT aus BOOLs da die bessere Wahl. Oder ein ARRAY von BOOLs, wenn es um eine größere Anzahl ähnlicher Signale geht.
[...]
Erst hatte ich das mit Lokalvariablen gelöst:
Code:
L "DB_Mess_Err".XXX; [COLOR="#FF0000"]T LW 8 ;U L 9.7;[/COLOR] = Stoerbit[21];

In anderen Bausteinen waren aber mehr temporäre Variablen, so dass Kollisionen damit möglich wären. Man müsste jedesmal ausrechnen, wo noch freie Lokalmerker sind.
Man muß nicht rechnen wenn man symbolisch programmiert, anstatt absolut adressiert im Speicher 'rumzuschmieren. Wie Du selbst erwähnt hast ist z.B. STRUCT die bessere Wahl. Auch in AWL kann man STRUCT und ARRAY deklarieren und auf deren Member symbolisch zugreifen. Schon im Beitrag #2 habe ich gezeigt, wie man eine Bit-Struktur in Lokaldaten richtig verwendet. Bei dem Code ist es egal, auf welcher Adresse in TEMP das WORD (STRUCT aus BOOLs) zum zusammenbasteln liegt, der Code wird vom AWL-Compiler automatisch auf die richtigen Adressen angepasst weil der Code symbolisch adressiert. Den Code kann man normalerweise problemlos in andere Bausteine einfügen (wenn diese sauber programmiert sind und nicht bereits absolut adressierte Zugriffe machen, so wie Du es versucht hast).

Hier kannst Du den Code für ein ganzes WORD finden: 16 Bits in WORD zusammenfassen via STRUCT in TEMP
Das geht natürlich auch umgekehrt: symbolisch auf Bits in einem WORD zugreifen via STRUCT in TEMP

Wenn man nur auf ein Bit eines WORD zugreifen will, dann braucht man noch nichtmal in TEMP-Speicher umkopieren sondern kann das Bit direkt im AKKU ausmaskieren oder in das A1-Statusbit schieben:
Code:
L     #MyWord
UW    W#16#80    //Bit .7 maskieren
U     <>0
=     #MyBit

// oder

L     #MyWord
SRW   8          //Bit .7 in A1 schieben
U     <>0
=     #MyBit

Harald
 
Zuviel Werbung?
-> Hier kostenlos registrieren
...In anderen Bausteinen waren aber mehr temporäre Variablen, so dass Kollisionen damit möglich wären. Man müsste jedesmal ausrechnen, wo noch freie Lokalmerker sind. Deshalb bin ich umgestiegen auf die Merker.
Wenn man versucht, den Inhalt temporärer Variablen über einen Aufruf eines FC oder FB hinaus im nächsten Zyklus weiter zu verwenden, dann ist das kein Seiteneffekt, wie Du weiter oben behauptet hast, sondern Unvermögen der Programmierers.
Gruß
Erich
 
Ich glaube, das Unvermögen von Machtnix besteht nicht in der speichernden Verwendung von temporären Variablen, sondern im symbolischen Ansprechen von überlappenden TEMP-Speicheradressen. Das beherrscht er nur bei M-Speicher und deshalb hat er sich anfangs unbelegten L-Speicher gesucht, wo er nach Herzenslust absolut adressiert drauf zugreifen kann, ohne andere temporäre Variablen zu überschreiben. Doch irgendwann wurde wohl beim Wiederverwenden der Schmiermerker-Idee dieses manuelle Suchen zu lästig und fehleranfällig und weil er die symbolische Lösung nicht kannte ist er dann auf globalen M-Speicher umgeschwenkt.

Harald
 
Man muß nicht rechnen wenn man symbolisch programmiert, anstatt absolut adressiert im Speicher 'rumzuschmieren.[ /QUOTE]

Ja, genau auch deshalb hab ich lieber Merker genommen, die ich per Symboltabelle benennen kann.

Mit temporären Variablen geht der Zugriff auf die nicht deklarierten Typen wieder nur umständlich über Pointer.
 
Zuletzt bearbeitet:
Zurück
Oben