Ablegen der Ein- und Ausgänge im DB !

SHendrik

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

Möchte mit meiner S7-300 ein Gebäudesteuerung bauen.
Dabei möchte ich für jede Anwendung z.B. Rollladen eine Funktion erstellen.
Diese wird nur mit einem DB_index aufgerufen.

In diesem DB stehen dann die Eingänge(Taster) / Ausgänge / Merker und Timer für diesen Kanal.

Auf den DB zugreifen ist kein Problem.

Habe mir das in der Funktion so vorgestellt :

AUF DB [#DB_index]
LAR1 P#0.0
O DBX [AR1,P#0.0]; //Taster
.....

Nur habe ich keine Ahnung, wie ich im DB sage, dass dort E 0.0 verwendet wird. Dort gibt es ja nur bool ??

Hoffe auf Eure Hilfe ...

Hendrik
 
Hallo SHendrik,
ich verstehe nicht ganz was du meinst.

Die Eingänge bzw. Ausgänge schreibe ich normalerweis mit den und Befehl in den DB:

U E12.3
= DB1.DBX.0.0
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Hallo SHendrik,
ich verstehe nicht ganz was du meinst.

Die Eingänge bzw. Ausgänge schreibe ich normalerweis mit den und Befehl in den DB:

U E12.3
= DB1.DBX.0.0
 
Sorry, vielleicht habe ich mich nicht richtig ausgedrückt !

Ich würde gern die Verweise auf die Hardware Ein und Ausgänge SM321/SM322, die bei mir E0 und A8 sind über eine Funktion beschreiben.

Die Konfiguration welcher Ein- bzw. Ausgang verwendet wird möchte ich aber im DB machen, um die eine Funktion für alle 10 Rollläden zu verwenden und dann nur die Funktion mit unterschieldichen DB_index 'en aufzurufen.

Daher sehen meine Abfragen nicht so:

O E0.0

sondern so aus

O DBX [AR1,P#0.0];

nun muss ich wahrscheinlich den E 0.0 noch im DB als ersten definieren.

Und genau damit kenne ich mich nicht aus.


Gruß

Hendrik
 
Indirekte Adressierung

Hallo,

für die Bitweise Zuordnung habe sind bereits genügt Beispiele vorhanden. Da meistens die E/A häufig hinter einander liegen, würde sich Byte/Word/Dword Umspeicherungen anbieten, dazu paar Beispiele:

Code:
      L     EB     0
      T     DBB [AR1,P#0.0]

      L     EB [MD   100]
      T     DBB [MD   104]


      L     EW     0
      T     DBW [AR1,P#0.0]

      L     EW [MD   100]
      T     DBW [MD   104]


      L     ED     0
      T     DBD [AR1,P#0.0]

      L     ED [MD   100]
      T     DBD [MD   104]




      L     PEB    0
      T     DBB [AR1,P#0.0]

      L     PEB [MD   100]
      T     DBB [MD   104]


      L     PEW    0
      T     DBW [AR1,P#0.0]

      L     PEW [MD   100]
      T     DBW [MD   104]


      L     PED    0
      T     DBD [AR1,P#0.0]

      L     PED [MD   100]
      T     DBD [MD   104]
Die PEB/PEW/PED werden für den Peripheriebereich verwendet, die je nach CPU ab 128/256/512 variieren kann, oder vom Programmierer eingestellt werden kann.

Wenn du noch fragen hast, melde dich einfach.
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Sorry, aber ich muss doch nochmal nachfragen.

Das Ziel ist es ein Programm zur Rollladensteuerung zu schreiben.

Dabei möchte ich eine Funktion erstellen, die die ganze Funktionalität enthält.

In dieser sollen aber keine Ein- und Ausgänge direkt programmiert sein.

Diese sollen im DB sein.

Somit könnte ich mit mehreren DB's mehrere Rollläden steuern.

Funktion sollte dabei so sein :

Im DB steht auf der entsprechenden Stelle ein Verweis auf den Eingang

Von der Funktion greife ich nur über einen Zeiger auf den DB und damit auf den Eingang zu ...

Ich möchte nicht erst alle Eingänge abfragen und das Ergebnis in den DB schreiben müssen.

Ich will nur dort einen Zeiger auf den Eingang und Ausgang hinterlegen.

Leider habe ich noch sehr wenig Erfahrung mit der SPS, aber in der Microcontroller Welt geht so was.

Sorry, dass ich nochmal nachfragen ...

Gruß

Hendrik
 
Hallo!

Ich würde Dir dazu raten deine Problemstellung mit einem FB und Instanz-DB zu lösen.
In diesem FB programmierst Du dann die Funktionalität wie Du sie möchtest, ungefähr so...

UN #Rolladen unten
U #Rolladen soll runter
S #Rolladen runter

U #Rolladen unten
R #Rolladen soll runter
...

Wenn Du nun diesen Funktionsbaustein von einem FC aus aufrufst, dann sieht das ungefärh so aus...

Call FB10; DB10
#Rolladen unten = E1.0
#Rolladen soll runter = E1.1
#Rolladen oben = E1.2
...

Dieses Call FB10... brauchst Du ja sicherlich öfters, einmal für jeden Rolladen... genau so ordnest Du dann ja bei dem Aufruf für jeden Rolladen auch die zugehörigen Endschalter und Befehlsstellen zu...

Ich hab das aus dem Gedächtnis geschildert, ich hoffe ich hab keinen Fehler eingebaut...

Viele Grüße, Tobias
 
Hallo.

Das kommt schon in die Richtung.
Wenn ich es richtig verstanden habe, muss ich dann bei jedem Aufruf
die Eingänge mit übergeben.

Wenn ich das im DB speichern könnte hätte ich dann eine saubere Trennung zwischen Konfig und Programm ...

Gruß

Hendrik
 
Zuviel Werbung?
-> Hier kostenlos registrieren
SHendrik schrieb:
Hallo.

Das kommt schon in die Richtung.
Wenn ich es richtig verstanden habe, muss ich dann bei jedem Aufruf
die Eingänge mit übergeben.

Wenn ich das im DB speichern könnte hätte ich dann eine saubere Trennung zwischen Konfig und Programm ...

Weder das eine noch das andere hat hier seine Richtigkeit. Grundsätzlich ist das möglich, in einem DB die Bereichszeiger abzulegen, die auf die Peripherie verweisen. Über einen Index spricht man den geplanten Bereich an und kann so die Peripherie lesen und schreiben, was damit der Frage deines Threadaufmachers entspricht.
Nur hat das einen entscheidenden Nachteil, das man sich damit fast aller Möglichkeiten einer schnellen Fehlersuche beraubt.

Das ganze in einen FB zu verpacken ist auch nicht das Gelbe vom Ei, aus meiner Sicht ist ein FC völlig ausreichend, und für jeden Rolladen errichtest du eine Instanz dieses FC. Wenn man das richtig codet, kommt dann sogar ganz ohne DB aus.

Gruß Barnee
 
Hallo.

Danke für die Antworten.

Mich würde trotzdem interessieren, wie das mit den Verweisen im DB
auf die Ein- / Ausgängen geht ??

Gruß

Hendrik
 
Zuviel Werbung?
-> Hier kostenlos registrieren
@SHendrik
Ich habe mal was aus meiner Schatztruhe gekramt. Bei der Anwendung waren ca. 200 Ventile zu steuern und zu kontrollieren. Der Ventilzustand wurde auf einem großen Fließbild per LED angezeigt. Ich habe damals die EA-Liste per Excel erfasst und konnte so den nachstehenden Quelltext für den DB erzeugen, in dem das liegen würde, was du als Konfig bezeichnest.
Das mit Excel zu machen bietet sich an, weil das bei der Masse sicher fehlerfrei abläuft wenn man die Anfangsbelegung der Datenworte aus den EA-Adressen errechnet:
W#16#01E1 entspricht 60.1, bzw. W#16#01E1 = 481 = 60 * 8 + 1
Ein bereichsinterner Zeiger besteht "normalerweise" aus 4 Byte, ich hatte für meine Zwecke aber nur die "unteren" 2 Byte hergenommen, weil in den "oberen" 2 Byte eh nur Nullen gestanden wären.
Aus nahe liegenden Gründen habe ich nachfolgend den DB-Quelltext nur für die 1. Ventileinheit dargestellt:
Code:
DATA_BLOCK "VENTIL_PARM"
TITLE =Ventilüberwachung
AUTHOR : HL
FAMILY : Ventile
VERSION : 0.1

  STRUCT
   V001_FRG     : BYTE   := B#16#01;	//Freigabe Ventil 001
   V001_FLAGS   : BYTE   := B#16#01;	//Flags Ventil 001
   V001_ES1     : WORD   := W#16#01E0;	//Endschalter ZU Ventil 001
   V001_ES2     : WORD   := W#16#01E1;	//Endschalter AUF Ventil 001
   V001_LED1    : WORD   := W#16#007C;	//LED rot ZU Ventil 001
   V001_LED2    : WORD   := W#16#007D;	//LED grün AUF Ventil 001
   V001_MV      : WORD   := W#16#0320;	//MV-Spule Ventil 001
   V001_ZKT     : INT    := 30;	       //Zeitparm. Ventil 001

  END_STRUCT ;	
BEGIN
   V001_FRG     := B#16#01;
   V001_FLAGS   := B#16#01;
   V001_ES1     := W#16#01E0;
   V001_ES2     := W#16#01E1;
   V001_LED1    := W#16#007C;
   V001_LED2    := W#16#007D;
   V001_MV      := W#16#0320;
   V001_ZKT     := 30;
   V001_TIMER   := L#0;

END_DATA_BLOCK
Man hätte für jede Ventil-Instanz auch einen eigenen DB machen und dann jeweils eine Instanz eines FC oder FB anwenden können. Ich hab mir aber lästige Tipparbeit erspart - das Eintippen der EA-Liste in die Excelliste war schon Arbeit genug und habe mir daher nur einen DB für "alle" Ventileinheiten gegönnt. Man kann mit ein paar simplen Tricks aus der Excelliste direkt den Quelltext für den DB erzeugen, der Quelltext wird dann in die AWL-Umgebung importiert und übersetzt und das war's dann. So konnte ich mir sicher sein, bei der Umsetzung der EA, die geringst mögliche Fehlerrate zu haben.

Wenn also die Ventileinheiten systematisch in dem DB abgebildet wurden, dann war es nahe liegend, die Ventileinheiten mit einer Schleife abzufragen. Um die Zykluszeiten nicht über Gebühr zu belasten, habe ich die Auswertung insgesamt auf 3 Zyklen verteilt, deshalb habe ich 3 Instanzen des FCs verwendet, den ich nachstehend in Ausschnitten zeige.

Man hätte auch anstelle des FC einen FB verwenden können, aber das war in der vorliegenden Anwendung eher eine Frage des Geschmacks, bei einem FB hätte man den Parameter "LastTime" als "VAR" somit statisch anlegen können, das wär's dann aber auch schon gewesen:
Code:
FUNCTION "MV_CNTRL" : VOID
TITLE =Ventilkontrolle
AUTHOR : HL
FAMILY : Ventile
VERSION : 0.1

VAR_INPUT
  Count        : INT ;	        // Schleifenzahl
  Start        : INT ;	        // Byte-Zeiger auf 1. Ventileinheit
  DB_NUM       : INT ;	        // Nummer des Datenbausteins
  RefTime      : DINT ;	        // Zeitreferenz in Millisekunden
END_VAR

VAR_IN_OUT
  LastTime     : DINT ;	        // Zeit beim letzten Zugriff
END_VAR

VAR_TEMP
  LOOPER       : INT ;	        // Schleifenzähler
  SWX01        : INT ;	        // Schmiermerker
  SWX02        : INT ;	        // Schmiermerker
  PTR1         : DWORD ;	        // temp. Zeiger
  PTR_FRG      : DWORD ;	        // Zeiger auf Freigabe
  PTR_LED1     : DWORD ;	        // Zeiger auf LED 1
  PTR_LED2     : DWORD ;	        // Zeiger auf LED 2
  PTR_ZKT      : DWORD ;	        // Zeiger auf Zeitparameter
  PTR_TIMER    : DWORD ;	        // Zeiger auf Zeitzelle
  deltaTime    : DINT ;	        // Differenzzeit seit letztem Zugriff
  ES1          : BOOL ;	        // Kopie von Endschalter 1
  ES2          : BOOL ;	        // Kopie von Endschalter 2
  MV           : BOOL ;	        // Kopie von Ventil-Ansteuerung
  STOEM        : BOOL ;	        // Störmeldung
  SAVE_DBNO    : WORD ;
  SAVE_AR1     : DWORD ;
  SAVE_AR2     : DWORD ;
END_VAR

Das war eine reine Vorsichtsmaßnahme (Registerinhalte retten) in dem ganzen Projekt, um irgendwelche Kollisionen zu vermeiden und hat damit jedes weitere Nachdenken überflüssig gemacht:
Code:
BEGIN

NETWORK
TITLE =Registerinhalte retten

      L     DBNO;
      T     #SAVE_DBNO;
      TAR1  #SAVE_AR1;
      TAR2  #SAVE_AR2;

Hier wurden alle internen Zeiger für einen Durchlauf bei der Bearbeitung einer Ventileinheit bestimmt:
Code:
NETWORK
TITLE =Lampenansteuerung für 2-Stellungsventile

// Datenbaustein mit den Parametern für die Indizierung aufschlagen
      L     #DB_NUM;
      T     #SWX01;
      AUF   DB [#SWX01];

      L     #Start;
      T     #SWX01;	// DBB-Index auf 1. Ventileinheit

      L     #Count;	// Anzahl der Durchgänge
LOPM: T     #LOOPER;

      L     #SWX01;	// DBX-Index auf Ventileinheit
      SLD   3;
      T     #PTR_FRG;	// Zeiger auf Freigabe
      LAR1  ;

      +     L#96;	// = 12 * 8
      T     #PTR_ZKT;	// Zeiger auf Zeitparameter

      +     L#16;	// = 2 * 8
      T     #PTR_TIMER;	// Zeiger auf Zeitzelle

Und hier siehst du z.B. die Auswertung für die Ventilendschalter. Der erste Ladebefehl holt den "bereichsinternen Zeiger" aus dem DB. Merke: im AR1 verweist der Zeiger auf den 1. Datenpunkt der aktuellen Ventileinheit, der bereichsinternen Zeiger für den 1. Endschalter steht im 3. und 4. Byte, deshalb "P#2.0", äquivalent muss es dann für den 2. Endschalter “P#4.0“ heißen. Da ich noch reichliche Bitbumserei mit den Valenzen betrieben habe (hier nicht weiter dargestellt), habe ich die Valenzen der Ein- Und Ausgänge teilweise in temporären lokalen Variablen abgelegt, weil ein Zugriff mit "E [#PTR1]" mehr Zeit kostet als ein Zugriff auf "#ES1" usw.usf.:
Code:
      L     DBW [AR1, P#2.0];
      T     #PTR1;
      U     E [#PTR1];
      =     #ES1;	// Valenz von Endschalter 1

      L     DBW [AR1, P#4.0];
      T     #PTR1;
      U     E [#PTR1];
      =     #ES2;	// Valenz von Endschalter 2
Code:
      O(    ;
      UN    #MV;	// Ventil-Ansteuerung
      UN    #ES1;	// Endschalter 1
      )     ;
      O(    ;
      U     #MV;	// Ventil-Ansteuerung
      UN    #ES2;	// Endschalter 2
      )     ;
      SPBN  ANFT;	// Zelle auf Startwert einstellen

Wie aus der FC-Schnittstelle ersichtlich, habe ich für verschiedene Ausgänge den "bereichsinternen Zeiger" in temporären Variablen abgelegt, weil Ausgänge weniger oft verknüpft werden. Eine Ventileinheit hat in dieser Anwendung 18 Byte belegt, klar das vor der Ausführung der Schleifenbedingung, der Zeiger auf den Beginn der nächsten Ventileinheit entsprechend eingestellt werden muss:
Code:
// Lampenprüfung
LAUS: SET   ;
      R     A [#PTR_LED1];	// LED 1
      R     A [#PTR_LED2];	// LED 2
LMPT: U     "DT_LED_TEST";	// Lampenprüfung
      S     A [#PTR_LED1];	// LED 1
      S     A [#PTR_LED2];	// LED 2
// ----------------------------------------------
      L     #SWX01;	// DBX-Index auf aktuelleVentileinheit
      +     18;
      T     #SWX01;	// DBX-Index auf nächste Ventileinheit

      L     #LOOPER;
      LOOP  LOPM;

Nachdem der FC seine eigentliche Arbeit beendet hat, wird der Zustand wieder eingestellt, der in den AR-Registern vor der Ausführung des Baustein vorhanden war:
Code:
NETWORK
TITLE =Registerinhalte wiederherstellen

      AUF   DB [#SAVE_DBNO];
      LAR1  #SAVE_AR1;
      LAR2  #SAVE_AR2;

END_FUNCTION

Nachstehend siehst du den Aufruf der 1. Instanz des FC:
Code:
      CALL "MV_CONTRL" (
            Count                   := 74,	// Schleifenzahl
            Start                   := 0,	// Byte-Zeiger auf 1. Ventileinheit
            DB_NUM                  := 3,	// Nummer des Datenbausteins
            RefTime                 := "REFTIME",	// Zeitreferenz in Millisekunden
            LastTime                := "LAST1");	// Zeit beim letzten Zugriff

Nachstehend siehst du den Aufruf der 2. Instanz des FC. Der Start der 75. Ventileinheit liegt bei 74 * 18 = 1332, 74 Ventile waren beim 1. Durchlauf bearbeitet worden, 18 Byte ist die Blockgröße einer Ventileinheit im Konfig-DB:
Code:
      CALL "MV_CONTRL" (
            Count                   := 74,	// Schleifenzahl
            Start                   := 1332,	// Byte-Zeiger auf 75. Ventileinheit
            DB_NUM                  := 3,	// Nummer des Datenbausteins
            RefTime                 := "REFTIME",	// Zeitreferenz in Millisekunden
            LastTime                := "LAST2");	// Zeit beim letzten Zugriff

In etwa entspricht das deinen Anforderungen zur Rolladensteuerung, die Konfiguration liegt in einem DB, das Programm versorgt sich mit EA-Zeigern aus dem DB.
Das ganze hat aber erhebliche Nachteile:
1. Keine dieser in dem FC angesprochenen EAs wird jemals in einem Querverweis auftauchen.
2. Bei Änderungen in der EA-Belegung wird's knifflig, wenn man das zu Fuß machen will.

Ich hoffe ich konnte dir helfen.

Gruß Barnee und noch ein schönes Rest-WE
 
Hallo!

Ich denke das was Du da forderst wird so nicht gehen...
Wenn ich Dich richtig verstandne habe, dann möchtest Du in dem Datenbaustein Eingänge und Ausgänge eintragen. In dem Datenbaustein stehen aber nur Variable zur Verfügung, so dass Absolute Adressen hier nicht eingetragen werden können.
Man kann sich dabei nur behelfen, indem man über Umwege eine zuordnung aufstellt, ähnlich

U E1.0
= DB10.DBX1.0

Dabei denke ich aber das man sich auf Grund der zusätzlichen Schnittstelle nur eine Fehlerquelle programmiert, welche dem Programm auch noch die Überischtlichkeit nimmt...

Wenn Du "nur" eine zusätzliche Möglichkeit brauchst, um eventuell einfach zwei Bedienstellen zu "tauschen", dann hast Du die Möglichkeit dieses über einfache Merker, ja sogar über den Datenbaustein, zu lösen.

Dann kannst Du z.B. sagen

U E1.0 //Endschalter Rollo Küche oben
U E1.1 //Endschalter Rollo Küche unten
U E1.2 //Endschalter Rollo Wohnzimmer oben
U E1.3 //Endschlater Rollo Wohnzimmer unten

dieses währe ja Deine "Verdrahtung", so wie man die halt Hardwaremäßig angeschlossen hätte....
Dann einfach

U E1.0
= M1.0

U E1.1
= M1.1
...

oder

U E1.0
= DB10.DBX1.0

U E1.1
= DB10.DBX1.1

...

dann hast Du die Möglichkeit einfach mittels dieser Zuordnung gewisse Endschalter, Taster oder was auch immer anderen Rolläden zuzuordnen, ohne ich das eigendliche Programm zu gehen...

Direkt aus dem Datenbaustein auf einen Eingang oder Ausgang Einwirken bzw. Abfragen ist meines Wissens nacht nicht möglich...

Viele Grüße, Tobias
 
@ Tobias

lefrog schrieb:
Hallo!

Ich denke das was Du da forderst wird so nicht gehen...
Wenn ich Dich richtig verstandne habe, dann möchtest Du in dem Datenbaustein Eingänge und Ausgänge eintragen. In dem Datenbaustein stehen aber nur Variable zur Verfügung, so dass Absolute Adressen hier nicht eingetragen werden können.

Ich geb dir mal den Tipp, sich mit "bereichsinternen Zeigern", "bereichsübergreifenden Zeigern" und überhaupt mit dem ANY-Zeiger zu beschäftigen. Dann lässt du das oben gesagte so nicht mehr stehen. In einer Variablen eines DBs kann man sehr wohl Zeiger speichern und bei der Anwendung spricht man je nach Ausführung und Art der Zeiger von "speicherindirekte Adressierung mit Bereichszeiger", "registerindirekte bereichsinterne Adressierung" oder "registerindirekte bereichsübergreifende Adressierung"!
In meinem zuvor gezeigten Beispiel habe ich die "speicherindirekte Adressierung mit Bereichszeiger" angewendet! Also wo ist das Problem?

Gruß Barnee
 
unzumutbar

@barnee

aus meiner Sicht ist das für den Instandhalter unzumutbar was du da abgeliefert hast. Gesund wäre wenn man alle E/A am FC parametriert. Und das sollte SHendrik auch tun. Warum so umständlich machen??

MfG
André Räppel
 
Hallo!

Gut - ich habe wiedereinmal was dazugelernt... nur wie Andre das auch sieht, für einen Instandhalter mehr wie unzumutbar... Ich jedenfalls halte das nicht wirklich für übersichtlich...

Viele Grüße, Tobias

EDIT: Ich bleibe aber dabei, ich kann in einen Datenbaustein nicht direkt Eingänge oder Ausgänge reinschreiben - wie E1.0 oder A12.3. Alles was mit irgendwelchen Zeigern passiert geht zu lasten der Übersichtlichkeit. Und ich wage zu behaupten das der Fragesteller keine 200 Rolläden verwalten möchte...
 
Zuviel Werbung?
-> Hier kostenlos registrieren
Re: unzumutbar

sps-concept schrieb:
@barnee

aus meiner Sicht ist das für den Instandhalter unzumutbar was du da abgeliefert hast. Gesund wäre wenn man alle E/A am FC parametriert. Und das sollte SHendrik auch tun. Warum so umständlich machen??

MfG
André Räppel

Hallo André
da geb ich dir völlig recht. Ich selbst hatte ja am Schluss meines Beitrages ausdrücklich darauf hingewiesen, welche Nachteile man sich mit dieser Methode einhandelt.

Aber in der Not frisst der Teufel manchmal fliegen....Der Kunde hatte damals sein Projekt ständig ausgeweitet und irgendwann bekam ich ein Grummeln im Bauch, ob die CPU das noch alles packen würde. Wenn ich die Möglichkeit zu Anfang des Projektes gehabt hätte, die Ausmaße richtig einschätzen zu können, dann hätte ich gleich von Anfang an 2 SPSen eingeplant. Durch diese Methode konnte Speicherplatz und Zykluszeit eingespart werden.

Ob sich das Verfahren allerdings für 10 Rolladen rechnet, ist außerdem noch eine ganz andere Frage....

Nix für ungut

Gruß Barnee
 
Zurück
Oben