{{ :elektronik:siemens_s7_arduino_modbus:header.png?nolink&3000 |}}
====== Siemens S7 mit Arduino und Modbus ======
===== Allgemein =====
Da wir in der Technikerschule (leider) eine S7-SPS einsetzen, musste ich meine Kenntnisse wieder etwas auffrischen. Was bietet sich da besser an, als die S7 mit einem Mikrocontroller zu verbinden?
Ich habe mir ein Gehäuse für die S7 gekauft und ein paar Taster/LEDs eingebaut. Im Gehäuse findet eine S7-1200 (1211C - kostet ca. 160€ ohne Software), Klemmen, ein Netzwerk-Switch und die Ansteuerplatine für die Taster/LEDs inklusive Arduino Platz. Natürlich habe ich zum nachrüsten noch etwas Platz gelassen und auch Anschlüsse vorbereitet.
Auf der Ansteuerplatine befindet sich ein Arduino, ein Schaltregler (24V->5V), ein 433Mhz Sender, ein 433Mhz Empfänger, ein MOSFET für die Beleuchtung und das ENC28J60-Modul (für wenige € aus China) für Ethernet.
Das ganze funktioniert erstaunlich gut. Ich habe zwar keine Tests gemacht, was das Antwortverhalten angeht, aber rein subjektiv ist das ganze echt flott. Wenn ich einen Taster auf die LED verknüpfe, dann kann man an der LED während des Drückens das Prellen als Blinken wahrnehmen (Merke: Das nächste mal hochwertigere Taster nehmen :-D).
Einzige Ausnahme ist das Versenden von einem 433Mhz Funksignal. Da die Bibliothek synchron, mit Warteschleifen funktioniert, entstehen beim Senden Verzögerungen von einigen ms. Das ist noch etwas unschön. Mal schauen, vielleicht kann man die Bibliothek umbauen, dass das Senden auch asynchron funktioniert.
===== Modbus =====
Modbus kann man seriell (RTU) oder über Ethernet (TCP) verwenden. Da meine SPS eine Ethernet-Schnittstelle besitzt, verwende ich die TCP-Variante.
Modbus unterstützt folgende Registertypen:
^ Registertyp ^ Benutzung ^ Zugriff ^
| Coil | Digital Output | Read/Write |
| Holding Register | Analog Output | Read/Write |
| Input Status | Digital Input | Read Only |
| Input Register | Analog Input | Read Only |
Diese können über Modbus-Funktionen aufgerufen werden. Digital-Werte entsprechen immer einem Bit, während analoge Werte 16-Bit entsprechen.
Die Arduino-Bibliothek unterstützt folgende:
* 0x01 - Read Coils
* 0x02 - Read Input Status (Read Discrete Inputs)
* 0x03 - Read Holding Registers
* 0x04 - Read Input Registers
* 0x05 - Write Single Coil
* 0x06 - Write Single Register
* 0x0F - Write Multiple Coils
* 0x10 - Write Multiple Registers
Als Software zum Testen von Modbus kann ich [[https://sourceforge.net/projects/qmodmaster/|QModMaster]] empfehlen. Damit habe ich die Funktionsfähigkeit der Arduino-Software getestet.
Es ist auf jeden Fall ratsam die (intigrierte) Hilfe von Siemens zum MB_CLIENT anzusehen, da dort sehr viele wichtige Punkte zur Implementierung enthalten sind. Dort wird beispielsweise erwähnt wie die Modbus-Funktionen in dem Baustein umgesetzt und beschaltet werden:
^ MB_MODE ^ Modbus-Funktion ^ Datenlänge ^ Funktion und Datentyp ^ MB_DATA_ADDR ^
| 0 | 1 | 1 bis 2000 | Output-Bits lesen: 1 bis 2000 Bits pro Aufruf | 1 bis 9999 |
| 0 | 2 | 1 bis 2000 | Input-Bits lesen: 1 bis 2000 Bits pro Aufruf | 10001 bis 19999 |
| 0 | 3 | 1 bis 125 | Halteregister lesen: 1 bis 125 WORD pro Aufruf | 40001 bis 49999 |
| 0 | 4 | 1 bis 125 | Input-Wörter lesen: 1 bis 125 WORD pro Aufruf | 30001 bis 39999 |
| 1 | 5 | 1 | Ein Output-Bit schreiben: Ein Bit pro Aufruf | 1 bis 9999 |
| 1 | 6 | 1 | Ein Halteregister schreiben: 1 WORD pro Aufruf | 40001 bis 49999 |
| 1 | 15 | 2 bis 1968 | Mehrere Output-Bits schreiben: 2 bis 1968 Bits pro Aufruf | 1 bis 9999 |
| 1 | 16 | 2 bis 123 | Mehrere Halteregister schreiben: 2 bis 123 WORD pro Aufruf | 40001 bis 49999 |
| 2 | 15 | 1 bis 1968 | Ein oder mehrere Output-Bits schreiben: 1 bis 1968 Bits pro Aufruf | 1 bis 9999 |
| 2 | 16 | 1 bis 123 | Ein oder mehrere Halteregister schreiben: 1 bis 123 WORD pro Aufruf | 40001 bis 49999 |
===== Software =====
==== Arduino ====
Es kommen folgende Bibliotheken für das Arduino zum Einsatz:
* [[https://github.com/sui77/rc-switch|rc-switch]] für die Ansteuerung der Funkmodule
* [[https://github.com/andresarmento/modbus-arduino|modbus-arduino]] für die Modbus TCP-Kommunikation
Die Modbus-Bibliothek wird scheinbar leider vom Author nicht mehr weiterentwickelt. Daher muss man zwei Patches anwenden, damit alles korrekt funktioniert:
* [[https://github.com/andresarmento/modbus-arduino/pull/22|Patch 1]] von Laserlicht
* [[https://github.com/andresarmento/modbus-arduino/pull/21/commits/ddcfc72a2e6c8c8cde4f2132b30735b193408391|Patch 2]] von seydamir
=== Code ===
++++ program.ino |
#include
#include
#include
#include
//IO-Belegung
#define LED_RED 0
#define ENC_INT 2
#define RF_REC 3
#define LED_YELLOW 4
#define LED_GREEN 5
#define LIGHT 6
#define LED_BLUE 7
#define ENC_CS 8
#define LED_BUTTON 9
#define LED_WHITE 10
#define ENC_SI 11
#define ENC_SO 12
#define ENC_SCK 13
#define RF_TRANS A0
#define ENDSWITCH A1
#define BUTTON A2
#define BUTTON_RED A3
#define BUTTON_YELLOW A4
#define BUTTON_GREEN A5
#define BUTTON_BLUE A6
#define BUTTON_WHITE A7
#define ENC_RST RST
//Fürs Programm definiert: 1xxx ISTS; 2xxx COIL; 3xxx IREG; 4xxx HREG
//IDs für Modbus-Variablen
const int ENDSWITCH_ISTS = 1001;
const int BUTTON_ISTS = 1002;
const int BUTTON_RED_ISTS = 1003;
const int BUTTON_YELLOW_ISTS = 1004;
const int BUTTON_GREEN_ISTS = 1005;
const int BUTTON_BLUE_ISTS = 1006;
const int BUTTON_WHITE_ISTS = 1007;
const int LED_RED_COIL = 2001;
const int LED_YELLOW_COIL = 2002;
const int LED_GREEN_COIL = 2003;
const int LED_BLUE_COIL = 2004;
const int LED_WHITE_COIL = 2005;
const int LED_BUTTON_HREG = 4001;
const int LIGHT_HREG = 4002;
const int RF_SEND_GROUP_HREG = 4003;
const int RF_SEND_DEVICE_HREG = 4004;
const int RF_SEND_TRIGGER_COIL = 2006;
const int RF_SEND_STATE_COIL = 2007;
const int RF_RECEIVE_GROUP_IREG = 3001;
const int RF_RECEIVE_DEVICE_IREG = 3002;
const int RF_RECEIVE_DATA_AVAILABLE_ISTS = 1008;
const int RF_RECEIVE_DATA_AVAILABLE_RST_COIL = 2008;
const int RF_RECEIVE_STATE_ISTS = 1009;
//In ModbusIP_ENC28J60.h die Konstante ENC28J60_CS ggf. anpassen!
//#define TCP_KEEP_ALIVE sollte aktiv sein
//Objekte erstellen
ModbusIP mb;
RCSwitch mySwitch = RCSwitch();
void setup() {
Serial.begin(115200);
byte mac[] = {0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED};
byte ip[] = {192, 168, 2, 175};
mb.config (mac, ip);
/*String ip_ = "";
for(int i = 0; i < 4; i++) {
ip_ += String(ether.myip[i]) + ((i<3) ? "." : "");
}
Serial.println("IP: " + ip_);*/
mySwitch.enableTransmit(RF_TRANS);
mySwitch.enableReceive(1); //Pin 3
//Outputs
pinMode(LED_RED, OUTPUT);
pinMode(LED_YELLOW, OUTPUT);
pinMode(LED_GREEN, OUTPUT);
pinMode(LED_BLUE, OUTPUT);
pinMode(LED_WHITE, OUTPUT);
pinMode(LED_BUTTON, OUTPUT);
pinMode(RF_TRANS, OUTPUT);
pinMode(LIGHT, OUTPUT);
//Pullups
digitalWrite(ENDSWITCH, HIGH);
digitalWrite(BUTTON, HIGH);
digitalWrite(BUTTON_RED, HIGH);
digitalWrite(BUTTON_YELLOW, HIGH);
digitalWrite(BUTTON_GREEN, HIGH);
digitalWrite(BUTTON_BLUE, HIGH);
digitalWrite(BUTTON_WHITE, HIGH);
//Modbus-Variablen erstellen
mb.addIsts(ENDSWITCH_ISTS, 0);
mb.addIsts(BUTTON_ISTS, 0);
mb.addIsts(BUTTON_RED_ISTS, 0);
mb.addIsts(BUTTON_YELLOW_ISTS, 0);
mb.addIsts(BUTTON_GREEN_ISTS, 0);
mb.addIsts(BUTTON_BLUE_ISTS, 0);
mb.addIsts(BUTTON_WHITE_ISTS, 0);
mb.addIsts(RF_RECEIVE_DATA_AVAILABLE_ISTS, 0);
mb.addIsts(RF_RECEIVE_STATE_ISTS, 0);
mb.addCoil(LED_RED_COIL, 0);
mb.addCoil(LED_YELLOW_COIL, 0);
mb.addCoil(LED_GREEN_COIL, 0);
mb.addCoil(LED_BLUE_COIL, 0);
mb.addCoil(LED_WHITE_COIL, 0);
mb.addCoil(RF_SEND_TRIGGER_COIL, 0);
mb.addCoil(RF_SEND_STATE_COIL, 0);
mb.addCoil(RF_RECEIVE_DATA_AVAILABLE_RST_COIL, 0);
mb.addIreg(RF_RECEIVE_GROUP_IREG, 0);
mb.addIreg(RF_RECEIVE_DEVICE_IREG, 0);
mb.addHreg(LED_BUTTON_HREG, 0);
mb.addHreg(LIGHT_HREG, 0);
mb.addHreg(RF_SEND_GROUP_HREG, 0);
mb.addHreg(RF_SEND_DEVICE_HREG, 0);
}
bool send_trigger_last = false;
bool receive_rst_last = false;
void loop() {
mb.task();
//Etwas soll gesendet werden!
if(!send_trigger_last && mb.Coil(RF_SEND_TRIGGER_COIL)) {
char group[] = "00000";
char device[] = "00000";
sprintf (group, "%05d", mb.Hreg(RF_SEND_GROUP_HREG));
sprintf (device, "%05d", mb.Hreg(RF_SEND_DEVICE_HREG));
if(mb.Coil(RF_SEND_STATE_COIL)) {
mySwitch.switchOn(group, device);
} else {
mySwitch.switchOff(group, device);
}
}
send_trigger_last = mb.Coil(RF_SEND_TRIGGER_COIL);
//Rücksetzen des Data-Aviable-Bits
if(!receive_rst_last && mb.Coil(RF_RECEIVE_DATA_AVAILABLE_RST_COIL)) {
mb.Ists(RF_RECEIVE_DATA_AVAILABLE_ISTS, false);
}
receive_rst_last = mb.Coil(RF_RECEIVE_DATA_AVAILABLE_RST_COIL);
//Etwas wurde empfangen
if (mySwitch.available()) {
int value = mySwitch.getReceivedValue();
if (value == 0) {
//Serial.print("Unknown encoding");
} else {
if(mySwitch.getReceivedProtocol()==1) {
const char* b = dec2binWzerofill(mySwitch.getReceivedValue(), mySwitch.getReceivedBitlength());
const char* rec = bin2tristate(b);
if(rec[10]!='1' && rec[11]!='1') {
char group[] = "00000";
char device[] = "00000";
bool on = false;
for(int i;i<5;i++) {
if(rec[i] == '0') group[i] = '1';
}
for(int i;i<5;i++) {
if(rec[i+5] == '0') device[i] = '1';
}
if(rec[10]!='F' && rec[11]!='0') on = true;
if(String(device).toInt()!=0) {
mb.Ireg(RF_RECEIVE_GROUP_IREG, String(group).toInt());
mb.Ireg(RF_RECEIVE_DEVICE_IREG, String(device).toInt());
mb.Ists(RF_RECEIVE_DATA_AVAILABLE_ISTS, true);
mb.Ists(RF_RECEIVE_STATE_ISTS, on);
/*Serial.println(group);
Serial.println(device);
Serial.println(on);
Serial.println(" ");*/
}
}
}
}
mySwitch.resetAvailable();
}
//Eingänge einlesen
bool button_red_state = !digitalRead(BUTTON_RED);
bool button_yellow_state = !digitalRead(BUTTON_YELLOW);
bool button_green_state = !digitalRead(BUTTON_GREEN);
bool button_blue_state = analogRead(BUTTON_BLUE) > 100 ? false : true; //Eingänge sind Analog-only
bool button_white_state = analogRead(BUTTON_WHITE) > 100 ? false : true;
bool button_state = !digitalRead(BUTTON);
bool endswitch_state = !digitalRead(ENDSWITCH);
//An Modbus transferrieren
mb.Ists(ENDSWITCH_ISTS, endswitch_state);
mb.Ists(BUTTON_ISTS, button_state);
mb.Ists(BUTTON_RED_ISTS, button_red_state);
mb.Ists(BUTTON_YELLOW_ISTS, button_yellow_state);
mb.Ists(BUTTON_GREEN_ISTS, button_green_state);
mb.Ists(BUTTON_BLUE_ISTS, button_blue_state);
mb.Ists(BUTTON_WHITE_ISTS, button_white_state);
//Modbus variablen ausgeben
digitalWrite(LED_RED, mb.Coil(LED_RED_COIL));
digitalWrite(LED_YELLOW, mb.Coil(LED_YELLOW_COIL));
digitalWrite(LED_GREEN, mb.Coil(LED_GREEN_COIL));
digitalWrite(LED_BLUE, mb.Coil(LED_BLUE_COIL));
digitalWrite(LED_WHITE, mb.Coil(LED_WHITE_COIL));
analogWrite(LED_BUTTON, min(mb.Hreg(LED_BUTTON_HREG), 255));
analogWrite(LIGHT, min(mb.Hreg(LIGHT_HREG), 255));
}
//Hilfsfunktionen
static const char* bin2tristate(const char* bin) {
static char returnValue[50];
int pos = 0;
int pos2 = 0;
while (bin[pos]!='\0' && bin[pos+1]!='\0') {
if (bin[pos]=='0' && bin[pos+1]=='0') {
returnValue[pos2] = '0';
} else if (bin[pos]=='1' && bin[pos+1]=='1') {
returnValue[pos2] = '1';
} else if (bin[pos]=='0' && bin[pos+1]=='1') {
returnValue[pos2] = 'F';
} else {
return "not applicable";
}
pos = pos+2;
pos2++;
}
returnValue[pos2] = '\0';
return returnValue;
}
static char * dec2binWzerofill(unsigned long Dec, unsigned int bitLength) {
static char bin[64];
unsigned int i=0;
while (Dec > 0) {
bin[32+i++] = ((Dec & 1) > 0) ? '1' : '0';
Dec = Dec >> 1;
}
for (unsigned int j = 0; j< bitLength; j++) {
if (j >= bitLength - i) {
bin[j] = bin[ 31 + i - (j - (bitLength - i)) ];
} else {
bin[j] = '0';
}
}
bin[bitLength] = '\0';
return bin;
}
++++
==== S7 ====
Zur Programmierung der S7 habe ich das TIA-Portal V13 verwendet. Ich verwende die auf ein Jahr begrenzte Version, welche ich von meiner Schule erhalten habe. Im S7-Starterkit ist die Software aber ebenfalls enthalten.
Ich habe die ganze Logik zur Kommunikation in einen Baustein (FB) gepackt. Dieser sieht bei mir aktuell so aus:
{{:elektronik:siemens_s7_arduino_modbus:s7_modbus_baustein.png?direct&300|}}
Bei der Erstellung des Bausteins muss Beachtet werden, dass beim FB der “Optimierte Bausteinzugriff” deaktiviert ist (Rechtsklick auf Baustein -> Eigenschaften). Dies wird von der Modbus-Funktion in S7 so gefordert.
{{:elektronik:siemens_s7_arduino_modbus:s7_optimierter_bausteinzugriff.png?direct&300|}}
Leider zählt Siemens die Modbus-Adressen anders, weshalb überall eine 1 dazuaddiert wird (siehe Quelltext). Zusätzlich zum MB_DATA_ADDR von der Tabelle oben.
++++ Variablentabelle |
Input
req Bool
LED_RED Bool
LED_YELLOW Bool
LED_GREEN Bool
LED_BLUE Bool
LED_WHITE Bool
LED_BUTTON Int
LIGHT Int
RF_SEND_GROUP String
RF_SEND_DEVICE String
RF_SEND_TRIGGER Bool
RF_SEND_STATE Bool
RF_RECEIVE_DATA_AVAILABLE_RST Bool
Output
BUTTON Bool
BUTTON_RED Bool
BUTTON_YELLOW Bool
BUTTON_GREEN Bool
BUTTON_BLUE Bool
BUTTON_WHITE Bool
ENDSWITCH Bool
RF_RECEIVE_GROUP String
RF_RECEIVE_DEVICE String
RF_RECEIVE_STATE Bool
RF_RECEIVE_DATA_AVAILABLE Bool
InOut
Static
ISTS Array[0..8] of Bool
COIL Array[0..7] of Bool
IREG Array[0..1] of Int
HREG Array[0..3] of Int
busy1 Bool
busy2 Bool
busy3 Bool
busy4 Bool
MB_CLIENT_1 MB_CLIENT
MB_CLIENT_2 MB_CLIENT
MB_CLIENT_3 MB_CLIENT
MB_CLIENT_4 MB_CLIENT
Temp
status Word
Constant
IP_OCTET_1 USInt 192
IP_OCTET_2 USInt 168
IP_OCTET_3 USInt 2
IP_OCTET_4 USInt 175
IP_PORT UInt 502
++++
++++ Source |
(* Optimierung beim DB muss deaktiviert werden! *)
(* Bausteineingänge einlesen *)
#HREG[0] := #LED_BUTTON;
#HREG[1] := #LIGHT;
#HREG[2] := STRING_TO_INT(#RF_SEND_GROUP);
#HREG[3] := STRING_TO_INT(#RF_SEND_DEVICE);
#COIL[0] := #LED_RED;
#COIL[1] := #LED_YELLOW;
#COIL[2] := #LED_GREEN;
#COIL[3] := #LED_BLUE;
#COIL[4] := #LED_WHITE;
#COIL[5] := #RF_SEND_TRIGGER;
#COIL[6] := #RF_SEND_STATE;
#COIL[7] := #RF_RECEIVE_DATA_AVAILABLE_RST;
(* Einzelne Modbus-Variablentypen übertragen *)
#MB_CLIENT_1(REQ := (NOT #busy1) AND #req,
DISCONNECT := false,
CONNECT_ID := 1,
IP_OCTET_1 := #IP_OCTET_1,
IP_OCTET_2 := #IP_OCTET_2,
IP_OCTET_3 := #IP_OCTET_3,
IP_OCTET_4 := #IP_OCTET_4,
IP_PORT := #IP_PORT,
MB_MODE := 0,
MB_DATA_ADDR := (10000 + 1 + 1001),
MB_DATA_LEN := 9,
BUSY => #busy1,
STATUS => #status,
MB_DATA_PTR := #ISTS);
#MB_CLIENT_2(REQ := (NOT #busy2) AND #req,
DISCONNECT := false,
CONNECT_ID := 2,
IP_OCTET_1 := #IP_OCTET_1,
IP_OCTET_2 := #IP_OCTET_2,
IP_OCTET_3 := #IP_OCTET_3,
IP_OCTET_4 := #IP_OCTET_4,
IP_PORT := #IP_PORT,
MB_MODE := 1,
MB_DATA_ADDR := (0 + 1 + 2001),
MB_DATA_LEN := 8,
BUSY => #busy2,
STATUS => #status,
MB_DATA_PTR := #COIL);
#MB_CLIENT_3(REQ := (NOT #busy3) AND #req,
DISCONNECT := false,
CONNECT_ID := 3,
IP_OCTET_1 := #IP_OCTET_1,
IP_OCTET_2 := #IP_OCTET_2,
IP_OCTET_3 := #IP_OCTET_3,
IP_OCTET_4 := #IP_OCTET_4,
IP_PORT := #IP_PORT,
MB_MODE := 0,
MB_DATA_ADDR := (30000 + 1 + 3001),
MB_DATA_LEN := 2,
BUSY => #busy3,
STATUS => #status,
MB_DATA_PTR := #IREG);
#MB_CLIENT_4(REQ := (NOT #busy4) AND #req,
DISCONNECT := false,
CONNECT_ID := 4,
IP_OCTET_1 := #IP_OCTET_1,
IP_OCTET_2 := #IP_OCTET_2,
IP_OCTET_3 := #IP_OCTET_3,
IP_OCTET_4 := #IP_OCTET_4,
IP_PORT := #IP_PORT,
MB_MODE := 2,
MB_DATA_ADDR := (40000 + 1 + 4001),
MB_DATA_LEN := 4,
BUSY => #busy4,
STATUS => #status,
MB_DATA_PTR := #HREG);
(* Schreiben der String-Ausgabewerte *)
#RF_RECEIVE_GROUP := INT_TO_STRING(#IREG[0]);
#RF_RECEIVE_DEVICE := INT_TO_STRING(#IREG[1]);
(* Führende Leerzeichen entfernen *)
WHILE LEFT(IN := #RF_RECEIVE_GROUP, L := 1) = ' ' DO
#RF_RECEIVE_GROUP := DELETE(IN := #RF_RECEIVE_GROUP, L := 1, P := 1);
END_WHILE;
WHILE LEFT(IN := #RF_RECEIVE_DEVICE, L := 1) = ' ' DO
#RF_RECEIVE_DEVICE := DELETE(IN := #RF_RECEIVE_DEVICE, L := 1, P := 1);
END_WHILE;
(* Auffüllen mit führenden Nullen *)
WHILE LEN(#RF_RECEIVE_GROUP) < 5 DO
#RF_RECEIVE_GROUP := CONCAT(IN1 := '0', IN2 := #RF_RECEIVE_GROUP);
END_WHILE;
WHILE LEN(#RF_RECEIVE_DEVICE) < 5 DO
#RF_RECEIVE_DEVICE := CONCAT(IN1 := '0', IN2 := #RF_RECEIVE_DEVICE);
END_WHILE;
(* Bausteinausgänge schreiben *)
#ENDSWITCH := #ISTS[0];
#BUTTON := #ISTS[1];
#BUTTON_RED := #ISTS[2];
#BUTTON_YELLOW := #ISTS[3];
#BUTTON_GREEN := #ISTS[4];
#BUTTON_BLUE := #ISTS[5];
#BUTTON_WHITE := #ISTS[6];
#RF_RECEIVE_DATA_AVAILABLE := #ISTS[7];
#RF_RECEIVE_STATE := #ISTS[8];
++++
===== Schaltung =====
Entschuldigt bitte den etwas verwirrenden Schaltplan. Aber ich wusste auf die schnelle nicht, wie ich ihn Übersichtlicher machen kann.
{{pdfjs 500px>:elektronik:siemens_s7_arduino_modbus:s7_gehaeuse.pdf}}
===== Bilder =====
{{:elektronik:siemens_s7_arduino_modbus:s7_gehaeuse_01.jpg?direct&300|}}
\\ Tests mit unbefestigter Platine
{{:elektronik:siemens_s7_arduino_modbus:s7_gehaeuse_02.jpg?direct&300|}}
\\ Tests mit unbefestigter Platine
===== 3D-Modelle =====
{{:elektronik:siemens_s7_arduino_modbus:s7_housing.stl?s=300&bgcolor=#ffffff|Gehäuse}}
{{:elektronik:siemens_s7_arduino_modbus:s7_housing_deckel.stl?s=300&bgcolor=#ffffff|Deckel}}
===== Dateien =====
Die SCL-Datei kann in TIA-Portal im Projektbaum unter “externe Quellen” hinzugefügt werden und dann per Kontextmenü entpackt werden.
{{ :elektronik:siemens_s7_arduino_modbus:s7-modbus.zip |Arduino und SCL-Quellen}}
{{tag>[arduino ethernet modbus plc s7 siemens simatic sps steuerung]}}
\\ ~~DISQUS~~