Fase tra trasmissione e ricezione array seriale? (RISOLTO)

Ciao Claudio,
a idea ti devo dare ragione, non ci avevo pensato, ma quindi basta un delay? E’ difficile però sapere il tempo che impiega il trasmettitore, si fa a caso provando? Ora analizzerò il codice di Sukko, potrebbe risolvere…

Per lo svuotamento del buffer, non serve perchè sono i dati nuovi che sostituiscono i precedenti? Provo a toglierlo.

Rieccomi,
ok per lo svuotamento del buffer mio, non serve, codice in meno :wink:

Sukko, ho applicato la tua funzione, modificata con le mie variabili e array, ma non mi restituisce nulla, ho convertito bene?

void leggi1()                              // prova lettura
{
  conta = 0;                               // azzero il contatore per i nuovi dati

  byte n = Serial2.available ();

  if (n > 0)
  {
    for (byte b = 0; b < n && conta < 40; b++)
      lettura[conta++] = Serial2.read ();

    lastRead = millis ();
  }

  if (lastRead > 0 && millis () - lastRead >= 3.0 / 57600)
  {
    if (conta >= 34)
    {
      verif = true;                     // dico che ho i 34 dati
    }
    else
    {
      verif = false;                      // dico di non prendere i dati, no buoni
    }

    conta = 0;
    lastRead = 0;
  }
}

Un delay "a casaccio" potrebbe portare al caso opposto, cioé una funzione che estrae i byte dal buffer di ricezione più lentamente di quanto arrivano. I byte vanno sempre letti dal buffer di ricezione nel più breve tempo possibile, ma la lettura deve continuare per il tempo necessario a riceverli tutti (anche se nel frattempo Serial.available qualche volta segnala zero).

Fondamentalmente bisogna continuare a provare a ricevere fino ad avere la quantità desiderata di byte.... che però non devono essere parte della trama attuale e parte della precedente. Per questo serve identificare la pausa intermedia, ad esempio con il metodo di Sukko, che è l'unico modo sicuro per determinare la fine della trasmissione in corso (e quindi prepararsi per quella nuova).

Oltre le pause ci sono altri modi per sincronizzarsi, l'idea di un header non è da scartare, ma bisogna fare attenzione a non confondere header con dati, il che richiede una serie di operazioni in più per sincronizzarsi da zero, come dei bit di controllo nell'header che cambiano in modo preciso (in sostanza usare una trasmissione multiheader).


Il codice di Sukko ha un piccolo errore, e un peccato veniale.
L'errore è nella riga (da te tradotta in):

if (lastRead > 0 && millis () - lastRead >= 3.0 / 57600)

Il valore 3.0/57600 è sempre inferiore a un millisecondo. Io scriverei 10ms secchi e basta:

if (lastRead > 0  &&  millis() - lastRead > 10)

Il peccato veniale è usare lastRead non solo come variabile temporale ma anche come variabile di stato... diciamo che la routine va in errore nel momento esatto in cui millis() ritorna zero (una volta ogni 49 giorni e qualcosa).

Invece il tuo codice ha un errore grosso, non è un loop, sono due if valutati al volo una sola volta e stop.

Sì, effettivamente il delay è da tarare, non ricordavo la velocità di trasmissione e sono andato a caso, nella speranza che fosse uno spunto, e non una fonte per un becero copia-incolla. Sicuramente non può essere < 1 ms.

Quando millis() ritorna 0 non dovrebbe succedere niente di strano, secondo la logica dell’aritmetica unsigned a 32 bit, sei sicuro? Ma poi questo coso deve stare acceso davvero più di 49 giorni?

Mi ero accorto era nel loop, metterò un while… Si, ho fatto un copia incolla, proprio mentalmente non ci sono, me lo studio passo passo… assolutamente non rimane acceso 49 giorni, sarebbe male :smiley: Legge i dati di una centralina sportiva per uso automotive, quanto potrà mai stare acceso, 2 ore? :slight_smile:
Domattina mi rimetto un po’ a programmare, vediamo cosa riesco a fare.
Grazie mille per i preziosi consigli

SukkoPera:
Quando millis() ritorna 0 non dovrebbe succedere niente di strano, secondo la logica dell'aritmetica unsigned a 32 bit

Non succede nulla al risultato della sottrazione che è corretto, ma essendo usata anche come stato per entrare nel secondo if, quella volta li non entrerebbe nell'if :wink:

Ahhh, vuoi dire che ci si perderebbe una lettura che avvenisse esattamente quando millis() va in overflow. Sì, hai ragione, ma essendo i dati periodici, non dovrebbe essere un grosso problema, ancora meno visto che 49 giorni non starà acceso ;). Giusta osservazione, però!

Vabbè, per ora abbandono, non mi va... Sukko, ma nel for che hai fatto, manca una graffa di apertura? Altrimenti cosa comprende quel for?? Scusate, ma sono duro uff :confused:

Non manca la graffa, comprende solo la riga immediatamente successiva, che altro non fa che accodare al buffer i byte ricevuti.

Buongiorno a tutti :slight_smile:
continuando le prove, non sono giunto a nulla, vi rimetto la parte di codice della lettura, che controlla e controlla mi pare corretto, ma non funziona, in particolare il secondo if non si verifica mai, ma anche togliendolo, i dati comunque non arrivano… Ho approcciato male io qualcosa?

void leggi1()                              // prova lettura
{
  conta = 0;                               // azzero il contatore per i nuovi dati
  lastRead = 0;

  while (verif == false)
  {
    byte n = Serial2.available ();          // salvo in n il numero dei byte nel buffer?

    if (n > 0)                              // leggo solo se ci sono dati nel buffer
    {
      for (byte b = 0; b < n && conta < 40; b++)
        lettura[conta++] = Serial2.read (); // leggo da seriale e salvo nel mio buffer
        
      lastRead = millis ();                 // prendo il tempo
    }

    if (lastRead > 0 && millis () - lastRead > 10)
    {
      if (conta >= 34)
      {
        verif = true;                       // dico che ho i 34 dati
      }
      else
      {
        verif = false;                      // dico di non prendere i dati
      }
    }
  }
}

Ho provato a mettere "byte n = Serial2.available ();" prima del ciclo while, per evitare accada quello che dice Claudio, che magari leggendo velocemente qualche volta available possa ritornare zero, ma non cambia niente, non esce da questo while...

Correggo quanto detto sopra, non c'entra l'available, che comunque viene eseguito una volta sola, non è nemmeno il while il problema, ma il ciclo for, non si verificano le condizioni per uscire da li, vedo se scopro quale condizione...

Allora, ho verificato il valore che ritorna da available, modificato la funzione, se non tolgo il 2° if, la lettura funziona, salvo dare valori casuali quando available non è 34 (giustamente); se lascio il 2° if a fare il suo lavoro, si blocca la lettura

void leggi1()                              // prova lettura
{
  conta = 0;                               // azzero il contatore per i nuovi dati
  lastRead = 0;
  verif = false;

  while (verif == false)
  {
    byte n = Serial2.available ();         // salvo in n il numero dei byte nel buffer?

    myGLCD.setBackColor (0, 0, 0);         //colore sfondo scritta
    myGLCD.setColor(255, 255, 255);        //setta il colore dei caratteri
    myGLCD.setFont(BigFont);               //mette caratteri grandi
    if (n < 1000) {
      myGLCD.print("  ", 65, 250);         // cancello display, orizz, vert
    }
    if (n < 100) {
      myGLCD.print(" ", 50, 250);
    }
    myGLCD.printNumI(n, 20, 250);          // scrivo il ritorno di available

    if (n > 0)                             // leggo solo se ci sono dati nel buffer
    {
      for (byte b = 0; b < n && conta < 40; b++)
        lettura[conta++] = Serial2.read (); // leggo da seriale e salvo nel mio buffer

      lastRead = millis ();                 // prendo il tempo
      //verif = true;                       // prova
    }

    if (lastRead > 0 && millis () - lastRead > 10)
    {
      if (conta >= 34)
      {
        verif = true;                       // dico che ho i 34 dati
      }
      else
      {
        verif = false;                      // dico di non prendere i dati
      }
    }
  }
}

Il problema è quà, non si verifica mai l'attesa del tempo

if (lastRead > 0 && millis () - lastRead > 10)

Prova 2 al posto di 10.

Grazie docsavage, proverò anche il tuo programma, ma ora ormai insisto sull’altro, sennò ammattisco :o
Ho modificato un po’ di cose, e sono arrivato alla lettura, anche se non è perfettissima, il problema era millis, ci voleva micros (e pensare che sukko nella vecchia discussione l’aveva scritto…)
Poi ho aggiunto un timeout per uscire dal while in caso di errori, venuto fuori così:

void leggi1()                              // prova lettura
{
  conta = 0;                               // azzero il contatore per i nuovi dati
  lastRead = 0;
  verif = false;
  lastm = millis();

  while (verif == false)
  {
    byte n = Serial2.available ();         // salvo in n il numero dei byte nel buffer?

    myGLCD.setBackColor (0, 0, 0);         //colore sfondo scritta
    myGLCD.setColor(255, 255, 255);        //setta il colore dei caratteri
    myGLCD.setFont(BigFont);               //mette caratteri grandi
    if (n < 1000) {
      myGLCD.print("  ", 65, 250);         // cancello display, orizz, vert
    }
    if (n < 100) {
      myGLCD.print(" ", 50, 250);
    }
    myGLCD.printNumI(n, 20, 250);          // scrivo il ritorno di available

    if (n > 0)                             // leggo solo se ci sono dati nel buffer
    {
      for (byte b = 0; b < n && conta < 35; b++)
        lettura[conta++] = Serial2.read (); // leggo da seriale e salvo nel mio buffer

      lastRead = micros ();                 // prendo il tempo
    }

    if (lastRead > 0 &&  micros() - lastRead > 10)
    {
      if (conta >= 34)
      {
        verif = true;                       // dico che ho i 34 dati
      }
    }
    if (millis() - lastm > 5)
    {
      break;
    }
  }
}

Docsavage, le specifiche non danno un timeout, dicono solo cosa spediscono, ogni 100 ms.

Sto provando la tua routine, funziona, ma a random, come da sempre prende letture sbagliate, provato un timeout da 1 a 5 ms, ma fa sempre lo stesso.

Il problema si verifica quasi sempre all’accensione, quando non trova il sincronismo e il buffer della seriale è ad un valore alto, una volta partita la lettura, è difficile dia valori a random… Per ora il codice migliore è quello di sukko, devo solo capire come aggiustare l’ultimo if che mi fa uscire dal while, perchè non lavora proprio bene…

void leggi2()                              // leggo i dati seriali dal bt remoto
{
  conta = 0;                               // azzero il contatore per i nuovi dati
  verif = false;
  
  while (conta < 34)
  {
    if (Serial2.available())
    {
      lettura[conta++] = Serial2.read();
      lastRead = millis();
    }

    if (millis() - lastRead > 5)
    {
      conta = 0;
    }
  }
  verif = true;                       // dico che ho i 34 dati
}

Scusate, ma questo?

void leggi2()                             // leggo i dati seriali dal bt remoto
{
  conta = 0;                              // azzero il contatore per i nuovi dati
  verif = false;

  if (Serial2.available() == 34)
  {
    for (byte b = 0;conta < 35; b++)
      lettura[conta++] = Serial2.read (); // leggo da seriale e salvo nel mio buffer

    verif = true;                         // dico che ho i 34 dati
  }
  else
  {
    while (Serial2.available() > 0)
    {
      Serial2.read();                     // svuoto il buffer di ricezione
    }
  }
}

Non riceve mai false letture, potrebbe andare? Ci divento scemo con questo affare :confused:

Ciao,
allora, io sapendo che la centralina spara ogni 100 ms, anche la lettura la faccio dal mio programma ogni 100 ms, naturalmente non so se prima, durante o dopo la trasmissione.

Questa ultima funzione, funziona bene, quà al pc col trasmettitore che simula, ma sulla vettura ni, ovvero leggendo il numero che ritorna da available, dalla centralina non rimane fisso a 34 (come quà), ma oscilla un poco sopra e sotto di qualche unità, quindi perdo diverse trasmissioni (non che sia un problema).

In effetti quello che dici è vero, e tende anche a sincronizzarsi da sola...

Ma io non riesco in altri modi, quella che funziona meglio è questa, ma sicuramente non è il modo giusto...

Si, ci posso stare, anche se perdo 3 letture non mi cambia nulla...
l'unica cosa che mi rimane è di evitare di leggere i dati errati, che invece accade, il boolean "verif" dovrebbe evitare questo, ma invece succede lo stesso, indagherò meglio, qualche stringa passa comunque a inquinare il mio array...

Ciao,
non ho capito cosa vuoi dire col checksum, verif è una variabile booleana che la uso io quando leggo i dati, e la setto a true se ho i dati, altrimenti rimane false. Allego il codice completo, anche se è grandino, comunque alla riga 517 c’è la lettura e scrittura sul display dei dati.

Per quanto riguarda la funzione di lettura, funziona, come dicevi tu, quando si va a leggere nel punto buono, se si becca quando è in trasmissione etc, è un casino, possibile non ci sia un modo per sapere il punto giusto? Ci lavorerò ancora un po’

BLUETOOTH_DUE_DISPLAY5.ino (52.2 KB)