Fase tra trasmissione e ricezione array seriale? (RISOLTO)

Ciao,
dopo diversi test, mi sembra di capire che se la lettura dell’array inizia sfasato, lo rimane per sempre, è corretto? Cioè, c’è un modo per mettere in fase la lettura con la trasmissione, oppure lo è per forza ad ogni invio seriale?
Mi accade questo, accendo l’arduino che trasmette, dopo accendo l’arduino che riceve, se parte bene, dopo va sempre bene, se parte con valori a caso, non si allinea più, rimane sempre a dare valori casuali…

Questo il codice del trasmettitore su arduino mega:

long pmillis = 0;
long pmillis1 = 0;
byte dati[34];
int giri;
boolean salito;

void setup() {
  delay (1000);

  salito = false;
  giri = 0;

  Serial1.begin(57600);

  dati[0] = 99;
  dati[1] = 99;
  dati[2] = 99;
  dati[3] = 99;
  dati[4] = 99;
  dati[5] = 99;
  dati[6] = 99;
  dati[7] = 99;
  dati[8] = 99;
  dati[9] = 99;

  dati[10] = 0; // 152
  dati[11] = 0;   // 8

  dati[12] = 99;
  dati[13] = 0;

  dati[14] = 90;
  dati[15] = 0;

  dati[16] = 10;
  dati[17] = 0;

  dati[18] = 1;
  dati[19] = 0;

  dati[20] = 255;
  dati[21] = 0;

  dati[22] = 141;
  dati[23] = 0;

  dati[24] = 50;
  dati[25] = 0;

  dati[26] = 30;
  dati[27] = 0;

  dati[28] = 35;
  dati[29] = 0;

  dati[30] = 80;
  dati[31] = 0;

  dati[32] = 45;
  dati[33] = 255;
}

void loop()
{
  if (millis() - pmillis1 >= 1) {
    pmillis1 = millis ();

    if (salito == false)
    {
      giri ++;
      if (giri >= 7000)
      {
        salito = true;        // dico che è al max
      }
    }

    if (salito == true)
    {
      giri --;
      if (giri == 0)
      {
        salito = false;        // dico che è al min
      }
    }
  }

  if (millis() - pmillis >= 100) {
    pmillis = millis ();

    dati[10] =  lowByte(giri);    // byte basso
    dati[11] =  highByte(giri);   // byte alto

    Serial1.write(dati, 34);      // manda via i dati
  }
} // END LOOP

questa invece la parte di ricezione, quà utilizzo arduino due, non metto tutto il programma, perchè immenso…

//***************** leggo dal BT ed estrapolo tutti i dati *****************
    if (millis() - pmillis >= 100 && alibt == true) { // legge il BT ogni X secondi
      pmillis = millis ();                          // se il BT è acceso

      leggi();                                      // leggo il BT

      RPM = lettura[11] * 256 + lettura[10];        // 1° byte H, 2° byte L
      TPS = lettura[13] * 256 + lettura[12];        // TPS %
      H2O_TEMP = lettura[15] * 256 + lettura[14];   // temp acqua gradi
      AIR_TEMP = lettura[17] * 256 + lettura[16];   // temp aria gradi
      MAP = lettura[19] * 256 + lettura[18];        // MAP bar
      LAMBDA = lettura[21] * 256 + lettura[20];     // lambda, unità
      V_BATT = lettura[23] * 256 + lettura[22];     // volt batteria X10
      SPEED = lettura[25] * 256 + lettura[24];      // velocità ruota Kph X10
      OIL_P = lettura[27] * 256 + lettura[26];      // pressione olio bar
      FUEL_P = lettura[29] * 256 + lettura[28];     // pressione benzina bar
      OIL_TEMP = lettura[31] * 256 + lettura[30];   // temperatura olio gradi
      CHECKSUM = lettura[33] * 256 + lettura[32];   // checksum
      // ****************** finito la lettura dal BT ************************
//***************************************************************

void leggi()                              // leggo i dati seriali dal bt remoto
{
  for (conta = 0; conta < 40; conta++)    // cancello l'array, svuoto il buffer (mio)
  {
    lettura[conta] = 0;
  }
  conta = 0;

  while (Serial2.available() > 0)         // Controlla se il bt ha qualche dato
  {
    if (conta < 40)                       // controllo di non superare 80 per l'array
    {
      c = Serial2.read();                 // legge la seriale
      lettura[conta] = c;                 // copio il carattere nella mio array
      conta++;                            // incrementa di 1
    }
    else                                  // overflow
    {
      Serial2.read();                     // svuoto il buffer di ricezione
    }
  }
}
//**********************************************************************

Preciso che attualmente non uso i bluetooth, ma le seriali sono collegate direttamente con fili (tramite adattatore livelli ttl visto la due lavora a 3,3V)

secondo me devi inizializzare la comunicazione cioè far capire al trasmettitore che il ricevente è pronto...e magari che il ricevente ha ricevuto o meno tutto quello che si aspettava....se non ricodo male tu stai simulando la comunicazione con una centralina...ma questa non ha un mezzo "protocollo" per scambio dati?

Ciao, si, l'arduino che tasmette simula la centralina, mi serve per provare quà sul banco, senza stare sempre sulla vettura... Io al trasmettitore non posso dire nulla, la centralina appena alimentata inizia a trasmettere i dati a 10 Hz. Protocollo non saprei, so come trasmette, manda 10 byte di header di valore decimale 99, poi trasmette 34 byte che sono 17 dati. Il sistema è utilizzato da un'app che riceve questi dati tramite bluetooth.

bhe se sai che l'header è sempre 10 byte con valore 99....verifica di riceverli e da quel momento abiliti la lettura

Qualcuno quà sul forum mi aveva sconsigliato di fare così.... Rifarò delle prove

magari mi sfugge il motivo...come mai?

Se parli di me, io non ti ho sconsigliato di fare così, intendevo solo dire che io non farei così ;).

Hai una sequenza di X byte spedita 10 volte al secondo, quindi ci sarà un intervallo tra una sequenza e l’altra. Quindi io aspetterei un certo timeout, da scegliere con cura a seconda della velocità di trasmissione. Accoderei i caratteri ricevuti in un buffer e dopo che questo timeout è trascorso dall’ultima ricezione, verificherei se il buffer ha la lunghezza attesa. In caso affermativo lo processerei, altrimenti lo scarterei e aspetterei il prossimo, visto che evidentemente ho iniziato a ricevere mentre la trasmissione era già in corso e me ne sono perso un pezzo.

ciao SukkoPera,

tu suggerisci il metodo del timeout per evitare l’eventuale problema che anche l’11mo byte sia 99 e che quindi produrrebbe un’errato check positivo!?

Ad esempio, sì. Ma non solo, la questione di questa header è un po' strana, se non ricordo male, se ne parlava nel thread originale.

Ciao, si Sukko, mi riferivo a te, di fatto ne abbiamo parlato solo noi, all'inizio scartavo i caratteri di valore 99, poi giustamente tu mi hai fatto notare che potrei avere dei dati che mi servono dello stesso valore, e quindi li avrei persi, ed hai ragione, pertanto ho fatto come mi hai suggerito tu, salvando tutta la stringa in un array, e successivamente prelevando i dati (non ho messo il timeout). Anche questa soluzione non funziona perchè giustamente potrei iniziare a leggere quando la stringa è a metà (mi sa che è quello che accade). Però non mi torna il discorso tempo che dici tu, e per me è complicato farlo... Possibile non c'è altro modo? Poi non mi torna una cosa, ammesso che la prima stringa arrivi a metà, io prendo dati sbagliati e li visualizzo male, ok, però la lettura successiva dovrebbe essere completa, data dalla funzione available, o sbaglio? Cioè, i dati trasmessi rimangono nel buffer, se quando io faccio la lettura i dati non ci sono, esco, se ci sono, come fanno a essere a metà?

E se invece nella lettura contassi di ricevere il valore 99 per 10 volte e poi salvassi i byte successivi?

:D mi sa che sei un po' troppo stressato dal progetto ...te l'ho suggerito un paio di post fa e giustamente SukkoPera ha illustrato qualche limite di questo metodo...

Già :confused: ora ci provo, sono 3 mesi uff, non ne posso più davvero :D

Uff, va male, gli errori con questa lettura aumentano… sbaglio qualcosa? Ho corretto un errore nel codice sotto

void leggi1()                             // lettura modificata
{
  for (conta = 0; conta < 40; conta++)    // cancello l'array, svuoto il buffer (mio)
  {
    lettura[conta] = 0;
  }
  conta = 0;
  verif = false;

  while (Serial2.available() > 0)         // Controlla se il bt ha qualche dato
  {
    if (verif == false)
    {
      c = Serial2.read();                   // legge la seriale
      if (c == 'c' && verif == false)       // contr se è num 99
      {
        conta++;                            // incr pos array
      }
    }

    if (conta == 9 && verif == false)
    {
      verif = true;                       // dico che ho letto 10 volte 99
      conta++;                            // incrementa di 1
    }

    if (verif == true)                    // controllo se ho letto 10 volte 99
    {
      if (conta < 40)                       // controllo di non superare 40 per l'array
      {
        c = Serial2.read();                 // legge la seriale
        lettura[conta] = c;                 // copio il carattere nella mio array
        conta++;                            // incrementa di 1
      }
      else                                  // overflow
      {
        Serial2.read();                     // svuoto il buffer di ricezione
      }
    }
  }

}

ciao...secondo me ci sono un po' troppe Serial2.read()

Ciao, quel codice non mi va, modificato più volte, è un disastro, ho modificato la vecchia lettura, pare funzioni, domani proverò sulla vettura, in pratica ho aggiunto un if che mi fa utilizzare i dati solo se il totale dei byte è 34, se invece va in overflow (contatore superiore a 34) ignoro di utilizzare i dati e non utilizzo la lettura… Potrebbe essere una cosa valida? Domani verifico meglio, quà sul banco funziona :slight_smile:

void leggi()                              // leggo i dati seriali dal bt remoto
{
  for (conta = 0; conta < 40; conta++)    // cancello l'array, svuoto il buffer (mio)
  {
    lettura[conta] = 0;
  }
  conta = 0;

  while (Serial2.available() > 0)         // Controlla se il bt ha qualche dato
  {
    if (conta < 40)                       // controllo di non superare 80 per l'array
    {
      c = Serial2.read();                 // legge la seriale
      lettura[conta] = c;                 // copio il carattere nella mio array
      conta++;                            // incrementa di 1
      if (conta >= 34)
      {
        verif = true;                     // dico che ho i 34 dati
      }
    }
    else                                  // overflow
    {
      verif = false;                      // dico di non prendere i dati, no buoni
      Serial2.read();                     // svuoto il buffer di ricezione
    }
  }
}

ciao…mi sembra già meglio…attenzione ai due if che verificano conta…il primo è <40 il secondo >=34…

Ma guarda che quel che ti ho proposto io non è niente di complicato… È più o meno così, vedi se lo capisci e se funziona, l’ho buttato giù al volo:

#define BUFSIZE 40

#define SPEED 9600

byte buf[BUFSIZE];

byte buflen = 0;

unsigned long lastRead = 0;

void loop () {
	byte n = Serial2.available ();
	if (n > 0) {
		for (byte b = 0; b < n && buflen < BUFSIZE; b++)
			buf[buflen++] = Serial2.read ();

		lastRead = millis ();
	}

	if (lastRead > 0 && millis () - lastRead >= 3.0 / SPEED) {
		if (buflen == BUFSIZE) {
			// Buffer completo, processare
		} else {
			// Buffer ricevuto solo parzialmente, scartare
		}

		buflen = 0;
		lastRead = 0;
	}
}

Ciao orso, il primo if che controlla di essere sotto 40 è per evitare l'overflow del mio array, che è lungo 40; mentre quello che controlla di essere uguale o maggiore di 34 è quello che mi dice ok che ho salvato 34 byte, e quindi posso utilizzare i dati, dovrebbe evitare che utilizzi i dati se la stringa fosse a metà, e quindi minore di 34... Ho sbagliato qualcosa? Sukko, grazie dell'esempio, con calma provo a realizzarlo

thedrifter: Ciao orso, il primo if che controlla di essere sotto 40 è per evitare l'overflow del mio array, che è lungo 40; mentre quello che controlla di essere uguale o maggiore di 34 è quello che mi dice ok che ho salvato 34 byte, e quindi posso utilizzare i dati, dovrebbe evitare che utilizzi i dati se la stringa fosse a metà, e quindi minore di 34

Il problema maggiore che vedo in quel while, ma in tutta la funzione leggi in generale, è che non si tiene conto dei tempi in cui avvengono le cose. Non solo la funzione potrebbe leggere la fine dei dati precedenti e l'inizio dei seguenti perché non considera la pausa intertrama di sincronizzazione, ma probabilmente leggerà spesso dati parziali perché il while legge i byte ricevuti più velocemente di quanto arrivano, e Serial.available potrebbe ritornare zero quando la trasmissione è ancora in corso.

A margine, non serve azzerare fisicamente ogni volta il buffer 'lettura', basta riportare l'indice (in questo caso 'conta') a zero ed è come se nel buffer non ci fosse niente.