Arduino IP ändern Fest speichern

Hallo liebe Arduinogemeinde,

ich habe ein kleines Projekt.

Siemens S7-300 als Logic und meine Arduinos mit Ethenetshield als EA Slave

Nun würde ich gerne per Putty die Ip ändern können.

Sprich ich habe 1 Arduino in Resever die standart ip ist 192.168.1.5
nun geht aber ein Arduino kaputt der die ip 192.168.1.6 hat.

nun kann ich zwar das programm ändern. möchte dies aber von außen lösen

Befehle - Augabe
Getip --> zeigt die aktuelle ip im Putty
Getmask --> zeigt die subnetzmaske
Getgw --> zeigt die gateway adresse

Setip 192.168.001.005 --> ändert die ip
Setmask 255.255.255.000 --> ändert die mask
Setgw 192.168.001.001 --> ändert die GW adresse.

Ip soll noch einer spannungsunterbrechnung beibehalten werden.

habt ihr da evtl ein paar beispiele oder wonach ich suchen muss? Stehe da echt auf dem schlauch

Warum flasht du nicht einfach , sobald einer defekt ist? Es gibt auch die Möglichkeit, die IP Adresse von der SD Karte zu lesen. Gibt eine Beispiele mit Hilfe von Google dazu.

naja ich würd es halt gerne extern ändern können.

hat da jemand eine idee oder ein tipp nach was ich da suchen muss?

Dann stell 192.168.178. fest, und stelle die letzten 3 stellen mit einem 8Bit-Schalter ein. Gehen dir aber 8Ports für flöten. Diesen fragst du dann im setup ab.

Alternativ musste mit USB dran und über Seriellen Monitor Parameter schicken, die der Arduino dann im EEPROM schieben soll. Dann holt er sich bei jedem Restart die Einstellungswerte aus dem Eeprom.

ich weiß, dass es mit dem Programm die einfachste lösung wär.

aber da ich das Projekt evtl dann veröffentlichen möchte kostenfrei wär es natürlich toll wenn die jeder hanz und franz per serial einstellen kann.

über SerialRead muss das ja irgendwie funktionieren.

vielleicht gibt es dafür bespiele oder du kannst mir da den ein oder andere tipp geben

und wie schiebe ich etwas fest in den eeprom?

Fest wird immer ins EEPROM geschrieben. Beispiele habe ich keine. Gibt aber genügend Sketche in der Arduino IDE und im Playground. Ansonsten behandelt fast jedes Arduino Buch dieses Thema.

na dann empfehle mir doch mal ein buch oder nenne mir mal stichpunkte bzw befehle nach was ich suchen muss um

eingabe:Setip
ausgabe:Bitte geben sie die ip ein
eingabe:192.168.000.005

im hintergrund soll er die ip in die ipBytes packen
ipByte1:192
ipByte2:168
ipByte3:000
ipByte4:005

ausgabe: ip wurde übernommen

Sketch nicht vollständig. Habe den Ethernet Teil rausgehalten. Das System sollte nun klar sein mit dem Eeprom.

Du fragst am besten dann in der setup() ab, ob IP geändert werden soll. Sprich mit PC dran und Serial Monitor.

Werte werden ins Eeprom an die Stellen geschriebne. Nun fehlt dir dann noch das auslesen in der setup vor der setIP Abfrage. Wenn du setIP ausführst., würdest du die alten Werte überschreiben.

Alle nötigen Infos sind bereits in der IDE hinterlegt unter Beispiele EEPROM

#include <EEPROM.h>

const int NUMBER_OF_FIELDS = 4; // Wie viele kommaseparierte Felder erwarten wir?
int fieldIndex = 0; // Das aktuell empfangene Feld
int values[NUMBER_OF_FIELDS]; // Array mit den Werte aller Felder


void setup()
{
  Serial.begin(9600); // Serieller Port sendet und empfaengt mit 9600 Baud
}

void setIP() {
  Serial.println("IP Einstellung, neue IP bitte wie folgt eingeben und mit Enter bestaetigen");
  Serial.println("192.168.178.100");

  if( Serial.available()) {
    for(fieldIndex = 0; fieldIndex < NUMBER_OF_FIELDS; fieldIndex ++)
    {
      values[fieldIndex] = Serial.parseInt(); // Numerischen Wert einlesen
    }
    Serial.print( fieldIndex);
    Serial.println(" Felder empfangen:");
    for(int i=0; i < fieldIndex; i++)
    {
      EEPROM.write(values[i],i);
    }
    fieldIndex = 0; // und von vorn anfangen
    Serial.println("Neue IP Adresse :");
    Serial.print(values[0]);Serial.print("."); Serial.print(values[1]);Serial.print("."); Serial.print(values[2]);Serial.print("."); Serial.println(values[3]);
  }
}


void loop()
{

}

okay danke,

wann springt er denn in die Void.setip()

Garnicht! Ich hab nur die Funktion erstellt. Würde es splitten! die ersten Textausgaben in setup. Im loop immer wieder nach
if(Serial.available() > 0 && newVar == false) { ...] abfragen.
Die newVar sollte eine statische/globale Variable sein, die gesetzt wird, sobald die Daten geändert wurden, damit der aufruf nicht erneut kommt.

char MPresponse[22]={};
byte ip1;
byte ip2;
byte ip3;
byte ip4;
byte sperre;
void setup(){
 Serial.begin(9600);
Serial.println("Bereit zum empfangen"); 
}


void loop(){
  
  
if (Serial.available() >= 22){  //reading a single 22 byte command
for (int i = 0; i <= 21; i++) {
MPresponse[i] = Serial.read();
}
MPresponse[22] = '\0';               //add null character to end of string
sperre = 1;
Serial.println("empgangen:");
Serial.println(MPresponse);

}
if(MPresponse[0] == 'G' && MPresponse[1] == 'e' && MPresponse[2] == 't' && MPresponse[3] == 'i' && MPresponse[4] == 'p' && sperre == 1){
 Serial.print("ihre IP: ");
 Serial.print(ip1);
 Serial.print(".");
 Serial.print(ip2);
 Serial.print(".");
 Serial.print(ip3);
 Serial.print(".");
 Serial.println(ip4);
sperre = 0;

}

if(MPresponse[0] == 'S' && MPresponse[1] == 'e' && MPresponse[2] == 't' && MPresponse[3] == 'i' && MPresponse[4] == 'p' && sperre == 1){
ip1 = (((MPresponse[6] -48)*100)+((MPresponse[7] -48)*10)+((MPresponse[8] -48)*1));
ip2 = (((MPresponse[10] -48)*100)+((MPresponse[11] -48)*10)+((MPresponse[12] -48)*1));
ip3 = (((MPresponse[14] -48)*100)+((MPresponse[15] -48)*10)+((MPresponse[16] -48)*1));
ip4 = (((MPresponse[18] -48)*100)+((MPresponse[19] -48)*10)+((MPresponse[20] -48)*1)); 
 Serial.print("Neue IP: ");
 Serial.print(ip1);
 Serial.print(".");
 Serial.print(ip2);
 Serial.print(".");
 Serial.print(ip3);
 Serial.print(".");
 Serial.println(ip4);
sperre = 0;
}


}

Problem:
gebe ist als erstes Getip 192.168.178.123
ein. Sagt er mit Ihre ip ist 0.0.0.0
das ist ja soweit richtig.

Nun gebe ich Setip 192.168.178.123 ein
Ihre neue ip ist 192.168.178.123
auch richtig.

ABER gebe ich nun wieder Getip 192.168.178.123 ein
kommt als Antwort: Ihre ip ist 0.168.178.123

wieso wird ip1 eine 0 ?

und kann ich nach Getip abbrechen? muss nun immer alle 22 stellen ausfüllen. würde es gerne so haben das er nur Getip einlesen braucht und gleich reinspringt

Du hast einen Puffer-Überlauf programmiert:
MPresponse[22] = '\0';

Ein Array der Größe 22 geht von 0 bis 21. Wenn du auf auf den Index 22 zugreifst, überschreibst du dir ip1, da der Speicher direkt hintereinander belegt wird.

Dann zwei weitere Sachen:
1.)
Wenn du es schon in ein char Array einliest, kannst du auch atoi() für die Wandlung nehmen:
http://www.cplusplus.com/reference/cstdlib/atoi/

Das ist kürzer, übersichtlicher und weniger fehleranfälllig. Den Offset gibt du als Addition zu MPresponse an. z.B. atoi(MPresponse + 4) für das 2. Oktett. MPresponse selbst entspricht dabei +0. Aber du kannst nicht die eckigen Klammern verwenden da die Funktion einen Zeiger als Parameter will. Man kann jedoch einfach einen festen Wert auf den Variablen-Namen addieren, da Arrays Zeiger auf das erste Element sind.

2.)
Für das Vergleichen von Teil-Strings gibt es strncmp():
http://www.cplusplus.com/reference/cstring/strncmp/
Da gibst du nur einen Vergleichs-Strings an und die Anzahl der Zeichen die verglichen werden sollen. Die Funktion liefert bei Gleichheit 0 zurück.

Wichtig ist hier die "n" Version zu verwenden, da das normale strcmp() den kompletten String vergleicht.

Okay, aber wenn ich eine stelle vergesse
Setip 192.168.178.12(3) 3 vergessen

dann steht beim nächsten eingeben
etip 192.168.178.123

weil er das G noch beim ersten buffer anbaut

gibt es da eine funktion die alles leert? das jede neue eingabe bei 0 beginnt.

Baue deine Einlese-Routine um. Statt auf die Anzahl der Zeichen abzufragen, stellst du den Serial-Monitor so ein, dass er am Ende ein Linefeed/Newline sendet (links von der Baudrate). Auf das fragst du dann ab:

const int SERIAL_BUFFER_SIZE = 25;
char serialBuffer[SERIAL_BUFFER_SIZE];

void loop()
{
    if(checkSerial())
    {
          //Auswertung hier
    }
}

bool checkSerial()
{
  static byte index;
  if(Serial.available())
  {
        char c = Serial.read();
	if(c != '\n' && index < SERIAL_BUFFER_SIZE - 1)
	{
		serialBuffer[index++] = c;
	}
	else
	{
		serialBuffer[index] = '\0';
		index = 0;
		return true;
	}
   }
   return false;
}

Wenn checkSerial() true zurück liefert hast du eine Zeile ausgelesen und kannst sie auswerten. Die nächste Eingabe beginnt dann wieder bei 0.

 if(checkSerial())
    {
          //Auswertung hier
    }

Hm wie soll ich das denn umbauen steh da etwas au dem schlauch

Du hast bisher deine Auslese-Sachen in loop(). Das ist jetzt alles in der Funktion checkSerial(). Die Funktion wird immer wieder aufgerufen und gibt solange false zurück bis das Linefeed kommt. Der Teil, den du machst wenn die Eingabe fertig eingelesen ist kommt dann innerhalb der geschweiften Klammern.

Falls, das klarer ist. Das ist die Kurzversion von dem hier:

if(checkSerial() == true)
{
}

also muss da der komplette alte code rein seh ich das richtig?

Nur der Teil in dem du das Array nach dem Einlesen verarbeitet/auswertest. Nicht alles.

was macht das denn?

sonst funktionierts, danke =)

		return true;
	}
   }
   return false;

was macht das denn?

Das kompiliert nicht, weil öffnende Klammern fehlen. und der Funktionsanfang.
macht also gar nichts.

Eine Funktion, die als

bool func()

deklariert ist, muss vereinbarungsgemäss einen bool (oder boolean) Wert zurückliefern.
Das kann auch vor dem Ende der Funktion passieren. Spart also evtl. if - else Ebenen.

/// bool checkSerial ()
//   liest Serial und liefert true zurück, wenn eine Eingabe, 
//   die im globalen char SerialBuffer[] gesammelt wurde, 
//   vollständig ist
bool checkSerial()
{
  if (Serial.available() )
  {
     zeichenLesen();
     if (allesAngekommen()) return true;
  }
return false; 
}

In diesem Code fehlen nun dei Funktionen

void zeichenLesen()

und

bool allesAngekommen()

erklärt aber die Funktion checkSerial