Serielle Schnittstelle Auslesen probleme

Hallo miteinander,

erst mal ein Danke an alle die mir bisher bei meinem Programm geholfen haben, ich habe jetzt ein Problem ich versuche alle Einzelprojekte für das Gesamtprojekt zusammen zu legen.

Ich habe dem Programm nun beigebracht das es auf bestimmte befähle antworten kann.

die befehle Kommen alle von der Seriellen Schnittstelle

mit dem Befehl „Config:“ wird das Bord dann Konfiguriert
Das Bord Antwortet mit „Config Start“

jetzt sollte es eigentlich möglich sein 4 Zahlenblöcke getrennt euch ein Komma oder Leerzeichen zu senden.
Aufbau
1 Zahlenblock: Legt fest, welcher Digitale Pin geschaltet werden soll
2 Zahlenblock: Legt fest, nach welcher Zeit ab Start gerechnet eingeschaltet werden soll
3 Zahlenblock: Legt die Dauer der Einschaltzeit fest

durch „Ende:“ kommt man aus der Konfiguration wider heraus.

Leider klappt das nicht so wie ich mir das vorstelle :frowning:
kann mir jemand sagen warum?

Gruß

Wenn ich die Abfrage so nicht machen kann dann muss ich das irgend wie mit den Befahlen machen.
das wäre doof :frowning:

Das ist der Code:

/* 
  Tropfen Box Firmware
  
  Befehle können über die Seriele Schnitstelle gesendet werden
  und Fangen immer mit einem Großen Buchstaben an und Enden
  mit einem : 
  
  Befehle     Antwort  
  Name:       Tropfen Box
  Firmware:   * Hier kommt die Versionsnummer
  Config:     Config Start
              
              * Jetzt kann die Hadware Neu gesätzt werden,
              * Die Alte Hadware wurde gellert
              
              * Datenstrucktur
              * - pin         ==> Legt fest, welcher Pin geschaltet werden soll
              * - vorlaufzeit ==> Legt fest, nach welcher Zeit ab Start gerechnet eingeschaltet werden soll
              * - dauer       ==> legt die Dauer der Einschaltzeit fest
                     Zeitangaben immer in Millisekunden
              * Zeile ist eine duchlaufende Zahl zwischen 0 udn 499 jede Zahl kann nur ein mal vorkommen

Ende:         Config Ende
              * Kann nur angewendet werden wenn Config gestartet wurde 
              * sonnst gibt es keine Reagzion
              * Solange sich das Bord in Config Start modus befindet kann es keine Hadware ansteuern.            
*/


#define ZEILENTRENNZEICHEN 13                                   // Zeilenumbruch Definiren

// Config Daten 
   char Firmware_Nr[] = "1.0.1";
   char Name[]        = "Tropfen Box";
   int startPin       = 2;                                      // Hier ist der taster angeschloßen
   int Baudrate       = 9600;                                   // Baudrate für die Übertragung zwischen Arduino und PC 

// Variablen Deklarieren und Füllen
   unsigned long gesamtDauer = 0;

// Zwischenspeicher 
   int Lauf = 0;

// Datenstrucktur 
   struct hardware_t{int pin;long vorlaufzeit; long dauer;};

// Arrey erstellen Maximal 500 Einträge
   hardware_t hardware[499];

// Größe des Array` ermitteln 
   int schritte = sizeof(hardware) / sizeof(hardware[0]);




// Das ist eine Funktion !!!
char* receiveBuffer()
/* Empfang einer Textzeile über Serial, Rückgabewert NULL: Zeile nicht/unvollständig empfangen
   oder Rückgabewert char-Pointer auf die vollständig empfangene Textzeile */
 {
  static char lineBuffer[100];                                              // Maximale Zeilenlänge festlegen
  static byte counter=0;
  char c;
  
  if (Serial.available()==0) return NULL;                                   // Nullpointer zurück
  if (counter==0) memset(lineBuffer,0,sizeof(lineBuffer));                  // Puffer vor Benutzung löschen
  c=Serial.read();                                                          // Aktueller Pufer in c Speichern

  if (c==ZEILENTRENNZEICHEN)                                                // wenn c gleich ZEILENTRENNZEICHEN dann aufführen 
   {
     counter=0;                                                             // Zähler zurücksätzen damit neue Zeilen empfangen werden kann
     return lineBuffer;                                                     // Volständige Zeile zurückgeben
   }
   else if (c>=32)                                                          // kein Steuerzeichen! (23 = Ascii zeichen !)
   {
    lineBuffer[counter]=c;                                                  // Zeichen im Zeilenpuffer einfügen
    if (counter<sizeof(lineBuffer)-2) counter++;
   }
   return NULL;
  }
// Das ist eine Funktion !!!


void setup() 
{
  Serial.begin(Baudrate);                                                    // Serielenport Starten
  pinMode(startPin, INPUT);                                                  // startPin auf INPUT setzen (Taster) 
}  




void loop() 
{  
 char* text=receiveBuffer();                                               // Alles aus der Serielenschnitstelle Lesen
 if (strcmp(text,"Name:")==0)     {Serial.println(Name);}                  // Befehl prüfen "Firmware:"
 if (strcmp(text,"Firmware:")==0) {Serial.println(Firmware_Nr);}           // Befehl prüfen "Firmware Nr:"
 if (strcmp(text,"Config:")==0)                                            // Befehl prüfen "Config:"
  {
   Serial.println("Config Start");
    memset(hardware, 0, sizeof(hardware));                                 // Hadware Werte alle auf 0 sätzen
    while(strcmp(text,"Ende:")!=0)
     {
       char* text=receiveBuffer();                                          // Alles aus der Serielenschnitstelle Lesen
        while (Serial.available() > 0)
        {
          int PIN         = Serial.parseInt();
          int VORLAUFZEIT = Serial.parseInt();
          int DAUER       = Serial.parseInt();
          int Zeile       = Serial.parseInt();

          hardware[Zeile].pin         = PIN;
          hardware[Zeile].vorlaufzeit = VORLAUFZEIT;
          hardware[Zeile].dauer       = DAUER;
           // Antwort 
          Serial.print(hardware[Zeile].pin); Serial.print(", "); Serial.print(hardware[Zeile].vorlaufzeit); Serial.print(", "); Serial.print(hardware[Zeile].dauer); Serial.print(", "); Serial.println(Zeile);
          }
        }
    for (int i=0;i<schritte;i++)
     {
      pinMode(hardware[i].pin,OUTPUT);                             // Pin auf OUTPUT setzen
      hardware[i].vorlaufzeit*=1000;                               // Millisekunden zu Mikrosekunden
      hardware[i].dauer*=1000;                                     // Millisekunden zu Mikrosekunden
      hardware[i].dauer+=hardware[i].vorlaufzeit; 
  
      if (hardware[i].dauer>gesamtDauer)                           // Wenn vorlaufzeit + dauer > gesamtDauer
        {gesamtDauer=hardware[i].dauer;}                           // Dann Speichere vorlaufzeit + dauer in gesamtDauer
     }
   Serial.println("Config Ende");

     }


  unsigned long starttime;
  unsigned long looptime;

  if (digitalRead(startPin)== HIGH)                                    // Taste Wurde gedrückt
   {
     Lauf = 0;                                                         // Programm darf Starten  
     while(digitalRead(startPin)== HIGH)                               // Die Schleife leuft so lange bis die Taste wider los gelassen wird
     {
       if (Lauf == 0)                                                  // Prüfen ob das programm Starten darf 
        {
          starttime=micros();                                          // Startzeit merken
          while (micros()-starttime<gesamtDauer)                       // so lange widerholen bis die Gesammte Dauer der Aktionen zeitmäßig vorbei ist
          {
            looptime=micros()-starttime;                               // Aktuelle verstrichene zeit im Loop 
            for (int i=0;i<schritte;i++)                               // Alle Aktionen durchgehen
            {
              if (looptime>=hardware[i].vorlaufzeit && looptime<hardware[i].dauer)
                digitalWrite(hardware[i].pin,HIGH);                    // Hardware EIN Schalten !!!!
              else  
                digitalWrite(hardware[i].pin,LOW);                     // Hardware Ausschalten !!!!
            }
          }
      
          // Nur zur Sicherheit nochmal alles abschalten
          for (int i=0;i<schritte;i++)
          {digitalWrite(hardware[i].pin,LOW);   }                      // Hardware Ausschalten !!!!
               Lauf = 1;                                               // Programm darf nicht widerholt werden.
         } 
      }
   }
 }

Das ist eine unschöne Hybrid-Version zwischen deiner Einlese-Funktion und dem Arduino-Parse Kram

Das kann man problemlos auf einmal erledigen. Man gibt das ein:

"Config:100,100,100,100"

Dann überprüfst du entweder mit strstr() oder strncmp() den Anfang des Strings. strncmp() überprüft nur die ersten n Zeichen. Wenn du da also für n strlen_P(PSTR("Config:")) einsetzt sollte es passen. Hier gleich mal die bessere _P Version damit nicht noch mehr RAM verbraucht wird.
strstr() geht auch, aber durchsucht den gesamten String wenn er nichts findet.

Dann springst du mit text = text + strlen_P(PSTR("Config:")) ; auf den Anfang der Zahlen. Hier bietet es sich dann eventuell an die Länge der Suchstrings irgendwo am Angang als Konstanten zu speichern. Dann muss man es nicht jedesmal extra hinschreiben und es wird nur einmal Flash belegt. Ist aber nicht zwingend nötig.

Von strncmp() gibt es auch eine _P Version die mit einem Suchstring im Flash arbeitet. Aber probier erst mal die normale Variante.

Dann strok() um den String zu splitten:

int val1, val2, val3, val4;

 val1 = atoi(strtok(text, ","));
 val2 = atoi(strtok(NULL, ","));
 val3 = atoi(strtok(NULL, ","));
 val4 =  atoi(strtok(NULL, ","));

Man könnte auch am Anfang strtok() mit ":" machen um den Anfang abzuschneiden. Aber Pointer-Arithmetik wie oben beschrieben ist da etwas eleganter.

Ok ich weis was du meinst, dein Beispiel ist auch schon sehr gut,

jetzt muss ich meine Grauen Zellen noch mal arbeiten lassen bis ich das alles umgesetzt bekommen habe.
ich finde das in dem Arduino IDE immer so unübersichtlich .... arrrrr.

ich versuche mein Glück mal.

melde mich dann mit erfolg oder Misserfolg wider.

Muecke:
ich finde das in dem Arduino IDE immer so unübersichtlich .... arrrrr.

Atmel Studio oder Visual Studio Professional mit Visual Micro plugin. Das hast du alles was es aus normalen IDEs gibt wie Auto-Vervollständung, Anzeige der Parameter von Funktionen beim Tippen oder eine Liste mit Funktionen deines Projektes. Zeilen-Nummern. Und vieles mehr.

Oder Code::Blocks.

EDIT:
Du solltest es außerdem so machen:

char* text=receiveBuffer(); 
if(text != NULL)
{
    ...
}

Und das danach nur parsen wenn auch wirklich was angekommen ist. receiveBuffer() gibt etwas ungleich NULL zurück wenn alles da ist. Davor sollte man nicht versuchen etwas mit dem Array zu machen. Das ist Zeitverschwendung.

Und bei den strcmp() Aufrufen if-else verwenden

In meiner Version musst da jetzt jedesmal "Config:" davor schreiben. Vielleicht etwas doof. Um das nur einmal zu machen solltest du aber auch keine while-Schleife verwenden. Sondern einfach ein Flag setzen in welchem Modus du gerade bist. Wenn du z.B. "boolean config = true" hast kannst du in dem Modus die strcmp() Abfrage auf "Config" weglassen und nur auf "Ende" abfragen und ansonsten Zahlen parsen.

loop() sollte immer durchlaufen und ständig receiveBuffer() abfragen! Was du sonst noch machst wird nur über Statusvariablen gesteuert.

ich meine das die genanten Programm alle auf WIN laufen ich habe hier einen MAC :frowning:
geht auch so ;-), es ist auch etwas Chaotisch für mich da ich die Codeschnipsel nicht alle zu 100% kenne, und immer erst wider lesen muss was was ist. peinlich und das bei so einem Kleinen Programm peinlich

Om das ist eine Gute Idee das baue ich gleich mal mit ein :wink:
also das „if(text != NULL)“

Den Rest werde ich mal versuchen umzusetzen wie du das beschrieben hast.
ich habe das Test Programm noch mal etwas umgeschrieben:

/* 
  Befehl              Reagzion             Antwort
  
  Name:               Ausgabe              Programm Name
  
  Firmware:           Ausgabe              Firmware Nr.
  
  Reset:              Sätzt das Array      Hadware Reset  
                      Hadware wider auf 
                      0
                      
  Print:              Ausgabe der hadware 
                      Config in einer Tabelle
                      
  Config:1,10,30,0    sätzt die Hadware    Zahlenfolge
                      Configuration neu ...
*/

   #define ZEILENTRENNZEICHEN 13                                // 13 ist Steuerzeichen CR (Carriage Return)

// Config Daten 
   char Firmware_Nr[] = "1.0.1";                                // Firmware
   char Name[]        = "Tropfen Box";                          // Programmmane
   int  startPin      = 2;                                      // Hier ist der taster angeschloßen
   int  Baudrate      = 9600;                                   // Baudrate für die Übertragung zwischen Arduino und PC 
   int  Lauf          = 0;                                      // Zwischenspeicher
   struct hardware_t{int pin;long vorlaufzeit; long dauer;};    // Hadware Strucktur
// Test Hadware Arrey füllen   
   hardware_t hardware[5]=
    {
      {3, 10, 30},
      {4, 50, 30},
    };
   int schritte = sizeof(hardware) / sizeof(hardware[0]);       // Anzahl der Hadware Schritte definiren


// Das ist eine Funktion !!!
char* receiveBuffer()
 {
  static char lineBuffer[100];                                              // Maximale Zeilenlänge festlegen
  static byte counter=0;
  char c;
  
  if (Serial.available()==0) return NULL;                                   // Nullpointer zurück
  if (counter==0) memset(lineBuffer,0,sizeof(lineBuffer));                  // Puffer vor Benutzung löschen
  c=Serial.read();                                                          // Aktueller Pufer in c Speichern

  if (c==ZEILENTRENNZEICHEN)                                                // wenn c gleich ZEILENTRENNZEICHEN dann aufführen 
   {
     counter=0;                                                             // Zähler zurücksätzen damit neue Zeilen empfangen werden kann
     return lineBuffer;                                                     // Volständige Zeile zurückgeben
   }
   else if (c>=32)                                                          // kein Steuerzeichen! (23 = Ascii zeichen !)
   {
    lineBuffer[counter]=c;                                                  // Zeichen im Zeilenpuffer einfügen
    if (counter<sizeof(lineBuffer)-2) counter++;
   }
   return NULL;
  }
// Das ist eine Funktion !!!

void setup()
 { 
    Serial.begin(Baudrate);                       // Serielenport Starten
    pinMode(startPin, INPUT);                     // startPin auf INPUT setzen (Taster) 
 }                                                 


void loop()
{
 char* text=receiveBuffer();                                                // Alles aus der Serielenschnitstelle Lesen
 if(text != NULL)
  {
     if (strcmp(text,"Name:")==0)                                               // Befehl prüfen "Name:"
       {Serial.println(Name);}                                                     // Ausgabe
     if (strcmp(text,"Firmware:")==0)                                           // Befehl prüfen "Firmware:"
       {Serial.println(Firmware_Nr);}                                              // Ausgabe
     if (strcmp(text,"Reset:")==0)                                              // Befehl prüfen "Reset:"
       {memset(hardware, 0, sizeof(hardware)); Serial.println("Hadware Reset");}   // Hadware Reseten und Ausgabe
     if (strcmp(text,"Print:")==0)                                              // Befehl prüfen "Print:"
       {  
          for (int i=0;i<schritte;i++)
          {
            Serial.print(hardware[i].pin);
            Serial.print(", ");
            Serial.print(hardware[i].vorlaufzeit);
            Serial.print(", ");
            Serial.println(hardware[i].dauer);
          }
       }
     // Hier muss jetzt die Erkennung Config rein
   }
}

das ich bei deiner Version immer "Config:" eingeben muss finde ich nicht so schlimm: später soll das Arduino über eine Andere Software angesprochen werden, damit ich eine Grafische Oberfläche habe und nicht alles Tippen muss, daher macht mir das nichts aus.

Musst du das alles per Hand eintippen, oder macht das ein Programm?

EDIT: ok, jetzt hast du es dazu geschrieben :slight_smile:

Bei "Config:100,...." musst du halt jedesmal das Wort davor schreiben. Kein Problem wenn das automatisch kommt, aber per Hand vielleicht nervig. Man kann das schon so machen dass du wirklich in einem anderen Modus bist, wie du es am Anfang beschrieben hast.

So grob:

boolean stateConfig;

void loop()
{
   char* text=receiveBuffer();
   if(text != NULL)
   {
          if(stateConfig == false)
          {
                 if (strcmp(text,"Name:")==0)
                     stateConfig = true;
          }
          else
          {
                //hier muss man jetzt nur noch auf "Ende" abfragen und sonst Zahlen parsen
          }
   }
}

Wenn dann "Ende" kommt setzt man stateConfig wieder auf false und es ist wieder so wie am Anfang.

Dann entfällt das mit strncmp() oder strstr() und du braucht nur noch den strtok() Teil.

Und vielleicht eine Fehlerbehandlung die falsche Eingaben abfängt. Das ist etwas komplizierter. Vielleicht die Variablen mit negativen Werten vorbesetzten und dann abfragen ob alle positiv sind. Dann weiß man man dass alle korrekt eingegeben wurden.

Und so ist es etwas besser:

     if (strcmp(text,"Name:")==0)                                               // Befehl prüfen "Name:"
       {Serial.println(Name);}                                                     // Ausgabe
     else if (strcmp(text,"Firmware:")==0)                                           // Befehl prüfen "Firmware:"

Du musst nicht immer alle Vergleiche machen. Wenn einer gültig ist, kann man abbrechen. Ist aber ne Kleinigkeit.

ne ich muss das nicht immer von Hand Tippen alles , kommt später von einem Programm das muss ich jedoch auch noch schreiben.
:slight_smile: das Schriebe ich aber in einer Sprache die ich etwas mehr verstehe wie das hier :slight_smile: nennt sich QBasic :slight_smile:

AH da meintest du das mit dem If .. else if das werde ich gleich mal Einsätzen.

Das mit dem Extra Modus muss nicht sein, war für mich vorhin nur Logisch da ich eine andere Abfrage gedacht hatte für die Zahlenwerte :slight_smile: was ja nicht geklappt hat :frowning: leider.

Jetzt bin ich gerade dabei zu verstehen was du und wie du das mit der Abfrage von Config:… meinst.
ich versuche was zu dem Befehl „strncmp()“ zu finden da ich dass zwar vom Prinzip her verstanden habe was ich machen muss,
ich habe gerade nur keinen Plan wie ich das Umsätzen kann.
wie gesagt der Extra Modus interessiert mich eigentlich nicht, da ich das Config ja immer mitsende. und somit unterscheiden kann
was das für Daten sind :slight_smile: ich weis nur noch nicht wie ich das auseinander nehme damit ich die Daten vergleichen kann.

Google einfach danach. Das erste was du findest ist das:
http://www.cplusplus.com/reference/cstring/strncmp/

Die Erklärungen da sind super und es gibt immer ein Beispiel, aber die Libs sind nicht 100%ig identisch zu dem was auf dem Arduino ist. Aber rein was die verfügbaren Funktionen betrifft.

Ansonsten gibt es noch die avr libc Seite, die alles enthält was wirklich auf dem Arduino ist:
http://www.nongnu.org/avr-libc/user-manual/group__avr__string.html#ga36cc0ab27fbcc70615214170ae79fbf7

Die Funktion hat einfach einen dritten Parameter für die Länge der zu vergleichenden Zeichen. strcmp() vergleicht den ganzen String. Da du jetzt aber noch mehr drin stehen hast geht das nicht mehr. Deshalb strncmp().
Oder strstr():
http://www.cplusplus.com/reference/cstring/strstr
Das durchsucht zwar den gesamten String, aber ist hier auch nicht schlimm. Der Rückgabe-Wert ist aber anders! Wenn der gesuchte String enthalten ist kommt ein Pointer ungleich NULL zurück.

Wenn du dann bei strncmp() für den 3. Parameter strlen() mit dem entsprechenden Such-String machst sollte er genau die korrekte Länge vergleichen. Du kannst den Parameter aber auch per Hand auf 7 setzten für "Config:". Das belegt dann auch kein zusätzliches RAM für die String-Konstante. :slight_smile:

Danke dir durch dich habe ich es jetzt fast Geschäft :slight_smile:

habe jetzt es hin bekommen das Config auszulesen und dann die Zahlen auch richtig auszulesen und in das Array zu schreiben :slight_smile:
ich kann es auch Resetten :slight_smile: das ist alles schon mal sehr gut,
ich lasse mir auch immer eine Kontrolle Zeile nach dem Empfang zusenden, so kann ich das dann auch Prüfen ob alles Richtig eingegeben wurde oder nicht.

jetzt habe ich nur ein Problem mein Prog hängt sich glaube ich auf :frowning: denn nachdem ich die taste gedrückt habe kann ich nichts mehr machen, ich finde nur den Fehler nicht,
vielleicht könnt da mal jemand drüber schauen und mir sagen wo der Wurm drin ist.

das ist der Code:

/* 
  Befehl              Reagzion             Antwort
  
  Name:               Ausgabe              Programm Name
  
  Firmware:           Ausgabe              Firmware Nr.
  
  Reset:              Sätzt das Array      Hadware Reset  
                      Hadware wider auf 
                      0
                      
  Print:              Ausgabe der hadware 
                      Config in einer Tabelle
                      
  Config:1,10,30,0    sätzt die Hadware    Zahlenfolge
                      Configuration neu ...
*/

   #define ZEILENTRENNZEICHEN 13                                // 13 ist Steuerzeichen CR (Carriage Return)

// Config Daten 
   char Firmware_Nr[] = "1.0.1";                                // Firmware
   char Name[]        = "Tropfen Box";                          // Programmmane
   int  startPin      = 2;                                      // Hier ist der taster angeschloßen
   int  Baudrate      = 9600;                                   // Baudrate für die Übertragung zwischen Arduino und PC 
   int  Lauf          = 0;                                      // Zwischenspeicher
   unsigned long gesamtDauer = 0;
   unsigned long starttime;
   unsigned long looptime;

   struct hardware_t{int pin;long vorlaufzeit; long dauer;};    // Hadware Strucktur
// Test Hadware Arrey füllen   
   hardware_t hardware[5]=
    {
      {3, 10, 30},
      {4, 50, 30},
    };
   int schritte = sizeof(hardware) / sizeof(hardware[0]);       // Anzahl der Hadware Schritte definiren


// Das ist eine Funktion !!!
char* receiveBuffer()
 {
  static char lineBuffer[100];                                              // Maximale Zeilenlänge festlegen
  static byte counter=0;
  char c;
  
  if (Serial.available()==0) return NULL;                                   // Nullpointer zurück
  if (counter==0) memset(lineBuffer,0,sizeof(lineBuffer));                  // Puffer vor Benutzung löschen
  c=Serial.read();                                                          // Aktueller Pufer in c Speichern

  if (c==ZEILENTRENNZEICHEN)                                                // wenn c gleich ZEILENTRENNZEICHEN dann aufführen 
   {
     counter=0;                                                             // Zähler zurücksätzen damit neue Zeilen empfangen werden kann
     return lineBuffer;                                                     // Volständige Zeile zurückgeben
   }
   else if (c>=32)                                                          // kein Steuerzeichen! (23 = Ascii zeichen !)
   {
    lineBuffer[counter]=c;                                                  // Zeichen im Zeilenpuffer einfügen
    if (counter<sizeof(lineBuffer)-2) counter++;
   }
   return NULL;
  }
// Das ist eine Funktion !!!

void setup()
 { 
    Serial.begin(Baudrate);                       // Serielenport Starten
    pinMode(startPin, INPUT);                     // startPin auf INPUT setzen (Taster) 
 }                                                 


void loop()
{
 char* text=receiveBuffer();                                                // Alles aus der Serielenschnitstelle Lesen
 if(text != NULL)
  {
     if (strcmp(text,"Name:")==0)                                               // Befehl prüfen "Name:"
       {Serial.println(Name);}                                                    // Ausgabe
     else if (strcmp(text,"Firmware:")==0)                                      // Befehl prüfen "Firmware:"
       {Serial.println(Firmware_Nr);}                                              // Ausgabe
     else if (strcmp(text,"Reset:")==0)                                         // Befehl prüfen "Reset:"
       {memset(hardware, 0, sizeof(hardware)); Serial.println("Hadware Reset");}   // Hadware Reseten und Ausgabe
     else if (strcmp(text,"Print:")==0)                                         // Befehl prüfen "Print:"
       {  
         for (int i=0;i<schritte;i++)
          {
            Serial.print(hardware[i].pin);
            Serial.print(", ");
            Serial.print(hardware[i].vorlaufzeit);
            Serial.print(", ");
            Serial.println(hardware[i].dauer);
          }
       }
     else if (strncmp(text,"Config:",7)==0)                                      // Befehl prüfen "Config:"
       {
             text = text + strlen_P(PSTR("Config:")) ;
             int pin         = atoi(strtok(text, ","));
             int vorlaufzeit = atoi(strtok(NULL, ","));
             int dauer       = atoi(strtok(NULL, ","));
             int Zeile       = atoi(strtok(NULL, ","));

          hardware[Zeile].pin         = pin;
          hardware[Zeile].vorlaufzeit = vorlaufzeit;
          hardware[Zeile].dauer       = dauer;
          Serial.print(pin); Serial.print(",");                                  // Ausgabe
          Serial.print(vorlaufzeit); Serial.print(",");                          // Ausgabe
          Serial.println(dauer);                                                 // Ausgabe
       }                                              
   }

  if (digitalRead(startPin)== HIGH)                                    // Taste Wurde gedrückt
   {
     Lauf = 0;                                                         // Programm darf Starten  
     while(digitalRead(startPin)== HIGH)                               // Die Schleife leuft so lange bis die Taste wider los gelassen wird
     {
        for (int i=0;i<schritte;i++)
         {
          pinMode(hardware[i].pin,OUTPUT);                             // Pin auf OUTPUT setzen
          hardware[i].vorlaufzeit*=1000;                               // Millisekunden zu Mikrosekunden
          hardware[i].dauer*=1000;                                     // Millisekunden zu Mikrosekunden
          hardware[i].dauer+=hardware[i].vorlaufzeit; 
      
          if (hardware[i].dauer>gesamtDauer)                           // Wenn vorlaufzeit + dauer > gesamtDauer
            {gesamtDauer=hardware[i].dauer;}                           // Dann Speichere vorlaufzeit + dauer in gesamtDauer
          }
       if (Lauf == 0)                                                  // Prüfen ob das programm Starten darf 
        {
          starttime=micros();                                          // Startzeit merken
          while (micros()-starttime<gesamtDauer)                       // so lange widerholen bis die Gesammte Dauer der Aktionen zeitmäßig vorbei ist
          {
            looptime=micros()-starttime;                               // Aktuelle verstrichene zeit im Loop 
            for (int i=0;i<schritte;i++)                               // Alle Aktionen durchgehen
            {
              if (looptime>=hardware[i].vorlaufzeit && looptime<hardware[i].dauer)
                digitalWrite(hardware[i].pin,HIGH);                    // Hardware EIN Schalten !!!!
              else  
                digitalWrite(hardware[i].pin,LOW);                     // Hardware Ausschalten !!!!
            }
          }
      
          // Nur zur Sicherheit nochmal alles abschalten
          for (int i=0;i<schritte;i++)
          {digitalWrite(hardware[i].pin,LOW);   }                      // Hardware Ausschalten !!!!
               Lauf = 1;                                               // Programm darf nicht widerholt werden.
       } 
      }
   }
}
text = text + strlen_P(PSTR("Config:")) ;

Das kannst du auch auf text += 7 vereinfachen wenn du willst

Du solltest vor dem Abspeichern überprüfen ob die Zeilennummer innerhalb der Array Grenze liegt. Kann es sein, dass du da mehr als 4 eingegeben hast? Solche Puffer-Überlaufe können tödlich sein, da du damit Variablen nach dem Array im Speicher überschreibst.

Hängt er sich auch auf wenn du nicht in das Array schreibst? Vielleicht mal versuchen etwas weiter einzugrenzen woran es genau liegt.

Ansonsten würde ich noch die _P Version von str(n)cmp() nehmen. z.B.:

if (strcmp_P(text, PSTR("Name:"))==0)

Spart jedesmal ein wenig RAM, da die String Konstanten beim Start nicht dauerhaft ins RAM kopiert werden. Geht genauso mit strncmp_P()

Genauso kannst du bei den print() Anweisungen (und nur da!) das machen:

Serial.println(F("Hadware Reset"))

Durch das F() bleiben die Strings dann auch im Flash. Das ist ein Arduino Konstrukt, das mit print() und println() geht. Und nur mit Strings-Konstanten. Nicht Variablen anderer Art.

Das hat aber nichts mit dem Absturz zu tun

Den Fahler kann ich nur soweit eingrenzen:

wenn ich die Firmware aufspule kann ich genau 1 mal mein Taster Drücken und das Programm (Hardware Einstellungen) wird ein mal ausgeführt.

Egal ob ich Config Daten über den Seriellen Monitor eingestellt habe oder nicht.
ich habe am Anfang ja die Testdaten noch Fix mit drin auch mit denen pasirt es :frowning:

ich habe den Eindruck als wenn was mit der Schleife nicht stimmt am Schluss denn ich Frage ja die Variable Lauf ab in der Speichere ich den Zustand meines Tasters ab so das bei jedem tasten druck nur ein mal meine Hardware durchlaufen wird.

ich kann nur keinen Fehler finden :frowning: warum das so ist :frowning:

ich kann nachdem ich die Taste gedrückt habe auch keinen Befehl mehr an das Bord senden es antwortet dann nicht mehr :frowning:
wenn ich die Firmware neu aufspiele dann geht es wider. also ein mal :frowning:

ps. das mit den

Serial.println(F("Hadware Reset"))

kann ich das auch machen wenn ich eine Variable ausgebe?
also so?

Serial.println(F(Name))

Sehe jetzt auf den ersten Blick nicht den Fehler. Das heißt aber nichts. Ging das schon mal?

Pins 0 und 1 hast du glaube ich nicht verwendet. Aber daran hängt die serielle Schnittstelle. Wenn du die auf Output schaltest, geht natürlich nichts mehr.

Du solltest den Taster aber entprellen. Das kann auch erst mal ganz primitiv mit einem delay(30) oder was in der Größenordnung nach dem ersten Einlesen des Zustands machen. Dann geht es erst weiter wenn das Prellen zu Ende ist. Ansonsten kann es sein, dass die while-Schleife nicht korrekt funktioniert.

Es gibt auch noch bessere Optionen:
http://arduino.cc/en/Tutorial/Debounce (per Hand)
GitHub - thomasfredericks/Bounce2: Debouncing library for Arduino and Wiring (mit Lib)

kann ich das auch machen wenn ich eine Variable ausgebe?

Nein. Man kann Strings als PROGMEM deklarieren und dann mit strcpy_P in einen temporären Puffer ins RAM kopieren (und sich auch Makros dafür schreiben). Man könnte auch den seriellen Eingangspuffer global deklarieren und diesen dann auch als Speicher für solche Strings verwenden. Das gibt es einige Möglichkeiten. Man sogar auf den Puffer verzichten und die chars einzeln auslesen.

Aber für nur einen relativ kurzen String ist das vielleicht auch mehr Aufwand als es sich lohnt. Ich habe das nur erwähnt weil du vorhast ein riesiges Array im RAM zu halten. Das sollte man auch bei 8kB nicht so verschwenderisch damit umgehen. Aber muss auch nicht gleich bis aufs allerletzte Byte optimieren.

Die anderen _P Funktionen sind einfach zu handhaben. Aber wenn der String nicht direkt als Parameter in der Funktion steht wird es komplizierter.

Eine andere Optimierungs-Möglichkeit ist der serielle Puffer selbst. Der muss keine 100 Byte haben wenn du nur so relativ kurze Strings einliest. Du brauchst nur mindestens maximale Stringlänge + 1. Die Hälfte reicht da wahrscheinlich.

Serenifly:
Sehe jetzt auf den ersten Blick nicht den Fehler. Das heißt aber nichts. Ging das schon mal?

ja das geht in einem meiner Anerben Programme :slight_smile:
muss das wohl noch mal alles aufzuwirbeln und neu zusammen Sätzen :wink:

Serenifly:
Pins 0 und 1 hast du glaube ich nicht verwendet. Aber daran hängt die serielle Schnittstelle. Wenn du die auf Output schaltest, geht natürlich nichts mehr.

Richtig so, die zwei Pins sind nicht in benutzung

ich werde mal versuchen Heute Abend noch mal das Prob auseinander zu nehmen.

Heute hat es Besser gelapt :slight_smile: bei mir :slight_smile:

ich habe alles noch mal raus gelöscht, also den Teil mit der Hardware Ansteuerung und habe es dann nach und nach eingefügt und mir immer wider Punkte geätzt die mir über den Seriellen Monitor eine aussage gemacht haben wo das Programm gerade ist.
Dabei ist mir dann aufgefallen das das Programm sich nicht aufhängt sondern einfach zu lange braucht, denn ich Lasse ja die Millisekunden zu Mikrosekunden umrechnen.
Die Routine die in meinem Anderen Programm nur ein mal aufgerufen wird habe ich jetzt immer bei Jedem Tastendruck Berechnen lassen was natürlich die Vorlaufzeit jedes mal um den Faktor 1000 ansteigen läst, beim ersten mal ging es noch gut beim Zweiten mal ist das dann so Lange das ich dachte das Programm Hängt sich auf. :slight_smile:
ich habe den teil jetzt umgeschrieben und zu dem Befehl Config gepackt wo er auch hin gehört :slight_smile:
Jetzt Klappt es.

jetzt muss ich noch die Fehlerabfragen einbauen, und dann ist die Firmware endlich fertig :-). man bin ich glücklich gerade.

Fehlerabfrage:

  1. Befehl nicht bekannt
  2. Geltungsbereich bei dem Befehl Config (PIN Nr. und Zeile)

habe ich eine Fehlerabfrage vergessen?

habe jetzt alle Kommentare Gelöscht dass ich den Code Posten kann habe sonst zu viele Zeichen :frowning:

/* 
  Befehl              Reagzion             Antwort
  
  Name:               Ausgabe              Programm Name
  
  Firmware:           Ausgabe              Firmware Nr.
  
  Reset:              Sätzt das Array      Hadware Reset  
                      Hadware wider auf 
                      0
                      
  Print:              Ausgabe der hadware 
                      Config in einer Tabelle
                      
  Config:1,10,30,0    sätzt die Hadware    Zahlenfolge
                      Configuration neu ...
*/

// Config Daten 
   #define ZEILENTRENNZEICHEN 13
   char Firmware_Nr[] = "1.0.1";
   char Name[]        = "Tropfen Box";
   int  startPin      = 2;
   int  Baudrate      = 9600;
   int  Lauf          = 0;
   unsigned long gesamtDauer = 0;
   unsigned long starttime;
   unsigned long looptime;
   struct hardware_t{int pin;long vorlaufzeit; long dauer;};
   hardware_t hardware[50]=
    {
      {3, 10, 30},
      {4, 525, 30},
    };
   int schritte = sizeof(hardware) / sizeof(hardware[0]);


// Funktion - Serielle Schnittstelle auslesen -
char* receiveBuffer() {
  static char lineBuffer[100];
  static byte counter=0; 
  char c;
  if (Serial.available()==0) return NULL;
  if (counter==0) memset(lineBuffer,0,sizeof(lineBuffer)) ;
  c=Serial.read();
  if (c==ZEILENTRENNZEICHEN){ 
     counter=0;
     return lineBuffer; }
   else if (c>=32) {
    lineBuffer[counter]=c; 
    if (counter<sizeof(lineBuffer)-2) counter++; }
   return NULL; }
// Funktion - Serielle Schnittstelle auslesen -

void setup() { 
    Serial.begin(Baudrate);
    pinMode(startPin, INPUT);
 
     pinMode(hardware[0].pin,OUTPUT);
    hardware[0].vorlaufzeit*=1000;
    hardware[0].dauer*=1000;
    hardware[0].dauer+=hardware[0].vorlaufzeit;
    pinMode(hardware[1].pin,OUTPUT);
    hardware[1].vorlaufzeit*=1000;
    hardware[1].dauer*=1000;
    hardware[1].dauer+=hardware[1].vorlaufzeit;

 
 
  }                                             // startPin auf INPUT setzen (Taster) 


void loop()
{
 char* text=receiveBuffer();
   if(text != NULL)
      {
         if (strcmp(text,"Name:")==0)
           {Serial.println(Name);}
         else if (strcmp(text,"Firmware:")==0)
           {Serial.println(Firmware_Nr);}
         else if (strcmp(text,"Reset:")==0)
           {memset(hardware, 0, sizeof(hardware)); Serial.println("Hadware Reset");} 
         else if (strcmp(text,"Print:")==0) 
           { 
             for (int i=0;i<schritte;i++) 
              { 
                Serial.print(hardware[i].pin); 
                Serial.print(", "); 
                Serial.print(hardware[i].vorlaufzeit); 
                Serial.print(", "); 
                Serial.println(hardware[i].dauer); 
              }
           } 
         else if (strncmp(text,"Config:",7)==0)
 { 
                 text = text + strlen_P(PSTR("Config:")) ; 
                 int pin         = atoi(strtok(text, ",")); 
                 int vorlaufzeit = atoi(strtok(NULL, ",")); 
                 int dauer       = atoi(strtok(NULL, ",")); 
                 int Zeile       = atoi(strtok(NULL, ",")); 
    
              hardware[Zeile].pin         = pin; 
              hardware[Zeile].vorlaufzeit = vorlaufzeit; 
              hardware[Zeile].dauer       = dauer; 

              pinMode(hardware[Zeile].pin,OUTPUT); 
              hardware[Zeile].vorlaufzeit*=1000; 
              hardware[Zeile].dauer*=1000;  
              hardware[Zeile].dauer+=hardware[Zeile].vorlaufzeit; 


              Serial.print(pin); Serial.print(",");
Serial.print(vorlaufzeit); Serial.print(",");
              Serial.println(dauer);
           }
       } 

  if (digitalRead(startPin)== HIGH && Lauf == 0)   
      {    
         Lauf = 1;
                   for (int i=0;i<schritte;i++)
                      {
                        if (hardware[i].dauer>gesamtDauer) 
                          { gesamtDauer=hardware[i].dauer;} 
                      }
                              starttime=micros();
                              while (micros()-starttime<gesamtDauer) 
                              {
                                looptime=micros()-starttime; 
                                for (int i=0;i<schritte;i++)
                                {
                                  if (looptime>=hardware[i].vorlaufzeit && looptime<hardware[i].dauer)
                                    digitalWrite(hardware[i].pin,HIGH);
                                  else  
                                    digitalWrite(hardware[i].pin,LOW); 
                                }
                              }
                              // Nur zur Sicherheit nochmal alles abschalten
                              for (int i=0;i<schritte;i++)
                              {digitalWrite(hardware[i].pin,LOW);} 
    
     } 
  else if (digitalRead(startPin)== LOW) {Lauf = 0;}

}

so habe gemerkt das ich das Falsche Programm eingearbeitet habe :frowning: sch.....
jetzt ist das Richtige drin.
Jetzt kann man bei einem Duchgang jede Hadware belibig offt ansteuern also Ein und Ausschalten lassen :slight_smile:
die Fehlerabfrage habe ich auch mit eingebaut und bei einem Fehler kommt nun eine Fehlermeldung und nicht die Prüfantwort.
jetzt kann ich mich dran machen und ein Freebasic Programm dafür zu schreiben das sich mit dem Arduino unterhalten kann :slight_smile:

man bin ich gerade Froh das der teil fertig ist :slight_smile:

Hier noch mal der Code volständig mut Fehlerausgabe:

/* 
  Befehl              Reagzion             Antwort
  
  Name:               Ausgabe              Programm Name
  
  Firmware:           Ausgabe              Firmware Nr.
  
  Reset:              Sätzt das Array      Hadware Reset  
                      Hadware wider auf 
                      0
                      
  Print:              Ausgabe der hadware 
                      Config in einer Tabelle
                      
  Config:1,10,30,0    sätzt die Hadware    Zahlenfolge
                      Configuration neu ...

Wenn ein fehler auftrit bei der Übertragung der Seriellen schnitstelle antwortet das Bord mit Fehler 
*/

        #define ZEILENTRENNZEICHEN 13
    int startPin           = 2;
   char Firmware_Nr[]      = "1.2.0";
   char Name[]             = "Tropfen Box";
    int Baudrate           = 9600;
    int Lauf               = 0;

    struct hardware_t{int pin;long vorlaufzeit; long dauer;};              // Struktur einer einzelnen Schaltzeit
    struct schaltzeit_t{int pin;long zeit; boolean geschaltet;};           // Struktur einer einzelnen Schaltzeit

    hardware_t hardware[201]=
{                                              // Vorlaufzeit und Dauer für die Hardware
  {3, 10000,  30000},
  {3, 500000, 30000},
};

    #define schritte sizeof(hardware)/sizeof(hardware[0])


    schaltzeit_t schaltzeiten[2*schritte];
    int anzahlSchaltzeiten;
    long geschalteteZeit[2*schritte];
    void sortSchaltzeiten(int n) 
    {
      schaltzeit_t temp;
      for(int x=0; x<n; x++) 
      {
        for(int y=0; y<n-1; y++) 
        {
          if (schaltzeiten[y].zeit>schaltzeiten[y+1].zeit) 
          {
            temp=schaltzeiten[y+1];
            schaltzeiten[y+1]=schaltzeiten[y];
            schaltzeiten[y]=temp;
          }
        }
      }
    }


    // Funktion - Serielle Schnittstelle auslesen -
      char* receiveBuffer() {
      static char lineBuffer[100];
      static byte counter=0;
      char c;
      if (Serial.available()==0) return NULL;
      if (counter==0) memset(lineBuffer,0,sizeof(lineBuffer));
      c=Serial.read();
      if (c==ZEILENTRENNZEICHEN){
      counter=0;
      return lineBuffer; }
      else if (c>=32) {
      lineBuffer[counter]=c;
      if (counter<sizeof(lineBuffer)-2) counter++; }
      return NULL; }
    // Funktion - Serielle Schnittstelle auslesen -


void setup() 
  {
    pinMode(startPin, INPUT);
    Serial.begin(Baudrate);
  }  

void loop() {  
  unsigned long starttime;
  unsigned long looptime;


   char* text=receiveBuffer();
     if(text != NULL)
        {
           if (strcmp(text,"Name:")==0)            {Serial.println(Name);}
           else if (strcmp(text,"Firmware:")==0)   {Serial.println(Firmware_Nr);}
           else if (strcmp(text,"Reset:")==0)      {memset(hardware, 0, sizeof(hardware)); Serial.println("Hadware Reset");}
           else if (strcmp(text,"Print:")==0)
             {
               for (int i=0;i<schritte;i++) 
                { 
                  Serial.print(hardware[i].pin);
                  Serial.print(", ");
                  Serial.print(hardware[i].vorlaufzeit);
                  Serial.print(", ");
                  Serial.println(hardware[i].dauer);
                }
             } // Print
           else if (strncmp(text,"Config:",7)==0)
             {
                   text = text + strlen_P(PSTR("Config:")) ;
                   int pin         = atoi(strtok(text, ","));
                   int vorlaufzeit = atoi(strtok(NULL, ","));
                   int dauer       = atoi(strtok(NULL, ","));
                   int Zeile       = atoi(strtok(NULL, ","));
      
                if (pin > startPin && pin < 21 && Zeile > -1 && Zeile < 200) 
                  {   
                    hardware[Zeile].pin         = pin;
                    hardware[Zeile].vorlaufzeit = vorlaufzeit;
                    hardware[Zeile].dauer       = dauer;
      
                    hardware[Zeile].vorlaufzeit*=1000;
                    hardware[Zeile].dauer*=1000;
      
                    Serial.print(pin); Serial.print(",");
                    Serial.print(vorlaufzeit); Serial.print(",");
                    Serial.println(dauer);
                   }
                 else 
                   { Serial.println("Fehler: Werte komnten nicht eingetragen werden."); }
             } // Config                                 
          else { Serial.println("Fehler: Befehl nicht bekannt"); }
          
         } // if(text != NULL)
  
     if(digitalRead(startPin)== HIGH && Lauf == 0)
        {
          Lauf = 1;
          anzahlSchaltzeiten=0;
          for (int i=0;i<schritte;i++)
          {
            pinMode(hardware[i].pin,OUTPUT);
            if (hardware[i].dauer>0)
            {
              schaltzeiten[anzahlSchaltzeiten].pin=hardware[i].pin;
              schaltzeiten[anzahlSchaltzeiten].zeit=hardware[i].vorlaufzeit;
              schaltzeiten[anzahlSchaltzeiten].geschaltet=true;
              anzahlSchaltzeiten++;
              schaltzeiten[anzahlSchaltzeiten].pin=hardware[i].pin;
              schaltzeiten[anzahlSchaltzeiten].zeit=hardware[i].vorlaufzeit+hardware[i].dauer;
              schaltzeiten[anzahlSchaltzeiten].geschaltet=false;
              anzahlSchaltzeiten++;
            }
          }
            starttime=micros();
            for (int i=0;i<anzahlSchaltzeiten;i++)
            {
              while ((looptime=micros()-starttime)<schaltzeiten[i].zeit);
              digitalWrite(schaltzeiten[i].pin,schaltzeiten[i].geschaltet);
            }
        }
     else if (digitalRead(startPin)== LOW) {Lauf = 0;}
  }