Frage zur seriellen Datenübertgung aus VB

Hallo,

folgende Situation:

Mit einem Button in VB übertrage ich einen kommaseparierten String (eigentlich nur Zahlen) an den Arduino.
Mit einem zweiten Button möchte ich nun einen Ablauf starten. Das "executed" benutze ich, da der Prozess in loop nur einmal ausgeführt werden soll.

übertrage Werte an den Arduino

if ( Serial.available())
  {
    char ch = Serial.read();
    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
    {
      for (int i = 0; i < min(NUMBER_OF_FIELDS, fieldIndex + 1); i++)
      {
        Serial.println(values[i]);
       values[i] = 0; //
      }
      fieldIndex =0; // für Neustart
    }
  }

Starte Prozess auf dem Arduino

   if (Serial.available()) {
    data = Serial.read();
    if (data == 'A') {
      executed = false;
     }
     else {
    }
}

Der eigentliche Prozess: LED blinkt x-mal = values[0]

  if (executed == false) {
    executed = true;
    // einmaliges Abarbeiten
    //if (Serial.available()) {
    for (int i = 0; i < [b]values[0][/b]; i++) {
      digitalWrite(ledPin, HIGH);

      delay(1000);
      digitalWrite(ledPin, LOW);

      delay(200);
    }
    //}
    
  }

Das PROBLEM: values[0] ist immer 0, obwohl ich von VB z.B. 3 übertrage.

Wer kann mir helfen? Danke!

Ich spekuliere, CR oder LF löschen Dir die Daten im else-Zweig.

Wenn du zwei Serial.read in deinem Sketch hast, woher weisst du, welches davon was liest?

Das mit dem zweiten Serial.read war mir nicht bewusst.

Ich habe nun versucht, mit nur einem Button aus VB alle Werte inkl. Routineauslöser zu übertragen.

  if ( Serial.available())
  {
    char ch = Serial.read();
    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
    {
      for (int i = 0; i < min(NUMBER_OF_FIELDS, fieldIndex + 1); i++)
      {
        Serial.println(values[i]);
       //values[i] = 0; //


       if(values[4] == 999)   // ****** startet Routine
       {
executed = true;
       }
       
      }

Leider klappt das auch nicht.

Was den CR bzw. LF angeht: In VB habe ich folgendes

values = txt_v1_start_T1.Text & "," & txt_v1_start_T2.Text & "," & txt_v1_groesseT.Text & "," & txt_verz_cam.Text & ",999," & vbCrLf

Habt ihr noch nen Tipp?

Und was ist "vbCrLf" anderes als CR LF?

agmue:
Und was ist "vbCrLf" anderes als CR LF?

Wie meinst du das? Sorry, VB und C ist für mich relativ neu.

Könntest du mir bitte einen konkreten Lösungvorschlag machen? Ich meine das höflich!
Danke!

Mache es doch erst mal einfacher und gib die Daten in der Eingabezeile des seriellen Monitors der IDE ein und schaue Dir über Serial.print an, was passiert.
Ich würde eine Zeile immer über Linefeed abschließen, da weißt Du, wann auf dem Arduiono alles angekommen ist.
Wenn das funktioniert, dann kannst Du das VP dazu nehmen.

Gruß Tommy

if (ch >= '0' && ch <= '9') {...}  // wenn eine Zahl kommt
else if (ch == ',') {...} // wenn ein Komma
else {...} // alle anderen Zeichen wie CR oder LF

In der letzen Zeile steht values[ i ] = 0;. Du überträgst Daten und löscht sie gleich wieder mittels CR oder LF. Oder verstehe ich Deinen Code falsch?

Ziel ist einfach, 4 Zahlen aus VB an den Arduino zu übergeben und dann eine Routine auszuführen.
Nach dem Ablauf der Routine sollen die 4 Zahlen unter Umständen in VB angepasst und wieder übertragen werden. Dann solle die Routine eben wieder starten. Ich sitze seit Tagen an dem Problem.

Was mach ich falsch?!

Wenn du sowas überträgst:

"123,222 X"

Wobei X das Kommando ist

 if ( Serial.available()) {
    char ch = Serial.read();
    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 == 'X') { executeX(values); fieldIndex = 0; reset(values); }
    else if (ch == 'A') { executeA(values); fieldIndex = 0; reset(values); }
    else { /* andere Zeichen (Leerzeichen CR LF)  ignorieren */ }
  }

Alternativ kannst du auch das Zeilenende-Zeichen gezielt zum Rücksetzen verwenden:

 else if ( ch == '\n' ) { reset(values); fieldIndex = 0; }

Danke dir, michael_X, aber was meinst du mit

executeX(values) ?

Ich verstehe ich nicht?

Möglicherweise hilft:

Serial.print(values[i],DEC);

Testsketch:

#define NUMBER_OF_FIELDS 20
char values[NUMBER_OF_FIELDS];
byte fieldIndex;

void loop()
{
  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')
    {
      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();
    }
    
  }
}

void setup()
{
  Serial.begin(9600);
  Serial.println("Anfang");
}

executeX(values) ist eine Funktion, die bei 'X' ausgeführt werden soll.

Danke.

Ich habe #define NUMBER_OF_FIELDS 3 gemacht.

Im seriellen Monitor habe "neue Zeile" eingestellt.

Gebe ich 123,456,789 ein und dann ENTER

kommt folgendes:

Anfang
31	0
32	0
33	0
2C	0
34	1
35	1
36	1
2C	1
37	2
38	2
39	2
A	2
123 -56 21

Du hast Deinen Sketch ja nur partiell gezeigt, daher kenne ich Deine Deklarationen nicht. "789" ist für mein char-Feld zu groß.

Ok, ich poste mal meinen kompletten Code. Ich bekomme es einfach nicht hin?!
Wie gesagt, ich möchte einfach ein paar Werte (Zahlen) an den Arduino übertragen.

int data;
int ledPin = 2;
int ledPinblau = 3;
int SchalterZustand;
int InputPin = 7;

const int NUMBER_OF_FIELDS = 5; // Anzahl kommaseparierte Felder
int fieldIndex = 0;
int values[NUMBER_OF_FIELDS]; // Array mit den Werten aller Felder

boolean executed = false;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(ledPinblau, OUTPUT);
  pinMode(InputPin, INPUT);
  Serial.begin(9600);
}

void loop() {

  Serial.println("verbunden");
  // put your main code here, to run repeatedly:

  int SchalterZustand;
  SchalterZustand = digitalRead(InputPin);
  Serial.println(SchalterZustand, DEC);

  if (SchalterZustand == 1) {
    digitalWrite(ledPin, HIGH);
    Serial.println("GEDRÜCKT");
    executed = false;
  }
  if (SchalterZustand == 0) {
    digitalWrite(ledPin, LOW);
  }

  //  if (Serial.available()) {
  //  data = Serial.read();
  //  if (data == 'A') {
  //    executed = false;
  //    }
  //   else {

  //  }

  // }

  if (Serial.available()) {
    char ch = Serial.read();
    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 {
      for (int i = 0; i < min(NUMBER_OF_FIELDS, fieldIndex + 1); i++) {
        Serial.println(values[i]);
        //values[i] = 0; //

        if (values[4] == 999) {
          executed = true;
        }

      }

      fieldIndex = 0; // für Neustart
    }
  }

  if (executed == false) {
    executed = true;
    // einmaliges Abarbeiten
    //if (Serial.available()) {
    for (int i = 0; i < values[0] + 1; i++) {
      digitalWrite(ledPin, HIGH);

      delay(1000);
      digitalWrite(ledPin, LOW);

      delay(200);
    }
    //}

  }

  if (values[1] == 777) {
    //data = Serial.read();

    executed = false;

  }

}

Wenn Du in meinem Sketch änderst:int values[NUMBER_OF_FIELDS];, dann erhälst Du bei der Eingabe "123,456,789" als Ausgabe

Anfang
31 0
32 0
33 0
2C 0
34 1
35 1
36 1
2C 1
37 2
38 2
39 2
A 2
123 456 789

Ich hab mir mal erlaubt, deinen Sketch etwas zu vereinfachen, und ihn so zu ändern, wie ich rate dass du es etwa gemeint haben könntest:

const int ledPin = 2;
const int InputPin = 7;  // Taster zum rücksetzen

const byte NUMBER_OF_FIELDS = 5; // Anzahl kommaseparierte Felder
int values[NUMBER_OF_FIELDS]; // Array mit den Werten aller Felder
byte fieldIndex = 0;

int executed = 0;
boolean cleared = true;

void setup() {
  pinMode(ledPin, OUTPUT);
  pinMode(InputPin, INPUT);
  Serial.begin(9600);
  Serial.println("verbunden");
}

void loop() {
  boolean SchalterZustand = digitalRead(InputPin);
  digitalWrite(ledPin, SchalterZustand);

  if (SchalterZustand == HIGH) {
    if (!cleared) {
      Serial.println("NEUSTART");
      clearValues();
      cleared = true;
    }
    executed = 0;
    return; // Erst warten bis der Taster wieder losgelassen wurde
  }
  if (cleared) delay(5); // Entprellen beim Loslassen des Tasters

  if (Serial.available()) {
    char ch = Serial.read();
    cleared = false;
    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 == '\r') {
      // nichts tun
    } else {
      for (int i = 0; i < min(NUMBER_OF_FIELDS, fieldIndex + 1); i++) {
        Serial.print (values[i]); Serial.print('\t');
      }
      Serial.println();
      if (values[4] == 999) {
        action();
        executed++;
        Serial.print(executed); Serial.println(" executed since Button pressed");
      }
      if (ch == '\n') {
        clearValues();  // neue Zeile
      }
    }
  }
}

void action() {
  for (int i = 0; i < values[0] + 1; i++) {
    digitalWrite(ledPin, HIGH);
    delay(200);
    digitalWrite(ledPin, LOW);
    delay(200);
  }
}

void clearValues() {
  for ( byte i = 0; i < NUMBER_OF_FIELDS; i++)
    values[i] = 0;
  fieldIndex = 0;
  Serial.println("cleared");
}

Die seltsame Idee mit der 999 als Kommando hab ich mal dringelassen. Soll ja immer noch dein Sketch sein.
(Ich würde neben den Ziffern, dem Komma und den NeueZeile-Zeichen noch mehr Zeichen einfach ignorieren oder als Kommando erkennen.)

Vielen herzlichen Dank für deinen Code Michael_X. Danke auch an die anderen. Ich komme einfach nicht weiter.

Nun habe ich zum x-ten Mal alles neu gemacht und diesen Code aus Schulungsunterlagen im Netz gefunden. Das Skript macht ein solch seriösen Eindruck, dass ich überzeugt bin, dass er funktioniert. (Nehmt es mir bitte nicht übel, wenn ich eure Bemühungen nochmal zur Seite gelegt habe.)

int werte[2]; //Array für die beiden Integerwerte
int arrayIndex = 0; //ArraYindex initialisieren.

void setup() {
  Serial.begin(9600);
//  pinMode (2‚ OUTPUT);
//  pinMode (3, OUTPUT);
pinMode (2, OUTPUT);
pinMode (3, OUTPUT);
    Serial.println("2wei Integerwerte getrennt mit Komma eingeben:");
    delay(1000);
  }

  void loop() {
  if (Serial.available())
  {
    char ch = Serial.read();
                if (ch >= 'O' && ch <= '9')
    {
      werte[arrayIndex] = (werte [arrayIndex] * 10) + (ch - 'O');

    }
    else if (ch == ',') // Wenn Komma, dann zun nächsten Arrayelement wechseln.
    {
      if (arrayIndex == 0)
        arrayIndex++;
    }
    else if (ch == '\n' && arrayIndex == 1) // Uenn letztes Zeichen Protokoll empfanoen und zwei Uerte de.
    {

      for (int i = 1; i <= werte[0] ; i++)
      {
        digitalWrite (2, HIGH);
        delay(200);
        digitalWrite(2, LOW);
        delay(200);
      }
      for (int i = 1; i <= werte[1]; i++)
      {
        digitalWrite (3, HIGH);
        delay(200);
        digitalWrite(3, LOW);
        delay(200);
      }
      for (int i = 0; i <= 1; i++) werte[i] = 0; //Wertearray zurücksetzen.
      arrayIndex = 0;
    }
    else
    {
      Serial.println("Verstehe ich nicht ...");
      for (int i = 0; i <= 1; i++) werte[i] = 0; // Wertearray zurücksetzen.
      arrayIndex = 0;
    }
  }
}

Im seriellen Monitor gebe ich z.B. 5,6 gefolgt von ENTER ein. Es kommt IMMER die Ausgabe "Verstehe ich nicht ..."; Bin ich zu doof?!

Ich krieg die Krise. :slight_smile:

@ agmue

Dein Code läuft jetzt bei mir. Super.

Dennoch bleibt die Frage, warum der zuletzt von mir gepostete nicht? Irgendwie muss ich die ja jetzt kombinieren, oder? Ich möchte ja jetzt auch was schalten.

Danke allen im Voraus!

photojo:
Ich möchte ja jetzt auch was schalten.

Mein Code, leicht erweitert, kann auch eine LED blinken lassen:

#define ledPin 13
#define NUMBER_OF_FIELDS 20
char values[NUMBER_OF_FIELDS];
byte fieldIndex;
uint16_t blinkZaehler;
const uint32_t blnkIntervall = 200;
uint32_t aktMillis, blinkMillis;

void loop()
{
  aktMillis=millis();
  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')
    {
      blinkZaehler = values[0] * 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
      Serial.println();
    }
  }

  if ((blinkZaehler > 0) && (aktMillis - blinkMillis >= blnkIntervall)) {
    blinkMillis = aktMillis;
    digitalWrite(ledPin, !digitalRead(ledPin));
    blinkZaehler--;
  }
}

void setup()
{
  Serial.begin(9600);
  Serial.println("Anfang");
  pinMode(ledPin, OUTPUT);
}