S7-1500 und Arduino Modbus Verbindung (Arduino Server)

S7-1500 und Arduino Modbus Verbindung (Arduino Server) deutsch Mit den Mikroprozessorlösungen von Arduino eröffnet sich eine neue Welt für Simatic-Anwendungen. Die Vielseitigkeit von Arduino-Sensoren kann durch ihren äußerst günstigen Preis ergänzt werden. Obwohl sich Simatic mit der IOT2040-Serie auch dieser Welt öffnet, ist es ein Schritt einfacher, Simatic direkt mit Arduino zu verbinden. Hierfür gibt es verschiedene Lösungen. Die Modbus-Verbindung wird in diesem Kapitel vorgestellt. Im folgenden Beispiel speichert Arduino die gesammelten Messdaten als Server. Die Daten werden Simatic als Client abgefragt. Arduino fasst in diesem Fall nur wenige Daten zusammen, der Schwerpunkt liegt auf der Modbus-Verbindung.

english With Arduino's microprocessor solutions, a new world opens up for Simatic applications. The versatility of Arduino sensors can be complemented by their extremely affordable price. Although Simatic also opens up to this world with the IOT2040 series, it is a degree easier to connect Simatic directly to Arduino. There are several solutions to this, the Modbus connection is presented in this chapter. In the example below, Arduino stores the collected measurement data as a server. The Simatic is queried data as a client. Arduino summarizes only a few data in this case, the focus is on the Modbus connection.

magyar Az Arduino mikroprocesszoros megoldásaival egy új világ nyílik a Simatic alkalmazásai előtt. Az Arduino szenzorok sokoldalúságát azok rendkívül kedvező árával lehet kiegészíteni. Habár a Simatic is nyit erre a világra az IOT2040-es sorozattal, egy fokkal egyszerűbb közvetlenül összekötni az Arduinoval a Simatic-ot. Erre több megoldás is adódik, ebben a fejezetben a Modbus kapcsolat kerül bemutatásra. A lenti példában az Arduino a begyüjtött mérésadatokat szerverként tárolja. Az adatokat a Simatic kliensként kérdezi le. Az Arduino ezesetben csak néhány adatot összegez, a hangsúly a Modbus kapcsolaton van.

Simatic-Arduino VerbindungTIA Portal Sicht
Klicken Sie auf das Bild, um es zu vergrößern.
Arduino Serial Monitor
Klicken Sie auf das Bild, um es zu vergrößern

deutsch Von der S7-Seite aus kann auf die Register des Arduino zugegriffen werden, indem die Standardfunktion "modbusClient" aufgerufen wird. Die erforderlichen Einstellungen finden Sie im mitgelieferten (herunterladbaren) Programm.

english From the S7 the registers of the Arduino can be accessed by calling the standard "modbusClient" function. The required settings can be found in the supplied (downloadable) program.

magyar Az S7 oldalról a standard "modbusClient" funkció hívásával lehet az Arduino regisztereit elérni. A mellékelt (letölthető) programban megtalálhatók a szükséges beállítások.

SCL-Programm download : callArduinoModbus.scl

Der Quellcode enthält eine Beschreibung eines scl-Codes (siehe Quellcode unten). Der Code kann im TIA-Portal geöffnet und übersetzt werden.

Klicken Sie hier, um den Code anzuzeigen - Click here to view the code

Klicken Sie hier, um den Code anzuzeigen - Click here to view the code

FUNCTION_BLOCK "callArduinoModbus"
{ S7_Optimized_Access := 'TRUE' }
VERSION : 0.1
   VAR 
      modbusParameter {InstructionName := 'TCON_IP_v4'; LibVersion := '1.0'; S7_SetPoint := 'False'} : TCON_IP_v4 := (64, 16#1, 16#0B, true, ([16#C0, 16#A8, 16#00, 16#2A]), 502, 503);
      modbusClient {InstructionName := 'MB_CLIENT'; LibVersion := '4.1'; S7_SetPoint := 'False'} : MB_CLIENT;
      modbusTime {InstructionName := 'TON_TIME'; LibVersion := '1.0'} : TON_TIME;
      modbusTrig { S7_SetPoint := 'True'} : Bool;
      timeOn : Bool;
      rec : Array[0..9] of Word;
      done : Bool;
      busy : Bool;
      error : Bool;
      status : Word;
      temp : Word;
   END_VAR
 
 
BEGIN
	// communication between Simatic S7-1500 and Arduino Mega over Modbus (holding registers)
	// Server-slave: Arduino Mega (with "heartbeat" and test-informations in holding registers
	// client-master: S7-1500
	// code: Vamos, 2020 -- ob121.com
 
 
	// read in sec raster
	#modbusTime(IN := NOT (#modbusTrig),
	            PT := t#500ms,
	            Q => #modbusTrig);
 
	// trigger for modbus read
	IF #modbusTrig THEN
	    IF #timeOn THEN
	        #timeOn := false;
	    ELSE
	        #timeOn := true;
	    END_IF;
	END_IF;
 
	// call modbus client
	#modbusClient(REQ:=#timeOn,
	              DISCONNECT:= FALSE,
	              MB_MODE:=0,
	              MB_DATA_ADDR:=40001,
	              MB_DATA_LEN:=6,
	              DONE=>#done,
	              BUSY=>#busy,
	              ERROR=>#error,
	              STATUS=>#status,
	              MB_DATA_PTR:=#rec,
	              CONNECT:=#modbusParameter);
 
	// monitor for Arduino informations
	#temp := #rec[0];   // heart beat (sec tick)
	#temp := #rec[1];   // humidity (/100, 0..100%, 2..5% accuracy)
	#temp := #rec[2];   // temperature (/100,  -40..80 °C, 0,5% accuracy) 
	#temp := #rec[3];   // heat index (/100, °C)
	#temp := #rec[4];   // light intensity (0..1024)
	#temp := #rec[5];
 
	// 0000: Instruction executed without errors.
	// 0001: Connection established.
	// 0003: Connection terminated.
	// 7000: #no job active AND no connection established (REQ=0, DISCONNECT=1).
	// 7001: Connection establishment triggered.
	// 7002: Intermediate call. Connection is being established.
	// 7003: Connection is being terminated.
	// 7004: Connection established AND monitored. No job processing active.
	// 7005: data is being sent.
	// 7006: data is being received.
	// 80BB: Invalid value at ActiveEstablished parameter
	// 80C8: #no response OF the server in the defined period.
	// 8187: the MB_HOLD_REG parameter has an Invalid Pointer. Data area is too small.
	// 8380: received Modbus frame has incorrect format OR too few bytes were received.
	// 8381: Function code is NOT supported.
	// 8382: the length OF the Modbus frame in the frame header does NOT match the number OF received bytes.
	// 8383: #error reading OR writing data OR access outside the address area
	// 8384: Invalid exception code received.
	// 8385: Diagnostics code NOT supported.
	// 8386: received function code does NOT match the one sent originally.
	// 8387: the protocol ID OF the Modbus TCP frame received BY the server is NOT "0".
	// 8388: the Modbus server sent a different data length than was requested.
	// 8389: Invalid data area definition
	// 80B6: Invalid connection type, only TCP connections are supported.
	// 80BB: Invalid value at ActiveEstablished parameter
	// 8188: the MB_MODE parameter has an Invalid value.
	// 8189: Invalid addressing OF data at the MB_DATA_ADDR parameter.
	// 818A: Invalid data length at the MB_DATA_LEN parameter.
	// 818B: the MB_DATA_PTR parameter has an Invalid Pointer.
	// 818C: Timeout at parameter BLOCKED_PROC_TIMEOUT OR RCV_TIMEOUT
	// 8200: A different Modbus request is currently being processed via the PORT.
 
END_FUNCTION_BLOCK

deutsch Für die Modbus Server-Funktion verwendet Arduino die Standard-Modbus-Bibliothek. Die Verwendung der Bibliothek ist speicherintensiv, daher reicht Uno für die Funktion nicht aus. Es muss die Mega-Karte verwendet werden (Ein Vergleich von Uno und Mega finden Sie hier). Die Verbindung funktioniert über Ethernet (Modbus TCP), daher sollten Sie die Ethernet-schild verwenden. Die folgenden Bibliotheken sind für die Modbus-Verbindung erforderlich:

english For the Modbus Server function, Arduino uses the standard Modbus library. Using the library is memory intensive, so Uno is not enough for the function, the Mega card must be used (a comparison of Uno and Mega can be found here). The connection works over Ethernet (Modbus TCP), so you should use the Ethernet shield. The following directories are required for the Modbus connection:

magyar A Modbus Server funkcióhoz az Arduino a standard Modbus könyvtárat használja. A könyvtár alkalmazása memóriaigényes, így az Uno nem elégséges a funkcióhoz, a Mega kártyát kell alkalmazni (az Uno és a Mega összehasonlítása itt található). A kapcsolat Etherneten működik (Modbus TCP), ezért az Ethernet shield-et érdemes használni. Az alábbi könyvtárak szükségesek a Modbus kapcsolathoz:

- https://github.com/arduino-libraries/ArduinoModbus
- https://github.com/arduino-libraries/ArduinoRS485

Arduino Mega, als Server (slave)

Arduino-Messungen

deutsch Arduino stellt Simatic im obigen Beispiel einige Messungen zur Verfügung:

  • Temperatur: DHT22-Sensormessung (-40..80 ° C, 0,5% Genauigkeit, teilbar durch 100)
  • Luftfeuchtigkeit (0..100%, 2..5% Genauigkeit, teilbar durch 100)
  • Wärmeempfindungsindex (abgeleitet von Temperatur und Luftfeuchtigkeit, teilbar durch 100)
  • Lichtintensität (0..1024, Fotosensor GL5506)
  • Anwesenheitssignal (heart-beat, sein Wert ändert sich alle 2 Sekunden)

Anschlussbelegung der Messungen: DHT22: Pin 9, Photosensor: A5.

english Arduino makes some measurements available to Simatic in the example above:

  • temperature: DHT22 sensor measurement (-40..80 ° C, 0.5% accuracy, divisible by 100)
  • humidity (0..100%, 2..5% accuracy, divisible by 100)
  • heat sensation index (derived from temperature and humidity, divided by 100)
  • light intensity (0..1024, GL5506 photo sensor)
  • presence signal (heart-beat, its value changes every 2 seconds)

Port assignment of measurements: DHT22: pin 9, photosensor: A5.

magyar Az Arduino a fenti példában néhány mérést tesz elérhetővé a Simatic számára:

  • hőmérséklet: A DHT22 szenzor mérése ( -40..80 °C, 0,5% pontosság, 100-zal osztandó)
  • páratartalom (0..100%, 2..5% pontosság, 100-zal osztandó)
  • hőérzet index (a hőmérsékletből és páratartalomból származik, 100-zal osztandó)
  • világítás-intenzitás (0..1024, GL5506 fotoszenzor)
  • jelenlét-jel (heart-beat, 2 másodpercenként változik az értéke)

Mérések port-kiosztása: DHT22: pin 9, fotoszenzor: A5.

Arduino Software

Libraries:
- https://github.com/arduino-libraries/ArduinoModbus
- https://github.com/arduino-libraries/ArduinoRS485
- https://github.com/adafruit/DHT-sensor-library
- https://github.com/adafruit/Adafruit_Sensor

Arduino-Programm download : modbus_server_mega.ino

Der Quellcode enthält eine Beschreibung eines Arduino-Codefile (siehe Quellcode unten). Der Code kann im Arduino geöffnet und übersetzt werden.

Klicken Sie hier, um den Code anzuzeigen - Click here to view the code

Klicken Sie hier, um den Code anzuzeigen - Click here to view the code

// Modbus Server Mega board 
// Test for Simatic s7-1500 Modbus connections
// Vamos Sandor - 2020 - ob121.com
// https://www.ob121.com/doku.php?id=de:project_s7:s7_arduino_modbus_master
 
#include <Ethernet.h>
#include <ArduinoModbus.h>
#include <DHT.h>
 
#define DHTPIN 9 
 
// Uncomment whatever type you're using!
//#define DHTTYPE DHT11   // DHT 11
#define DHTTYPE DHT22   // DHT 22  (AM2302), AM2321
//#define DHTTYPE DHT21   // DHT 21 (AM2301)
 
DHT dht(DHTPIN, DHTTYPE);
 
word hum, temp, heatidx, lightint;
bool _2s;
unsigned long TimeAct, TimePrev, HoldingResult, InputResult, HeartBeat, i, StartingAddr;
long Cmd;
 
EthernetServer EthServer(502);
ModbusTCPServer modbusTCPServer;
 
void setup() {
  // Ethernet Settings
  byte mac[] = { 0x4E, 0xA0, 0xBE, 0x3F, 0xFE, 0x0F };  // Define MAc address
  byte ip[] = { 192, 168, 0, 42 };                      // Define IP address
  byte subnet[] = { 255, 255, 255, 0 };                 // Define SubNEt mask
 
  // initialize the ethernet device
  Ethernet.begin(mac, ip, subnet);                      // Assign MAC, IP, and subnet mask
  Serial.begin(9600);
  EthServer.begin();          // start listening for clients
  modbusTCPServer.begin();    // start listening for clients
  dht.begin();                // start dht
 
  // Define Holding register:
  HoldingResult = modbusTCPServer.configureHoldingRegisters(0, 100);
  InputResult = modbusTCPServer.configureInputRegisters(0, 100);
 
  Serial.print("Holding Reg init result =");
  Serial.print(HoldingResult);
  Serial.print("\n");
 
  Serial.print("Input Reg init result =");
  Serial.print(InputResult);
  Serial.print("\n");
 
  Serial.print("Modbus server address=");
  Serial.println(Ethernet.localIP());
  Serial.print("\n");
}
 
void loop() {
  // Modbus server accept incoming connections
  EthernetClient client = EthServer.available();
 
  if (client.connected()) {
    modbusTCPServer.accept(client);
    // poll for Modbus TCP requests, while client connected
    modbusTCPServer.poll();
    // Serial.print("poll");
  }
 
  //---------------------------------------------------------------------------------
  // TIME  clock 2s
  TimeAct = millis();     // Millis value between  0 and  655535
 
  _2s = false;
  if (  ( (TimeAct > TimePrev) and (TimeAct - TimePrev) > 2000) or ((TimeAct < TimePrev) and (65535 - TimePrev + TimeAct) > 2000 )  ) {
    _2s = true;
    TimePrev = TimeAct;
  }
  //---------------------------------------------------------------------------------
  // HeartBeat
  if (_2s) {
    HeartBeat++;
    if (HeartBeat > 255) {
      HeartBeat = 0;
    }
    Serial.print("HeartBeat=");
    Serial.println(HeartBeat);
    Serial.print("\n");
    dht22();                // call dht sensor  
    light();                // call photosensor
  }
  //---------------------------------------------------------------------------------
  // Modbus server  :
 
  // holding register 40001: heartbeat (FC3)
  modbusTCPServer.holdingRegisterWrite(0x00, HeartBeat);  // heart beat 2sec
  modbusTCPServer.holdingRegisterWrite(0x01, hum);        // humidity (/100, 0..100%, 2..5% accuracy)
  modbusTCPServer.holdingRegisterWrite(0x02, temp);       // temperature (/100,  -40..80 °C, 0,5% accuracy) 
  modbusTCPServer.holdingRegisterWrite(0x03, heatidx);    // heat index (/100, °C)
  modbusTCPServer.holdingRegisterWrite(0x04, lightint);   // light intensity (0..1024)
  modbusTCPServer.holdingRegisterWrite(0x05, 5);          // res
  modbusTCPServer.holdingRegisterWrite(0x06, 6);          // res
 
}
 
void dht22() {
  float h = dht.readHumidity();
  float t = dht.readTemperature();  
  float f = dht.readTemperature(true);
  // Check if any reads failed and exit early (to try again).
  if (isnan(h) || isnan(t) || isnan(f)) {
    Serial.println(F("Failed to read from DHT sensor!"));
    hum = 0;         // in errorcase: 0
    temp = 0;        // in errorcase: 0
    heatidx = 0;     // in errorcase: 0
    return;
  }
 
  // Compute heat index in Fahrenheit (the default)
  float hif = dht.computeHeatIndex(f, h);
  // Compute heat index in Celsius (isFahreheit = false)
  float hic = dht.computeHeatIndex(t, h, false);
 
  Serial.print(F("Humidity: "));
  Serial.print(h);
  Serial.print(F("%  Temperature: "));
  Serial.print(t);
  Serial.print(F("°C "));
  Serial.print(f);
  Serial.print(F("°F  Heat index: "));
  Serial.print(hic);
  Serial.print(F("°C "));
  Serial.print(hif);
  Serial.println(F("°F"));  
 
  h = h * 100.0;
  t = t * 100.0;
  hic = hic * 100.0;
 
  hum = (word) h;
  temp = (word) t;
  heatidx = (word) hic; 
}
 
void light() {
  // light sensor (photosensor): GL5506 (light resisitance (10 lux): 2-6 KOhm,
  // dark resistance 0.15 MOhm
 
  int val = analogRead(5);             // read from A5
  Serial.print("Light intensity : " );
  Serial.println(val); 
  lightint = (word) val;
}

Weiteren Simatic Themen