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");
}
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.
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....
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");
}
}
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 ...
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