Speziellen String aus Serialdata auslesen und auf SD speichern.

Hallo, ich bin seit geraumer Zeit stummer Mitleser in diesem Forum, bisher haben mir auch die Topics und Fragen bei meinen eigenen Projekten geholfen.... leider stehe ich heute aber vor einen Problem, das mir die Suche im Forum und auch bei G**gle nicht beantworten konnte.

Ich möchte speziell aus Marlin (Marlin mit Ramps1.4 board und Reprap full graphic ) mit dem M-code 114
die aktuelle Position auslesen und über ein zweites Arduinoboard ( Uno mit datalogger-shield ) einlesen und auf SD speichern. Dabei soll halt nur dieser string ausgewertet und auf SD geschrieben werden.

ich habe bereits eine Routine gefunden, die genau auf das Schlüssel-Zeichen im String wartet und per Serieller Schnittstelle auf dem zweiten Arduino auch ausgeben kann.

Leider klappt das aber dann nicht die beiden Sketches (String rausfischen und Datalogging ) zu verbinden.
Ich bin leider nicht der C++ Geek und muss versuchen mich mit den Beispielen durch try and error zum Ergebnis zu bewegen.

lange rede kurzer Sinn.... ich möchte einen Arduino Uno auf einen seriellen String warten lassen

#200.00;300.00;0.00;1.98;#ok

und sobald das Startzeichen # kommt den gesamten string auf SDkarte schreiben.

vielleicht gibt es hier im Forum jemanden, der mir einen kleinen Denkanstoss geben kann.

vielen Dank schon mal

noneed:
#200.00;300.00;0.00;1.98;#ok

und sobald das Startzeichen # kommt den gesamten string auf SDkarte schreiben.

Durchdenke erst mal Deinen Ablauf neu, da Du 2 mal das # hast.

Gruß Tommy

Hallo Thomy56, das mit dem zweiten # ist kein Problem, das kann ich beliebig ändern
leider vertragen sich der datalog und der stringread sketch nicht, wenn ich sie versuche zusammen zu verwurschten...

ich habe gerade versucht den code zu posten, aber wie bekomme ich das code-fenster hin?

Gefunden

als Logging sketch hätte ich gerne diesen genommen:

#include <Wire.h>
#include "RTClib.h"

RTC_DS1307 rtc; // Zugriff auf RTC

char WochenTage[7][12] = {"Sonntag",
                          "Montag",
                          "Dienstag",
                          "Mittwoch",
                          "Donnerstag",
                          "Freitag",
                          "Samstag"};



#define LOGDATEI "pyr"



#include <SPI.h>
#include "SdFat.h"

// Chip Selector auf Arduino Board
const uint8_t chipSelect = SS;

// Separatorzeichen für Dateiausgabe
const String SEP = ";";

// Zugriff auf Dateisystem der SD Card
SdFat sd;

// Log-Datei
SdFile datei;

// Fehlermeldungen im Flash ablegen.
#define error(msg) sd.errorHalt(F(msg))


/////////////////////////////////////////////////////////////////
// DEKLARATIONEN TemperaturSensor
/////////////////////////////////////////////////////////////////

/*const int   TMP36Pin              = A0;
const float VersorgungsSpannung   = 5.0;  // ändern für 3.3V
const int   ZeitZwischenMessungen = 5;    // in Sekunden
*/



// initRTC()
//    Echtzeituhr initialisieren

void initRTC()
{
    if (! rtc.begin()) { // ist eine Uhr angeschlossen?
      Serial.println("Echtzeituhr fehlt");
      while(1); // Fehlerschleife
    }
    if (! rtc.isrunning()) { // Uhr schon gesetzt?
    Serial.println("RTC bisher noch nicht gesetzt!");
    // => Initialisiere Zeit und Datum auf Datum/Zeit des Host-PCs
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
}



//
// initSDCardReader()
//    Kartenleser initialisieren
/
void initSDCardReader()
{
  const uint8_t NAMENSLAENGE= sizeof(LOGDATEI) - 1;
  char dateiName[13] = LOGDATEI "00.csv"; // Z.B. TMP3604.csv
 
  delay(1000);
  // SD Card mit SPI_HALF_SPEED initialisieren, um Fehler
  // bei Breadboardnutzung zu vermeiden.  Sonst => SPI_FULL_SPEED 
  if (!sd.begin(chipSelect, SPI_HALF_SPEED)) { // Zugriff auf SD?
    sd.initErrorHalt();
  }
 
  // Dateiformat 8.3
  if (NAMENSLAENGE > 6) {
    error("Dateipräfix zu lang");
  }

  // Standarddateiname LOGDATEI  + laufende Nummer, z.B.
  // TMP3603.csv
  // Sobald alle Suffixe 00..09 verbraucht sind,
  // geht es von vorne los: round robin
 
  while (sd.exists(dateiName)) {
    if (dateiName[NAMENSLAENGE + 1] != '9') {
     dateiName[NAMENSLAENGE + 1]++;
    }
    else if (dateiName[NAMENSLAENGE] != '9') {
      dateiName[NAMENSLAENGE + 1] = '0';
      dateiName[NAMENSLAENGE]++;
    }
    else {
      error("Kann Datei nicht erzeugen");
    }
  }
  // Jetzt öffnen:
  if (!datei.open(dateiName, O_CREAT | O_WRITE | O_EXCL)) {
    error("Datei öffnen misslungen!");
  }

  Serial.print(F("Logging auf: "));
  Serial.println(dateiName);

  // Header schreiben
  schreibeHeader();
}


/////////////////////////////////////////////////////////////////
//
// setup()
//    Echtzeituhr und SD Card Leser initialisieren
//
/////////////////////////////////////////////////////////////////
void setup()
{
  Serial.begin(9600); // Serielle Kommunikation an
  initRTC();          // Echtzeituhr initialisieren
  initSDCardReader(); // SD Card initialisieren
}


/////////////////////////////////////////////////////////////////
//
// temperaturInCMessen()
//   Temperatur vom TMP36 über Analogeingang lesen
//
/////////////////////////////////////////////////////////////////
/*float temperaturInCMessen()
{
  int digitalWertTmp36 = analogRead(TMP36Pin); // A0 einlesen
  float messwertSpannung = digitalWertTmp36 * VersorgungsSpannung / 1024.0;

  Serial.print("Spannung gemessen an Analogeingang ");
  Serial.print(TMP36Pin);
  Serial.print(" => ");
  Serial.println(messwertSpannung);

  // Wir berücksichtigen ausschließlich Celsius
  float temperaturInC = (messwertSpannung - 0.5) * 100;
 
  Serial.print("Temperatur in C = ");
  Serial.println(temperaturInC);
  return temperaturInC;
}


*/


 


/////////////////////////////////////////////////////////////////
//
// ausgebenZeit()
//   Zeitausgabe zur Diagnose
//
/////////////////////////////////////////////////////////////////
void ausgebenZeit(DateTime jetzt) // easy Code
{
    Serial.print(jetzt.year(), DEC);
    Serial.print('/');
    Serial.print(jetzt.month(), DEC);
    Serial.print('/');
    Serial.print(jetzt.day(), DEC);
    Serial.print(" (");
    Serial.print(WochenTage[jetzt.dayOfTheWeek()]);
    Serial.print(") ");
    Serial.print(jetzt.hour(), DEC);
    Serial.print(':');
    Serial.print(jetzt.minute(), DEC);
    Serial.print(':');
    Serial.print(jetzt.second(), DEC);
    Serial.println();
}


/////////////////////////////////////////////////////////////////
//
// loop()
//   In jeder Iteration
//      Temperatur messen
//      Zeit erfassen
//      Daten auf SC Card schreiben
//      Terminierungsbedingung prüfen und ggf. stoppen
//      inkl. Dateischließen!
//
/////////////////////////////////////////////////////////////////
void loop()
{
 
  // Messwert am TMP36 auslesen
  //float temperaturInC = temperaturInCMessen();

  // Vorgegebene Zeit warten
  //delay(ZeitZwischenMessungen * 1000);

  // Datum & Zeit holen:
  DateTime jetzt = rtc.now();
  ausgebenZeit(jetzt); // und schreiben am seriellen Monitor

  // Jetzt Daten schreiben:
  schreibeMessung("!", "C", jetzt);

  // Zufallsmechanismus für Stopp der Messungen
  if (random(7) == 1) {
      dateiSchliessen();
  }
}


/////////////////////////////////////////////////////////////////
// Statt in einer .csv-Datei könnte man z.B. auch im JSON Format
// speichern !!!
/////////////////////////////////////////////////////////////////

/////////////////////////////////////////////////////////////////
//
// schreibeHeader
//    Schreiben von Header Information in Datei
//
/////////////////////////////////////////////////////////////////
void schreibeHeader() {
  datei.println(F("Temperaturmessungen mit TMP36 mit Nutzung eines Dataloggers"));
  datei.print(F("Datum")); 
  datei.print(SEP);
  datei.print(F("Zeit")); 
  datei.print(SEP);
  datei.print(F("Temperatur (Einheit Celsius)"));
  datei.println();
}



// schreibeMessung()
//    messwert nehmen und in gewählter Einheit ausgeben
//    und zusammen mit Datum und Uhrzeit in Datei schreiben

void schreibeMessung(float messwert,
                     String einheit,
                     DateTime jetzt)
{
  datei.print(jetzt.day());
  datei.print(".");
  datei.print(jetzt.month());
  datei.print(".");
  datei.print(jetzt.year());
  datei.print(SEP);
  datei.print(jetzt.hour());
  datei.print(":");
  datei.print(jetzt.minute());
  datei.print(":");
  datei.print(jetzt.second());
  datei.print(SEP);
  datei.print(messwert);
  datei.print(einheit);
  datei.println();
   // Dateisync, um Datenverlust zu vermeiden:
  if (!datei.sync() || datei.getWriteError()) {
    error("Schreibfehler!");
  }
}



// dateiSchliessen()
//    Datei wieder schließen

void dateiSchliessen()
{
  datei.close();
  Serial.println(F("Datei steht bereit!"));
  SysCall::halt();
}

// ********************** DATEIENDE *****************************

halt den teil mit dem tm36 gegen den serial read austauschen...

als Fehler zeigt er mir dann aber schreibe Header was not declared, oder sonstiges, das ich halt nicht nachvollziehen kann. wenn ich schreibeHeader auskommentiere bringt er andere Fehler

Fehlerbeschreibungen "... oder so" sind immer unheimlich hilfreich.

Schreibe mal eine Deklaration Deiner Funktion oben hin vors setup.

void schreibeHeader();

Normalerweise macht die IDE das im Hintergrund aber manches Mal bekommt sie das nicht hin.

Gruß Tommy

Also Beide Sketche allein funktionieren ja....
nur leider zusammen gewurschtelt nicht.

entschuldige bitte das durcheinander, aber erst wollte das hier das mit den beiden posts nicht klappen (mehr als 900 Zeichen) und jetzt hab ich auch noch so eine blöde 5minuten Beschränkung Der andere Beispielssketch ist der:

void setup() {
  // put your setup code here, to run once:
Serial.begin(115200);
}


int getIntFromString (char *stringWithInt, byte num)
// input: pointer to a char array
//returns an integer number from the string (positive numbers only!)
// num=1, returns 1st number from the string
// num=2, returns 2nd number from the string, and so on
{
  char *tail; 
  while (num>0)
  {
    num--;
    // skip non-digits
    while ((!isdigit (*stringWithInt))&&(*stringWithInt!=0)) stringWithInt++;
    tail=stringWithInt;
    // find digits
    while ((isdigit(*tail))&&(*tail!=0)) tail++;
    if (num>0) stringWithInt=tail; // new search string is the string after that number
  }  
  return(strtol(stringWithInt, &tail, 0));
}  


void loop(void) 
{
  char commandbuffer[40];
  char c;
  int i=0;
  int int1, int2;
  // Puffer mit Nullbytes fuellen und dadurch loeschen
  memset(commandbuffer,0,sizeof(commandbuffer));
  if (Serial.available())
  {
    delay(100);
    while (Serial.available())
    {
      c=Serial.read();
      if (c>32) // Nur Zeichen mit ASCII-Code oberhalb Leerzeichen
      {
        commandbuffer[i] = c;
        i++;
      }  
    }
  }
  if (strstr(commandbuffer,"#")==commandbuffer)
  {
    Serial.print("Messung: ");
    Serial.println(commandbuffer);
    int1=getIntFromString(commandbuffer,1);
    Serial.print("Erste Zahl : ");Serial.println(int1);
    int2=getIntFromString(commandbuffer,2);
    Serial.print("Zweite Zahl: ");Serial.println(int2);
  }
  else if (strcmp(commandbuffer,"RING")==0)
  {
    Serial.print("Ring erkannt: ");
    Serial.println(commandbuffer);
  }
  else if (strcmp(commandbuffer,"")!=0)
  {
    Serial.print("Eingabe verworfen: ");
    Serial.println(commandbuffer);
  }
}

wobei ich lediglich das commandbuffer auf die SD-karte schreiben will..
die Aufteilung des strings brauch ich nicht.

if (strstr(commandbuffer,"#")==commandbuffer)

Das geht, aber ist extrem verwirrend. Du vergleichst da letztlich nur Zeiger.

Wenn du abfragen willst ob am Anfang ein bestimmtes Zeichen steht, kannst du das direkt machen. commandBuffer[0] == '#' z.B.
Dann sieht man sofort was gemeint ist

Danke für den Tipp, das werde ich gleich mal probieren.

So, kompilieren tut er ohne Fehler, leider loggt er aber auch nicht. :-[
bei Eingabe des Schlüsselzeichens #; tut er nix.

ich habe es auch schon mit start with probiert, aber dann schreibt er alles mögliche, auch das was ich nicht mitschreiben will... Das Format ist jetzt #;200.00;200.00; also Start-zeichen und 2 Koordinaten. den rest macht der Datenlogger dazu... (wenn es dann mal funktioniert. )

vielleicht könnte mir da jemand noch mal unter die Arme greifen... :o :frowning:

#include <SoftwareSerial.h>
#include <Adafruit_ADS1015.h>
String readString;
Adafruit_ADS1115 ads;  /* Use this for the 16-bit version */
//SoftwareSerial mySerial(4, 5); // RX, TX
#include <Wire.h>
#include "RTClib.h"
RTC_DS1307 rtc; // Zugriff auf RTC

char WochenTage[7][12] = {"Sonntag",
                          "Montag",
                          "Dienstag",
                          "Mittwoch",
                          "Donnerstag",
                          "Freitag",
                          "Samstag"};

#define LOGDATEI "PYR"

#include <SPI.h>
#include "SdFat.h"

// Chip Selector auf Arduino Board
const uint8_t chipSelect = SS;

// Separatorzeichen für Dateiausgabe
const String SEP = ";";

// Zugriff auf Dateisystem der SD Card
SdFat sd;

// Log-Datei
SdFile datei;

// Fehlermeldungen im Flash ablegen.
#define error(msg) sd.errorHalt(F(msg))


const int   TMP36Pin              = A0;
const float VersorgungsSpannung   = 5.0;  // ändern für 3.3V
const int   ZeitZwischenMessungen = 5;    // in Sekunden

void initRTC()
{
    if (! rtc.begin()) { // ist eine Uhr angeschlossen?
      Serial.println("Echtzeituhr fehlt");
      while(1); // Fehlerschleife
    }
    if (! rtc.isrunning()) { // Uhr schon gesetzt?
    Serial.println("RTC bisher noch nicht gesetzt!");
    // => Initialisiere Zeit und Datum auf Datum/Zeit des Host-PCs
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
  }
}


void initSDCardReader()
{
  const uint8_t NAMENSLAENGE= sizeof(LOGDATEI) - 1;
  char dateiName[13] = LOGDATEI "00.csv"; // Z.B. TMP3604.csv
 
  delay(1000);
  // SD Card mit SPI_HALF_SPEED initialisieren, um Fehler
  // bei Breadboardnutzung zu vermeiden.  Sonst => SPI_FULL_SPEED 
  if (!sd.begin(chipSelect, SPI_HALF_SPEED)) { // Zugriff auf SD?
    sd.initErrorHalt();
  }
 
  // Dateiformat 8.3
  if (NAMENSLAENGE > 6) {
    error("Dateipräfix zu lang");
  }

  // Standarddateiname LOGDATEI  + laufende Nummer, z.B.
  // TMP3603.csv
  // Sobald alle Suffixe 00..09 verbraucht sind,
  // geht es von vorne los: round robin
 
  while (sd.exists(dateiName)) {
    if (dateiName[NAMENSLAENGE + 1] != '9') {
     dateiName[NAMENSLAENGE + 1]++;
    }
    else if (dateiName[NAMENSLAENGE] != '9') {
      dateiName[NAMENSLAENGE + 1] = '0';
      dateiName[NAMENSLAENGE]++;
    }
    else {
      error("Kann Datei nicht erzeugen");
    }
  }
  // Jetzt öffnen:
  if (!datei.open(dateiName, O_CREAT | O_WRITE | O_EXCL)) {
    error("Datei öffnen misslungen!");
  }

  Serial.print(F("Logging auf: "));
  Serial.println(dateiName);

  // Header schreiben
  schreibeHeader();
}


void setup()
{
  Serial.begin(9600); // Serielle Kommunikation an
   //mySerial.begin(9600);// Serielle Kommunikation an
    Serial.println("Hello;Pyrlogger aktivated");
  Serial.println("settingup Marlin, look on LCD");

   //mySerial.print("M117 PyR-Logger ready");
  initRTC();          // Echtzeituhr initialisieren
  initSDCardReader(); // SD Card initialisieren
}




/////////////////////////////////////////////////////////////////
//
// GlobalstrahlunginW()
//  Pyranometer
//
/////////////////////////////////////////////////////////////////
float GlobalstrahlunginWMessen()

{
int16_t results;
/* Be sure to update this value based on the IC and the gain settings! */
  float   multiplier = 3.0F;    /* ADS1015 @ +/- 6.144V gain (12-bit results) */
  //float multiplier = 0.1875F; /* ADS1115  @ +/- 6.144V gain (16-bit results) */
   results = ads.readADC_Differential_0_1();  
float W;
 float GlobalstrahlunginW = (results*1.094) ;
  Serial.print(results);
  W=("M117",results);
  Serial.println(GlobalstrahlunginW);
  //mySerial.println(W);
  
  return GlobalstrahlunginW;
}

/////////////////////////////////////////////////////////////////
void ausgebenZeit(DateTime jetzt) // easy Code
{
    Serial.print(jetzt.year(), DEC);
    Serial.print('/');
    Serial.print(jetzt.month(), DEC);
    Serial.print('/');
    Serial.print(jetzt.day(), DEC);
    Serial.print(" (");
    Serial.print(WochenTage[jetzt.dayOfTheWeek()]);
    Serial.print(") ");
    Serial.print(jetzt.hour(), DEC);
    Serial.print(':');
    Serial.print(jetzt.minute(), DEC);
    Serial.print(':');
    Serial.print(jetzt.second(), DEC);
    Serial.println();
}



void loop()
{
     char commandBuffer[0] ;
     
    
     //memset(commandBuffer,0,sizeof(commandBuffer));
  while (Serial.available()) {
    delay(10);  
  
  
  
      commandBuffer[0] = Serial.read();
    
    
  
  if (commandBuffer[0]=="#;")
  {
    Serial.print("Connect erkannt: ");
  
    

      
              Serial.println(commandBuffer);
              
             // Datum & Zeit holen:
             DateTime jetzt = rtc.now();
             //ausgebenZeit(jetzt); // und schreiben am seriellen Monitor
             float GlobalstrahlunginW = GlobalstrahlunginWMessen();
             schreibeMessung(commandBuffer,GlobalstrahlunginW,jetzt);
          }

   if (commandBuffer[0]=="ende")
       {
       
             Serial.println("Messung Beendet");
            // mySerial.println("M117 Messung bendet");
             dateiSchliessen();
       
       }

  
  } 


}



void schreibeHeader() {
  datei.println(F("Homogenitätsmessung mit Pyranometer "));
  datei.print(F("Datum")); 
  datei.print(SEP);
  datei.print(F("Zeit")); 
  datei.print(SEP);
  datei.print(F("W/m2"));
  datei.print(SEP);
  datei.print(F("#"));
  datei.print(SEP);
  datei.print(F("X"));
  datei.print(SEP);
  datei.print(F("Y"));
  //datei.print(SEP);
  //datei.print(F(""));
  datei.println();
}



void schreibeMessung(String position,
                     float messwert,
                     DateTime jetzt)
{
  datei.print(jetzt.day());
  datei.print(".");
  datei.print(jetzt.month());
  datei.print(".");
  datei.print(jetzt.year());
  datei.print(SEP);
  datei.print(jetzt.hour());
  datei.print(":");
  datei.print(jetzt.minute());
  datei.print(":");
  datei.print(jetzt.second());
  datei.print(SEP);
  datei.print(messwert);
  datei.print(SEP);
  datei.print(position);
  Serial.println();
  Serial.print(jetzt.day());
  Serial.print(jetzt.month());
  Serial.print(".");
  Serial.print(jetzt.year());
  Serial.print(SEP);
  Serial.print(jetzt.hour());
  Serial.print(":");
  Serial.print(jetzt.minute());
  Serial.print(":");
  Serial.print(jetzt.second());
  Serial.print(SEP);
  Serial.print(messwert);
  Serial.print(SEP);
  Serial.print(position);
  Serial.println();
   // Dateisync, um Datenverlust zu vermeiden:
  if (!datei.sync() || datei.getWriteError()) {
    error("Schreibfehler!");
  }
}



void dateiSchliessen()
{
  datei.close();
  Serial.println(F("Datei steht bereit!"));
 // mySerial.println("M117 Datei fertig");
  SysCall::halt();
}

Es geht nicht weil du nicht verstehst was du tust. Und weil du den Unterschied zwischen einem C String (in doppelten Anführungszeichen) und einem Zeichen (in einfachen Anführungszeichen) nicht verstehst.

Ein einzelnes Zeichen kannst du mit == vergleichen. Bei einem ganzen C String geht das nicht, weil es ein Array ist. Und Array Variablen sind Zeiger auf das erste Element. Wenn du also == "test" machst wird nur die Adresse vergleichen. Und das ist nicht wahr.

Um Strings zu vergleichen gibt es strcmp(). Der Teil war korrekt. Und mit strstr() kann man nach Teil-Strings suchen. Aber du hattest strstr() verwendet um nach einem Zeichen zu suchen. Das ist Unsinn. Erstens gibt es dafür strchr() und zweitens wolltest du abfragen ob das Zeichen am Anfang steht. Das geht eben direkt mit ==

Also um einen ganzen String zu vergleichen wie vorher strcmp() verwenden! Und um abzufragen ob am Anfang ein # steht:

if(commandBuffer[0] == '#');

Und was soll das:

 char commandBuffer[0] ;

Du musst wirklich ein paar Grundlagen lernen! Das ist ein Array der Größe 0. Damit kannst du nichts machen

Und schau dir wie gesagt den Unterschied zwischen "#" und '#' an. Das sind zwei ganz verschiedene Dinge!

Und mach nicht das:

void schreibeMessung(String position, ....)

Übergebe eine Referenz damit keine Kopie gemacht wird:

void schreibeMessung(String& position, ....)

Bei Integern und ähnlichem ist das egal. Die haben nur ein paar Byte. Aber Arduino String Objekte sind etwas größer.

@ Serenifly,
vielen Dank für deine Hilfe.

Ja, ich gebe zu, das ich gerade von Strings und serial.readings keine große Ahnung habe :confused: .
Bisher habe ich immer die erforderlichen examples gefunden... nur hier leider nicht.

Dieses Projekt hat auch ganz klein angefangen, leider kam das eine zum anderen und jetzt hänge ich drin und es muss fertig werden, zumindest laufen, finetuning kann ich es später noch.

ich werde deine Tipps beherzigen und mich eingehender mit dem Thema befassen.
:roll_eyes: