Geteilter Speicher zwischen TcCOM-Instanzen
In machen Anwendungen kann es vorteilhaft sein, dass sich TcCOM-Instanzen einen Speicherbereich teilen, sodass bestimmte Strukturen/Variablen einmal in einem Objekt definiert werden und alle anderen Objekte auf diese Speicherstelle referenzieren.
Um dies zu erreichen, können Sie in TwinCAT zwei unterschiedliche Wege verfolgen:
- Verknüpfen von TcCOM-Instanzen in TwinCAT mit Data Pointern
- Nutzen von globalen Variablen (Exported Global/Imported Extern)
Im weiteren Verlauf dieses Kapitels werden beide Wege beschrieben.
Während Sie mit Data Pointern flexibler sind in der Verknüpfung der Daten, haben Sie bei der Nutzung von globalen Variablen den Vorteil, dass die Struktur/Variable nur einmal im Speicher vorhanden ist. Bei Data Pointern wird in jeder TcCOM-Instanz eine lokale Kopie der Daten gehalten.
Hinweis | |
Datenübertragung nicht Threadsafe Nutzen Sie Data Pointer und Globale Variablen mit Vorsicht. Der Datenaustausch erfolgt nicht Threadsafe. Deshalb empfehlen wir dringend, alle beteiligten TcCOM-Instanzen im selben Task-Kontext zu betreiben. |
Verknüpfen von TcCOM-Instanzen in TwinCAT mit Data Pointern
Im Folgenden wird beschrieben, wie Sie gezielt per Data Pointer einen gemeinsamen Speicherbereich zwischen TcCOM-Instanzen nutzen können.
Wie im Bereich Konfiguration des Datenzugriffs auf Daten eines TcCOM-Objekts beschrieben, können Sie DataAreas per DataPointer erreichbar machen. Per DataPointer erreichbar sind Input Destination DataArea, Output Source DataArea sowie Standard DataArea. Sie können prinzipiell jede Variablen-Gruppe, Modell-Parameter, DWork, BlockIO usw. als Standard DataArea anlegen und damit als Data Pointer erreichbar machen.
Zielstellung
Im Folgenden wird gezeigt, wie Sie gezielt einen Teilbereich von Variablen per DataPointer zugänglich machen und nicht gleich den ganzen Variablen-Gruppen-Bereich. Das Grundkonzept basiert auf der Nutzung von Data Store Memory Blöcken in Simulink®.
Modell mit DataStore
In einem Modell „DataStoreObject“ wird ein Data Store Memory Block angelegt. In diesem Beispiel mit nur einer einzigen Variable vom Typ double. Diese Variable wird mit einem Data Store Read ausgelesen, mit einem Input multipliziert und auf einen Ausgang gegeben.

Unter TC TcCom Interface wird die Option DataStore: Data Access von None auf Standard DataArea geändert und das Simulink®-Modell in ein TcCOM übersetzt. Wenn das Objekt in TwinCAT instanziiert wird, sehen Sie die folgende Darstellung:

Die DataStore DataArea wird nun im Prozessabbild angezeigt und enthält eine Variable vom Typ LREAL, auf welche per DataPointer zugegriffen werden kann.
Modell mit DataPointer
In einem zweiten Simulink®-Modell wird durch eine Clock ein double-Wert erzeugt und dieser auf den TC Module Output gegeben.

In der Konfiguration des TC Module Output wird der connection type auf DataPointer sowie der Datentyp auf double gestellt.

Wenn dieses Modell in ein TcCOM-Objekt übersetzt wird, sehen Sie in TwinCAT die folgende Darstellung:

Unter Data Pointer wird nun der Name des TC Module Output „PtrToMyDataStore“ vom Typ LREAL angezeigt. Diese kann nun mit Doppelklick auf die DataStoreObject_DW_MyDataStore verknüpft werden.
Beide TcCOM-Instanzen sollten in derselben Task aufgerufen werden, da die Kommunikation nicht Threadsafe ist.
![]() | Wenn unterschiedliche Tasks verwendet werden, müssen Sie als Anwender dafür Sorge tragen, dass Daten konsistent sind und zu passenden Zeitpunkten gelesen oder geschrieben werden. |
Das Verhalten des hier aufgeführten Beispiels wird in untenstehender Grafik gezeigt.
Wird der Eingang In1 des DataStore Modells manuell auf 1 gesetzt und der Ausgang Out1 über das TwinCAT Scope beobachtet, sieht man eine ansteigende Gerade. Das bedeutet, dass per Pointer der ansteigende Wert aus der Clock in den DataStore des DataStoreObject-TcCOM geschrieben wird.

![]() | Lesender Zugriff per TC Module Input Lesender Zugriff auf eine DataArea kann per DataPointer über den TC Module Input realisiert werden. |
![]() | Lokale Datenkopie in jedem Modul Der Simulink CoderTM erzeugt den C/C++ Code in der Art, dass für die TC Module Input und TC Module Output lokale Variablen angelegt werden und somit jede Modulinstanz eine lokale Kopie der Daten enthält. Entsprechend erhöht sich der Speicherbedarf des Projekts mit jeder Instanz. |
Nutzen von globalen Variablen (Exported Global/Imported Extern)
Im Folgenden wird beschrieben, wie Sie in Simulink® über die Storage Classes eine globale Variable im TcCOM anlegen können und diese in anderen TcCOM referenzieren.
Zielstellung
Es wird ein Simulink® Parameter GlobalParam angelegt, welcher eine Struktur von 3 Elementen enthält. Ziel ist es, diese Struktur über ein TcCOM-Objekt zu definieren und weitere TcCOM-Objekte zu instanziieren, die auf diese Struktur über geteilten Speicherbereich zugreifen, sodass Änderungen im definierenden TcCOM direkt in allen verbundenen TcCOM-Instanzen ankommen.
Modellierung in Simulink®
Es werden zwei Simulink®-Modelle erstellt:
- Modell „DataDefiner“
- Modell „DataUser“
Des Weiteren wird ein Simulink®-Bus definiert und als Simulink®-Paramater namens GlobalParam
angelegt. Das Modell DataDefiner bestimmt am Ende den Inhalt von GlobalParam, während die Modelle DataUser den Inhalt nur lesen.

Beachten Sie, dass die Definition der Storage Class von GlobalParam im Folgenden für den DataDefiner und DataUser unterschiedlich gesetzt werden. Für den DataDefiner wird als Storage Class Exported Global gesetzt, während für den DataDefiner die Storage Class auf Imported Extern gestellt wird.
Das folgende Skript bündelt die beiden beschriebenen Simulink®-Modelle in einem Treiber, vgl. Bündelung mehrerer Modelle in einem TwinCAT-Treiber.
thisDir = fileparts(mfilename("fullpath"));
% model names
mdlNames = ["DataDefiner","DataUser"];
codeDirectories = fullfile(thisDir,strcat(mdlNames,'_tcgrt'));
isParamDefiner = [true,false];
% instantiate project configuration
projCfg = TwinCAT.ModuleGenerator.ProjectExportConfig('FullPath',fullfile(thisDir,'TcCppProj','DataSharingModules.vcxproj'));
regenerate = false;
for i=1:length(mdlNames)
% generate code for the models (only if the code directory doesn't exist) -> remove the directory to rebuild specific models
if regenerate || ~isfolder(codeDirectories(i))
% load the model and apply basic settings
mdl = load_system(mdlNames(i));
set_param(mdl,'SystemTargetFile','TwinCatGrt.tlc');
set_param(mdl,'CodeInterfacePackaging','C++ class');
set_param(mdl,'TcCom_TcComWrapperFb','off');
set_param(mdl,'TcProject_Generate','off');
set_param(mdl,'SolverType','Fixed-step');
% adapt the storage class of the shared parameter structure
if isParamDefiner(i)
GlobalParam.CoderInfo.StorageClass = "ExportedGlobal";
else
GlobalParam.CoderInfo.StorageClass = "ImportedExtern";
end
% generate code and close the model
slbuild(mdl);
close_system(mdl,0);
end
% add the class export configuration to the "global" project export configuration
mdlProjCfg = TwinCAT.ModuleGenerator.ProjectExportConfig.Load(codeDirectories(i));
clsCfg = mdlProjCfg.ClassExportCfg{1};
projCfg.AddClassExportConfig(clsCfg)
end
% generate and build the project
TwinCAT.ModuleGenerator.ProjectExporter(projCfg);
Konfiguration in der TwinCAT XAE
- Erstellen Sie in der TwinCAT XAE eine Instanz des DataDefiners (mehr sind nicht erlaubt!). Hingegen können Sie beliebig viele DataUser-Instanzen erzeugen.
- 1. Stellen Sie unter Parameter (Init) > Parameter GlobalParam_sharing für den DataDefiner auf „Define“.
- 2. Stellen Sie unter Parameter (Init) > Parameter GlobalParam_sharing für alle DataUser auf „Inherit“.
- 3. Erstellen Sie eine Task.
- 4. Weisen Sie diese Task allen erstellten Instanzen zu.
- 5. Aktivieren Sie das Projekt.

- Verändern Sie, bspw. über das Block Diagram, die Werte von GlobalParam im DataDefiner und beobachten Sie die direkte Auswirkung auf die DataUser-Instanzen.