SPS-Automapping

Einführung

Mit Hilfe von speziellen Kommentaren, die hinter die SPS-Variablen-Deklaration eingefügt werden, kann eine automatisierte Konfiguration von BACnet-Objekten aus dem SPS-Programm vorgenommen werden. Dabei können BACnet-Objekte angelegt, BACnet-Property-Variablen mit SPS-Variablen verknüpft und BACnet-Properties initialisiert werden.

Das SPS-Automapping kann über den BACnet-Server im Reiter "Settings" durchgeführt werden, nachdem das SPS-Projekt in die Hardware-Konfiguration eingefügt wurde. Durch Betätigung des Buttons "Map", nach der Selektion des gewünschten SPS-Programms, wird das Automapping ausgelöst:

SPS-Automapping 1:

SPS-Automapping für BACnet-Server

Im folgenden Quellcodeauszug ist die Verwendung der Automapping-Kommentare veranschaulicht. Es wird eine lokierte Variable "av0" vom Typ REAL angelegt. Die verwendeten Kommentare definieren BACnet-Properties für die Verwendung des Automappings. Die generelle Kommentar-Syntax ist durch die SPS vorgegeben und wird durch "(*" eingeleitet und "*)" abgeschlossen. Kommentare mit dem speziellen Präfix "~" werden vom SPS-Compiler für die entsprechenden Symbole in die TPY-Datei überführt. Diese als "Property" bezeichneten speziellen Kommentare haben immer den Aufbau "( NAME : WERT : KOMMENTAR )". Für das BACnet-Automapping setzt sich der "NAME" aus "BACnet_[BACnet-Property-Name]" zusammen. "WERT" gibt je nach BACnet-Property einen entsprechenden Wert vor, die im Speziellen erläutert werden.

Im Beispiel wird das Symbol "av0" mit 3 BACnet Properties annotiert. Es wird festgelegt, dass es sich um ein AnalogValue-Objekt handelt (AV). Die Objekt-Instanz ist 100. Bei der Property ObjectIdentifier ist zu beachten, dass diese im SPS-Kommentar nur die Instanz-Nummer und nicht zusätzlich den kodierten Objekt-Typ wie in BACnet enthält. Im Beispiel wird beim Automapping also ein BACnet-Objekt vom Typ AnalogValue mit der Instanznummer 100 angelegt. Pro Symbol kann eine Verknüpfung mit einer zyklischen BACnet-Property-Variable vorgenommen werden. Variablen die nicht verknüpft werden sollen, können mit dem Kommentar "NOLINK" (siehe Anmerkung im Anhang) versehen werden. Pro Symbol darf genau eine Property zum Verknüpfen existieren. Im Beispiel wird die Property PresentValue des AnalogValue-Objekts mit der SPS-Variable "av0" verknüpft.

av0 AT %I* : REAL;         (* ~ (BACnet_ObjectType     :  AV        : NOLINK)
                    (BACnet_ObjectIdentifier   :  100       : NOLINK)
                    (BACnet_PresentValue       :        : )
                *)

Im Folgenden ist ein weiteres Beispiel dargestellt. In diesem Fall wird ein BACnet-Objekt vom Typ BinaryInput angelegt. Eine Objektinstanz ist nicht definiert. Beim Automapping wird dann automatisch eine verfügbare Objektinstanznummer generiert. Im Beispiel ist demonstriert wie die Werte bestimmter BACnet-Properties vorinitialisiert werden können. Die BACnet-Properties Description und ObjectName werden mit den Werten "Hello, BACnet" bzw. "BinaryInput_1" initialisiert. Nach dem Automapping sind dann im erzeugten BACnet-Objekt im Reiter "Settings" die entsprechenden Werte übernommen und werden beim Aktivieren der Konfiguration "Online" sichtbar. Zusätzlich wird der Objektname im System-Manager-Baum verwendet. Verknüpft wird im Beispiel eine Variable vom Typ BOOL mit der Property PresentValueBool. Während der BACnet-Datentyp der PresentValues von Binär-Objekten ein Aufzählungstyp ist, wurde für den effizienten Umgang mit der SPS die Hilfs-Property PresentValueBool eingeführt, um boolesche Variablen verknüpfen zu können. Details hierfür können im Kapitel "Prozessdaten" nachgelesen werden.

bi0 AT %I* : BOOL;         (* ~ (BACnet_ObjectType     : BI         : NOLINK)          
                    (BACnet_Description    : Hello, BACnet  : NOLINK)
                    (BACnet_ObjectName     : BinaryInput_1  : NOLINK)
                    (BACnet_PresentValueBool   :        : )
                *)

Auch bei Verwendung von Variablen primitiven Typs können mehrere Variablen mit einem BACnet-Objekt verknüpft werden. Hierzu müssen bei zwei Variablen identische Objekttyp- und Objektinstanz-Parameter angegeben werden. Im Beispiel werden die BACnet-Properties PresentValue und StatusFlags mit dem AnalogValue-Objekt "101" verknüpft. Um versehentlich doppelt vergebene Objektinstanznummer als Fehler melden zu können, muss beim 2. Symbol, welches sich auf ein zuvor erzeugtes BACnet-Objekt bezieht, der Kommentar "OBJREF" ergänzt werden. "OBJREF" muss hierbei immer bei der BACnet-Property "ObjectIdentifiert" deklariert werden. Soll ein Objekt über den Namen über 2 Symbole zugeorgnet werden, muss bei der Deklaration der Property ObjectName "OBJREF" verwendet werden.

av0 AT %I* : REAL;         (* ~ (BACnet_ObjectType     : AV         : NOLINK)
                    (BACnet_ObjectIdentifier   : 101        : NOLINK)
                    (BACnet_PresentValue       :        :)
                *)
av0_StatusFlags AT %I* : WORD; (* ~ (BACnet_ObjectType     : AV         : NOLINK)
                    (BACnet_ObjectIdentifier   : 101        : OBJREF,NOLINK)
                    (BACnet_StatusFlags    :        :)
                *)

Kommandierbare Properties

Von der SPS kann auch schreibend auf BACnet-Objekte zugegriffen werden. Kommandierbare BACnet-Properties sind mit einem PriorityArray verbunden und unterstützen Schreibzugriffe mit den Prioritäten 1 bis 16. Durch die Verwendung von Prioritäten können andere Systemkomponenten Signale der SPS übersteuern. Generell gilt beim schreibenden Zugriff von der SPS auf BACnet, dass nur beim Programmstart, sowie bei Änderung ein Wert von BACnet übernommen wird. Wird vom BACnet-Netzwerk konkurrierend auf eine gleiche Prioritätsstufe geschrieben, kann es sein, dass der SPS-generierte Wert vom BACnet-Wert abweicht. Bei priorisierten Zugriffen sollte aber in den meisten  Fällen eine Prioritätsstufe exklusiv verwendet werden. Bei mehreren potentiellen gleichprioren Änderungsquellen kann auch die BACnet-Property RelinquishDefault verwendet werden.

Im Beispiel ist eine "Q"-lokierte Variable definiert, die mit dem PresentValue eines AnalogOutput-Objektes verknüpft wird. Dabei führt das Schreiben der SPS zu einem Eintrag in Prioritätsstufe "8" des PriorityArray. Kommandierbar sind jeweils die PresentValue-Properties von BinaryValue-, BinaryOutput-, AnalogValue-, AnalagOutput-, MultistateValue- und MultistateOutput-Objekten. Die jeweils höchste aktive Priorität (1=höchste, 16=niedrigste) resultiert als PresentValue. Eine Priorität im PriorityArray ist aktiv, wenn sie nicht NULL ist. Sind alle Elemente im PriorityArray NULL nimmt PresentValue den Wert der BACnet-Property RelinquishDefault an.

ao0_PresentValue8 AT %Q* : REAL;(*~ (BACnet_ObjectType     : AO         : NOLINK)
                    (BACnet_PresentValue_Priority8 :        :)
                *)

Eine Besonderheit kommandierbarer Properties ist der Eintrag NULL im PriorityArray, der in BACnet ein eigener Datentyp darstellt - im Gegensatz zu den jeweiligen Wertdatentypen (REAL, BINARY_PV, UNSIGNED). Der Wert NULL, der eine Prioritätsstufe im PriorityArray deaktiviert, kann für die jeweiligen Objekte wie folgt über die verknüpfte Variable geschrieben werden:

Strukturierte Programmierung

Für die strukturierte Verknüpfung von BACnet-Objekten werden auch Funktionsblöcke (FBs) beim Automapping unterstützt. Der abgebildete Quellcodeausschnitt zeigt die Deklaration eines BACnet-Funktions-Bausteins. Um beim Automapping betrachtet zu werden, müssen diese Bausteine mit dem Präfix "FB_BACnet" beginnen. Im Beispiel wurde ein FB für ein AnalogOutput-Objekt definiert, der als Vorlage in der BACnet-SPS-Bibliothek "TcBACnet.lib" vorliegt. Dabei werden die Properties PresentValue, StatusFlags, Reliability und OutOfService als Eingangsvariablen zur SPS verknüpft, die Property PresentValue mit der Priorität 8 schreibend.

FUNCTION_BLOCK FB_BACnet_AnalogOutput
VAR_OUTPUT
    ObjectType: E_BACNETOBJECTTYPE;       (* ~ (BACnet_ObjectType       : AO   : NOLINK) *)
    PresentValue AT%I*: REAL;         (* ~ (BACnet_PresentValue     :      :) *)
    StatusFlags AT%I*: UINT;          (* ~ (BACnet_StatusFlags      :      :) *)
    Reliability AT%I*: E_BACNETRELIABILITY;   (* ~ (BACnet_Reliability      :      :) *)
    OutOfService AT%I*: BOOL;         (* ~ (BACnet_OutOfService     :      :) *)END_VAR
VAR_INPUT
    PresentValue_Priority8 AT%Q*: REAL;       (* ~ (BACnet_PresentValue_Priority8 ::) *)END_VAR

Im Hauptprogramm (bzw. einem anderen FB, Programm) kann dieser FB instanziiert werden. Auch bei der Instanziierung können zusätzlich Kommentare angegeben werden. Kommentare auf Instanziierungsebene gewinnen gegenüber Kommentaren auf FB-Deklaraktionsebene. Im Beispiel wird ein AnalogOutput-Objekt angelegt, die Objektinstanz und die BACnet-Property Description auf Instanziierungsebene initialisiert. Durch die FB-Deklaration werden bei dem erzeugten BACnet-Objekt die Properties PresentValue, StatusFlags, Reliability und OutOfService sowie PresentValue_Priority8 verknüpft.

ao1 : FB_BACnet_AnalogOutput;         (* ~ (BACnet_ObjectIdentifier : 100 :NOLINK)   
                           (BACnet_Description      : FB-basiertes AO: NOLINK)
                          *)

BACnet-FBs können hierarchisch verwendet werden, das heißt, es kann z.B. ein "FB_BACnet_Pumpe" definiert werden, der mehrere FB_BACnet_AnalogOutput-Instanzen enthält. Für Schachtelungstiefen größer eins wird jeweils ein StructuredView-Objekt im System-Manager angelegt. BACnet-Kommentare werden dabei nicht auf mehrere Hierarchieebenen heruntergereicht. Nur Instanziierungs- und Deklarationsebene werden unterstützt. Eine Ausnahme bildet der BACnet-Kommentar BACnet_ObjectIdentifier, der über mehrere Hierarchieebenen aufgelöst wird, um eine ID-Vergabe für geschachtelte FB's zu unterstützen.

SPS-Automapping 2:

Wird auf einer oberen Ebene eine Objekt-Instanz angegeben, hat diese Auswirkung auf potenziell viele Objekte des gleichen Typs. Bei der Generierung einer Objekt-ID wird von der angegebenen ID ausgegangen (ist z. B. eine Objektinstanz von 1000 angegeben, wird ab 1000 eine neue freie ID gesucht). Ein FB_BACnet_Raum mit 2 AV- und 2 BV-Objekten und angegebener Start-ID von 1000 wird also die BACnet-Objekte AV:1000, AV1001, BV:1000 und BV:1001 erzeugen. Die resultierenden Objekt-IDs werden vor der Ausführung der eigentlichen Mapping-Operation berechnet. Existieren Objekte mit den ermittelten IDs z.B. durch ein IO-Mapping schon, werden die existierenden Objekte verwendet bzw. verknüpft und keine neuen Objekte erstellt.

Neben verschachtelten FBs werden auch eindimensionale Arrays unterstützt. Das folgende Beispiel zeigt die Deklaration eines Arrays raeume vom Typ FB_BACnet_Raum, welches weitere BACnet-Objekte enthält. Auf diese Weise können systematisch Einheiten gleicher Funktionalität verwaltet werden. Es werden auch Arrays auf verschiedenen Schachtelungsebenen unterstützt. So kann z.B. ein BACnet-Objekt fbHaus[1].EtageU.Raum[10].tmpSoll generiert werden.

raeume : ARRAY[0..10] OF FB_BACnet_Raum;

Strukturierte Programmierung: Konfiguration von FB-Instanzen

BACnet-Kommentare auf FB-Deklarations-Ebene gelten für alle Instanzen des FB gleichermaßen. Für bestimmte BACnet-Properties kann eine Definition auf Instanzebene Anwendung finden. So können z.B. instanzbasierte ObjectIdentifier definiert oder die Hardwareanbindung auf Io-Module pro Instanz konfiguriert werden. Im Folgenden ist ein Beispiel dargestellt bei dem BACnet-Properties auf Instanz-Ebene festgelegt werden.

FUNCTION_BLOCK FB_BACnet_SubSub
VAR
  bi  : FB_BACnet_BinaryInput; (*~(BACnet_OutOfService : TRUE: NOLINK)*)
  bi2 : FB_BACnet_BinaryInput;
END_VAR
FUNCTION_BLOCK FB_BACnet_Sub
VAR
  sub1   : FB_BACnet_SubSub;
  sub2   : FB_BACnet_SubSub; 
  subArr : ARRAY[0..1] OF FB_BACnet_SubSub;
END_VAR
PROGRAM SIMPLE
VAR
s1 :FB_BACnet_Sub; (* ~ { BACnet_ObjectIdentifier<sub1/bi>    : 1017   : }
            { BACnet_ObjectIdentifier<sub2>       : 1028   : }
            { BACnet_ObjectIdentifier<subArr[0]/bi>   : 5555   : }
            { BACnet_ObjectName<sub2/bi>          : biname : NOLINK }
           *)
END_VAR

Durch die Definition eines Instanzpfades nach dem BACnet-Property-Namen können BACnet-Property-Definitionen auf Sub-Elemente eines FB angewendet werden. Hierfür kann der Instanzpfad durch Angabe in "<" und ">" vorgegeben werden. Im obigen Beispiel wird z.B. den BACnet-Objekt bi der Instanz sub1 ein ObjectIdentifier 1017 vorgegeben. Einzelne Sub-Ebenen werden dabei durch "/" abgetrennt. Es können auch BACnet-Property-Definitionen an Zwischenebenen konfiguriert werden. Im Beispiel wird der ObjectIdentifier 1028 an die FB-Instanz sub2 übergeben. Diese veranlasst in diesem Beispiel, dass die BACnet-Objekte s1.sub2.bi die Object-ID 1028 und s1.sub1.bi2 die Objekt-ID 1029 bekommen. Die Instanzpfadangabe kann auch Array-Elemente enthalten.

ARRAY[01..03] OF FB_BACnet_AnalogValue; (* ~
   (BACnet_Description<[1]>:1. OG Raum 1 Temp: NOLINK)
   (BACnet_Description<[2]>:1. OG Raum 2 Temp: NOLINK)
   (BACnet_Description<[3]>:1. OG Raum 3 Temp: NOLINK)
*)

Auch die direkte Parametrierung von Array-Elementen auf Programm- oder globaler Ebene wird unterstützt. Im Beispiel wird die BACnet-Property Description von 3 Array-Elementen initialisiert.

Strukturierte Programmierung: View-Konfiguration

Beim SPS-Automapping werden für jede Verschachtelungstiefe in Form von Programmen und Funktionsblöcken StructuredView-Objekte angelegt, um die Strukturierung auf innerhalb der SPS auf BACnet abzubilden. Je nach verwendetem Anlagenkennzeichungssystem (AKZ) kann es notwendig sein die Benennung von BACnet-Objekten und deren Struktur mit einem Namenspräfix anzupassen. Mit Hilfe des SPS-Kommentars "BACnet_StructuredViewPath" ist es möglich für das SPS-Automapping eigene Namenspräfixe zu definieren. "BACnet_StructuredViewPath" kann eine beliebige Variable auf den gewünschten Strukturierungsebenen annotieren.

PROGRAM MAIN
VAR
  viewDummy : BOOL; (* ~     ( BACnet_StructuredViewPath        : \/Building1\/Floor2 : ) 
( BACnet_StructuredViewPathDescription : \/Haus 1\/Flur 2 : )
            ( BACnet_StructuredViewPathObjectId    : \/1000\/9: )
             *)
  room1 : FB_BACnet_Room; (* ~( BACnet_Description : Description of structured view object room1: ) *)
  room2 : FB_BACnet_Room;
END_VAR

Im Beispiel wird für alle BACnet-Objekte innerhalb des Funktionsblock FB_BACnet_Room nicht der Name MAIN.room1.XXX sondern Building1.Floor2.room1.XXX verwendet. Neben der Verwendung für den Objektnamen der BACnet-Objekte wird auch für jede Hierarchieebene ein StructuredView-Objekt angelegt. Hierarchieebenen werden durch die Zeichenkette "\/" definiert.

Mit Hilfe der SPS-Kommentare "BACnet_StructuredViewPathDescription" und "BACnet_StructuredViewPathObjectId" können die BACnet-Property Description sowie die ObjectIdentifier der erzeugten StructuredView-Objekte festgelegt werden. StructuredView-Objekte, die über komplexe Funktionsbausteine erzeugt werden; Im Beispiel room1 und room2, können über die SPS-Kommentare BACnet_Description und BACnet_ObjectIdentifier konfiguriert werden.

Anlagenkennzeichnung

Je nach gefordertem Anlagenkennzeichnungssystem kann es notwendig sein, die generierten BACnet-Objektnamen anzupassen. Per Default werden für die Trennung von Strukturebenen Punkte (".") verwendet. Durch die Angabe eines "StructureSeparator" kann an Stelle des Punkts auch ein anderes Symbol verwendet werden bzw. das Trennsymbol auch vollständig entfernt werden. Das folgende Beispiel zeigt die Definition des Trennsymbols "_". Das Trennsymbol sollte einmalig pro Projekt z.B. an einer globalen Variable definiert werden.

akzDummy : BOOL; (* ~( BACnet_StructureSeparator :_: ) *) 

Schreibschutz und optionale Properties

Für die Steuerung von Schreibschutz und optionalen Properties wurden spezielle Kommentaroptionen eingeführt. Im Kommentarteil der SPS-Kommentare können in Form einer ","-separierten Liste zusätzliche Optionen angegeben werden. DISABLE deaktiviert dabei eine optionale Property. WRITEPROTECT aktiviert den Schreibschutz einer schreibbaren Property. Es ist darauf zu achten, dass die Option NOLINK bei der Konfiguration multipler Properties angegeben wird. Das folgende Beispiel zeigt die Konfiguration von Schreibschutz und optionalen Properties.

bo1: FB_BACnet_BinaryOutput; (* ~(BACnet_NotifyType         :    : DISABLE,NOLINK)
                 (BACnet_ChangeOfStateTime      :    : DISABLE,NOLINK)
                 (BACnet_ChangeOfStateCount     :    : DISABLE,NOLINK)
                 (BACnet_ActiveText         : AN     : WRITEPROTECT,NOLINK)
                 (BACnet_InactiveText       : AUS    : WRITEPROTECT,NOLINK)  
                  *)

Bei BACnet-Properties mit invertierter Optionallogik, also BACnet-Properties die beim Anlegen eines BACnet-Objektes zunächst deaktiviert sind, kann der Kommentar ENABLE verwendet werden. Ein Beipiel hierfür ist das Aktivieren eines mittelwertbildenen Filters im AnalogInput-Objekt mittels der herstellerspezifischen BACnet-Property AvgFilterCycles:

fbAI : FB_BACnet_AnalogInput; (* ~(BACnet_AvgFilterCycles     : 20    : ENABLE,NOLINK ) *)

Initialisierung komplexer Property-Werte

Der Initialisierung von Property-Werten über das SPS-Automapping sind durch die verwendete SPS-Kommentar-Syntax Grenzen gesetzt. So können die reservierten Zeichen "(", ")", ":", "*" und " nicht verwendet werden. Zusätzlich kann bei BACnet-Properties mit Auswahltyp (Choice) oder optionalen Feldern nicht immer eindeutig jede Zeichenkette analysiert werden, wenn eine optimierte Darstellungsform wie im System Manager verwendet wird.

Für bestimmte Properties wurden spezielle Parser implementiert, die eine vereinfachte Konfiguration von Property-Werten ermöglichen. Im folgenden Beispiel ist dargestellt, wie die Property StateText eines MultiStateValue-Objekts initialisiert werden kann.

mv : FB_BACnet_MultiStateValue;  (* ~(BACnet_StateText   : {Low;Medium;High}       : NOLINK )*)

BitField-Properties (EventEnable, AckRequired) können durch die Angabe einer Hexadezimalzahl initialisiert werden. Hier empfiehlt sich Übernahme des entsprechenden Werts im System Manager:

bi : FB_BACnet_BinaryInput;      (* ~(BACnet_EventEnable : 0xE005          : NOLINK )*)

Auch die Property Priority des Objekts NotificationClass kann verkürzt initialisiert werden. Hierfür wird diese Array-Property im Beispiel mit den Werten 12, 12 und 122 initialisiert. Für die Initialisierung von BitField-Properties wurde zusätzlich die übersichtlichere Form der Array-artigen Initialisierung implementiert. Im Beispiel werden in der Property AckRequired die Bits für "to_offnormal" und "to_fault" gesetzt. Eine BitField-Property mit keinem gesetzten Bit kann durch die Zeichenkette "{}" initialisiert werden.

nc : FB_BACnet_NotificationClass;(* ~(BACnet_Priority    : {12;12;222}         : NOLINK)
                     (BACnet_AckRequired : {to_offnormal;to_fault} : NOLINK)
                  *)

Da nicht für alle komplexen Properties eigene Parser implementiert werden können, wurde die Möglichkeit der Initialisierung mit Hilfe von XML eingeführt. XML hat den Vorteil, dass die reservierten Zeichen der Kommentarsyntax nicht verwendet werden müssen und so keine Einschränkung bei der Initialisierung der Property-Werte besteht. Die XML-Werte für die Property-Initialisierung können sehr einfach durch die Copy&Paste Funktion von Property-Werten erstellt werden. Eine Property kann hierfür im System Manager unter Verwendung aller Komfort-Funktionen (Wizards) erstellt werden. Über das Kontextmenü in der Property-Ansicht ("Online" bzw. "Settings") kann über "Copy Value" (bzw. die Tastenkombination STRG-C) der aktuelle Wert einer Property in die Zwischenablage eingefügt werden und im PLC-Control über "Einfügen" bzw. STRG-V verwendet werden.

SPS-Automapping 3:

Wird die SHIFT-Taste beim Auslösen der Funktion "Copy Value" gehalten, wird die XML-Zeichenkette als eine Zeile kopiert - sonst wird eine strukturierte Variante im Mehrzeilenmodus erzeugt. Die Verwendung des Einzeilenmodus ermöglicht eine übersichtlichere Variablen-Deklaration im SPS-Programm. Das nachfolgende Beispiel zeigt wie die Property StartTime eines TrendLog-Objekts mit Hilfe der XML-Syntax initialisiert wird:

tl : FB_BACnet_TrendLog; (* ~(BACnet_StartTime : 
<BACnetDateTime>
  <date>
    <year>112</year>
    <month>7</month>
    <day>16</day>
    <dayOfWeek>1</dayOfWeek>
  </date>
  <time>
    <hour>12</hour>
    <minute>30</minute>
    <second>0</second>
    <hundredths>0</hundredths>
  </time>
</BACnetDateTime>
: NOLINK )*)

Property-Referenzen

Für die Initialisierung von Referenz-Properties wurde die Option REFERENCE eingeführt. Durch die automatische Generierung von Objekt-IDs können Referenzen auf Properties anderer SPS-BACnet-Objekte nicht durch die direkte Wert-Initialisierung von Properties erfolgen, da die Objekt-IDs zur Implementierungszeit des SPS-Programms unbekannt sind. Durch die Angabe der Option REFERENCE und einem Property-Namen als Suffix können automatisch generierte Objekte referenziert werden. Als Beispiel ist im Folgenden eine einfache Heizung skizziert. Die Angabe von Soll-, Ist- und Stellwert erfolgt über Analog*-BACnet-Objekte, die über Referenzen mit einem Loop-Objekt verknüpft werden.

fbSollwert   : FB_BACnet_AnalogValue;
fbStellwert  : FB_BACnet_AnalogOutput;
fbIstwert    : FB_BACnet_AnalogInput;
fbTempRegler : FB_BACnet_Loop; (* ~(BACnet_ManipulatedVariableReference : ./fbStellwert : REFERENCE_PresentValue) 
                   (BACnet_SetpointReference        : ./fbSollwert  : REFERENCE_PresentValue)
                   (BACnet_ControlledVariableReference  : ./fbIstwert   : REFERENCE_PresentValue) 
                *)

Bei der REFERENCE-Funktionaliät wird zwischen relativer und absoluter Referenzierung unterschieden. Relative Referenzen beziehen sich immer auf den aktuellen Kontext und werden mit "./" eingeleitet. Der aktuelle Kontext bezieht sich immer auf die aktuelle Deklarationsebene im Programm bzw. Funktionsbaustein. Mit Hilfe relativer Referenzierung können auch Objekt in anderen Programmen bzw. Funktionsbausteinen verwendet werden. Ein Beispiel ist die Deklaration eines LOOP-Objekts im "MAIN"-Programm; um ein Objekt im Programm "IO_OBJECTS" zu referenzieren kann die Syntax "./../IO_OBJECTS/fbAO" verwendet werden. Absolute Referenzen beginnen immer direkt mit dem Programmnamen (z.B. MAIN.fbBvI oder MAIN.haus1.raum1.uv24Vok). Bei globalen Variablen muss der "." am Beginn entfernt werden.

SPS-Automapping 4:

Generell beziehen sich alle Referenzen auf Symbolnamen in der SPS nicht auf den BACnet-Objektnamen!

Generell gilt, das Referenzen die potentiell BACnet-Objekte in anderen Geräten (BACnetDeviceObjectPropertyReference) enthalten können, auch mit der Funktion REFERENCE initialisiert werden können. Handelt es sich bei dem Zielsymbol um ein FB_BACnet_Remote_*-Baustein, wird die Ziel-Geräte-ID automatisch eingetragen.

Die Option REFERENCE funktioniert auch für Schedule- und TrendLog-Objekte:

bi      : FB_BACnet_BinaryInput;
bv      : FB_BACnet_BinaryValue;
tl      : FB_BACnet_TrendLog; (* ~(BACnet_LogDeviceObjectProperty       : ./bi      : REFERENCE_PresentValue) *)
sched   : FB_BACnet_Schedule; (* ~(BACnet_ListOfObjectPropertyRefs      : ./bv      : REFERENCE_PresentValue) *)

Für entfernte Objekte zeigt der folgenden Ausschnitt ein Beispiel. Im Beispiel wird eine absolute Referenz innerhalb des MAIN-Programms verwendet.

bvRemote : FB_BACnet_RemoteBinaryValue; (* ~ (BACnet_ObjectType       : BV : NOLINK)
                         (BACnet_DeviceID     : 32 : NOLINK)
                         (BACnet_ObjectIdentifier : 2 : NOLINK) *)
fbTLog   : FB_BACnet_TrendLog;      (* ~ (BACnet_LogDeviceObjectProperty : MAIN.bvRemote : REFERENCE_PresentValue) *)

 

Mehrere Referenzen in der Property ListOfObjectPropertyRefs des Schedule-Objekts können über folgende Syntax festgelegt werden:

 schedMultiRef : FB_BACnet_Schedule;     (* ~ (BACnet_ListOfObjectPropertyRefs : Object=COOLING.bPrgCool;Property=PresentValue;
                                        Object=fbGlob;Property=PresentValue; : REFERENCE) *)

Auch für weitere komplexere BACnet-Properties mit Referenzen existiert eine spezielle Initialisierung, die im Folgenden anhand kurzen Beispiels vorgestellt werden soll. Zunächst folgt die Initialisierung der Action-Property des Command-Objekts, welche für die Steuerung von ablaufbasierten Vorgängen verwendet werden kann.

fbCmdBo  : FB_BACnet_BinaryOutput;
fbCmdBV19: FB_BACnet_BinaryValue; (* ~(BACnet_ObjectIdentifier : 19 : ) *)fbCmdAv  : FB_BACnet_AnalogValue;
fbCmdMv  : FB_BACnet_MultiStateValue;
fbCmd    : FB_BACnet_Command; (* ~(BACnet_Action :          
   Action=1;Command=1;Object=./fbCmdBo;Property=PresentValue;Value=ACTIVE;Priority=16;Delay=0;Quit=TRUE;
   Action=1;Command=2;Object=./fbCmdBo;Property=PresentValue;Value=NULL;Delay=1;Quit=FALSE;
   Action=1;Command=3;Object=BinaryValue_19;Property=PresentValue;Value=NULL;Delay=1;Quit=FALSE;
   Action=1;Command=4;Object=./fbCmdAv;Property=PresentValue;Value=NULL;
   Action=1;Command=5;Object=./fbCmdAv;Property=PresentValue;Value=12.3;Delay=1;Quit=FALSE; 
   Action=2;Command=1;Object=./fbCmdMv;Property=PresentValue;Value=2;Delay=1;Quit=FALSE; 
: REFERENCE )*)

Im folgenden Beispiel wird die Initialisierung der ListOfGroupMembers-Property des Group-Objekts dargestellt.

fbGroupAv:  FB_BACnet_AnalogValue;
fbGroupBv : FB_BACnet_BinaryValue;
fbGroup   : FB_BACnet_Group;(* ~(BACnet_ListOfGroupMembers :
   Object=./fbGroupAv;Property=PresentValue;Property=StatusFlags;Property=HighLimit;Property=LowLimit;
   Object=./fbGroupBv;Property=PresentValue;Property=StatusFlags;Property=OutOfService 
: REFERENCE ) *)


Mit Hilfe des EventEnrollment Objektes können Alarmbedingungen definiert werden, die über die des Instrinsic Reporting hinausgehen. Im Folgenden wird die Initialisierung der EventEnrollment-Objekte mit Hilfe einer verkürzten Syntax demonstriert:

fbEEAv   : FB_BACnet_AnalogValue;
fbEEWarn : FB_BACnet_EventEnrollment;(* ~
   (BACnet_ObjectPropertyReference : ./fbEEAv : REFERENCE_PresentValue)
   (BACnet_EventParameters     : EventType=out_of_range;timeDelay=5;lowLimit=0;highlimit=10;deadband=0;:REFERENCE )
   (BACnet_NotificationClass       : 10 : nolink )
   (BACnet_EventMessageTexts       : {Warning;Sensorfault;Normal operation} : nolink )
*)  
fbEEBo   : FB_BACnet_BinaryOutput;
bEEHours : FB_BACnet_EventEnrollment; (* ~
   (BACnet_ObjectPropertyReference : ./fbEEBo : REFERENCE_ElapsedActiveTime)
   (BACnet_EventParameters     : EventType=unsigned_range;highlimit=60; :REFERENCE )
   (BACnet_NotificationClass       : 10 : nolink )
   (BACnet_EventMessageTexts       : {Maximum operating hours exceeded; ; } : nolink )
*)

Einbindung von Hardware-Modulen

Die Anbindung von Hardware-Modulen kann grundsätzlich über das Io-Automapping erfolgen und die Zuordnung zu SPS-Objekten durch die Angabe von ObjectIdentifiern im SPS-Code. Um eine effiziente Code-Generierung von BACnet-Projekten zu ermöglichen, ist es auch möglich die Hardware-Anbindung direkt hinter der Deklaration von BACnet-Objekten in der SPS zu konfigurieren. Hierfür existiert die LINKPATH-Option. Mit dieser Option ist es möglich eine BACnet-Property-Variable eines BACnet-Objekts direkt mit einem IO-Modul zu verknüpfen. Hier wird dann keine Verlinkung zu einer SPS-Variablen, sondern eine reine Device-Device-Verknüpfung erstellt.

Das folgende Beispiel zeigt die Verknüpfung eines BACnet-Objekt BinaryInput mit der 3. Klemme (einer KL1002) auf dem 1. Kanal. Über das PresentValue des FB_BACnet_BinaryInput kann dann im SPS-Programm direkt auf den Hardware-Wert zugegriffen werden.

bi : FB_BACnet_BinaryInput;(* ~{ BACnet_RawIoBinaryBoolValue : TIID^Rt-Ethernet^BK9000^Term 3 KL1002^Channel 1^Input : LINKPATH } *)

Durch die Angabe eines zusätzlichen Parameters der LINKPATH-Option können Offset1, Offset2 und die Bitgröße für die Verknüpfung auch direkt vorgegeben werden (LINKPATH<[Offset1],[Offset2],[Bitgröße]>).. Ist die Bitgröße auf den Wert 0 festgelegt, wird automatische die maximal mögliche Anzahl von Bits verknüpft. Ohne die Angabe der zusätzlichen Parameter wird für Offset1 und Offset2 der Wert 0 verwendet. Offset1 bezieht sich auf die BACnet-Property-Variable und Offset2 auf den externen Link.

bx : FB_BACnet_BinaryInput;(* ~{ BACnet_RawIoBinaryBoolValue : TIID^Rt-Ethernet^BK9000^Term 3 KL1002^Channel 1^Input : LINKPATH<0,0,1> } *)

Im Zusammenhang mit Funktionsbausteinen können auch Sub-Elemente von FB-Instanzen direkt mit einem Hardware-Modul verbunden werden. Hierfür kann die Instanzpfad-Syntax "<[]>" nach der zu verknüpfenden BACnet-Property verwendet werden.

PROGRAM SIMPLE
VAR
s1 :FB_BACnet_Sub; (* ~ { BACnet_RawIoBinaryBoolValue<sub1/bi>  : TIID^Rt-Ethernet^BK9000^Term 3 KL1002^Channel 1^Input : LINKPATH }
            { BACnet_RawIoBinaryBoolValue<sub2/bi>  : TIID^Rt-Ethernet^BK9000^Term 3 KL1002^Channel 2^Input : LINKPATH }
            { BACnet_RawIoBinaryBoolValue<sub1/bi2> : TIID^Rt-Ethernet^BK9000^Term 2 KL1002^Channel 2^Input : LINKPATH }      
            *)
END_VAR

Zusätzlich ermöglicht das SPS-Automapping auch die Verknüpfung von Variablen außerhalb von BACnet. Mit der Option "ExtLink" kann ein beliebieges, lokiertes SPS-Symbol mit einer externen Variablen z.B. einem Hardware-Modul verknüpft werden. Mit der Option "ExtLink2" können 2 SPS-externe Variablen miteinander verknüpft werden. Über zusätzliche Parameter (wie auch bei LINKPATH) können Offset1, Offset2 und die Bitgröße für die Verknüpfung angegeben werden. Im Folgenden ist je ein Beispiel für die Verwendung dieser Optionen dargestellt.

b1 AT%I*: BOOL;   (* ~{ ExtLink  : TIID^Rt-Ethernet^BK9000^Term 2 (KL1002)^Channel 2^Input  : } *)
bDummy  : BOOL;   (* ~{ ExtLink2 : TIID^Rt-Ethernet^BK9000^Term 5 (KL2012)^Channel 1^Output : 
                   TIID^Rt-Ethernet^BK9000^Term 2 (KL1002)^Channel 2^Input } 
           *)
b1 AT%I*: BOOL;   (* ~{ ExtLink<0;0;1>  : TIID^Rt-Ethernet^BK9000^Term 2 (KL1002)^Channel 2^Input  : } *)
bDummy  : BOOL;   (* ~{ ExtLink2<0;0;1> : TIID^Rt-Ethernet^BK9000^Term 5 (KL2012)^Channel 1^Output : 
                      TIID^Rt-Ethernet^BK9000^Term 2 (KL1002)^Channel 2^Input } 
           *)

Als Ausgangspunkt für die Verknüpfung von Hardware-Modulen kann der EXP-Export verwendet werden. Im EXP-Export-Konfigurationsdialog kann mit der Option "Export I/O configuration" die BACnet-Objekt-Konfiguration für die TcBACnet.lib erzeugt werden. Hierbei wird für jeden im Projekt vorhandenen Io-Bus ein entsprechendes Programm mit den Hardware-BACnet-Objekten und ihrer Verknüpfung erstellt. Die Prozedur EXP-Export, SPS-Automapping erzeugt dann die gleiche BACnet-Konfiguration, die auch ein IO-Automapping erzeugt. Der Vorteil der SPS-Variante ist, dass Hardware-Objekte in strukturierte Funktionsbausteine der SPS integriert werden können bzw. Hardware-Kanäle, die nicht via BACnet sichtbar sein sollen, gelöscht werden können.

SPS-Automapping 5:

SPS-Automapping für BACnet-Clients

Sollen SPS-Variablen mit Prozessdaten-Properties von entfernten (remote) BACnet-Objekten verknüpft werden, dann kann als Kommentar zusätzlich zum Objekttyp und -instanz eine Device-ID angegeben werden. In diesem Fall werden SPS-Variablen mit zuvor angelegten BACnet-Objekten (z.B. durch Scannen von Clients) verknüpft. Ist ein Client mit noch nicht vorhanden wird dieser automatisch angelegt. Auch nicht vorhandende Objekte werden erzeugt. Die erzeugte Hierarchie ist dabei flach. StructuredView-Objekt für Clients werden vom SPS-Automapping momentan nicht unterstützt.

Im folgenden Quelltextausschnitt ist eine Variable vom Typ REAL angelegt. Diese wird beim Automapping mit der Property PresentValue des Objekts AnalogValue:100 unter dem Client mit der BACnet-ID "42" verknüpft. Die Prozessdatenvariable des remote BACnet-Objekts wird dabei automatisch aktiviert.

av0 AT %I* : REAL;         (* ~ (BACnet_ObjectType         : AV    : NOLINK) 
                    (BACnet_DeviceID           : 42    : NOLINK)
                    (BACnet_ObjectIdentifier       : 100   : NOLINK)
                    (BACnet_PresentValue       :       :)
                *)

Für die Konfiguration der prozessdatenspezifischen Parameter von Client-Properties existieren Hilfs-Properties, um alle im System-Manager einstellbaren Optionen automatisiert konfigurieren zu können. Dabei handelt es sich um die Schreibpriorität bei PresentValue-Properties, die Zykluszeit, das COV-Increment und das COV-Resubscriptioninterval für COV-Subscriptions sowie Flags zur Konfiguration, ob Daten zyklisch, per COV oder OnChange verarbeitet werden sollen. Der folgende Quellcodeausschnitt zeigt die Verwendung dieser Hilfs-Properties.

ao0 AT %Q* : REAL;         (* ~ (BACnet_ObjectType         : AO     : NOLINK)
                    (BACnet_DeviceID           : 42     : NOLINK)
                    (BACnet_ObjectIdentifier       : 0      : NOLINK)
                    (BACnet_RemotePriority     : 8      : )
                    (BACnet_RemoteCycleTimeWrite   : 1000   : )
                    (BACnet_RemoteFlagsWrite       : WRITEONCHANGE : )
                    (BACnet_PresentValue       :    : )
                *)

ao1 AT %I* : REAL;         (* ~ (BACnet_ObjectType         : AO     : NOLINK)
                    (BACnet_DeviceID           : 42     : NOLINK)
                    (BACnet_ObjectIdentifier       : 0      : NOLINK)
                    (BACnet_PresentValue       :    : )
                    (BACnet_RemoteCycleTimeRead    : 1000   : )
                    (BACnet_RemoteFlagsRead    : COV    : )
                    (BACnet_RemoteCovincrement     : 0,5    : )              
                    (BACnet_RemoteResubscriptionInterval: 60: )
                *)

Für die RemoteFlagsWrite können dabei die folgenden Werte - Für Ausgangsvariable (%Q) - Also vom projektieren Controller zum entfernten Gerät - verwendet werden:

Für RemoteFlagsRead - Eingangsvariable (%I) - Lesend von einem entfernten Gerät gilt:

Werden die Hilfs-Properties bei den Remote-Objekten nicht angegeben, dann werden die im System-Manager verwendeten Default-Einstellungen angewendet:

Bei Verwendung der Remote-Bausteine der TcBACnet.lib kann die Art der Prozessdatenübertragung auch bei der FB-Instanziierung angegeben werden. Die Parameter der Remote-Konfiguration beziehen sich dabei gemeinsam auf alle aktivieren BACnet-Properties. Im folgenden Beispiel wird also die Übertragungsart der Prozessdaten auf ConfirmedCOV gestellt bei den Properties des *EX-Bausteins: StateOfChangeCount, PresentValue, StatusFlags, EventState sowie Reliability.

 bvRemote : FB_BACnet_RemoteBinaryValue_EX; (* ~ (BACnet_ObjectType : BV : NOLINK)
                        (BACnet_DeviceID   : 32 : NOLINK)
                        (BACnet_ObjectIdentifier : 20 : NOLINK)
                        (BACnet_RemoteFlagsRead : ConfirmedCOV : )
                        (BACnet_RemoteResubscriptionInterval : 3600 : )  
                        *)


Bei prioritätsbasierten Properties (PresentValue) kann schreibend eine Priorität konfiguriert werden, um einen Zugriff auf höhere Prioritäten des PriorityArray zu aktivieren. Wie auch im Serverfall ist es möglich den Wert NULL in das zugeordnete PriorityArray zu schreiben, um diese Prioritätsstufe zu deaktivieren. Bei Analog- und Binary-Objekten geschieht das äquivalent zum Serverfall (Wert > 1 für Binary-Objekte; NaN für Analog-Objekte). Bei AnalogOutput-Objekten findet keine Überwachung des Min-/MaxPresValue-Bereichs statt - NULL kann hier also nur durch NaN erzeugt werden. Bei Multistate-Objekten führt abweichend vom Serverfall nur das Schreiben von 0 zu NULL im PriorityArray. Aus Performance-Gründen wird die Property NumberOfStates nicht vom entfernten Gerät ausgelesen.

Zusammen mit der TwinCAT-BACnet-SPS-Bibliothek "TcBACnet.lib" existiert eine effiziente Möglichkeit "gescannte" Client-Konfigurationen in der SPS zu verwenden. Nachdem die zu verwendenden Clients im System-Manger (z.B. durch Scannen eines BACnet-Netzwerks) eingefügt wurden, kann über den Reiter "Settings" des BACnet-Device via "Export" und Angabe einer Ziel-Datei mit der Endung "EXP" die Variablendeklaration und entsprechende Annotierung mit Automapping-Kommentaren generiert werden. Diese kann in ein SPS-Projekt im PLC Control importiert werden. Dabei werden die Basis-BACnet-FBs der Bibliothek verwendet (z.B. "FB_BACnet_RemoteAnalogInput").

Remap

Bei der Verwendung persistenter Daten existiert bei späteren Erweiterungen die Herausforderung, eine eindeutige Zuordnung der persitierten Daten und Ihrem Pendent im SPS-Programm herzustellen. Persistente Daten werden eindeutig über den ObjektIdentifier zugeordnet. Wird bei einer Erweiterung ein Objekt in ein Programm eingefügt, kann es vorkommen, dass nachfolgende, generierte BACnet-ObjectIdentifier verschoben werden und damit die Zuordnung der persistenten Daten zerstört wird. Um diese Problematik zu beheben, wurde die Funktion des Remap implementiert. Remap kann auf einem schon gemappten SPS-Projekt durchgeführt werden, wenn an diesen Änderungen/Erweiterungen vorgenommen wurden.

Das SPS-Projekt wird dabei auf Änderungen durchsucht und dabei:

Anhang