Salve a tutti.
Tempo fa, grazie all'aiuto del forum (e soprattutto di docdoc), sono riuscito a completare il mio piccolo progetto implementando una comunicazione seriale tra un Arduino Due e un Mega che, fino a oggi, ha svolto egregiamente il suo compito. Oggi però, dopo un considerevole aumento di dati inviati e/o trasmessi, mi ritrovo ad avere dei "leggeri" inceppamenti nelle comunicazioni. Lo sketch per la comunicazione ricalca lo schema che mi aveva spiegato docdoc a suo tempo, più o meno (a parte leggere variazioni) il seguente:
// Nota: dimensionare i buffer
#define MAXBUF 8
char buf[MAXBUF]; // Buffer di ricezione
char cmd[MAXBUF-2]; // Ultimo comando ricevuto (esclusi ':' e ';')
...
void loop() {
LeggiComando();
...
}
void LeggiComando() {
if (Serial1.available()) {
char ch = Serial1.read();
// Se il primo carattere non è ':' lo ignoro
if ( c == 0 && ch != ':' )
return;
// Se è il terminatore, elaboro il comando
if ( ch == ';' ) {
// termino la stringa del buffer
buf[c] = '\0';
// Copio il comando nel buffer del comando
strcpy(cmd, buf);
// Resetto il buffer per ricevere i prossimi
c = 0;
// Faccio quello che devo fare, interpretando il comando.
EseguiComando();
}
else {
// Controllo l'overflow del buffer, scartando il pacchetto errato ossia che
// non contiene il terminatore
if (c == MAXBUF-1) {
c = 0;
return;
}
// E' un carattere interno del comando, lo memorizzo nel buffer
buf[c++] = ch;
}
}
}
void EseguiComando() {
// Ad esempio:
if ( strcmp(cmd, "Z2") ) {
// Comando Z2
...
return;
}
if ( strcmp(cmd, "Y3") ) {
// Comando Y3
...
return;
}
... eccetera
}
La mia domanda è la seguente:
se prevedo di inviare pacchetti da 200 bit e/o riceverne altrettanti, più o meno in contemporanea, si può ancora utilizzare la seriale classica(con i dovuti aggiustamenti dello sketch) o risulta limitativa e conviene un altro tipo di protocollo? In sostanza, gli inceppamenti son dovuti a un limite del protocollo o semplicemente a un limite del mio sketch? Preciso che uso le porte HW (Baud 115200) e la comunicazione è a massimo tre metri di distanza.
Grazie a tutti.
Sono 25 byte a pacchetto. Il buffer ne può contenere due interi. Se i pacchetti non arrivano più velocemente di quanto possono essere elaborati (estratti dal buffer), problemi non ce ne dovrebbero essere. Se il dubbio è la distanza,basta provare un collegamento vicino per escludere la causa hardware.
Grazie per la risposta.
I pacchetti sono continui, trattandosi di sistema per il controllo di un telescopio. Quindi vi è la trasmissione dall'unità centrale (Arduino Due) dei dati della posizione corrente, del tempo siderale, dell'ora locale e degli eventuali track attivi. Dal Mega, che fa da interfaccia TFT, vengono spediti i comandi di controllo telescopio. Quindi, per rispondere anche a @speedyant , che ringrazio, direi che i compiti sono egualmente ripatiti.
Quindi come minimo c'è da elaborare un pacchetto ogni 2,17 millisecondi.
Se l'elaborazione delle funzioni richiamate dura più di questo tempo si perdono dati.
Rimane comunque da fare la prova di collegamento a breve distanza.
Poi nella lettura del pacchetto non farei una singola read ad ogni loop, ma scriverei un while che (ad ogni loop) legge "a raffica" tutti i byte finora arrivati:
void LeggiComando()
{
while (Serial1.available())
{
char ch = Serial1.read();
// Se il primo carattere non è ':' lo ignoro
if ( c == 0 && ch != ':' ) continue;
// Se è il terminatore, elaboro il comando
if ( ch == ';' )
{
// termino la stringa del buffer
buf[c] = '\0';
// Copio il comando nel buffer del comando
strcpy(cmd, buf);
// Resetto il buffer per ricevere i prossimi
c = 0;
// Faccio quello che devo fare, interpretando il comando.
EseguiComando();
}
else
{
// Controllo l'overflow del buffer, scartando il pacchetto errato ossia che
// non contiene il terminatore
if (c == MAXBUF-1)
{
c = 0;
continue;
}
// E' un carattere interno del comando, lo memorizzo nel buffer
buf[c++] = ch;
}
}
}
Diciamo che utilizzare il continue non migliora molto, anzi, il codice arriva effettivamente troppo "a valanga". Però potrebbe essere un'idea, calibrando meglio il mio codice. Ci lavorerò su.
Per curiosità, ho provato a inserire uno svuota buffer dopo il strcpy(cmd, buf); con la classica sequenza:
while (Serial1.available()) {
byte temp = Serial1.read();
}
A questo punto funziona quasi tutto, ma purtroppo, nel momento in cui in effetti serve più rapidità (controllo manuale di uno stepper motor), mi blocca.
Piuttosto, se qualcuno ha esperienza al riguardo, mi interesserebbe sapere se una comunicazione RS485 può aiutare a rendere il tutto un po' più equilibrato e non fuori controllo, come succede ora. Ho l'impressione che fino a quando i dati dono pochi, la classica seriale vada più che bene, ma per dati un tantino più complessi, non regga il passo.
Con la 485 cambiano solo le tensioni/correnti sui fili, ma sempre comunicazione seriale asincrona start/stop nrz rimane. Se i problemi non sono hardware, con la 485 non cambierebbe niente.
Proposito, a quanti baudrate sono attualmente impostate?
Siamo già a 115200.
Per quanto riguarda i limiti Hardware ormai sopraggiunti, direi che siamo d'accordo. So che qualcuno, con analogo problema, ha manipolato il buffer seriale, in HardwareSerial.cpp, per aumentare il buffer seriale, ma non vorrei arrivare a tanto...
Se il problema è l'estrazione troppo lenta dal buffer, anche aumentarlo non servirebbe. Bisogna gestire un pacchetto ogni 2,17 ms (compreso tutto quello che c'è da fare a pacchetto ricevuto). Ipotizzo che ci siano troppe altre cose che rallentano questa operazione.
Che comunque, se parliamo di 2 seriali hardware, non è certo la velocità più alta raggiungibile, puoi viaggiare tranquillamente a 10 volte tanto, certo a quel punto la distanza ed il cavo usato cominciano a farsi sentire.
Poi, se come dice Claudio, il problema è nell'elaborazione dei dati andare più veloce non ti servirà a molto, ma puoi senz'altro provare anche ad alzare il baudrate.
In effetti ho provato ad aumentare oltre i 115200 e la cosa peggiora. Credo che, come scrive Claudio (se ho ben capito) si debba gestire meglio il pacchetto dati in base alla finestra temporale. Ciao.
Aggiornamento.
Per il momento ho risolto utilizzando millis().
In sostanza, dal lato TFT (Arduino Mega) veniva lanciata (di continuo) una stringa di richiesta coordinate astronomiche (tecnicamente si chiamano Ascensione Retta e Declinazione), una stringa richiesta orario locale e una stringa richiesta Tempo Siderale; tutti parametri visualizzati in tempo reale sullo schermo TFT. A quel punto l'unità centrale spediva a valanga quei dati (in aggiunta ad eventuali altri comandi tipo comando motore stepper etc.) creando l'inceppamento del sistema.
Usando millis ho "imbrigliato" l'invio delle stringhe ogni 250ms, dando una trasmissione equilibrata. Il codice invio stringa risulterà questo:
unsigned long previousMillis = 0;
.
.
.
.
if (millis() - previousMillis >= 250) { // Se sono passati 250 ms eseguo il codice seg.
MYSERIAL->print(":RC#"); // Invio richiesta coordinate astronomiche
MYSERIAL->print(":LS#"); // Invio richiesta ora locale e ora siderale
readCommands(); // Vado a leggere i miei dati aggiornati
previousMillis = millis(); // "Azzero il timer e lo rendo disponibile per la prossima lettura
}
La pubblico nel caso possa tornare utile ad altri. Non è una soluzione elegantissima ma è molto semplice e funzionale. Grazie a tutti per gli spunti e l'aiuto!
Ciao
Effettivamente stavo anche io proprio per chiederti se fosse necessario un tale flusso continuo di dati, la visualizzione sul TFT sicuramente non richiede un tale dettaglio, e nel tuo caso 4 aggiornamenti al secondo sono più che sufficienti.
Sì, in effetti fino a che non ho effettuato un ultimo aggiornamento, il problema non sussisteva. In sostanza, prima i calcoli erano fatti contemporaneamente dal Mega e dall'Arduino Due. Dopo, come è giusto che sia, ho demandato i calcoli esclusivamente all'Arduino Due, e il controllo del TFT al Mega (che si limita a ricevere gli aggiornamenti da visualizzare, appunto la "valanga" di dati). E lì il sistema è andato in crash, e non tanto per l'entità delle informazioni ricevute, ma per la loro cadenza d'invio. Ora però va di nuovo alla grande!