Fase tra trasmissione e ricezione array seriale? (RISOLTO)

Testerò qualche giorno questo barbatrucco: nel momento in cui scarto la stringa perchè metà, doppia etc, ho messo un delay di 10 ms, in modo da sfalzare la successiva lettura... Per ora da buoni risultati...
Nel caso dopo un po' di letture tornasse a fare le letture nel momento che l'altro è in trasmissione, si risposta di 10 ms, ok che perdo una lettura, ma tanto il nostro occhio non riesce a vedere dei valori che cambiano ogni 100 ms, posso starci tranquillamente :wink:
Vediamo che accade

Ciao,
scusami ancora, ma è una cosa che non so, ti riferisci all'ultimo dato che arriva? Che è il checksum della centralina? Quindi si controlla quello se è corretto e in quel modo si sa che la stringa è arrivata ed è giusta?
Quindi appena letta la stringa converto subito i 2 byte del checksum, e con un if verifico che sia giusto?
grazie a tutti, mi avete dato un grande aiuto, ho imparato un po' di cose :wink:

thedrifter:
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.

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

Il sistema che stai usando secondo me è il più difficile, perché abbiamo una ricezione che ha i suoi tempi, e un programma che la testa in modo totalmente asincrono affidandosi più o meno al caso per beccarla giusta.

Il modo giusto sarebbe un programma event driven, quando viene ricevuta una trama corretta solo allora si attiva il resto del programma per elaborare/visualizzare i dati (ma ovviamente non so cosa deve fare il resto del programma e sa ha altri tempi da rispettare). In questo modo il programma sarebbe sempre agganciato al trasmettitore e non perderebbe neanche una trama (salvo errori di ricezione che la facciano scartare ovviamente).

Lo scarto potrebbe avvenire solo per questi motivi:

  • non ricevuti tutti i byte
  • errore checksum

Scrivo anche la mia versione di ‘leggi’ sulla falsariga di quella di Sukko. Questa leggi esce se e solo se ha ricevuto una trama corretta (per lunghezza e checksum), altrimenti prova a ricevere la trama seguente.

byte lettura[34];        // array ricezione dati
byte conta;              // indice array e conteggio nr.byte ricevuti
byte inrx;               // stato ricezione, false=attesa dati, true=in lettura
unsigned long lastRead;  // memorizza tempo ultimo dato ricevuto

void leggi()
{
    conta = 0;                                      // byte ricevuti = 0
    inrx = false;                                   // stato non in ricezione
    while(true)                                     // ciclo di ascolto senza fine
    {
        if (Serial.available())                     // se c'e`qualcosa da leggere
        {
            while (Serial.available())              // svuota tutto il buffer
            {
                byte b = Serial.read();
                if (conta < 34) lettura[conta] = b; // memorizza max 34 byte
                conta++;                            // ma conta tutti i byte ricevuti
            }
            inrx = true;                            // imposta stato ricezione in corso
            lastRead = millis();                    // salva tempo a questo momento
        }

        if (inrx  &&  millis()-lastRead > 10)       // se stato ricez. e arriva pausa
        {
            if (conta == 34)                        // se ricevuti esattamente 34
            {
                ...calcolo del checksum...
                if (..checksum corretto..) return;  // e chk corretto ritorna
            }
            conta = 0;                              // altrimenti ci si mette in
            inrx = false;                           // attesa prossima trama
        }
}

Ciao Claudio,
concordo pienamente con quello che dici, però dalle prove fatte, di 3 esempi non ne funziona uno.... Riprovo anche questo che hai messo tu :wink:
Invece il mio ultimo sta dando ottimi risultati, considerando come dici tu che è affidato al caso.... :smiley:

Ormai io ti do solo un ultimo consiglio: cerca di CAPIRE cosa succede, e COME i vari pezzi di codice che provi affrontano il problema, invece di provare cose A CASO sperando che funzionino. Ne saresti uscito un mese fa.

Sukko, mi passi per svogliato, anche se un po' lo sono :D, ma non sai le nottate che ci ho fatto, saranno 3 mesi che smatto, non pensare che non provi, ne ho fatte un centinaio di modifiche, è che proprio non ho idea di come fare, altrimenti non avrei chiesto aiuto, e mi pare non sia nemmeno poi tanto facile, altrimenti mi sarebbe arrivato un aiuto netto e funzionante..... A forza di provare qualcosa, ci arriverò :wink:

Il fatto è che se avessi capito la logica di quel che ti ho proposto io, avresti già risolto. Si tratta solo di sistemare il delay, un po' ragionando, un po' a tentativi. Invece ti ostini a provare cose a caso che funzionano una volta ogni tanto, perché seguono una logica sbagliata.

Si, hai ragione, ma non pensare che non abbia lavorato sul tuo codice, hai visto quante volte l'ho postato ricorretto, ma non trovo il modo, quell'if che hai messo col tempo, non funziona, e poi non capisco, perchè dopo la lettura e aver salvato i 34 dati, devo aspettare 10 ms, e poi per fare cosa? Semmai in quei 10 ms che aspetto devo sempre controllare con available che non arrivino nuovi dati, se arrivano però? li butto? devo mettere un flag che mi avvisa se arrivano etc, se non è così non ho capito...

thedrifter:
perchè dopo la lettura e aver salvato i 34 dati, devo aspettare 10 ms

Controllare quei 10ms di silenzio serve a capire che il trasmettitore ha sicuramente finito di inviare, quindi sappiamo con certezza di essere arrivati ad una pausa, il prossimo treno passa dopo 83ms per cui c'è tutto il tempo per elaborare quanto appena ricevuto e mettersi in ascolto del prossimo. Così non si perde mai il treno :slight_smile:

Questo è il tuo codice reso funzionante (male) con alcune modifiche, lascia sare le modifiche, che alcune sono errate…

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 < 40; 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;
    }
  }
}

Tu fai un available, che restituisce X
poi fai la lettura perchè n è > 0
l’if successivo (quello del tempo) non si verifica mai, e nemmeno il mio boolean true, perchè la prima lettura ha un available superiore a 100 (diverse letture accodate), e se io non mi fermo di salvare a 34, avrò sempre i dati superiori e non li leggerò. Se invece mi fermo io a leggerne 34, li avrò sempre buoni (34), ma con contenuto errato.
Di fatto non riesco a capire cosa vorresti fare tu con quel millis, aspetti che?
:slight_smile:

Claudio, ascolto del prossimo??? Allora non devo leggere ogni 100 ms? Io devo sempre leggere? E comunque, nella prima lettura, non riuscirò mai a trovare quei 10 ms di silenzio che dici tu, dovrei preventivamente svuotare il buffer, e poi ripartire... credo

Ecco, appunto, non hai capito la logica, come volevasi dimostrare…

La centralina ti spedisce N byte a 57600 bps. Ogni bit impiega quindi 1 / 57600 = 0.000017 secondi, ovvero 17 us. Un byte richiede 10 bit (8 bit + 1 start + 1 stop), quindi 170 us. Immagino che la centralina non abbia motivo di fare pause durante la trasmissione del messaggio, quindi gli N byte ti arriveranno uno dietro l’altro. Finché ne arrivano “a raffica” li accodi nel buffer. Se non ne arrivano per un certo timeout da calibrare (diciamo il tempo di 2-3 di caratteri, per questo avevo originariamente scritto 3 * 1 / 57600) vuol dire che la trasmissione corrente è finita e che quindi puoi processare il messaggio, se questo è valido (ovvero se ha la lunghezza attesa e/o il checksum corrisponde).

Se il messaggio viene inviato 10 volte al secondo, ci sarà una pausa di circa 100 ms (dovresti sottrarre il tempo di trasmissione dell’intero messaggio, ma bisogna vedere cosa fa esattamente la centralina, potrebbe aspettare 100 ms e amen) tra un invio e l’altro, per cui il totale di timeout e tempo di processamento del messaggio deve essere inferiore a questo intervallo.

Il mio codice non funziona perché l’hai implementato a modo tuo, non come l’ho scritto io. Se metti tutto nel loop dovrebbe funzionare. Poi se proprio vuoi splittare le parti dovrai farlo seguendo una certa logica, chiamando ripetutamente ciò che va chiamato ripetutamente, ad esempio.

È la terza volta che ci provo, ma meglio di così non lo so spiegare. Pensaci un po’ sopra.

Io capisco cosa vuoi dire, ma allora perchè non me l'hai detto subito che io devo "leggere" sempre? Io continuavo a chiamare la funzione ogni 100 ms, invece come dici tu praticamente è sempre in lettura nel loop... Io pensavo fosse "tempo perso" leggere sempre.
Proverò a rifare tutto, mettendolo nel loop :wink:
Abbi pazienza :stuck_out_tongue:

Io ho scritto una roba, tu l'hai implementata a modo tuo, e sono io che non dico le cose??? :o

Pensavo che il tuo essendo un esempio, lo avevi messo nel loop così... L'ho detto tante volte che leggevo ogni 100 ms... Vabbè, ora ci riprovo :slight_smile: grazie per la pazienza

thedrifter:
Claudio, ascolto del prossimo??? Allora non devo leggere ogni 100 ms? Io devo sempre leggere?

Come detto nel post #22 :smiley:

E comunque, nella prima lettura, non riuscirò mai a trovare quei 10 ms di silenzio che dici tu, dovrei preventivamente svuotare il buffer, e poi ripartire... credo

A questo serve la variabile di stato 'inrx' (che Sukko ha condensato nella lastRead facendole fare una doppia funzione).

In sostanza se ci si mette in ricezione a metà di una trasmissione, al momento del timeout saranno arrivati meno byte e si scarta. Se invece ci si mette in ricezione durante una pausa, la funzione continua ad ascoltare, ed è solo dal momento in cui inizia a ricevere byte che comincia a tenere conto del tempo (mettendo 'inrx' a true e quindi attivando l'if che controlla millis).

La terza possibilità è che all'inizio il trasmettitore abbia già inviato diverse trame (saturando il buffer interno di Arduino di 64(?) byte), allora la funzione leggerebbe tutto in un colpo svuotando il buffer e scartando quanto ricevuto.

Rimane da gestire il controllo del checksum quando vengono ricevuti esattamente 34 byte seguiti da 10ms di silenzio (cioè probabile trama corretta).

Ci sto lavorando, ma la prima lettura, mi trova 127 byte nel buffer e rimane li, si blocca, ora vedo col tuo codice...

Rieccomi :slight_smile:
stanotte poi la connessione è andata out, non sono riuscito a scrivere... Si docsavage, hai ragione anche tu, perdo tempo a saltellare fra un codice e l'altro... Adesso mi sto concentrando su questo, inserito nel loop; stanotte ho fatto tardi a fare un po' di prove, la lettura c'è, con un problema, alla prima si blocca, available restituisce 127 e rimane li... Premetto che ora sto utilizzando il bluetooth, se spengo e riaccendo, dopo funziona la lettura; possibile vada svuotato il buffer perchè saturo? Dal codice che mi avete dato non dovrebbe svuotarsi dato che continua a leggere? Oppure fermandosi a 40 byte sono pochi?

Doc, dove ho scritto che con la centralina non va? Di solito se va quà con arduino, va anche con la centralina, o ho scritto male, oppure era una banalità che ho risolto...

Ciao

Si, il problema del ritorno dell'available era dato perchè si spezzava la lettura, successivamente si verificava anche quà al pc, dipendeva dal caso come iniziava a leggere, pertanto questo non è un problema.
Quella funzione va, affidata al caso...

Ora sto lavorando all'ultima che mi avete dato, sto cercando di capire perchè non si sblocca dalla prima lettura...

Torno stasera, ora non ci sono mentalmente e devo tornare al lavoro, forse c'è da fare un riepilogo, perchè ci siamo persi qualcosa... :slight_smile: