Errata visualizzazione su seriale, random

Sto facendo comunicare due Arduino tramite collegamento seriale attraverso due moduli Bluetooth e visualizzazione su display 4x20.
Il tutto funziona abbastanza bene nel senso che quello che viene digitato tramite terminale sul primo Ardu viene visualizzato sul display collegato al secondo Ardu. Ho riscontrato che inviando singoli caratteri tutto funziona perfettamente mentre inviando delle stringhe più lunghe alle volte il primo carattere non viene visualizzato. Facendo debug sulla stringa di arrivo noto che quando accade la mancata visualizzazione prima arriva il carattere mancante quindi avviene un acapo e quindi arriva tutto il resto.
Il listato di ricezione è il seguente:

#include <Wire.h>  																	 
#include <LiquidCrystal_I2C.h>
#include <Metro.h>
#include <SoftwareSerial.h>
/*-----------( Dichiara costanti )---------

/*-----------( Dichiara oggetti)-----------
 setta l' LCD address a 0x27 per display a 20 caratteri e 4 linee (viceversa 0x20 se non funziona)
 Setta i pin sul chip I2C chip usato per la connessione all' LCD:
                      addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
*/
LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Setta l'indirizzo LCD I2C
Metro pausa = Metro(10);             // pausa 10 ms
Metro pausa1 = Metro(1000);
SoftwareSerial mySerial(10, 11);    // RX, TX ricezione da Bluetooth

//-----------( Dichiara variabili )----------

String stampabile="";                    // stringa di arrivo dati

void setup()
{
  Serial.begin(9600);               // per debug
  mySerial.begin(9600);
  lcd.begin(20, 4);                 // inizializza il display su 4 righe e per 20 caratteri e accende il display
  for(int i = 0; i < 3; i++)        // 3 accensioni del display rapide
  {
    lcd.backlight();
    delay(150);
    lcd.noBacklight();
    delay(150);
  }
  lcd.backlight();                    // termina con display acceso
  lcd.clear();                       

}
void loop(){
 if (mySerial.available()){                 // quando arriva il carattere sulla seriale...
     stampabile = "";                        // pulisce la stringa
     lcd.clear();                              // pulisci lo schermo           
     while(mySerial. available()>0){
       char ext = mySerial.read();         // leggo
       if (pausa.check() == 1){             // inserisce una pausa di 10 ms
         stampabile += ext;                  // aggiugo il carattere letto alla stringa
       } 
     }
     Serial.println(stampabile);            // debug 
   }
  lcd.setCursor(0, 0);
  lcd.print("Potenza " + stampabile + " W");
}

Suggerimenti?
Grazie

Ho fatto una ulteriore prova sostituendo i moduli Bluetooth con dei moduli Xbee sempre in configurazione seriale trasparente e tutto magicamente funziona senza perdere un colpo... quindi il problema è dovuto ai moduli utilizzati.

Idee sul perché di questo difetto?

Non comprendo perché hai inserito un ritardo di 10ms prima di aggiungere il carattere alla String.

Comunque, se puoi usa un char array al posto dell'oggetto String per evitare problemi di saturazione di memoria.

Nella mia ignoranza, pensavo che fosse un problema di ritardi ( o di eccessiva velocità di qualche operazione) il motivo della perdita di qualche dato e quindi ho provato a "rallentare" un po'.
Proverò a toglierlo.

Se fosse un problema di saturazione di memoria (di cosa, di Arduino?) perché allora con gli Xbee va tutto a meraviglia e non perde un colpo?

PS: la risposta ... " e allora usa gli Xbee al posto del BT" non è ammessa.... :slight_smile: :slight_smile:

Ho modificato un po' il tuo sketch per prevedere il problema del dimensionamento della String ed eliminato la libreria Metro (inutile o quasi) ottimizzando la ricezione e la stampa.

#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <SoftwareSerial.h>

// -----------( Dichiara oggetti)-----------

/* setta l' LCD address a 0x27 per display a 20 caratteri e 4 linee (viceversa 0x20 se non funziona)
 Setta i pin sul chip I2C chip usato per la connessione all' LCD:
                      addr, en,rw,rs,d4,d5,d6,d7,bl,blpol
*/

LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Setta l'indirizzo LCD I2C
SoftwareSerial mySerial(10, 11);      // RX, TX ricezione da Bluetooth

String stampabile;                    // stringa di arrivo dati

void setup() {
  Serial.begin(9600);                 // per debug
  mySerial.begin(9600);
  lcd.begin(20, 4);                   // inizializza il display su 4 righe e per 20 caratteri e accende il display
  for (int i = 0; i < 3; i ++) {      // 3 accensioni del display rapide
    lcd.backlight();
    delay(150);
    lcd.noBacklight();
    delay(150);
  }
  lcd.backlight();                    // termina con display acceso
  lcd.clear();
  stampabile.reserve(30);               // riserva N caratteri per la stringa più lunga da ricevere
}

void loop() {
  stampabile = "";                      // pulisce la stringa
  while (mySerial. available() > 0) {   // quando arriva il carattere sulla seriale...
    char ext = mySerial.read();         // leggo
    stampabile += ext;                  // aggiungo il carattere letto alla stringa
  }
  if (stampabile.length() > 0) {        // stringa piena
    Serial.println(stampabile);         // debug
    lcd.clear();                        // pulisci lo schermo
    lcd.setCursor(0, 0);
    lcd.print("Potenza " + stampabile + " W");
  }
}
stampabile.reserve(30);

Massimo credo che questo debba andare nel setup...

Grazie, Mario.

Mi era sfuggito e ho modificato lo sketch.

Nel dubbio toglierei i ritardi. E non userei il tipo stringa: essendo dianamica occupa memoria e tempo..potrebbe essere che ci metta troppo tempo ad elaborare tra un carattere e l'altro e cosi si perda i colpi.. come esperimento potresti provare a ridurre la velocità della seriale (es. 4800)

Nulla, ho provato a eliminare i ritardi, ho provato ad abbassare la velocità ma il problema permane.
Sto provando a fare un codice senza string ma con array di char ...

Puoi fare vedere anche il listato che usi per tramettere?

Eccolo

#include <Metro.h>
Metro delay_start = Metro(3000);
int numero;

void setup(){

    Serial.begin(9600);
    randomSeed(analogRead(0));
}

void loop(){

  numero= random(32000);
  if(delay_start.check()==1){
    Serial.print(numero);  
  }
}

Ciao,
di solito quando invio su seriale o simili non mi affido solo alle tempistiche della stessa e creo un protocollo anche se semplice per poter capire quando inizia o finisce una sequenza.
Es (se invii solo ascii): 0x02 -- messaggio -- 0x03
Chi riceve attende lo 0x02 per considere inizio messaggio e lo 0x03 per la fine (e quindi esempio mettere su display). Non so se è applicabile al tuo caso, ma in generale per me ha sempre funzionato

Ok, il tuo sicuramente è un metodo elegante e corretto, mentre io sto facendo solo delle prove di funzionamento(non sono esperto) per capire i concetti basilari. La cosa curiosa che ho notato e che se al posto dei moduli bluetooth inserisco due moduli Xbee tutto funziona benissimo.

Es (se invii solo ascii): 0x02 -- messaggio -- 0x03
Come mai questi due valori esadecimali? Hanno uno scopo preciso ?

Storicamente per le comunicazioni seriali sono usati questi due.
In effetti su alcune tabelle ascii sono chiamati 0x02 -->STX (start communication) ed 0x03 --> ETX (end of communication).
In pratica semplicemente basta usare due caratteri che sa siano diversi da quelli che invii in modo da renderli univocamente indentificabili (es. se invii solo esadecimale A-Z, 0-9 sicuramente 0x02 e 0x03 sono fuori dal range)

Per completezza del post... dopo innumerevoli tentativi, penso di aver trovato il problema delle letture incomplete che secondo me sta nella velocità di Arduino a fare le elaborazioni rispetto al flusso di dati in ingresso dei moduli BT.

Inserendo un delay, il tutto si è stabilizzato e funziona benissimo ininterrottamente ormai da 3 giorni.

Il codice funzionanate pertanto è questo:

  if(mySerial.available()>0){
    stampabile = "";                       // pulisce la stringa
    lcd.clear();                             // pulisci lo schermo
    delay(20);                              // attende l'arrivo dei caratteri                     
    while(mySerial.available()){
      char ext = mySerial.read();         // leggo
      stampabile += ext;                   // aggiungo il carattere letto alla stringa  
    }
    lcd.setCursor(0, 0);
    lcd.print("Potenza " + stampabile + " W");  
  }

Ho scritto anche del codice senza l'utilizzo delle stringhe ma con dei caratteri identificativi di inizio e fine come consigliatomi ed ugualmente il tutto funziona bene nonostante la lunghezza maggiore rispetto a quanto sopra indicato.
Grazie a tutti