Salvare i commandi inviati via Serialport su una SD

Ciao, ho un piccolo problema,

ho scritto un Programma con Visual basic che deve mandare dei commandi tramite il SerialPort al mio Arduino Mega2560.
L'arduino deve memorizarle su la carta SD questi commandi.
Tramite un button nel mio Programma(Visual basci) che si chiama receive , l'arduino deve leggere quello che che scritto nel txt.file della SD e inviarlo al mio Programma tramite SerialPort.

Il mio problema e che quando invio il commando (e un string) dal mio programma all'arduino e lo voglio scrivere in un txt.file sulla SD , non ce lo scrivo, il txt file mi rimane vuoto.

Mi scuso per il mio italiano, sono un italiano che scrive dalla germania.
Ho scritto anche sull forum tedesco ma non ci siamo riusciti sul momento a risolvere il problema.

A importante da sapere e che usa la libreria SD.h.

Qui ce il mio codice dell Arduino:

/Globale Variablen
/*----------Variabli per trasmettere---------------------------------------*/
int ist_senden= 1; //Falls Arduino an GUI sendet
const int ledPin1= 22;  //Mit Digital PIN 22 verbundene Led  (senden)-(rote led)
/*----------------------------------------------------------------------*/



/*----------Variabli per ricevere------------------------------------*/
const int ledPin2= 23; /*MIt Digital PIN 23 verbundene Led (empfangen)-(gelbe led) */
int ist_receive=2; //Falls Arduino von GUI empfangen soll


/*-----------SD Card-----------------------------------------------------*/
/* Verbindung - SPI an Mega2560
**MISO - pin 51
**MOSI - pin 50
**CLK - pin 52
**SS/CS (Chipselect) - pin 4  -> Standard chipselect pin 53
!!-----pin 53 somit als OUTPUT legen , da nicht verwendet-----*/

#include <SD.h>
int const chipSelect=53; //pin 4 für CS/SS-pin
String dataString;  //Variable zum SpeiSern von Serialport-Daten
File Datei; //um file zu öffnen bzw. auch zu 

/*----------------------------------------------------------------------*/
/*-----------Auswahlvariable für Swtich-Case----------------------------*/
int inByte=0; //Variable wo das Empfangene kontrollbit abgespeichert wird(als Byte)
/*----------------------------------------------------------------------*/

//*----------- Hier beginnt das Programm---------------------------------*//

//*------Standard einstellung, die konstant sind in void setup()---------*//

void setup()
{
  Serial.begin(9600); //Serialport öffnen mit baudrate 9600
  //pinMode(ledPin1, OUTPUT); //ledPin1(senden LED), wird als Output gesetzt
  //pinMode(ledPin2, OUTPUT); //ledPin2 (empf. LED), wird als Output gesetzt
  
  pinMode(53, OUTPUT); //da standard-Pin CS/SS nicht verwendet diesen als OUTPUT legen
  
}
/*------------------------------------------------------------------------*/


/*-------Diese Funktionen werden ständig abgefragt in loop----------------*/
void loop()
{
    if (Serial.available() > 0) //Prüfen , ob mindestens ein Zeichen im Port vorhanden ist (Hier prüfe ich , ob senden oder EMpfangen)
  {
    inByte = Serial.read(); //lese zeichen au und speichere in chr vom typ char
     
  
  switch (inByte)
  {

    /*Senden der Daten von Arduino zur GUI*/    
    case 1: 
    
              blink_send();
              //Aufruf der Funktion zum auslesen von SD
              read_SD();
              
             
              
              break; //beende case 1
    
    /* Von GUI empfangen*/          
    case 2:
              if (Serial.available() > 0 )
              
              {
                
                byte pos= 0;
                char buffer[15];
                delay(10);
                while (Serial.available() && pos < 15){
                  buffer [pos++] = Serial.read();
                  
                }
             
                write_SD(buffer); 
                
              } 
                blink_receive();
               
               break;
           
   }
  }
}
//############################################################################################################################################################//
//++++++++++++++++++++++++++++++++++++Funktionenbereich: Alle Funktionen, die innerhalb des Programms aufgerufen werden+++++++++++++++++++++++++++++++++++++++//
//############################################################################################################################################################//

/*---------------------funktion für das Blinken beim senden an GUI----------------------*/
/*---------------------Blink funktion 0,5sek an und 0,5sek aus--------------------------*/

/*Rote LED*/

void blink_send()
{
  
  digitalWrite(ledPin1, HIGH); //leuchtet
  delay(500); //leuchtet 0,5 sek
  digitalWrite(ledPin1, LOW); //aus
  delay(500);
  
}
/*-------------------------------------------------------------------------------------*/


/*----------Funktion die in Case 2 aufegrufen wird, damit LED blinkt-------------------*/

/*gelbe LED*/

void blink_receive()
{
  digitalWrite(ledPin2, HIGH); //leuchtet
  delay(500); // 0,5sek an
  digitalWrite(ledPin2,LOW); //aus
  delay(500); //0,5sek aus
  
}  
 
/*-------------------------------------------------------------------------------------*/

 //---------------------Funktion, die in SD-Karte speichert-----------------------------//     
void write_SD(char* buffer) //* ist zeiger auf zeichen in char array
{
  
   Serial.print("Initializing SD Card.....");
   if(!SD.begin(chipSelect)){
     Serial.println("Initialization failed, card not present!");
     return;
   }
   Serial.println("card initialized.");
   Datei= SD.open("commands.txt", FILE_WRITE);
   if (!Datei){
     Serial.println("Error to open commands.txt");
   }
      
   Datei.println(buffer); //Schreibe inhalt in SD-Karte
   Datei.close(); //Schliessen damit daten in SD gespeichert werden
  
}
    
//------------------------------------Funktion zum Auslesen der SD-Card-------------------------------------//
void read_SD(){
  Serial.print("Initializing SD Card.......");
  Serial.write(13); //Carriage_Return Line feed
  /*if (card.init(SPI_HALF_SPEED, chipSelect)){
    Serial.println("SD Card detected");
  }
  else{
    Serial.println(" No SD Card detected ");
  }
  delay(1000); */
  if (!SD.begin(chipSelect)){
    Serial.println("Initialization failed, card not present!");
    return;  //tue nichts
    
  } 
  Serial.println("Card was detected");
  //Öffne Datei commands.txt
  Datei=SD.open("COMMANDS.txt");
  
  //wenn File/Datei vorhanden
  if(Datei){
    //lese solange file aus bis nichts mehr zu lesen ist
    while (Datei.available()){
      Serial.write(Datei.read()); //Schreibe an port Inhalt , das von Sd ausgelesne wird
      delay(500);
    }
    
    //Nach lesen Datei schliessen
    Datei.close();
  }
    else
    //falls Datei nicht geöfnet werden konnte
    Serial.println("error opening commands.txt");
    Serial.write(13); //Carriage return line feed
    Serial.print("It is not possible to read out the file");
    
    //Serial.print("Testaus :"); Serial.println(inByte); 
   
}      
//-------------------------------------------------------------------------------------------------------//

Codice del VB:

Private Sub btn_i2c_send_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_i2c_send.Click
        'Mit try wird versucht Übertragung an Arduino durchzuführen'
        Try

            'öffne Serielle Anschlussverbindung, sofern nicht bereits geöffnet'
            If Not SerialPort_i2c.IsOpen Then SerialPort_i2c.Open()

            SerialPort_i2c.Write(Chr(kontrol_sende))
            'SerialPort_i2c.Write(kontrol_sende)

            'falls Verbindung zum Device besteht, doch es wird auf sendbutton gedrückt und leere Texbox, meldung + verbindung schliessen
            If txtbox_i2c.Text = "" Or Cmbport_i2c.Text = "" Then

                SerialPort_i2c.Close()
                MsgBox("Please check if you select the COM-Port" & vbCrLf & " Please check the input of the command")

            Else   'sonst Schreibe / sende Ínhalt der Textbox an Arduino'
                SerialPort_i2c.WriteLine(txtbox_i2c.Text) ' durch vbr = Enter, d.h. wenn ein ganzer String wird ein enter gesendet und arduino weiß ok gsnzer String
                MsgBox("Transfer successful")
            End If

            'Falls Übertragung fehlschlägt, Catch block um fehler auszubügeln und eigene message von vb'
        Catch ex As Exception
            MsgBox("Transfer failed - Please check the connection" & vbCrLf & ex.Message)
        End Try

        'Nach Übertragung Port wieder freistellen'

        If SerialPort_i2c.IsOpen = True Then
            SerialPort_i2c.Close()
        End If

    End Sub

Sarei contento se si potrebbe risolvere il problema :smiley:

Grazie

Please pardon my English. This code has a bug of the type known as a "race condition":

  case 2:
	if (Serial.available() > 0) {
		byte pos= 0;
		char buffer[15];
		delay(10);
		while (Serial.available() && pos < 15) {    // <-- race condition
		buffer [pos++] = Serial.read();
	}

After testing for the presence of any number of characters, the code attempts to read up to 15 characters. If they have not all arrived in the serial input buffer by the time this code is first run, the code will exit prematurely, and fail to read the data and write it to the SD card.

A common solution is to have an "end of input" character, perhaps a carriage return ('/r' or '/n') to signal that all the input characters have been received so that this loop can be rewritten so the race condition won't happen.

Good luck with your project,

-br

Non ho problemi, ma per gli altri utenti del forum italiano forse sarebbe meglio se metti i commenti del programmii in italiano e non in tedesco.
Tschüß Uwe

billroy:
Please pardon my English. This code has a bug of the type known as a "race condition":

  case 2:
if (Serial.available() > 0) {
	byte pos= 0;
	char buffer[15];
	delay(10);
	while (Serial.available() && pos < 15) {    // <-- race condition
	buffer [pos++] = Serial.read();
}



After testing for the presence of any number of characters, the code attempts to read up to 15 characters. If they have not all arrived in the serial input buffer by the time this code is first run, the code will exit prematurely, and fail to read the data and write it to the SD card.

A common solution is to have an "end of input" character, perhaps a carriage return ('/r' or '/n') to signal that all the input characters have been received so that this loop can be rewritten so the race condition won't happen.

Good luck with your project,

-br

How do you mean this, can you show me please , how i can d this?

Scusameti qui il programma con i commenti in italiano

Codice Arduino:

/*Codice per salvare e trasmettere i dati tramite und carta SD*/


//Variabli
/*----------Variabili per tramsettere---------------------------------------*/
int ist_senden= 1; //Falls Arduino an GUI sendet
const int ledPin1= 22;  //led collegata con pin 22
/*----------------------------------------------------------------------*/



/*----------Variabli per ricevere------------------------------------*/
const int ledPin2= 23; /*led collegata con PIN23
int ist_receive=2; //


/*-----------SD Card-----------------------------------------------------*/
/* Connessione  - SPI sul Mega2560
**MISO - pin 51
**MOSI - pin 50
**CLK - pin 52
**SS/CS (Chipselect) - pin 4  -> Standard chipselect pin 53


#include <SD.h>
int const chipSelect=53; //pin 4 für CS/SS-pin
//String dataString;  //Variable zum SpeiSern von Serialport-Daten
File Datei;  

/*----------------------------------------------------------------------*/
/*-----------Variabile per usare Switch-case----------------------------*/
int inByte=0; //Variabile per salvare il numero ricevuto dalla GUI(in formato Byte)
/*----------------------------------------------------------------------*/

//*----------- Inizio del programma---------------------------------*//



void setup()
{
  Serial.begin(9600); //aprire Serialport baudrate 9600
  //pinMode(ledPin1, OUTPUT); 
  //pinMode(ledPin2, OUTPUT); 
  
  pinMode(53, OUTPUT); 
  
}
/*------------------------------------------------------------------------*/


/*-------Loop----------------*/
void loop()
{
    if (Serial.available() > 0) // (controllare se arriva und 1 o un 2 per sapere se arduino deve ricevere o trasmettere)
  {
    inByte = Serial.read(); 
     
  
  switch (inByte)
  {

    /*Se e un 1 trasmettere dal arduino nella GUI/    
    case 1: 
    
              blink_send();
              
              read_SD();
              
             
              
              break; //beende case 1
    
    /* Se e un 2 ricevere dalla GUI*/          
    case 2:
              if (Serial.available() > 0 )
              
              {
                
                byte pos= 0;
                char buffer[15];
                delay(10);
                while (Serial.available() && pos < 15){
                  buffer [pos++] = Serial.read();
                  
                }
             
                write_SD(buffer); 
                
              } 
                blink_receive();
               
               break;
           
   }
  }
}
//############################################################################################################################################################//
//+++++++++++++++++++++++++++++++++++Funzioni per il programma +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
//############################################################################################################################################################//





void blink_send()
{
  
  digitalWrite(ledPin1, HIGH); 
  delay(500); //leuchtet 0,5 sek
  digitalWrite(ledPin1, LOW); 
  delay(500);
  
}
/*-------------------------------------------------------------------------------------*/


/*-------------------------------------------------------------------------------------*/

/*gelbe LED*/

void blink_receive()
{
  digitalWrite(ledPin2, HIGH); //leuchtet
  delay(500); // 0,5sek an
  digitalWrite(ledPin2,LOW); //aus
  delay(500); //0,5sek aus
  
}  
 
/*-------------------------------------------------------------------------------------*/

 //---------------------Funktione, che memorizza i dati ricevuto dal serialport sulla SD-----------------------------//     
void write_SD(char* buffer) //* ist zeiger auf zeichen in char array
{
  
   Serial.print("Initializing SD Card.....");
   if(!SD.begin(chipSelect)){
     Serial.println("Initialization failed, card not present!");
     return;
   }
   Serial.println("card initialized.");
   Datei= SD.open("commands.txt", FILE_WRITE);
   if (!Datei){
     Serial.println("Error to open commands.txt");
   }
      
   Datei.println(buffer); //Scrivi sulla SD
   Datei.close(); //Chiudi per memorizzare
  
}
    
//------------------------------------Funzione per leggere dalla SD-------------------------------------//
void read_SD(){
  Serial.print("Initializing SD Card.......");
  Serial.write(13); //Carriage_Return Line feed
  /*if (card.init(SPI_HALF_SPEED, chipSelect)){
    Serial.println("SD Card detected");
  }
  else{
    Serial.println(" No SD Card detected ");
  }
  delay(1000); */
  if (!SD.begin(chipSelect)){
    Serial.println("Initialization failed, card not present!");
    return;  //tue nichts
    
  } 
  Serial.println("Card was detected");
  //Öffne Datei commands.txt
  Datei=SD.open("COMMANDS.txt");
  
  //wenn File/Datei vorhanden
  if(Datei){
    //leggi fino che ce un contenuto
    while (Datei.available()){
      Serial.write(Datei.read()); //scrivo il contenuto della SD sul Serialport
      delay(500);
    }
    
    
    Datei.close();
  }
    else
    //se il file non e stato aperto
    Serial.println("error opening commands.txt");
    Serial.write(13); //Carriage return line feed
    Serial.print("It is not possible to read out the file");
    
    //Serial.print("Test :"); Serial.println(inByte); 
   
}      
//-------------------------------------------------------------------------------------------------------//

Codice VB 2010:

Private Sub btn_i2c_send_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btn_i2c_send.Click
        /Trasmissione sul arduino dei dati
        Try

            'accedi alla communicazione Serialport
            If Not SerialPort_i2c.IsOpen Then SerialPort_i2c.Open()

            SerialPort_i2c.Write(Chr(kontrol_sende))
            'SerialPort_i2c.Write(kontrol_sende)

            'chiudi il Serialport se tu premi il button send ma non scrivi il commando che si dee inviare
	    
            If txtbox_i2c.Text = "" Or Cmbport_i2c.Text = "" Then

                SerialPort_i2c.Close()
                MsgBox("Please check if you select the COM-Port" & vbCrLf & " Please check the input of the command")

            Else   
                SerialPort_i2c.Write(txtbox_i2c.Text) 
                MsgBox("Transfer successful")
            End If

            
        Catch ex As Exception
            MsgBox("Transfer failed - Please check the connection" & vbCrLf & ex.Message)
        End Try

        'Dopo la trasmissione chiudi il Serialport

        If SerialPort_i2c.IsOpen = True Then
            SerialPort_i2c.Close()
        End If

    End Sub

Spero che s trovero un soluzione

Grazie

A common solution is to have an "end of input" character, perhaps a carriage return ('/r' or '/n') to signal that all the input characters have been received so that this loop can be rewritten so the race condition won't happen.

Can you expain me this please `?

Something like this:

#define BUFSIZE 15
case 2:
	{
	byte pos= 0;
	char buffer[BUFSIZE];
	buffer[0] = 0;
	while (pos < BUFSIZE-1) {
		if (Serial.available()) {
		char c = Serial.read();
		if ((c == '\n') || (c == '\r')) break;
		buffer[pos++] = c;
		buffer[pos] = 0;
	}

Edit: Of course the VB program must be modified correspondingly to send a carriage return or line feed ascii character at the end of the command text.

that means , that my code its to fast to read aout all characthers via the serial library?

thanks a lot:D. I try this a give you a feedback but i have a question about this.

if ((c == '\n') || (c == '\r')) break;
		buffer[pos++] = c;
		buffer[pos] = 0;

This code line means if my c variable is a '\n or a '\r' the finished to read out from serial.
but what means the buffer[pos++]=c; ?

the last one is, that you initialize the buffer with 0 an overwrite the content?

billroy:
Something like this:

#define BUFSIZE 15

case 2:
{
byte pos= 0;
char buffer[BUFSIZE];
buffer[0] = 0;
while (pos < BUFSIZE-1) {
if (Serial.available()) {
char c = Serial.read();
if ((c == '\n') || (c == '\r')) break;
buffer[pos++] = c;
buffer[pos] = 0;
}




Edit: Of course the VB program must be modified correspondingly to send a carriage return or line feed ascii character at the end of the command text.

i cant compile this code, there are a little error

O provato il codice ma non funziona, sono un po disperato, perche non ci riesco e da ore che provo

Ce qualcuno che mi potrebbe aiutare?