Arduino Lektion 56: 4 Phasen Schrittmotor steuern

In diesem Tutorial möchte ich gerne den 5V , 4 Phasen Schrittmotor mit Treiberplatine ULN2003 vorstellen.

Schrittmotor 28BYJ-48 mit Treiberplatine ULN2003
Schrittmotor 28BYJ-48 mit Treiberplatine ULN2003

Bezug

Den 5 V, 4 Phasen Schrittmotor vom Typ „28BYJ-48 ULN2003“ kann man über eBay.de und amazon.de günstig erwerben. Wobei man darauf achten sollte das es das „komplett Set“ ist, denn es gibt den Motor und die Platine einzeln jedoch ist das „komplett Set“ günstiger zu erwerben.

Technische Daten des  4 Phasen Schrittmotor

  • Betriebsspannung des Schrittmotors 5V
  • Betriebsspannung der Platine 5V / 12V (einstellbar über einen Jumper)
  • Abmaße
    • Durchmesser des Motors 28mm
    • Platinengröße 40,5mm x 21,3mm

Der Schrittmotor hat eine Übersetzung mit einem Zahnradgetriebe von 1: 64 d.h. für eine Umdrehung von 360° benötigt dieser Schrittmotor

360° : 64 Schritte = 5,625°  pro Schritt.

Bei einer Halbschritt Übersetzung bedeutet das, dass wir 64 * 64 Schritt für eine volle Umdrehung benötigen.
64 * 64 = 4096 Schritte pro voller Umdrehung

Diese Berechnung erfolgte aus den Angaben aus dem Datenblatt des Schrittmotors 28BYJ-48.

Aufbau

Für den Aufbau der Schaltung verwende ich einen Wemos D1 mini, dieser verfügt über ein Wifi Modul welches wir später in einem Beispiel verwenden wollen.

Aufbau - Schrittmotor am Wemos D1 Mini
Aufbau – Schrittmotor am Wemos D1 Mini

Der Schrittmotor wird mit einer Treiberplatine geliefert (Bezeichnung UNL2003) an diese kann man eine 5V oder 12V Versorgungsspannung anlegen. Die 5V liefert der Microcontroller, jedoch sollte man hier aufpassen das die Last des Motors nicht zu hoch wird denn mit der Last steigt die Stromaufnahme und der Microcontroller ist hier leider begrenzt.

UNL2003 Wemos D1 mini
IN1 D5
IN2 D6
IN3 D8
IN4 D7
GND
+ 5V

Schaltung

Schaltung - Wemos D1 Mini und Schrittmotor
Schaltung – Wemos D1 Mini und Schrittmotor

Ermitteln der Kraft des Schrittmotors

Der Schrittmotor hat je nach Geschwindigkeit eine stärkere bzw. geringere Kraft um ein Objekt wie zbsp. eine Welle zu bewegen. Ich möchte nun einmal einen kleinen Versuch starten eine 0,5l Wasserflasche aus einer Höhe von ca. 75cm anzuheben. Dabei werde ich die Flasche immer mehr füllen und auch die Geschwindigkeit erhöhen.

Aufbau Winde zum ermitteln der Kraft des Schrittmotors
Aufbau Winde zum ermitteln der Kraft des Schrittmotors

Es konnte ermittelt werden das, der Schrittmotor eine Maximale Kraft von 300g (3Nm) ab der Geschwindigkeitsstufe 2 aufbringen kann. Die Stufe 1 ist die Schnellste kann jedoch weniger Kraft aufbringen.

Tabelle mit den Messergebnissen
Tabelle mit den Messergebnissen

Quellcode

Für die nachfolgenden Beispiele wird die Bibliothek „Arduino-and-ULN2003-Stepper-Motor-Driver“ von rydepier benötigt. Diese Bibliothek kann man sich aus dem GitHub Repository herunterladen.

Wie man eine Bibliothek in der Arduino IDE installiert habe ich im Tutorial Arduino IDE, Einbinden einer Bibliothek ausführlich erläutert.

Einfaches Beispiel

Der Bibliothek „StepperMotor“ liegt bereits ein Beispiel bei welches nach einer kleinen Konfiguration sofort lauffähig ist.

#include <StepperMotor.h> //Einbinden der Bibliothek StepperMotor.h

StepperMotor motor(D5,D6,D8,D7); // IN1, IN2, IN3, IN4

//Die maximale Geschwindigkeit bei 5Volt ist 15 RPM (RoundsPerMinute)
//Je größer der Wert ist desto langsamer wird der Motor. 
//Mit einem langsamen Motor kann man größere Kräfte erzeugen!
int motorSpeed = 1; 

//Es benötigt 4096 Schritte für eine volle Umdrehung.
int motorSteps = 4096; 

//Wert für die Pause zwischen den Schritten.
int motorDelay = 1000;

void setup(){
  motor.setStepDuration(motorSpeed);
}

void loop(){
  //Erst eine volle Umdrehung entgegen des Uhrzeigersinns durchführen.
  motor.step(motorSteps); 
  delay(motorDelay); //Eine kleine Pause einlegen.

  //Danach eine volle Umdrehung im Uhrzeigersinn durchführen.
  motor.step(-motorSteps);
  delay(motorDelay); //Eine kleine Pause einlegen.
}

Video

Wemos D1 Mini mit 4 Phasen Schrittmotor 28BYJ-48 und Teiberplatine ULN2003

Webseite zum steuern des Schrittmotors 28BYJ-48 mit Treiberplatine ULN2003

Durch einen Kommentar auf einem meiner früheren Beiträge, bin ich auf eine wohl performantere Lösung von Seitenaufrufen hingewiesen worden. Dieses möchte ich nun in diesem Beispiel anwenden.

Die Webseite soll auf einem mobilen Endgerät laufen daher wähle ich die Einstellung für einen AccessPoint.

Damit sich mein Handy (Huawei P20 lite) mit dem Netzwerk verbinden konnte,  musste ich die Mobilen Daten sowie die Einstellung „WLAN+“ unter den WLAN Einstellungen deaktivieren.

Erstellen der Webseite

Die Webseite muss als String im Sketch hinterlegt werden. Ich schreibe zuerst die Seite in einem Editor wie Notepad++ oder PSPad da diese mit einem entsprechenden Highlighting beim schreiben unterstützt.

Webseite für die Steuerung des Schrittmotors
Webseite für die Steuerung des Schrittmotors
Quellcode der Webseite

Nachfolgend nun den Quellcode für die Webseite.
Dieser Code muss noch um die echte IP-Adresse des Servers ergänzt werden dieses wird dann im Quellcode des Sketches erfolgen.

<html><head><meta charset="utf-8">  
		<title>Online Schrittmotorsteuerung</title>
		<style>
			label{ display:inline-block; width:230px;}
			.lbl {width:100px;}
			.textfield {width:60px;}
		</style>
	</head>
	<body>
		<h2>Schrittmotorsteuerung</h2>
		<fieldset>
		  <legend>Konfiguration</legend>
		  <label>Drehrichtung</label>
		  <input type="radio" value="1" name="direction" id="vRbtn"/>
		  <label for="vRbtn" class="lbl">Vorwärts</label> 
		  <input type="radio" value="2" name="direction" id="rRbtn"/>
		  <label for="rRbtn" class="lbl">Rückwärts</label> 
		  <br/><br/>
		  <label for="spTField">Geschwindigkeit</label>
		  <input class="textfield" type="number" value="1" id="spTField" min="1" max="15"/>
		  <br/><br/>
		  <label for="sVUTField">Schritte für eine volle Umdrehung</label>
		  <input class="textfield" type="number" value="4096" id="sVUTField" min="1"/>
		  <br/><br/>
		  <label for="sTField">Schritte</label>
		  <input class="textfield" type="number" value="10" id="sTField" min="1"/>
		  <br/><br/>
		  <input type="button" value="Speichern" id="cSBtn"/>
		</fieldset>
		<div style="margin:0px auto; width:100px">
		<br/><br/>
		<input type="button" value="Start" id="startBtn"/>
		</div>
		<script>
			var ipadresse = "-undefined-";
			
			var drehrichtung = 1;
			var schritteVolleUmdrehung = 4096;
			var schritte = 10;
			var geschwindigkeit = 1;
			
			if(drehrichtung === 1){
			  document.getElementById("vRbtn").checked = true;
			} else {
			  document.getElementById("rRbtn").checked = true;
			}
			
			document.getElementById("spTField").value(geschwindigkeit);
			document.getElementById("sVUTField").value(schritteVolleUmdrehung);
			document.getElementById("sTField").value(schritte);
			
			document.getElementById("startBtn").onclick = startMotor;
			document.getElementById("cSBtn").onclick = saveConfiguration;
			
			function startMotor(){
				window.open("http://"+ipadresse+"/index.html?start=1","_self");
			}
			
			function saveConfiguration(){
				var direction = document.getElementById("vRbtn").checked?1:2;
				var svu = document.getElementById("sVUTField").value;
				var st = document.getElementById("sTField").value;
				var sp = document.getElementById("spTField").value;
				window.open("http://"+ipadresse+"/index.html?direction="+direction+"&svu="+svu+"&st="+st+"&sp="+sp,"_self");
			}
		</script>
	</body>
</html>

Dieser Html Code muss nun in den Arduino Sketch eingefügt werden. Dazu werde ich diesen Code auf das Minimum reduzieren, d.h. alle unnötigen Leerzeichen sowie Zeilenumbrüche werden entfernt.

Das kann man per Hand oder aber auch bequem über eine Seite wie https://www.willpeavy.com/minifier/ lösen.

Das Ergebnis zu meinem Code wäre:

<html><head><meta charset="utf-8"> <title>Online Schrittmotorsteuerung</title><style>label{display:inline-block; width:230px;}.lbl{width:100px;}.textfield{width:60px;}</style></head><body><h2>Schrittmotorsteuerung</h2><fieldset> <legend>Konfiguration</legend> <label>Drehrichtung</label> <input type="radio" value="1" name="direction" id="vRbtn"/> <label for="vRbtn" class="lbl">Vorwärts</label> <input type="radio" value="2" name="direction" id="rRbtn"/> <label for="rRbtn" class="lbl">Rückwärts</label> <br/><br/> <label for="spTField">Geschwindigkeit</label> <input class="textfield" type="number" value="1" id="spTField" min="1" max="15"/> <br/><br/> <label for="sVUTField">Schritte für eine volle Umdrehung</label> <input class="textfield" type="number" value="4096" id="sVUTField" min="1"/> <br/><br/> <label for="sTField">Schritte</label> <input class="textfield" type="number" value="10" id="sTField" min="1"/> <br/><br/> <input type="button" value="Speichern" id="cSBtn"/></fieldset><div style="margin:0px auto; width:100px"><br/><br/><input type="button" value="Start" id="startBtn"/></div><script>var ipadresse="-undefined-";var drehrichtung=1;var schritteVolleUmdrehung=4096;var schritte=10;var geschwindigkeit=1;if(drehrichtung===1){document.getElementById("vRbtn").checked=true;}else{document.getElementById("rRbtn").checked=true;}document.getElementById("spTField").value(geschwindigkeit);document.getElementById("sVUTField").value(schritteVolleUmdrehung);document.getElementById("sTField").value(schritte);document.getElementById("startBtn").onclick=startMotor;document.getElementById("cSBtn").onclick=saveConfiguration;function startMotor(){window.open("http://"+ipadresse+"/index.html?start=1","_self");}function saveConfiguration(){var direction=document.getElementById("vRbtn").checked?1:2;var svu=document.getElementById("sVUTField").value;var st=document.getElementById("sTField").value;var sp=document.getElementById("spTField").value;window.open("http://"+ipadresse+"/index.html?direction="+direction+"&svu="+svu+"&st="+st+"&sp="+sp,"_self");}</script></body></html>

Die Lesbarkeit ist nun auf fast 0% gesunken, jedoch sind durch diese Art der Komprimierung die Bytes welche für den String benötigt werden gesunken.

Ergebnis der Komprimierung durch Minify einer Html Seite
Ergebnis der Komprimierung durch Minify einer Html Seite

Damit diese Seite später in dem Sketch verwendet werden kann müssen alle Anführungszeichen escaped werden, d.h. es muss ein Backslash „\“ davor gestellt werden. Dieses mache ich in der Anwendung NotePad++ durch die Funktion „Suchen & Ersetzen“.

Durch das bearbeiten der Seite kann diese nun nicht mehr mit einem Browser vernünftig dargestellt werden.

Aufbau des Sketches in der Arduino IDE

Erzeugen des AccesssPoints

Wie man einen AccessPoint einrichtet habe ich im Tutorial Wemos D1 Mini (ESP8266) als AccessPoint einrichten bereits beschrieben, daher möchte ich hier auf die Besonderheit eingehen damit dieser eine Webseite anzeigen kann.

Wir benötigen für die Anzeige einer Webseite zusätzlich einen Serverdienst diesen binden wir über die Bibliothek „ESP8266WebServer.h“ in den Sketch ein. Der Webserver läuft über den Port 80 (dies ist der übliche Port für einen HTTP Webserver).

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>

ESP8266WebServer server(80);

int countConnectedDevices = 0;

// Wird ausgeuehrt wenn "http://<ip address>/" aufgerufen wurde
void callHome(){
  String text = "";
  text+="Hallo Welt!";
  server.send(200, "text/html", text);
}

void setup(){
  Serial.begin(115200);
  Serial.println();

  boolean result = WiFi.softAP("WemosAP", "geheim123");  
  Serial.print("Verbindung wurde ");
  if(result == false){
    Serial.println("NICHT ");
  }
  Serial.print("erfolgreich aufgebaut!");

  Serial.println("Server IP-Adresse:");
  Serial.print(WiFi.softAPIP());

  //Wenn der Client eine Anfrage startet.
  server.on("/", callHome);

  // Starte den Server
  server.begin();
}

void loop(){
  if(countConnectedDevices != WiFi.softAPgetStationNum()){
     countConnectedDevices = WiFi.softAPgetStationNum();
     Serial.printf("Anzahl der Verbundenen Geräte= %d\n", countConnectedDevices);
  }
  
  server.handleClient();
}

Wenn dieser Sketch ausgeführt wird, dann wird als erstes auf dem seriellen Monitor der Arduino IDE folgende Ausgabe sichtbar:

Ausgabe auf dem seriellen Monitor der Arduino IDE
Ausgabe auf dem seriellen Monitor der Arduino IDE

Wir sollten also nun das gesicherte Netzwerk „WemosAP“ sehen.
Hat man sich erfolgreich zum Netzwerk verbunden so navigiert man mit
einen beliebigen Browser zur IP-Adresse „192.168.4.1“ es sollte
dann die Ausgabe „Hallo Welt!“ erscheinen.

Ausgabe im Browser (Google Chrome)
Ausgabe im Browser (Google Chrome)

Ersetzen wir also nun den Text „Hallo Welt!“ gegen unsere Webseite und ersetzen im JavaScript Block den Platzhalter für die IP-Adresse durch die echte.

Screenshot Schrittmotorsteuerung (mobile Ansicht)
Screenshot Schrittmotorsteuerung (mobile Ansicht)

Sketch mit der Webseite und dem Code für den Schrittmotor

#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <StepperMotor.h> 

ESP8266WebServer server(80);
StepperMotor motor(D5,D6,D8,D7);

int countConnectedDevices = 0;

int drehrichtung = 1;
int schritteVolleUmdrehung = 4096;
int schritte = 10;
int geschwindigkeit = 1;

IPAddress ipAdresse;

void callHome(){
  Serial.println("callHome");
  server.send(200, "text/html", getWebpage());
}

void callStart(){
  Serial.println("callStart");
  printArgs();

  motor.setStepDuration(geschwindigkeit);
  switch(drehrichtung){
    case 1 : motor.step(schritte); break;
    case 2 : motor.step(-schritte); break;
  }
  
  server.send(200, "text/html", getWebpage());
}

void callConfig(){
  Serial.println("callConfig");
  printArgs();
  server.send(200, "text/html", getWebpage());
}

void printArgs(){
  for (int i = 0; i < server.args(); i++) {
      String parameterName = server.argName(i);
      String parameterValue = server.arg(i);

      if(parameterName == "svu"){
        schritteVolleUmdrehung = parameterValue.toInt();
      } else if(parameterName == "st"){
        schritte = parameterValue.toInt();
      } else if(parameterName == "sp"){
        geschwindigkeit = parameterValue.toInt();
      } else if(parameterName == "direction"){
         drehrichtung = parameterValue.toInt();
      } 
      
      Serial.print(parameterName);
      Serial.print(" : ");
      Serial.println(parameterValue);
  } 
}

String getWebpage(){
   String webpage ="<html><head><meta charset=\"utf-8\"> <title>Online Schrittmotorsteuerung</title><style>label{display:inline-block; width:230px;}.lbl{width:100px;}.textfield{width:60px;}</style></head><body><h2>Schrittmotorsteuerung</h2><fieldset> <legend>Konfiguration</legend> <label>Drehrichtung</label> <input type=\"radio\" value=\"1\" name=\"direction\" id=\"vRbtn\"/> <label for=\"vRbtn\" class=\"lbl\">Vorwärts</label> <input type=\"radio\" value=\"2\" name=\"direction\" id=\"rRbtn\"/> <label for=\"rRbtn\" class=\"lbl\">Rückwärts</label> <br/><br/> <label for=\"spTField\">Geschwindigkeit</label> <input class=\"textfield\" type=\"number\" value=\"1\" id=\"spTField\" min=\"1\" max=\"15\"/> <br/><br/> <label for=\"sVUTField\">Schritte für eine volle Umdrehung</label> <input class=\"textfield\" type=\"number\" value=\"4096\" id=\"sVUTField\" min=\"1\"/> <br/><br/> <label for=\"sTField\">Schritte</label> <input class=\"textfield\" type=\"number\" value=\"10\" id=\"sTField\" min=\"1\"/> <br/><br/> <input type=\"button\" value=\"Speichern\" id=\"cSBtn\"/></fieldset><div style=\"margin:0px auto; width:100px\"><br/><br/><input type=\"button\" value=\"Start\" id=\"startBtn\"/></div><script>var ipadresse=\""+ipAdresse.toString()+"\";var drehrichtung="+drehrichtung+";var schritteVolleUmdrehung="+schritteVolleUmdrehung+";var schritte="+schritte+";var geschwindigkeit="+geschwindigkeit+";if(drehrichtung===1){document.getElementById(\"vRbtn\").checked=true;}else{document.getElementById(\"rRbtn\").checked=true;}document.getElementById(\"spTField\").value=geschwindigkeit;document.getElementById(\"sVUTField\").value=schritteVolleUmdrehung;document.getElementById(\"sTField\").value=schritte;document.getElementById(\"startBtn\").onclick=startMotor;document.getElementById(\"cSBtn\").onclick=saveConfiguration;function startMotor(){window.open(\"http://\"+ipadresse+\"/start.html?start=1\",\"_self\");}function saveConfiguration(){var direction=document.getElementById(\"vRbtn\").checked?1:2;var svu=document.getElementById(\"sVUTField\").value;var st=document.getElementById(\"sTField\").value;var sp=document.getElementById(\"spTField\").value;window.open(\"http://\"+ipadresse+\"/config.html?direction=\"+direction+\"&svu=\"+svu+\"&st=\"+st+\"&sp=\"+sp,\"_self\");}</script></body></html>";
   return webpage;
}

void setup(){
  Serial.begin(115200);
  Serial.println();

  boolean result = WiFi.softAP("WemosAP", "geheim123");  
  Serial.print("Verbindung wurde ");
  if(result == false){
    Serial.println("NICHT ");
  }
  Serial.println("erfolgreich aufgebaut!");
  
  Serial.println("");
  
  Serial.println("Server IP-Adresse:");
  ipAdresse = WiFi.softAPIP();
  Serial.print(ipAdresse);

  //Wenn der Client eine Anfrage startet.
  server.on("/", callHome);
  server.on("/start.html", callStart);
  server.on("/config.html", callConfig);

  // Starte den Server
  server.begin();
}

void loop(){
  if(countConnectedDevices != WiFi.softAPgetStationNum()){
     countConnectedDevices = WiFi.softAPgetStationNum();
     Serial.printf("Anzahl der Verbundenen Geräte= %d\n", countConnectedDevices);
  }
  
  server.handleClient();
}

 

4 Gedanken zu „Arduino Lektion 56: 4 Phasen Schrittmotor steuern

  • Oktober 1, 2019 um 16:18
    Permalink

    ich bekommen den StepperMotor.h nicht installiert.
    Downloade mir die Datei „Arduino-and-ULN2003-Stepper-Motor-Driver-master.zip“
    Gehe auf Menü „Sketch->Library importieren…->Add Library… klicke die Datei an.
    Gehe auf Bibliotheksverwaltung und gebe im Suchfeld „StepperMotor.h“
    keine Treffer…

    Immer wenn ich das Programm überprüfe gibt er mir die Fehlermeldung:
    xit status 1
    no matching function for call to ‚Stepper::Stepper(const uint8_t&, const uint8_t&, const uint8_t&, const uint8_t&)‘

    Was mache ich falsch ?

    Antwort
  • November 1, 2019 um 20:55
    Permalink

    Hallo Herr Draeger,
    erst mal herzlichen Dank für diese Anleitung! Mir ist allerdings aufgefallen, dass bei dem void callStart die schrittmotor-Pins nicht wieder auf Null/LOW gezogen werden nach der Bewegung, was zur Folge hat, das es passiert, dass ein oder zwei Schrittmotor-Pins auf High stehen bleiben und der Schrittmotor dadurch warm wird.
    hier die Änderung in dem void callStart:
    void callStart(){
    Serial.println(„callStart“);
    printArgs();

    motor.setStepDuration(geschwindigkeit);
    switch(drehrichtung){
    case 1 : motor.step(schritte); break;
    case 2 : motor.step(-schritte); break;
    }
    digitalWrite(D5, LOW);
    digitalWrite(D6, LOW);
    digitalWrite(D7, LOW);
    digitalWrite(D8, LOW);

    Serial.println(„Motor stop“);

    server.send(200, „text/html“, getWebpage());
    }
    Dann habe ich noch eine Frage, wie ist es möglich, in der Zeile, wo sich der Start-Button befindet, weitere Buttons einzurichten, die aber feste Werte haben/übermitteln. Beispiel ein Button soll vorwärts 10 heißen und dann eben vorwärts 10 Schritte laufen. Also quasi vordefinierte Buttons mit festen Werten. Für Hilfe in diesem Bereich und dem Quellcode wäre ich Ihnen dankbar!

    Gruß
    Wolfgang

    Antwort
    • November 2, 2019 um 19:34
      Permalink

      Hi,

      danke für deine Anmerkung zu meinem Code.

      Wenn du eine weitere Schaltfläche bzw. Button dem HTML Formular hinzufügen möchtest dann wäre dieses ein weiteres Html INPUT Type Button Element.
      Im nachfolgenden ein kleines Beispiel wie du zwei Schaltflächen implementieren kannst welche dann die Funktion „callStart“ aufruft.


      Bitte probiere das doch mal, und melde dich einfach mal zurück.

      Gruß,

      Stefan Draeger

      Antwort
  • November 25, 2019 um 17:17
    Permalink

    Hi,

    cooles Projekt,
    habe das mal nach gebaut, hatte am Anfang auch Probleme mit der library StepperMotor.h
    Hab mir diese Bibliothek wie oben beschrieben, aus dem GitHub Repository heruntergeladen und manuell installiert.
    Außerdem ist der Code noch von folgenden Printouts auf dem seriellen Monitor erweitert worden.

    void callStart() {
    long startTime = 0;
    Serial.println(„callStart“);
    printArgs();
    motor.setStepDuration(geschwindigkeit);
    startTime = millis();
    switch (drehrichtung) {
    case 1 : motor.step(schritte); break;
    case 2 : motor.step(-schritte); break;
    }
    // Erweiterung
    // Zusaetzliche Printout fuer den Serial Monitor
    Serial.print(„time: „);
    Serial.println(millis() – startTime);
    Serial.print(„geschwindigkeit: „);
    Serial.println(geschwindigkeit);

    // Pins auf Null/LOW setzen (Wolfgang)
    digitalWrite(D5, LOW);
    digitalWrite(D6, LOW);
    digitalWrite(D7, LOW);
    digitalWrite(D8, LOW);

    Serial.println(„Motor stop“);
    //Ende
    server.send(200, „text/html“, getWebpage());
    }

    Suche noch ein Beispiel wo ich genau für eine komplette Umdrehung 60 Sekunden brauche,
    aber leider kann man bei “ geschwindigkeit “ keine Komma-Werte angeben.
    int geschwindigkeit = 1;

    Wie schon gesagt sehr schönes Projekt.

    Gruß
    ///Helge

    Antwort

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert.