Array mit Messdaten befüllen

Hallo zusammen,
ich lese die Daten einer digitalen Messuhr aus.
Insgesamt führe ich in einer Messreihe 39 Messungen aus, die Messungen werden durch den Empfang eines Zeichens 'A' ausgelöst. Nun möchte ich die Messergebnisse in ein Array schreiben.

Ich bekomm das mit dem Array befüllen nicht auf die Reihe. Igendwie steh ich auf der Leitung. Mit meinem Ansatz bleib ich in der for Schleife hängen.

Könnt ihr mir mal auf die Sprünge helfen? :confused:

double data[39];

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

void loop() {

		while  (Serial.available() > 0) {
			 char messung = Serial.read();

			 if (messung == 'A') {
				
				for(int i=0;i<39;i++) {
				data[i] = caliper.fetch(); // Messung und Wert in Array schreiben
				}				
			 }
		 }		

				for(int i=0;i<39;i++){
					Serial.println(data[i]);
				}
}

Wenn Du das Ganze etwas lesbarer formatierst (+T in der IDE hilft Dir dabei) kann man die Zusammenhänge besser sehen.

Gruß Tommy

Sorry, +T ausgeführt :grin:

double data[39];

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

void loop() {

  while  (Serial.available() > 0) {
    char messung = Serial.read();

    if (messung == 'A') {

      for (int i = 0; i < 39; i++) {
        data[i] = caliper.fetch(); // Messung und Wert in Array schreiben
      }
    }
  }

  for (int i = 0; i < 39; i++) {
    Serial.println(data[i]);
  }
}

double data[39] geht im Index von 0 bis 38. Du schreibst über Arraygrenzen hinaus.

Gruß mTommy

Hm... versteh ich nicht ich lese ein i<39. Das ist doch 38. Überseh ich da was?

Hallo,

nö du übersiehst nichts, diesmal hat Tommy was übersehen. :slight_smile:
Sicherer ist eine Konstante zu definieren und überall im Sketch einzusetzen.
Bsp. const byte SIZE = 39;

Nur weist du 39x den gleichen Wert von caliber.fetch deinem Array zu.
Was ist und was macht caliber.fetch() ?
Du siehst selbst das dein Sketch unvollständig ist!

Ihr habt natürlich mit <39 recht. Fehler von mir.

Kommt Deine Messeinrichtung mit Abfragen in ms-Abständen zurecht?
Was passiert denn überhaupt und was nicht? Hänge doch mal ein paar serielle Ausgaben rein, damit Du siehst, was passiert.

Gruß Tommy

Hallo,

mit caliper.fetch wird einfach die Messuhr ausgelesen über eine library, das funktioniert auch bestens und natürlich ist die included.

Das kontinuierliche Auslesen wenn 'A' ankommt geht einwandfrei, nur das befüllen des Arrays bring ich nicht hin.

Tommy56:
Ihr habt natürlich mit <39 recht. Fehler von mir.

Kommt Deine Messeinrichtung mit Abfragen in ms-Abständen zurecht?
Was passiert denn überhaupt und was nicht? Hänge doch mal ein paar serielle Ausgaben rein, damit Du siehst, was passiert.

Gruß Tommy

Die Messung wird etwa 5 mal/sec angestoßen. Das geht.

Ich kann die Ausgabe gerade nicht testen aber nach meiner Erinnerung kommt etwa 10 mal hintereinander 0.000 raus und dann nichts mehr.

Hallo,

zur Zeit ist das nicht erklärbar warum das nicht funktionieren soll.
Zeige mal was kommt ...

const byte SIZE = 20;

void setup() {
  Serial.begin(57600);

  for (byte i=0; i<SIZE; i++) {
    Serial.println( caliper.fetch() );
  }
}

void loop() {

}

Edit:
Kann auch sein das die caliber.fetch Funktion zwischendurch 0 ausgibt wenn keine neuen Daten anliegen.
Füge dann in die for Schleife ein delay(500) ein.
Poste die Ausgaben beider Varianten.

Nach dem Formatieren mit ctrl-T hätte dir eigentlich auffallen müssen, dass deine Ausgabeschleife ständig aufgerufen wird - unabhängig davon, ob Du ein 'A' oder überhaupt irgendetwas gesendet hast oder nicht.
D.h. mit dem Start des Sketches beginnt er sofort und endlos den Inhalt von data auszugeben. Und da da ja erstmal nur 0.00 drinsteht, schreibt er dir damit den seriellen Monitor voll. Da immer der gleiche Wert ausgegeben wird, merkst Du die weiteren Ausgaben gar nicht mehr. Gib auch mal den Index mit aus, dann siehst Du das:

for (int i = 0; i < 39; i++) {
    Serial.print(i); Serial.print(" - ");
    Serial.println(data[i]);
  }

Und dann verschiebe die Ausgabe-Schleife unmittelbar hinter die Leseschleife.

Der Aufruf von caliber.fetch() sollte nicht das Problem sein. So wie ich das sehe, liest der Aufruf direkt vom Messschieber, und blockiert solange, bis die Daten übertragen sind. Ob es sinnvoll ist, so schnell hintereinander auszulesen ist einen andere Frage ...

Hallo,

haste richtig erkannt. Nur einmal mit 'A' angestoßen wird data gefüllt und der Inhalt von data bleibt erhalten. Anders formuliert sollte nach dem ersten 'A' nie mehr 0 kommen außer der Messwert ist 0. Das verschieben der for ist dennoch sinnvoll. Vollkommen richtig. Im Detail sollte noch ein Fehler verborgen sein den derzeit nur der TO liefern kann.

So - wenn ich nun die ganze Sache ohne Array befüllen mache, also direkt zurück sende per Serial.print, dann funktioniert das ganze wunderbar. Unterschied ist das if beim Serial.available, da das in der Loop ja ständig durchlaufen soll. Es gibt hier auch keine Timing Probleme.

Kann es sein, dass die Sache mit dem Array und einer Schleife zum Befüllen derart Rechenleistung kostet, dass das so nicht machbar ist? Ich wollte eigentlich eine Entlastung des Serial Verkehrs durch Einsatz eines Arrays erreichen und die Daten erstmal sammeln und dann senden.

// Diese Lösung funktioniert sehr gut

double data;
void setup() {
  Serial.begin(57600);
}
void loop() {

  if (Serial.available() > 0) {
    char messung = Serial.read();
    if (messung == 'A') {
      data = caliper.fetch(); // Messwert holen
      Serial.print(data); // Messwert senden
    }
  }
}

Ich habe dann auch mal das printen des Index und der Werte direkt hinter die for Schleife verschoben (wie von MicroBahner vorgeschlagen). Ergebnis ist, dass egal ob nun der Messbefehl kommt oder nicht, gemessen wird. Und zwar ständig 39 mal und dann wieder von vorn. Es kommen zwar Messwerte aber offensichtlich andauernd und nicht zu meinem gesendeten Messbefehl.

Der kleine Sketch von Doc Arduino bringt korrekte 20 Messdaten.

Meiner Ansicht nach liegt der Fehler erstmal in der Logik des Sketches, da ich in der for Schleife hängen bleibe bis zu deren Ende aber eigentlich dazwischen mal den Eingang der seriellen Daten prüfen müsste.

Hi

Anders herum wir ein Schuh draus!

Bei Deinem letzten Sketch guckst Du in JEDEM loop()-Durchlauf, ob neue Daten vorhanden sind.
Bei jedem 10000.ten Durchlauf kommt Da ein 'JAAA' raus - dieses Byte holst Du ab und sendest Das auch direkt an Dein Terminal.
Dann passiert wieder 9999 Durchläufe rein gar Nichts - ist ja auch Nichts Da, was abgeholt werden könnte.

In Deiner Schleife aber liest Du Daten, EGAL, ob Da Welche sind, oder nicht!!
Du prüfst, ob mindestens 1 Byte vorhanden ist - und liest dann 39 Byte ein.

-> StateMaschine
Wenn A gelesen wurde, Daten Empfang Aktiv
Wenn Daten Empfang Aktiv UND Daten verfügbar, das nächste Byte (nur EINS) einlesen und im Array positionieren.
Wenn wir dabei das 39.te empfangen haben, ist das Array fertig und kann weiter verarbeitet werden.

MfG

dr_nobody:
Ergebnis ist, dass egal ob nun der Messbefehl kommt oder nicht, gemessen wird. Und zwar ständig 39 mal und dann wieder von vorn. Es kommen zwar Messwerte aber offensichtlich andauernd und nicht zu meinem gesendeten Messbefehl.

Natürlich, so ist das ja auch programmiert.

Dann erklär doch mal genau was Du willst? Soll bei jedem 'A' nur einmal gemessen werden? Das war aus deinem Eingangssketch nicht ersichtlich. Und wozu willst Du dann das Array benutzen? Wann sollen die Daten an den seriellen Monitor geschickt werden?
39 mal 'A' empfangen und dann erst die erfassten Daten senden?

MicroBahner:
Natürlich, so ist das ja auch programmiert.

Dann erklär doch mal genau was Du willst? Soll bei jedem 'A' nur einmal gemessen werden? Das war aus deinem Eingangssketch nicht ersichtlich. Und wozu willst Du dann das Array benutzen? Wann sollen die Daten an den seriellen Monitor geschickt werden?
39 mal 'A' empfangen und dann erst die erfassten Daten senden?

Da hab ich wohl nicht klar ausgedrückt: Ja, es soll bei jedem 'A' genau einmal gemessen werden und dieser Wert ins Array und das 39 mal hintereinander, dann ist eine Messrunde abgeschlossen. Wenn das Array voll ist, sollen die Daten per Serial.print an den PC gesendet werden aber so weit bin ich noch nicht. Erstmal muss das Einlesen der Werte funktionieren.

@postmaster-ino
Das muss ich mir erst mal durch den Kopf gehen lassen und zum Thema lesen. Danke für den Hinweis.

Hi

Dachte an Was in dieser Richtung:
ungetestet - nur im Editor runtergeschrieben

...
if (messung_aktiv){
   if (Serial.available()){  //Wenn Messung Aktiv UND Daten vorhanden
      data[i]=caliper.fetch(); // Messung und Wert in Array schreiben
      i++;
      if (i==39){  //Wenn 39 Daten eingelesen wurden
         messung_fertig=true;  //Flag, daß eine fertige Messung da ist
         messung_aktiv=false;  //Flag löschen, keine Messung mehr aktiv
         i=0;
      }
   }
}else{
   if (Serial.Available()){   //wenn keine Messung aktiv ist, nur auf Start-Zeichen prüfen
      val=Serial.read();
      if (val=='A'){
         messung_aktiv=true;  //und Messung aktivieren
      }
   }
}
if (messung_fertig){  //wenn wir fertig sind, irgend Was damit anstellen
   //Messergebisse verarbeiten
   messung_fertig=false;
}

MfG

Dann darfst Du die Messung bei Empfang eines 'A' nicht in einer for-Schleife runterrasseln, sondern musst eine Messnummer global mitführen und immer nur 1x messen.

Auf der Basis deines ersten Sketches wäre das dann etwa sowas:

double data[39];
byte messnr = 0;

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

void loop() {

  if  (Serial.available() > 0) {
    char messung = Serial.read();

    if (messung == 'A') {
      data[messnr++] = caliper.fetch(); // Messung und Wert in Array schreiben
    }
  }

  if ( messnr >= 39 ) {
    for (int i = 0; i < 39; i++) {
      Serial.println(data[i]);
    }
  messnr = 0;
  }
}

Die Verbesserungsvorschläge, die schon gemacht wurden, kannst Du dann ja selbst einarbeiten.

Hallo, was spricht gegen diese Lösung?

double data[39];
int i = 0;

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

void loop() {

  if (Serial.available()) {
    char messung = Serial.read();

    if ((messung == 'A') && (i < 39)) {
      data[i] = caliper.fetch(); // Messung und Wert in Array schreiben
      i++;
    }
  }
}

Grundsätzlich mal nichts, ausser dass ich so einen nichtssagenden Variablennamen wie 'i' nicht für eine globale Variable verwenden würde.
Allerdings kann das ja nur ein Fragement sein, denn nach der 39. Messung passiert hier ja nichts mehr. Irgendwo musst Du die Daten auch auswerten, und dann auch deinen Messzähler zurücksetzen, ähnlich wie in meinem Beispiel.
Die zusätzliche Abfrage, dass der Index nicht zu groß wird, schadet aber auf jeden Fall nicht, auch wenn Du den woanders - z.B. in der Auswertung - noch begrenzt. Je nach Art der Auswertung könnte das sogar notwendig sein.