Seriell mehrere Variablen verarbeiten

Hallo

Ich kenne mich etwas aus, aber jetzt bin ich an meinen Grenzen :stuck_out_tongue_closed_eyes:
Ich bau mir gerade ne Cocktailmaschine und habe 4 Ventile.
Diese 4 Ventile sind f√ľr 4 Zutaten,
Am PC will ich ein Programm schreiben wo man Rezepte schreiben kann (Rezeptname und Dosierzeit der jeweiligen Ventile).
An den Arduino Mega 2560 werden dann 4 Zeiten √ľbertragen.
Dosiert wird dann mit:
digitalWrite(Ventil1, HIGH);
delay(zeit1);
digitalWrite(Ventil1, LOW);
das gleiche dann f√ľr Ventil 2, 3, 4.
Ich kann zwar was seriell einlesen, jedoch nur einen Wert
Wie muss der code f√ľr das ‚Äúserial.read‚ÄĚ beim Arduino aussehen wenn ich die Zeiten in einem Array √ľbertrage zb [20,30,10,40]
Wie kann ich also das Array einlesen und die 4 Daten verarbeiten, damit sie dann bei zeit1, zeit2, zeit3 und zeit4 stehen?

Mit Serial.read() kannst du eh nur 1 Buchstaben einlesen.

F√ľr jeden anderen Text, ob nun "100" oder "100,200,0,300" musst du mehr Aufwand treiben.

Probier mal ob du mit Serial.parseInt weiterkommst. Dein PC muss halt immer 4 Zahlen und 3 Kommas schicken.

Stelle den Serial Monitor unten rechts so ein dass ein Linefeed/Newline am Ende gesendet wird:

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

const int NUMBER_OF_VALUES = 4;
unsigned int values[NUMBER_OF_VALUES];

void setup()
{
 Serial.begin(9600);
}

void loop()
{
 if (readSerial(Serial))
 {
   parseSerial();


   //hier was mit den Werten machen
 }
}

void parseSerial()
{
 byte index = 0;

 char* ptr = strtok(serialBuffer, ",;");
 while (ptr != NULL && index < NUMBER_OF_VALUES)
 {
   values[index++] = atol(ptr);
   ptr = strtok(NULL, ",;");
 }

 for (byte i = 0; i < index; i++)       //nur zum Test! Kann entfernt werden
   Serial.println(values[i]);
 Serial.println(F("---"));
}

bool readSerial(Stream& stream)
{
 static byte index;

 while (stream.available())
 {
   char c = stream.read();

   if (c == '\n' && index > 0)
   {
     serialBuffer[index] = '\0';
     index = 0;
     return true;
   }
   else if (c >= 32 && index < SERIAL_BUFFER_SIZE - 1)
   {
     serialBuffer[index++] = c;
   }
 }
 return false;
}

readSerial() liefert true zur√ľck wenn die Zeile eingelesen wurde. parseSerial() konvertiert den String in Integer. Danach kann man was man damit tun.

Danke!

Die seriellen Daten werden dann in der Variable serialBuffer gespeichert oder? Wenn ich den seriellen Monitor öffne und ich 1111 sende, steht:

1111

wenn ich aber 111111 sende, kommt

45575

Ich muss aber eine 16 stellige Zahl senden f√ľr die 4 Variablen die 4 stellen lang sind (millisekunden) wenn dieses "√úbertragungsproblem" gel√∂st ist, wie kann ich dann diese Variable aufteilen von serialBuffer 100200300200 in: zeit1 100 zeit2 200 zeit3 300 zeit4 200

Die einzelnen Zahlen werden mit Kommas oder Strichpunkten getrennt!! Wie willst du denn sonst 10 von 100 unterscheiden? :confused: Das macht man so egal wie man es letztlich einliest. Auch beim primitiven, blockierend parseInt() brauchst du Trennzeichen

Also z.B. so 100,200,300,400 (und automatisch ein LF am Ende)

Und eine Zahl geht so maximal bis 65.535. Das wären 65 Sekunden, was reichen sollte :)

readSerial() liest die Zeichen St√ľck f√ľr St√ľck in einen C String ein (d.h. ein Null-terminiertes char Array). parseSerial() geht dann durch den String und wandelt die einzelnen Zahlen entlang der Delimiter (Komma oder Strichpunkt) in Integer und schreibt diese in das Array values.

Aso ok :cold_sweat: Sorry kleiner Verständnisfehler von mir

Danke jetzt bin ich schon ein gro√ües St√ľck weiter :grin:

Ach ja, SERIAL_BUFFER_SIZE hat mit 20 Bytes genau Platz f√ľr 4 * 4 Zeichen + 3 Delimiter + 1 Terminator. Wenn du also mal mehr als 4 Ziffern pro Zahl oder mehr als 4 Zahlen √ľbertragen willst, musst du den Puffer gr√∂√üer machen. Aber keine Sorge - da kann nichts √ľberlaufen. Wenn eine Eingabe zu lang ist wird sie einfach hinten abgeschnitten.

Man kann das auch anders l√∂sen und statt erst mal einen String einzulesen die einzelnen Ziffern einer Zahl gleich aufaddieren. Damit spart man sich den Puffer f√ľr den String. Aber so ist man flexibler.

Wenn *) du das eh nur verwendest um damit ein delay zu steuern, brauchst du auch kein array.
Weder f√ľr den eingelesenen Text, noch f√ľr deine 4 Zeiten.

Der Serial Eingangspuffer fasst 64 Zeichen, das sollte reichen.

const byte VentilPin[] = {3,4,5,6};
void setup() {
   for (byte i = 0; i < sizeof(VentilPin); i++) 
      pinMode(VentilPin[i], OUTPUT);
}

byte VentilNr; // Index auf VentilPin Array
void loop() {
  if (Serial.available()) {
      unsigned int Dauer = Serial.parseInt();
      if (Dauer > 0) {
         digitalWrite(VentilPin[VentilNr], HIGH);
         delay (Dauer);
         digitalWrite(VentilPin[VentilNr], LOW);
      }
      VentilNr++;
      if (VentilNr >= sizeof(VentilPin) ) {
          // Fertig, passende Anzeige
          VentilNr = 0; // wieder von vorn
      }
   }
}

Serenifly‚Äôs Lieblingsroutine ist nat√ľrlich auch super, besonders zum Verstehen, was da gemacht wird.


Nachtrag
*) Delay ist generell Mist, √ľbrigens. Fasl so schlimm wie 4 Delay nacheinander.
Da hast du keine M√∂glichkeit, interaktiv einzugreifen (‚ÄúNotAus‚ÄĚ :wink: ) ( ausser Reset ).

Danke jetzt funktioniert das Arduino Programm Falls jemand anderes nach derselben Lösung sucht so werden dann die Ventil angesteuert:

void loop()
{
 if (readSerial(Serial))
 {
   parseSerial();
    digitalWrite(Y1, HIGH);    
    delay(values[0]);        
    digitalWrite(Y1, LOW);

    digitalWrite(Y2, HIGH);    
    delay(values[1]);        
    digitalWrite(Y2, LOW);

    digitalWrite(Y3, HIGH);    
    delay(values[2]);        
    digitalWrite(Y3, LOW);
    
    digitalWrite(Y4, HIGH);    
    delay(values[3]);        
    digitalWrite(Y4, LOW);  
 }
}

Wenn du mehrmals die gleichen Sachen machen musst, denke immer in Arrays und for-Schleifen. Siehe #7. Bei vier Ventilen ist es kein Problem dass auch per Hand zu schreiben. Aber bei mehr Zutaten artet das in Arbeit aus und wird sehr un√ľbersichtlich.

Cocktail Maschinen sind anscheinend ein einigermaßen beliebtes Projekt. Da gab es hier schon ein paar mal Code wie man das blockierungsfrei ansteuert :) Aber auch wenn man bei Null anfängt, ist das ein nettes Thema um zu lernen mit millis() umzugehen.