Un aiuto con le stringhe............

Ciao a tutti, è da tanto che non programmo seriamente, ma non mi ricordavo che fosse un casino simile manipolare delle stringhe.
Ci ho perso tutta la giornata ma non ne sono venuto a capo.
Sto sviluppando un pde che prende i dati seriali da un GPS e poi se mai dovessi riuscire a manipolare le stringhe, "dovrebbe" compiere determinate azioni in base a quello che gli dice il gps.
Allora, il pde è questo:

#include <string.h>
#include <ctype.h>
#include <SoftwareSerial.h>

#define  MONITORRXPIN    0
#define  MONITORTXPIN    1
#define  GPSRXPIN        8
#define  GPSTXPIN        9
#define  RXBUFFERLENGHT  500
#define  GPRMCCOMMAND    "$GPRMC"
#define  GPGGACOMMAND    "$GPGGA"
#define  GPGSACOMMAND    "$GPGSA"  
#define  GPGSVCOMMAND    "$GPGSV"

char   byteGPS = -1;
char   RXBuffer[RXBUFFERLENGHT];
int    CharCount=0;

SoftwareSerial GPSSerial =  SoftwareSerial(GPSRXPIN, GPSTXPIN);

void setup()
{
  pinMode(MONITORRXPIN, INPUT);
  pinMode(MONITORTXPIN, OUTPUT);
   
  GPSSerial.begin(4800);
  Serial.begin(9600);
  InitRXBuffer();
}

void loop()
{
   byteGPS=GPSSerial.read();     

   if (byteGPS >= 0)
   {
     RXBuffer[CharCount]=byteGPS;    
     CharCount++; 
     Serial.print(byteGPS, BYTE);     
     if (CharCount >= RXBUFFERLENGHT)
     {
       Serial.print("Errore superamento buffer");
       return;
     }       
    
     if (byteGPS==13)
     {
       CharCount=0;
       InitRXBuffer();
     }
   }
} 
  
void  InitRXBuffer()
{
  for (int i=0;i < RXBUFFERLENGHT;i++) { RXBuffer[i] = 0; }
}

E mi da questo risultato (che è corretto):

$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPRMC,212320.718,V,,,,,,,230911,,*29
$GPGGA,212321.709,,,,,0,00,,,M,0.0,M,,0000*59
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPRMC,212321.709,V,,,,,,,230911,,*28
$GPGGA,212322.709,,,,,0,00,,,M,0.0,M,,0000*5A
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPRMC,212322.709,V,,,,,,,230911,,*2B
$GPGGA,212323.739,,,,,0,00,,,M,0.0,M,,0000*58
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPGSV,3,1,10,20,75,047,,23,65,203,,32,48,072,,24,40,141,*74
$GPGSV,3,2,10,17,34,270,,31,26,056,,11,25,157,,04,20,309,*70
$GPGSV,3,3,10,14,13,044,,10,01,272,*78
$GPRMC,212323.739,V,,,,,,,230911,,*29
$GPGGA,212324.709,,,,,0,00,,,M,0.0,M,,0000*5C
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPRMC,212324.709,V,,,,,,,230911,,*2D
$GPGGA,212325.709,,,,,0,00,,,M,0.0,M,,0000*5D
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPRMC,212325.709,V,,,,,,,230911,,*2C
$GPGGA,212326.718,,,,,0,00,,,M,0.0,M,,0000*5E
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPRMC,212326.718,V,,,,,,,230911,,*2F
$GPGGA,212327.709,,,,,0,00,,,M,0.0,M,,0000*5F
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPRMC,212327.709,V,,,,,,,230911,,*2E
$GPGGA,212328.709,,,,,0,00,,,M,0.0,M,,0000*50
$GPGSA,A,1,,,,,,,,,,,,,,,*1E
$GPGSV,3,1,10,20,75,047,,23,65,203,,32,48,072,,24,40,141,*74
$GPGSV,3,2,10,17,34,270,,31,26,056,,11,25,157,,04,20,309,*70

Il testo viene scritto byte per byte in seriale e sembra funzionare, però se tiro via la riga che scrive
byte per byte e provo a fargli scrivere l'array, il risultato non è lo stesso:

#include <string.h>
#include <ctype.h>
#include <SoftwareSerial.h>

#define  MONITORRXPIN    0
#define  MONITORTXPIN    1
#define  GPSRXPIN        8
#define  GPSTXPIN        9
#define  RXBUFFERLENGHT  100
#define  GPRMCCOMMAND    "$GPRMC"
#define  GPGGACOMMAND    "$GPGGA"
#define  GPGSACOMMAND    "$GPGSA"  
#define  GPGSVCOMMAND    "$GPGSV"

char   RXBuffer[RXBUFFERLENGHT];
int    CharCount=0;

SoftwareSerial GPSSerial =  SoftwareSerial(GPSRXPIN, GPSTXPIN);

void setup()
{
  pinMode(MONITORRXPIN, INPUT);
  pinMode(MONITORTXPIN, OUTPUT);
   
  GPSSerial.begin(4800);
  Serial.begin(9600);
  InitRXBuffer();
}

void loop()
{
   char   byteGPS = -1;

   byteGPS=GPSSerial.read();        

   if (byteGPS >= 0)
   {
     RXBuffer[CharCount]=byteGPS;
     CharCount++; 
//   Serial.print(byteGPS, BYTE);   ************** commentato riga che scrive byte per byte
     if (CharCount >= RXBUFFERLENGHT)
     {
       Serial.print("Errore superamento buffer");
       return;
     }       
    
     if (byteGPS==13)
     {
    // **************** aggiunto ciclo for che scorre l'array e invia alla seriale un carattere per volta 
     for (int i=0; i <= strlen(RXBuffer)-1; i++)
      {
         Serial.print(RXBuffer[i], BYTE);
      }       
     Serial.println("");
    //****************************************************************************
       CharCount=0;
       InitRXBuffer();
     }
   }
} 
  
void  InitRXBuffer()
{
  for (int i=0;i < RXBUFFERLENGHT;i++) { RXBuffer[i] = 0; }
}

Ho evidenziato le righe modificate/aggiunte.

Il risultato è questo:

,,,*1E

GSV,3,1,11,23,85,194,,20,61,082,,04,36,306,,32,34,085,*7B

f23,148,,31,19,041,,13,14,224,*7A

3f14,282,,11,09,159,,30,00,028,*48

21,V,,,,,,,230911,,*26

$GPGGA,220354.713,,,,,0,00,,,M,0.0,M,,0000*51

,,,,,*1E

RMC,220354.713,V,,,,,,,230911,,*20

$GPGGA,220355.713,,,,,0,00,,,M,0.0,M,,0000*50

,,,,,*1E

RMC,220355.713,V,,,,,,,230911,,*21

$GPGGA,220356.721,,,,,0,00,,,M,0.0,M,,0000*52

,,,,,*1E

RMC,220356.721,V,,,,,,,230911,,*23

$GPGGA,220357.713,,,,,0,00,,,M,0.0,M,,0000*52

,,,,,*1E

RMC,220357.713,V,,,,,,,230911,,*23

$GPGGA,220358.713,,,,,0,00,,,M,0.0,M,,0000*5D

,,,,,*1E

GSV,3,1,11,23,85,194,,20,61,082,,04,36,306,,32,34,085,*7B

f23,148,,31,19,041,,13,14,224,*7A

3f14,282,,11,09,159,,30,00,028,*48

13,V,,,,,,,230911,,*2C

$GPGGA,220359.721,,,,,0,00,,,M,0.0,M,,0000*5D

,,,,,*1E

RMC,220359.721,V,,,,,,,230911,,*2C

$GPGGA,220400.713,,,,,0,00,,,M,0.0,M,,0000*57

,,,,,*1E

RMC,220400.713,V,,,,,,,230911,,*26

$GPGGA,220401.713,,,,,0,00,,,M,0.0,M,,0000*56

cf
$GPRMC,220401.713,V,,,,,,,230911,,*27

$GPGGA,220402.721,,,,,0,00,,,M,0.0,M,,0000*54

,,,,,*1E

RMC,220402.721,V,,,,,,,230911,,*25

$GPGGA,220403.713,,,,,0,00,,,M,0.0,M,,0000*54

,,,,,*1E

GSV,3,1,11,23,85,194,,20,61,082,,04,36,306,,32,34,085,*7B

f23,148,,31,19,041,,13,14,224,*7A

3f14,282,,11,09,159,,30,00,028,*48

13,V,,,,,,,230911,,*25

$GPGGA,220404.713,,,,,0,00,,,M,0.0,M,,0000*53

,,,,,*1E

RMC,220404.713,V,,,,,,,230911,,*22

$GPGGA,220405.724,,,,,0,00,,,M,0.0,M,,0000*56

,,,,,*1E

RMC,220405.724,V,,,,,,,230911,,*27

$GPGGA,220406.715,,,,,0,00,,,M,0.0,M,,0000*57

,,,,,*1E

RMC,220406.715,V,,,,,,,230911,,*26

$GPGGA,220407.715,,,,,0,00,,,M,0.0,M,,0000*56

,,,,,*1E

RMC,220407.715,V,,,,,,,230911,,*27

$GPGGA,220408.723,,,,,0,00,,,M,0.0,M,,0000*5C

,,,,,*1E

GSV,3,1,11,23,85,194,,20,61,082,,04,36,306,,32,34,085,*7B

f23,148,,31,19,041,,13,14,224,*7A

3f14,282,,11,09,159,,30,00,028,*48

23,V,,,,,,,230911,,*2D

$GPGGA,220409.715,,,,,0,00,,,M,0.0,M,,0000*58

,,,,,*1E

RMC,220409.715,V,,,,,,,230911,,*29

$GPGGA,220410.715,,,,,0,00,,,M,0.0,M,,0000*50

,,,,,*1E

RMC,220410.715,V,,,,,,,230911,,*21

$GPGGA,220411.724,,,,,0,00,,,M,0.0,M,,0000*53

,,,,,*1E

RMC,220411.724,V,,,,,,,230911,,*22

$GPGGA,220412.715,,,,,0,00,,,M,0.0,M,,0000*52

,,,,,*1E

RMC,220412.715,V,,,,,,,230911,,*23

$GPGGA,220413.715,,,,,0,00,,,M,0.0,M,,0000*53

,,,,,*1E

GSV,3,1,11,23,85,194,,20,61,082,,04,36,306,,32,34,085,*7B

f23,148,,31,19,041,,13,14,224,*7A

3f14,282,,11,09,159,,30,00,028,*48

15,V,,,,,,,230911,,*22

$GPGGA,220414.724,,,,,0,00,,,M,0.0,M,,0000*56

,,,,,*1E

RMC,220414.724,V,,,,,,,230911,,*27

Mi sono fatto l'idea che nel primo caso, viene scritto byte per byte in tempo reale, mentre nel secondo
il tempo che arduino impiega a scorrere l'array e a printarlo in seriale fa passare dei cicli di cpu in cui
il gps continua ad inivare dati che vanno persi perchè non scaricati dal buffer.
Però, se il problema è veramente questo, come potrei risolverlo?
La prova di scrittura dell'array l'ho fatta non perchè mi serva stamparlo a video tramite seriale, ma perchè
non risuscivo a capire come mai mi era impossibile manipolare le strinche con strcmp e strcpy.
Se qualcuno ha qualche dritta :slight_smile:
Grazie.
Ciao.

Penso anche io che il tuo problema sia la software serial. Prova ad abbassare il baud rate della software serial e a portare quello della seriale vera a 115200, così hai meno tempi morti.

P.S. L'IDE di arduinio ha messo a disposizione una classe apposita per le stringhe. Se hai da manipolarle pesantemente ti conviene dargli un'occhiata. Il link è questo: String() - Arduino Reference

Mi è venuta a mente un'altra cosa (guarda, stavo per andare a letto, sono tornato al pc apposta :smiley: ). Se fosse il problema della software serial, la prima stringa in teoria dovrebbe stampartela correttamente... Fammi sapere.

Non conosco le librerie in oggetto ma mi pare che ci sia un errore logico di fondo, ossia il tuo codice dovrebbe/vorrebbe fare questo:

  1. inizializzo le comunicazioni col GPS e la Seriale->PC
  2. mi metto in attesa e ricevo i dati eventualmente spediti dal GPS mettendoli in un array
  3. nel momento in cui leggo il byte 13 (carattere invio, presumo), stampo sulla seriale->PC i dati raccolti
  4. reinizializzo il buffer di ricezione e mi rimetto in ascolto

Ecco, il problema sono i puntoi 3 e 4, secondo me.
Col punto 3 tu ti metti ad inviare i dati verso il PC ma il GPS non continua a spedirti i dati verso l'Arduino? A me pare di sì.
Dopo che hai spedito l'array al PC, tu al punto 4 reinizializzi il buffer di ricezione, ma così cancelli i dati che avevi ricevuto dal GPS fino a quel momento. Così poi ti metti in ascolto in un punto imprecisato della comunicazione, per mandare i dati ancora al PC appena arriva un carattere 13.

non usare la libreria
SoftwareSerial.h
ma la newsoftseria NewSoftSerial | Arduiniana

poi per leggere un byte usa il controllo se ci sono dati presenti con

if (device1.available() > 0)
  {
    int c = device1.read();
    ...
  }

Ciao Uwe

Janos:
Penso anche io che il tuo problema sia la software serial. Prova ad abbassare il baud rate della software serial e a portare quello della seriale vera a 115200, così hai meno tempi morti.

P.S. L'IDE di arduinio ha messo a disposizione una classe apposita per le stringhe. Se hai da manipolarle pesantemente ti conviene dargli un'occhiata. Il link è questo: String() - Arduino Reference

Grazie, non sapevo di questa classe per le stringhe.
Per quanto riguarda la velocità della seriale, posso sicuramente aumentare quella che va vero sil pc a 115200 ma non ho trovato nulla per cambiare la velocità del gps.

Janos:
Mi è venuta a mente un'altra cosa (guarda, stavo per andare a letto, sono tornato al pc apposta :smiley: ). Se fosse il problema della software serial, la prima stringa in teoria dovrebbe stampartela correttamente... Fammi sapere.

Si, la prima la riceve correttamente a parte un carattere ascii casuale all'inizio dovuto forse a qualche spuria.
Inoltre, se io gli faccio printare via seriale ogni byte che riceve, vedo tutti i dati correttamente.

leo72:
Non conosco le librerie in oggetto ma mi pare che ci sia un errore logico di fondo, ossia il tuo codice dovrebbe/vorrebbe fare questo:

  1. inizializzo le comunicazioni col GPS e la Seriale->PC
  2. mi metto in attesa e ricevo i dati eventualmente spediti dal GPS mettendoli in un array
  3. nel momento in cui leggo il byte 13 (carattere invio, presumo), stampo sulla seriale->PC i dati raccolti
  4. reinizializzo il buffer di ricezione e mi rimetto in ascolto

Ecco, il problema sono i puntoi 3 e 4, secondo me.
Col punto 3 tu ti metti ad inviare i dati verso il PC ma il GPS non continua a spedirti i dati verso l'Arduino? A me pare di sì.
Dopo che hai spedito l'array al PC, tu al punto 4 reinizializzi il buffer di ricezione, ma così cancelli i dati che avevi ricevuto dal GPS fino a quel momento. Così poi ti metti in ascolto in un punto imprecisato della comunicazione, per mandare i dati ancora al PC appena arriva un carattere 13.

Ma finchè io non ho printato tramite il ciclo for tutto l'array e non l'ho inizializzato, il ciclo di loop non è finito e qundi le istruzioni che scaricano i dati seriali e li mettono sul buffer non vengono eseguite...................o sbaglio?

uwefed:
non usare la libreria
SoftwareSerial.h
ma la newsoftseria NewSoftSerial | Arduiniana

poi per leggere un byte usa il controllo se ci sono dati presenti con

if (device1.available() > 0)

{
    int c = device1.read();
    ...
  }




Ciao Uwe

Provo a studiarmi newsotseriale e vediamo se risolve.
Grazie :slight_smile:

Stefanoxjx:
Ma finchè io non ho printato tramite il ciclo for tutto l'array e non l'ho inizializzato, il ciclo di loop non è finito e qundi le istruzioni che scaricano i dati seriali e li mettono sul buffer non vengono eseguite...................o sbaglio?

Ma la seriale implementata nell'Arduino ha un buffer di 128 byte. Se arrivano più dei 128 byte, i vecchi dati vanno persi, sovrascritti dai nuovi. Usare la NewSoftSerial può aiutarti nel senso che la libreria riceve i dati dal buffer di Arduino anche quando il tuo codice non fa una lettura esplicita però devi sempre tenere a mente il limite dei 128 byte. Puoi provare ad alzarlo modificando il file HardwareSerial.cpp nel core di Arduino però poi diminuisci la memoria SRAM a disposizione del programma.

Grazie a tutti dei consigli.
NewSoftSerial ha risolto il problema alla grande :slight_smile:

uwefed:
non usare la libreria
SoftwareSerial.h
ma la newsoftseria NewSoftSerial | Arduiniana

poi per leggere un byte usa il controllo se ci sono dati presenti con

if (device1.available() > 0)

{
    int c = device1.read();
    ...
  }




Ciao Uwe

specifichiamo: la softserial NON usa gli interrupt, quindi se arrivano dati mentre non stai facendo una read(), vengono persi per sempre. Invece sia la seriale harware che la NewSoftSerial parcheggiano i dati in arrivo, anche se stai facendo altro, in un buffer, da cui potrai leggeri con calma.
ovvio rimane il "piccolo" problema dell'overflow del buffer, spiegato da leo72, ma a meno che tu non faccia calcoli pazzesci o uso di delay, non dovrestiincappare nel problema