Brauche Hilfe bei Datenempfang und -verarbeitung.

Folgender CODE hat folgende Aufgabe:

#define NUMBER_OF_FIELDS 20
int values[NUMBER_OF_FIELDS];
byte fieldIndex;
int cam;
void setup()
{
  Serial.begin(9600);
  //Serial.println("Anfang");
  pinMode (2, OUTPUT);
  pinMode (3, OUTPUT);
  pinMode (4, OUTPUT);
}
void loop()
{
  Serial.println("verbunden");
  if ( Serial.available())
  {
    char ch = Serial.read();
    Serial.print(ch, HEX);
    Serial.print('\t');
    Serial.println(fieldIndex);
    if (ch >= '0' && ch <= '9') // ASCII-Zeichen zwischen 0 und 9?
    {
      if (fieldIndex < NUMBER_OF_FIELDS) {
        values[fieldIndex] = (values[fieldIndex] * 10) + (ch - '0');
      }
    }
    else if (ch == '|')
    {
      fieldIndex++;
    }
    else if (ch == '\n')
    {


      if (values[2] == 2) {
        digitalWrite (2, HIGH); // Ventil_1 auf zum Durchspülen
      } else if (values[2] == 1) {
        digitalWrite (2, LOW);
      } else if (values[2] == 0) {
        // Routine für TaT
        delay (values[0]); // Verzögerung vor Öffnung 1
        digitalWrite (2, HIGH); // Ventil_1 auf
        delay (values[1]);  // offen
        digitalWrite(2, LOW); // zu
        if (values[5] == 1) // Ventil_1 Öffnung 2, wenn checkbox true
        {
          delay (values[3]); // warte
          digitalWrite (2, HIGH); // auf
          delay (values[4]); // offen
          digitalWrite(2, LOW); // zu

        }
        // Kamera verzögert auslösen
        delay (values[9]);
        digitalWrite(3, HIGH);
        delay (50);
        digitalWrite(3, LOW);
      }
      for (int i = 0; i < min(NUMBER_OF_FIELDS, fieldIndex + 1); i++)
      {
        Serial.print(values[i], DEC);
        Serial.print(" ");
        values[i] = 0; // loeschen
      }
      fieldIndex = 0; // für Neustart
      Serial.println();
    }

  }
}

Über VB erhält der Arduino eine pipesepariert Zeichenkette gefolgt von einem „New line“.

80|500|0|90|300|-1|100|49|0|213|300|-1|-1|363|0|0|0|0|0|0|0

Dann wird ein Ventil maximal dreimal hintereinander für eine bestimmte Zeit geöffnet. Das Ventil gibt Wassertropfen ab, die dann schließlich fotografiert werden.
Dieser Code funktioniert sehr gut.

Nun möchte ich zwei weitere Ventile ins Spiel bringen. Mit delay(…) geht das ja nicht mehr, weil die drei Ventile nicht hintereinander, sondern auch gleichzeitig öffnen sollen. Zum Testen habe ich natürlich keine Ventile sondern LEDs im Einsatz.
Seit Woche probiere ich ohne Erfolg.

Die von VB übermittelten Daten sehen wie folgt aus:
1|200|200|1|200|200|1|200|200|0|0|0|0|0|999|1|210|215|1|220|230|1|240|250|0|0|0|0|0|999|1|210|215|1|220|230|1|240|250|0|0|0|0|0|999|222|300|1|1

Jeweils 14 Werte (999 ist der "Trenner") sind für ein Ventil vorgesehen, der Rest für die Ansteuerung von Kamera und Blitz.
Die Werte 1-14, 15- … wollte ich in ein zweidimensionales Array (3 rows, 14 cols) speichern und dann zur Ansteuerung einer eigenen Funktion benutzen, den Rest der Daten (Kamera/Blitz) sollen in ein eigenes Array.
Egal wie ich es versuche, entweder reagiert der Arduino gar nicht oder er hängt sich auf oder die Ventile/LEDs sind offen/an und gehen nicht mehr zu/aus. Auch die Eingabe dieses Strings am seriellen Monitor bringt keinen Erfolg.
Wer kann mir bitte etwas auf die Sprünge helfen, einen Ansatz aufzeichnen? Muss ich wie im obigen Code die Werte nach dem abarbeiten wieder löschen (Zeile …). Oder ist dieser Code ansich schon „perfekt“ und muss „nur“ entsprechend angepasst und erweitert werden? Brauche ich serialflash()? Ich komme einfach nicht weiter?!

Vielen Dank im Voraus.

Ablaufsteuerung
Meine Standardantwort zu Ablaufsteuerungen:

Eine Stichworte Sammlung für Google Suchen:
Endlicher Automat,
State Machine,
Multitasking,
Coroutinen,
Ablaufsteuerung,
Schrittkette,
BlinkWithoutDelay,

Blink Without Delay
Der Wachmann

Multitasking Macros
Intervall Macro

Danke für deinen Tipp. Ich werde mir das mal ansehen. Mal sehen wie weit ich komme.
Evtl. lasse ich mir das gegen Bezahlung machen, zumindest ansatzweise, da ich nicht nochmal soviel Zeit "verplämpern" will.

So, ich stelle gerade fest, dass das Senden einer langen Kette wie
1|200|0|1|200|200|1|200|200|0|0|0|0|0|999|1|210|215|1|220|230|1|240|250|0|0|0|0|0|999|1|210|215|1|220|230|1|240|250|0|0|0|0|0|999|222|300|1|1|

von VB an den Arduino nicht funktioniert, ein kürzer Ausdruck kommt aber schon an und löst meine gewünschten Routinen aus.

Was kann ich da konkret machen?

Danke!

photojo:
Was kann ich da konkret machen?

Uns Deinen aktuellen kompletten Sketch zeigen? Oder sollen wir die Lösung erwürfeln? :wink:

Gruß Tommy

Der komplette Sketch ist in meinem Eingangsposting zu sehen. Mein Hauptproblem ist im Moment, dass die langen Array nicht "angenommen" werden.

Da Du zwischendurch Infos bekommen hast, hätte es ja sein können, dass der nicht mehr aktuell ist.

Ansonsten zähle mal Deine übermittelten Zahlen bei der langen Variante und vergleiche diesen Wert mit der Länge Deines Arrays.

Gruß Tommy

Hi,

das Übermitteln der Daten klappt erstmal.

Nun stoße ich auf folgendes Problem: ganz unten setze ich alle Werte des Arrays auf 0. So habe ich das aus einem Tutorial im Netz. Die Diode brennt nun immer, siehe "markierte" Stelle im Code. Irgendwie auch nachvollziehbar, da values[] nach Datenempfang ja "leer" bzw. alles auf Null ist.
Könnt ihr mir bitte weiterhelfen? Vielen Dank!

#define NUMBER_OF_FIELDS 15
int values[NUMBER_OF_FIELDS];
byte fieldIndex;
int ventil_1 = 2;

int cam;
// loop without delay
unsigned long LED_timestore;
int LedStatus = LOW;
int LedPin = 4;
//

void setup()
{
  Serial.begin(9600);
  //Serial.println("Anfang");
  pinMode (2, OUTPUT);
  pinMode (3, OUTPUT);
  pinMode (4, OUTPUT);
}
void loop()
{
  //loop without delay: hier blinkt einfach eine Kontroll-Diode
  //  if (LedStatus == LOW) {
  //  if (millis() - LED_timestore > 1000) {
  //    digitalWrite(LedPin, HIGH);
  //     LED_timestore = millis();
  //     LedStatus = HIGH;
  //   }
  //  } else {
  //   if (millis() - LED_timestore > 250) {
  //     digitalWrite(LedPin, LOW);
  //     LedStatus = LOW;
  //   }
  //  }
  //loop without delay

  if ( Serial.available() > 1)
  {
    Serial.println("verbunden");
    char ch = Serial.read();
    Serial.print(ch, HEX);
    Serial.print('\t');
    Serial.println(fieldIndex);
    if (ch >= '0' && ch <= '9') // ASCII-Zeichen zwischen 0 und 9?
    {
      if (fieldIndex < NUMBER_OF_FIELDS) {
        values[fieldIndex] = (values[fieldIndex] * 10) + (ch - '0');
      }
    }
    else if (ch == '|')
    {
      fieldIndex++;
    }
    else if (ch == '\n')
    {


      if (values[9] == 1) {
        digitalWrite (2, HIGH); // Ventil_1 auf zum Durchspülen
      } else if (values[9] == 0) {
        digitalWrite (2, LOW);
        //} else if (values[2] == 0) {
        // Routine für TaT
        //der Teil geht
        //delay (values[1]); // Verzögerung vor Öffnung 1
        //digitalWrite (2, HIGH); // Ventil_1 auf
        //delay (values[2]);  // offen
        //digitalWrite(2, LOW); // zu
        // der Teil geht ENDE

        if (LedStatus == LOW) {
          if (millis() - LED_timestore > values[2]) {   // ************************
            digitalWrite(ventil_1, HIGH);
            LED_timestore = millis();
            LedStatus = HIGH;
          }
        } else {
           if (millis() - LED_timestore > 250) {
            digitalWrite(ventil_1, LOW);
           LedStatus = LOW;
           }
        }

      }

      for (int i = 0; i < min(NUMBER_OF_FIELDS, fieldIndex + 1); i++)
      {
        Serial.print(values[i], DEC);
        Serial.print(" ");
       values[i] = 0; // loeschen
      }
      fieldIndex = 0; // für Neustart
      // Serial.println();
    }

  }
}

Ja, Du leerst unten das Array.
Was soll denn Deiner Meinung nach passieren, wobei Du unsere Hilfe brauchst?

Oder anders gefragt: Wo ist Dein Problem?

Gruß Tommy

Wenn ich das Array aber nicht leere, dann geht es eben überhaupt nicht.

Eure Hilfe bräuchte als dahingehend, wie ich z. B. übertragene Werte "dauerhaft" bis zur Übertragung neuer Werte speichern kann. Denn wie gesagt, wenn ich values[...] = 0 weglasse, dann macht der Arduino nicht das was ich will.

Ich glaube, es wäre sinnvoll, wenn Du mal zusammenhängend und ausführlich beschreibst, was Du genau willst.

Gruß Tommy

Hallo Tommy,

ich dachte, ich habe das oben in meinem Eingangsposting bereits getan.
Also, es geht darum: 3 verschiedene Ventile geben jeweils maximal 3 Tropfen Wasser ab. Anschließend löse ich eine Kamera und einen Blitz aus.
Da die drei Ventile gleichzeitig öffnen sollen, geht das also mit delay() nicht mehr.
In VB generiere ich folgende Zeichenfolge, die ich übertrage:

1|200|200|1|200|200|1|200|200|0|0|0|0|0|999|1|210|215|1|220|230|1|240|250|0|0|0|0|0|999|1|210|215|1|220|230|1|240|250|0|0|0|0|0|999|222|300|1|1

Ich greife mal die ersten 15 Werte raus:
1|200|200|1|200|200|1|200|200|0|0|0|0|0|999|
Wert 1: 1 oder 0: Ventil 1 aktiv/nicht aktiv
Wert 2: ms vor erster Öffnung
Wert 3: Öffnungdauer in ms
Wert 4: 1 oder 0: Ventil 1: zweite Öffnung ja oder nein
Wert 5: ms vor zweiter Öffnung
Wert 6: Öffnungdauer für zweite Öffnung in ms
Wert 7: 1 oder 0: Ventil 1: dritte Öffnung ja oder nein
Wert 8: ms vor dritter Öffnung
Wert 9: Öffnungdauer für dritte Öffnung in ms
Wert 10: 1 oder 0: öffnen Ventil 1 dauerhaft zum spülen
Wert 11 - 14: Reserve
Wert 15: hier 999 = Ende Parameter Ventil 1

Das wiederholt sich analog für Ventil 2 und 3

Dann kommen die letzten vier Werte, hier 222|300|1|1
Öffne Kameraverschluss nach 222-(300:2) Millisekunden, löse Blitz nach 222 Sekunden aus und schließe dern Kameraverschluss nach 222+(300:2) Millisekundnen. Die beiden 1er legen nur fest, ob die Kamera/Blitz auslösen soll oder nicht.

Ich hoffe, dass ich das ganze ausführlich genug schildern konnte.

Gruß
Jo

Ja, darunter kann ich mir jetzt etwas vorstellen.
Du brauchst also erst mal ein Array mit 49 int-Werten, wenn ich mich nicht verzählt habe.
Es gibt mehrere Möglichkeiten, das zu realisieren.

3 mal je 15 für die 3 Ventile + die 4 Endwerte. Es ist erst mal einfacher, die 999 mit abzuspeichern.

Ich würde zu structs neigen, also etwa so:

struct ventil {
  uint8_t status; // 0 geschlossen, 1 in Vorwartezeit, 2 offen
  uint8_t zyklus; // 0 bis 2 = die 3 Offnungen, 4 Spülen
  uint32_t lastMillis;
  uint16_t werte[14]; // die Zeiten aus der Schnittstelle (ohne die 999);
};

uint16_t kamera[4]; // letzten 4 Werte

ventil ventile[3];

Eine andere Variante wäre ein Array aus den 49 Werten.

Gruß Tommy

Das mit "struct" kenne/kannte ich noch nicht. Daher würde ich es bevorzugen, alle gesendenten Werte in ein Array zu übertragen. Mit dem Array bzw. dessen Werte schließlich meine gewünschten Operationen mit eigenen Funktionen auszuführen, ich denke, das kriege ich irgendwie hin, vielleicht auch nochmal mit kleineren Hilfestellungen im Forum.
Mein Hauptproblem ist im Moment aber einfach das, dass ich die 49 Werte ordentlich übertragen und gespeichert bekomme, damit ich mit ihnen arbeiten kann.
Wenn da mal einen "Mustercode" eines erfahreren Programmierers sehen könnte, wäre mir sehr geholfen. Wo und wie ich dann meinen eigentlichen Prozeduren implementiere probiere ich halt dann.

So, habe weiter probiert und mal Blink ohne delay() eingebaut.

#define NUMBER_OF_FIELDS 15
int values[NUMBER_OF_FIELDS];
byte fieldIndex;
int ventil_1 = 2;
int loops = 0;
int cam;
// loop without delay
unsigned long LED_timestore;
int LedStatus = LOW;
int LedPin = 4;
//

void setup()
{
  Serial.begin(9600);
  //Serial.println("Anfang");
  pinMode (2, OUTPUT);
  pinMode (3, OUTPUT);
  pinMode (4, OUTPUT);
}
void loop()
{
  //loop without delay: hier blinkt einfach eine Kontroll-Diode
  //  if (LedStatus == LOW) {
  //  if (millis() - LED_timestore > 1000) {
  //    digitalWrite(LedPin, HIGH);
  //     LED_timestore = millis();
  //     LedStatus = HIGH;
  //   }
  //  } else {
  //   if (millis() - LED_timestore > 250) {
  //     digitalWrite(LedPin, LOW);
  //     LedStatus = LOW;
  //   }
  //  }
  //loop without delay

  if ( Serial.available() > 1)
  {
    Serial.println("verbunden");
    char ch = Serial.read();
    Serial.print(ch, HEX);
    Serial.print('\t');
    Serial.println(fieldIndex);
    if (ch >= '0' && ch <= '9') // ASCII-Zeichen zwischen 0 und 9?
    {
      if (fieldIndex < NUMBER_OF_FIELDS) {
        values[fieldIndex] = (values[fieldIndex] * 10) + (ch - '0');
      }
    }
    else if (ch == '|')
    {
      fieldIndex++;
    }
    else if (ch == '\n')
    {
      if (values[9] == 1) {
        digitalWrite (2, HIGH); // Ventil_1 auf zum Durchspülen
      } else if (values[9] == 0) {
        //digitalWrite (2, LOW);
        //} else if (values[2] == 0) {
        // Routine für TaT
        //der Teil geht
        //delay (values[1]); // Verzögerung vor Öffnung 1
        //digitalWrite (2, HIGH); // Ventil_1 auf
        //delay (values[2]);  // offen
        //digitalWrite(2, LOW); // zu
        // der Teil geht ENDE
      }
      for (int i = 0; i < min(NUMBER_OF_FIELDS, fieldIndex + 1); i++)
      {
        Serial.print(values[i], DEC);
        Serial.print(" ");
        //  values[i] = 0; // loeschen
      }
      fieldIndex = 0; // für Neustart
      // Serial.println();

      loops = 0;

    }

  }
  while (loops < 1) {
    if (LedStatus == LOW) {
      if (millis() - LED_timestore > 2000) {
        digitalWrite(ventil_1, HIGH);
        LED_timestore = millis();
        LedStatus = HIGH;
      }
    } else {
      if (millis() - LED_timestore > 500) {
        digitalWrite(ventil_1, LOW);
        LedStatus = LOW;

      }
    }
    loops = 1;
  }
  // if (millis() - LED_timestore > values[2]) {
  //   LED_timestore = millis();
  //   if (LedStatus == LOW) {
  //     LedStatus = HIGH;
  //   } else {
  //     LedStatus = LOW;
  //   }
  //   digitalWrite(ventil_1, LedStatus);
  // }
}

Die Variable loops benutze ich, damit das "Blinken" nur einmal ausgeführt wird, eben dann, wenn Daten empfangen wurden. Leider funktioniert das nicht. Die LED geht beim Senden von VB in ein Dauerleuchten über?!

Weil Du loops zwischendrin wieder auf 0 setzt.

Gruß Tommy

Muss ich doch. Das "Blinken" soll bei jedem Senden EINMAL abgearbeitet werden. Wie soll ich es denn sonst machen?

Gruß Jo

Ok, ich denke, ich habs, zumindest das erstmal.

Ich könnte verzweifeln:

#define NUMBER_OF_FIELDS 21
int values[NUMBER_OF_FIELDS];

byte fieldIndex;
int ventil_1 = 2;
int loops = 0;
int cam;
// loop without delay
unsigned long LED_timestore;
int LedStatus = LOW;
int LedPin = 4;
//
int interval = 0;

void setup()
{
  Serial.begin(9600);
  //Serial.println("Anfang");
  pinMode (2, OUTPUT);
  pinMode (3, OUTPUT);
  pinMode (4, OUTPUT);
}
void loop()
{
  //loop without delay: hier blinkt einfach eine Kontroll-Diode
  //  if (LedStatus == LOW) {
  //  if (millis() - LED_timestore > 1000) {
  //    digitalWrite(LedPin, HIGH);
  //     LED_timestore = millis();
  //     LedStatus = HIGH;
  //   }
  //  } else {
  //   if (millis() - LED_timestore > 250) {
  //     digitalWrite(LedPin, LOW);
  //     LedStatus = LOW;
  //   }
  //  }
  //loop without delay

  if ( Serial.available())
  {
    Serial.println("verbunden");
    char ch = Serial.read();
    Serial.print(ch, HEX);
    Serial.print('\t');
    Serial.println(fieldIndex);
    if (ch >= '0' && ch <= '9') // ASCII-Zeichen zwischen 0 und 9?
    {
      if (fieldIndex < NUMBER_OF_FIELDS) {
        values[fieldIndex] = (values[fieldIndex] * 10) + (ch - '0');
      }
    }
    else if (ch == '|')
    {
      fieldIndex++;
    }
    else if (ch == '\n')
    {
      delay(500);
      loops = 0;
      if (values[9] == 1) {
        digitalWrite (2, HIGH); // Ventil_1 auf zum Durchspülen
      } else if (values[9] == 0) {
        //digitalWrite (2, LOW);
        //} else if (values[2] == 0) {
        // Routine für TaT
        //der Teil geht
        //delay (values[1]); // Verzögerung vor Öffnung 1
        //digitalWrite (2, HIGH); // Ventil_1 auf
        //delay (values[2]);  // offen
        //digitalWrite(2, LOW); // zu
        // der Teil geht ENDE
      }
      interval = values[2];
      for (int i = 0; i < min(NUMBER_OF_FIELDS, fieldIndex + 1); i++)
      {
        Serial.print(values[i], DEC);
        Serial.print(" ");
        values[i] = 0; // loeschen
      }
      fieldIndex = 0; // für Neustart
    }
  }

  while (loops < 2) {
    if (LedStatus == LOW ) {
      if (millis() - LED_timestore > 2000) {     // <<<<------------- HIER
        digitalWrite(ventil_1, HIGH);
        LED_timestore = millis();
        LedStatus = HIGH;
      }
    } else {
      if (millis() - LED_timestore > interval) {
        digitalWrite(ventil_1, LOW);
        LedStatus = LOW;
        loops++;
      }
    }
  }



  // while (loops != 1){
  //     if (millis() - LED_timestore > interval) {
  //     LED_timestore = millis();
  //     if (LedStatus == LOW) {
  //       LedStatus = HIGH;
  //     } else {
  //      LedStatus = LOW;
  //    }
  //    digitalWrite(ventil_1, LedStatus);
  //  }
  // }

}

Warum wartet der Arduino mit der Zeile

if (millis() - LED_timestore > 2000)

nicht die 2000 ms ab, bis er die LED auf HIGH setzt?! GRRR. :slight_smile:

Lass Dir doch mal direkt darüber die Werte von millis() und LED_Timestore ausgeben und nimm die ganzen auskommentierten Blöcke raus. Die verhindern Übersichtlichkeit.

Gruß Tommy