Arduino hackt die empfangenen serielle daten ab

Hallo habe ein Problem mit dem empfangen der Daten via Serialport mit dem Arduino.
Und zwar sende ich von einer GUI folgendene parameterzeile : 2;3;4 oder zb 3;4;5;5.
Problem ist, dass mir der Arduino immer den ersten Wert nicht speichert d.h. der Arduino speichert mir dann immer folgenden Wert:

;3;4 oder ;4;5;5-> den ersten Wert nimmt er nicht wahr.

Was kann das sein? _> eventuell Serialport problem?

milito: Was kann das sein? _> eventuell Serialport problem?

Nein, zu 99,99% sitzt das Problem vor dem Monitor und hat irgendwas programmiert, das nicht funktioniert.

Ja wo ist denn dann bitteschön der Fehler :D:

Hier der code:

    while((Serial.available()))
    {
    Datei=SD.open("I2C.csv", O_CREAT | O_WRITE);
    Datei.print(parameter = Serial.read());
    Datei.close();
   }

Bzw. wo ist der Fehler?

Open() und Close() sollten aus der while-Schleife raus. Wieso machst du das ständig?

Das ist wohl der Fehler, nur warum macht er das so. Ich denke er will, wenn was von der Seriellen kommt eine Datei öffnen und die Daten in einer Datei speichern.

Ich würde vorher ein " open Flag" schicken das die Datei öffnet. Dann die Daten.....in der Schleife und dort immer nach dem ende Flag parsen das "ende Flag" schließt die Datei. Die Flags sollten Zeichen sein die in den Daten nicht vorkommen.

Man kann auch als erstes Byte die Anzahl der zu lesenden Bytes schicken. Dann öffnet man nach Empfang des ersten Bytes die Datei und wenn alles eingelesen wurde schließt man sie.

milito: Ja wo ist denn dann bitteschön der Fehler :D:

Das ist bei den spärlichen Angaben schwer zu sagen.

Es könnte beispielsweise ein Problem mit der Software auf der Senderseite vorliegen, z.B. wenn diese auf einem PC läuft und nach folgender Logik sendet: - Serielle Schnittstelle zum Arduino öffnen - Eine Zeile senden - Serielle Schnittstelle zum Arduino schließen

Eine Arduino-gerecht programmierte GUI-Software würde stattdessen die serielle Schnittstelle zum Arduino nur einmal öffnen, beispielsweise beim Programmstart. Und bei Programmende die serielle Schnittstelle schließen. Und zum Senden immer nur: - Eine Zeile senden Also ohne die Schnittstelle dauernd zu öffnen und zu schließen, was beim Arduino jedesmal einen automatischen Reset auslöst.

Falls die sendende GUI-Software nicht in geeigneter Form programmiert ist, sondern die Schnittstelle vor jeder zu sendenden Zeile neu öffnet, müßte man beim Arduino notfalls hardwaremäßig eingreifen und den Auto-Reset verhindern.

Wie ist es denn, wenn die Daten nicht "von einer GUI" sondern über den "Seriellen Monitor" der Arduino-Software gesendet werden, ist dann auch der erste Wert weggeschnitten? Oder nur, wenn die Daten "von einer GUI" kommen?

jurs:

Also ohne die Schnittstelle dauernd zu öffnen und zu schließen, was beim Arduino jedesmal einen automatischen Reset auslöst.

Was aber nur passiert, wenn der Sender ein DTR am COM mit auf die Reise gibt.

rudirabbit:
Das ist wohl der Fehler, nur warum macht er das so.
Ich denke er will, wenn was von der Seriellen kommt eine Datei öffnen und die Daten in einer Datei speichern.

Ich würde vorher ein " open Flag" schicken das die Datei öffnet.
Dann die Daten…in der Schleife und dort immer nach dem ende Flag parsen
das “ende Flag” schließt die Datei.
Die Flags sollten Zeichen sein die in den Daten nicht vorkommen.

Ja genau möchte die Daten, die von der Seriellen schnittstelle kommen in die SD-card schreiben.
Ja wie meinst du das mit dem open-Flag setzen, bzw wie mach ich so etwas? Gibt es vllt Beispiele dazu diem an durchkompilieren kann?

und zum jurs antwort:
also öffne und schliesse die Serielle Schnittstelle nur einmal und zwar beim programmstart und schliesse Sie beim Programmende.

Also liegt es definitiv an dem SD.open und close();

so beim SerialMonitor getestet und er hackt auch einen Wert ab :(. Sende 3;0;0;0 und er gibt 3;0;0; aus

milito: Also liegt es definitiv an dem SD.open und close();

Welche SD-Library verwendest Du denn?

Wenn es die Standard-SD-Library von Arduino ist, würde ich als Filemode eher das verwenden, was dafür laut Dokumentation vorgesehen ist. http://arduino.cc/de/Reference/SDopen

Du verwendest: Datei=SD.open("I2C.csv", O_CREAT | O_WRITE); Laut Dokumentation vorgesehen wäre: Datei=SD.open("I2C.csv", FILE_WRITE);

Wie ist es damit?

ja verwendete die Standard SD-Library :D. Ok werde es schnell mal versuchen und berichten Danke

SO habs ausprobiert, hackt den ersten Wert immer noch ab :(. Danke trotzdem Ohje das gibts doch nicht :(

milito: SO habs ausprobiert, hackt den ersten Wert immer noch ab :(. Danke trotzdem Ohje das gibts doch nicht :(

Poste mal den ganzen Sketch!

milito: Ja wie meinst du das mit dem open-Flag setzen, bzw wie mach ich so etwas? Gibt es vllt Beispiele dazu diem an durchkompilieren kann?

Er meint, dass du vom PC Kommandos für das Öffnen und Schließen schickst. Dieses Prinzip - über das erste Byte die Aktion festzulegen - wurde dir schon mehrmals vorgeschlagen. Dazu musst du einfach auf dem Arduino das erste Byte auswerten und dementsprechend was anderes machen. Wenn du halt nicht dazu auch die Anzahl der Bytes (dann im zweiten Byte) schickst, dürfen die Kommandos nicht in den Daten vorkommen. Wenn du als Daten nur ASCII schickst, kannst du für die Kommandos Zahlen >128 nehmen.

ok hier der code:

const int EN=24;

const int chipselect_mc = 49;
byte instruction;
byte adresse;
byte data;

const int kipp_left=30;//Pin digital 30
const int kipp_right=31;//pin digital 31
int left=0;
int right=0;

byte value;
//int tasterState = 0; //initialiesern der Statusabfrage-Variable des Tasters

#include <SD.h>    //SD-Library
#include <Wire.h> //i2c library
#include <SPI.h> //SPI- library




/*#############################################################################*/


/*###############################SD-Variablen###################################*/
int const chipSelect =53; //chipselect pin 53
File Datei;

char parameter;
char inByte; //kontroll $ bzw. ?
int index; //Position für Char Array (Buffer)
char Text[500]; //für die Parameter[i2c]
char Text2[400]; //für die Parameter SPI
/*##############################################################################*/

/*##################I2C- Scnanner ###############*/
byte checkfault; //errorvaraible für ack (12c)
byte address; //i2c adresse
int AnzDevices; //anzahl der i2c-devices
/*###############################################*/

/*###################I2C-COntrol#######################################################*/
byte error_check; //errorcheck variable enthält return-wert von Wire.endTransmission()
/*#####################################################################################*/

/*###########################################################HAUPTPROGRAMM#############################################################*/
void setup()
{
  //Serialport verbindung mit 9600Baudrate
  Serial.begin(9600);
  Wire.begin();//I2C-Vebindung initialisieren
  SPI.begin(); //SPI- initialisieren
  /*########LED Konfig#########*/
  pinMode(ledPin1, OUTPUT);
  pinMode(ledPin2,OUTPUT);
  
  /*#######ENABLE-PIN########*/
  pinMode(EN,OUTPUT);
  //digitalWrite(EN,LOW); //Standard Enablepin auf low->0V
  
  /*###########################*/
 /*ChipSelect Pin , den standard als Ausgangs sonst geht SD library nicht*/ 
  pinMode(53, OUTPUT); //Sd-Karte
  pinMode(25, OUTPUT); //Microchip-Board 
 /*######################################################################*/
 
 /*############################Taster-Konfig####################################*/
 pinMode(kipp_left, INPUT_PULLUP); //kippstellung links in pin30 INPUT_PULLUP->interner pullup, somit pullup aktivieren
 pinMode(kipp_right, INPUT_PULLUP);//kippstellung rechts in pin31 und wird input-widerstand aktiviert (intern)
 /*kippleft= low -> linksstellung
   kippright= low= rechtsstellung
  kippleft & kippright = HIGH -> mittelstellung */
/*##############################################################################*/
}

void loop()
{
  //wird ein zeichen über Serialport empfangen?
  if (Serial.available() > 0)
  {
    //falls ja, schreibe diesen in inByte
    inByte = Serial.read();
  
  /*##################################I2C################################*/  
    //falls inByte= $ -> ASCII(36), Arduino im Sendemodus
      if (inByte==36)//falls $=36 ankommt arduino sendet, sonst empfangen
      {
        blink_send();
        read_SD();
      }//endif 36
      
      else //(inByte==38)
      {
        //blink_receive();
        if(!SD.begin(chipSelect))
        {
          Serial.println("No SD-card");
          return;
        }//end if Sd.begin
        //Serial.println("SD-card ok");
        //-----------überprüfen Datei da---------------------//
        // wenn ja= löscheu nd erstelle eine neue ,sonst//
        //wenn keine da, erstelle neue Datei//
          if(SD.exists("I2C.csv"))
          {
            SD.remove("I2C.csv");
            //Datei=SD.open("I2C.csv",O_CREAT | O_WRITE);
            //Datei.println("Anz_para ; Address ; Register ; Data ");
            //Datei.close();
            
          }//sd exists
          //falls Datei nicht vorhanden erstelle neue Datei
          //else
          //{
            //Datei=SD.open("I2C.csv",O_CREAT | O_WRITE);
            //Datei.println("Anz_para ; Address ; Register ; Data ");
            //Datei.close();
            
          //}//end else
          write_SD();
         }
        //endif
  
      if (inByte==63) //falls ?=63 in Byte dann führe funktion i2c-scan durch
      {
         i2c_scan();
      }
        /*###########ENABLE-PIN###############*/
         if(inByte==38) //empfängt & d.h. enable is true
           {
            digitalWrite(EN,HIGH);
            Serial.println("EN-EIN");
           } 
          
          if(inByte==45)
           {
            single_control_i2c();
           }//endif 
            
          if(inByte==47)
           {  
            read_out_i2c();
           }//endif
           
         if(inByte==43) //falls + ankommt -> enable pin disable
          {
            digitalWrite(EN,LOW);
            Serial.println("EN-AUS");
                
          }   
    //falls Arduino &(38) empfängt , d.h. er empfänngt von GUI
    
     /*###############################SPI###################################*/
      //falls Arduinio ascii(33)->! empfängt, dann soll er in datei für spi dieparameter schreiben   
        if(inByte==33)
        {
          write_sd_spi();
        }//endif
        
        //empfängt "#"
        else if (inByte==35)
        {
          read_sd_spi();
        }//endif
        
        //falls "=" empfangen wird//
        else if (inByte==61)
        {
          single_control_spi();
        }//end if
        
        //falls "*" empfangen wird//
        else if(inByte==42)
        {
          read_out_spi();
        }     
   }//endif Serial available

   
   /*######################################tasterabfrage#######################################################*/
     left = digitalRead(kipp_left);
     right = digitalRead(kipp_right);
     if(left == LOW)
     {
       digitalWrite(EN,HIGH);
       control_i2c(); //Aufruf der Funktion 
       Serial.println("Linkssstellung an ");
       delay(100);
       
     }//endif left (i2c)
     /*Eventuell eine LED, falls control-i2c blink, falls nicht leuchtet bzw bleibt aus */
     
     if (right== LOW)
     {
       digitalWrite(EN,LOW);
       //control_spi();
       Serial.println("Rechtsstellung an");
       delay(100);
     }   
      
   /*##########################################################################################################*/     
 }//end loop

/*############################################################################################################################################*/    
 
/*#######################################Funktionen#################################################################*/


/*##################blinken beim senden an GUI##################*/
void blink_send()
{
  digitalWrite(ledPin1,HIGH);
  delay(500);
  digitalWrite(ledPin1,LOW);
  delay(500);
}
/*##############################################################*/


/*################blinken beim empfangen von gui################*/
void blink_receive()
{
  digitalWrite(ledPin2,HIGH);
  delay(500);
  digitalWrite(ledPin2,LOW);
  delay(500);
}
/*###############################################################*/


/*################auslesen von SD karte [i2c](i2c.csv)#####################*/
void read_SD()
{
  Serial.println("-----------------------------------");
  Serial.println("Initializing SD card...");
  if(!SD.begin(chipSelect))
  {
    Serial.println("---------------------------------");
    Serial.println("Initialization failed");
    return; //tue nichts
  }
  Serial.println("-----------------------------------");
  Serial.println("SD Card initialized");
  
  
  //Datei öffnen
  Datei=SD.open("I2C.csv");
  
  if(Datei)
  {
    Serial.println("===file content===");
    
    //lese solange etas in txt enthalten ist
    while(Datei.available())
    {
     //delay(30); 
     Serial.write(Datei.read());
     
    //wenn nicht klappt mit delay dann innerhalb der whileschleife char inhalt = Datei.read(); und ausßerhalb Serial.write(inhalt);
    }//end while
    
    //außerhalb dann Serial.write(inhalt);
    //close file
    Datei.close();
   
    Serial.println("===end===");
  }//endif
  else
  {
    Serial.println("-----------------------------------");
    Serial.println("Error opening file");
  }//end else
  
}//end fu
          
/*##############################################################################################*/


/*#################################Schreiben auf SD-Karte(I2C)##########################################*/
void write_SD()
{
  //wiederhole die schleife,solange ein Zeichen an Serialport anliegt
  //und Buffer nicht überschritten wird
  Datei=SD.open("I2C.csv",O_CREAT | O_WRITE);
  Datei.println("Anz_Parameter; Address; Register; Data");
  Datei.close();
  if (Serial.available()>0)
  {
    while((Serial.available()))
    {
      Datei=SD.open("I2C.csv",FILE_WRITE);
    //Datei=SD.open("I2C.csv", O_CREAT | O_WRITE);
    Datei.print(parameter = Serial.read());
    Datei.close();
    
      }//end while
  }//end if
}//end fu

milito: inByte = Serial.read();

Da liest Du in der loop-Funktion ja schon immer ein Zeichen weg, bevor die Funktion "write_SD()" mit der geposteten while-Schleife überhaupt aufgerufen wird: inByte = Serial.read();

Warum wunderst Du Dich dann, dass Dir in der Funktion "write_SD()" genau dieses eine schon vorher ausgelesene Zeichen zum Speichern auf der SD-Karte fehlt?

wie sorry das verstehe ich gerade nicht ? wo meinst du das?

ok, sollte ich dafür eine andere variable nehmen?
Also hab es weiterhin getestet, manchmal hackt er das nicht ab , aber meistens. also ich verstehe nichts mehr :frowning:
habe mal zwei bilder von der ausgabe zum anschauen mal mit hochgeladen, vllt is es deutlicher

bild1.jpg

bild2.jpg

milito:
ok, sollte ich dafür eine andere variable nehmen?

Ne, beschreib mal lieber das gesendete Protokoll in Worten!
Und zwar das gesamte gesendete Protokoll, nicht nur die Zeichen, die auf SD-Karte gespeichert werden sollen. Und in allen Datails.

Wenn das Protokoll in sich sauber und logisch korrekt formulierbar ist, mit irgendeiner fehlertoleranten Art der Synchronisierung, z.B. eine Sendepause zwischen zwei Zeilen, die man per Timeout erkennen kann, oder ein Zeilenende-Steuerzeichen (Carriage Return oder Linefeed oder beides), dann läßt sich das mit irgendeinem sauber strukturierten Code auch wieder auseinanderpflücken.

Du pflückst das was ankommt, falsch auseinander. Und deshalb landet das was ankommt, in Deiner Programmlogik nicht da, wo es aufschlagen sollte. Z.B. die mit Semikolon gesendeten Zahlen erst (meistens) ab der zweiten Zahl auf der SD-Karte, weil die erste Zahl schon vorher aus dem seriellen Puffer ausgelesen wird und auf irgendwas anderes geprüft wird, insbesondere auf “if (inByte==36)”. Wenn da als “inByte” aber schon das erste Zeichen gelesen wurde aus der Zeile, die eigentlich komplett gespeichert werden sollte, dann fehlt in der zu speichernden Zeile das vorher als “inByte” ausgelesene Zeichen am Anfang der Zeile.