Streaming seriale ... disordinato : comunicazioni tra QT e microcontrollori
-
Ciao a tutti, ho un problema con la lettura di un flusso dati da seriale.
In pratica il pc (Win10) legge i pacchetti passati da un microcontrollore (Arduino UNO o STM32), tali pacchetti consistono in una serie di 8 valori racchiusi tra parentesi quadre e separati
da una virgola:[357,3812,375,357,3811,375,3811,0][357,3814,375,357,3812,375,3812,0] ecc
In particolare il secondo valore si riferisce al valore di millis(), cioè al tempo trascorso in millisecondi, mentre il quarto, il quinto e il sesto contengono i primi tre valori
del pacchetto precedente a scopo di debug, il settimo è ancora il millis() e l'ultimo è una variabile di controllo che assume il valore uno nel caso il 4°, il 5° o il
6° valore non concordassero con quelli precedenti. Tale controllo viene fatto dal microcontrollore per verificere problemi interni.
Il problema però è sul lato PC.
il mio programmino legge la seriale tramite://Funzione di lettura seriale "arduino" void MainWindow::readSerial() { char * dataBuffer; uint16_t size = arduino->bytesAvailable(); //qDebug() << " size" << size; dataBuffer = new char[size + 1]; // + 1 byte for '\0' arduino->read(dataBuffer, size); dataBuffer[size] = '\0'; // to cut a long story short ;-) if (dataBuffer!="") { //Salva il file nel percorso indicato da pathfile. Il file sarà "dataraw_yy_mm_dd-hh_mm_ss" QString dateTimeStringraw=(pathfile+"dataraw_"+dateTimeString); QFile fOut(dateTimeStringraw); if (fOut.open(QFile::WriteOnly | QFile::Text | QIODevice::Append)) { QTextStream z(&fOut); z << dataBuffer << '\n'; fOut.close(); } else { . std::cerr << "error opening output file\n"; // return EXIT_FAILURE; }
tutto sembra procedere bene (a volte anche 25min di acquisizione a 230400 baud) finchè, improvvisamente:
[290,862252,0,290,862249,0,862249,0] 1927 32768
[290,862254,0,290,862252,0,862252,0] 1927 32768
[290,862256,0,290,862254,0,862254,0] 1927 32768
[290,862258,0,290,862256,0,86226,0,866206,0] 1928 32768 <-----
[368,866211,0,368,866208,0,866208,0] 1928 32768
[368,866213,0,368,866211,0,866211,0] 1928 32768
[370,866215,0,368,866213,0,866213,0] 1928 32768
[370,866217,0,370,866215,0,866215,0] 1928 32768....
[372,866571,0,372,866569,0,866569,0] 1928 32768
[372,866573,0,372,866571,0,866571,0] 1928 32768
[372,866575,0,372,866573,0,866573,0] 1928 32768
[372,866577,0,372,8665723,0] 1928 32768 <------
[308,862627,0,309,862625,0,862625,0] 1928 32768
[309,862629,0,308,862627,0,862627,0] 1928 32768
....I valori che seguono la parentesi chiusa indicano il numero di chiamate di arduino->read(dataBuffer, size) e il valore di "size", cioè il valore di arduino->bytesAvailable();
Da quello che ho visto l'errore si verifica quando c'è una nuova lettura.
Da notare che il tempo prima "salta" avanti di circa 4sec e poi torna indietro di circa 4sec.
I valori di controllo (4°,5° e 6° valore) sembrano conservati come se non fosse un errore di trasmissione ma, piuttosto , qualcosa avesse sovrascitto la parte evidenziata tra le due frecce e, in effetti, i due valori di tempo "esterni" all'errore (862258 e 862627) coprono circa lo stesso intervallo di quello "interni" ( 866211 e 866577).
La mia impressione è che il buffer vada in overflow e continui a prendere valori che poi andranno a sovrascrivere la parte iniziale del buffer stesso ( forse ho detto una bestialità...) ma non capisco il perchè... (il valore finale della terz'ultima riga "8665723" potrebbe essere il 866575 con il 5 troncato- quindi (86657) - che ha sovrascritto un 862623 (valore plausibile per la riga precedente) ->(86657)(23))
La parte finale del file, interrotta , è:[368,866017,0,368,866015,0,866015,0]
[368,866019,0,368,866017,0,866017,0]
[368,866021e potrebbe essere sensato come ordine di grandezza.
Qualcuno ha qualche consiglio? Il problema non sembra influenzato dalla velocità di trasmissione, penso sia più un problema di controllo dei dati...
Grazie 1000 -
Ciao, si tratta di un protocollo elementare, a caratteri stampabili.
Lato pc il buffer di lettura è enorme e dubito proprio che vada in overflow. Ad ogni modo basta che provi con un putty o con qualche altro programma a monitorare la seriale e vedi subito se l'errore è lato pc o lato mico.
Se vuoi puoi usare questo programma
http://www.denisgottardello.it/QtComPort/index.php
di cui trovi anche i sorgenti
metterlo in bridge tra micro e programma pc e vedere cosa di dicono programma e pc.
Secondo me il problema sta lato micro, ma senza codice è dura vedere dove sta il problema.
Non avete previsto un crc o qualcosa del genere? -
Ciao e grazie per il suggerimento, in effetti monitorando contemporaneamente la porta potrei vedere subito se i problemi dipendono dalla comunicazione o dal programma in acquisizione. Avevo rinunciato al controllo crc perchè alla fine dovrei leggere i dati provenienti da un altro micro e sul quale non potrei intervenire sul codice di uscita. L'idea dell'overflow era in effetti buttata lì, idee che vengono all'una di notte...
Non ho messo il codice del micro perchè è poco più di una sequenza di Serial.print e non volevo appesantire troppo il post.
Lunedì controllo e posto i risultati.
Grazie mille e buon fine settimana a tutti. -
Un grazie immenso a drdebug, grazie al suo consiglio ho visto subito che il problema era proprio nel micro (o, meglio , nei micro visto che ho usato un Arduino UNO e un STM32...), ora devo capire perchè, visto che -come ho già detto- è poco più di una serie di Print.Serial().
I#define SERIAL_SPEED 115200 const int y_Pin = A0; const int trav_pin = A1; const int delayTime = 700; int test = 0; struct { unsigned long time_x; uint16_t y_value; uint16_t tr_value; unsigned long time_x_old; uint16_t y_value_old; uint16_t tr_value_old; } csv_array; uint16_t y_value_temp; uint16_t tr_value_temp; uint16_t y_value_arch; uint16_t tr_value_arch; unsigned long time_x_arch; bool start = true; void setup() { Serial.begin(SERIAL_SPEED); csv_array.time_x = millis(); Serial.flush(); } void loop() { for (;;) { y_value_temp = analogRead(y_Pin); tr_value_temp = analogRead(trav_pin); csv_array.time_x_old = csv_array.time_x; csv_array.y_value_old = csv_array.y_value; csv_array.tr_value_old = csv_array.tr_value; csv_array.y_value = map(y_value_temp, 0, 1023, 0, 1023); csv_array.tr_value = map(tr_value_temp, 0, 1023, 0, 1023); csv_array.time_x = millis(); if (start == false) { if (y_value_arch != csv_array.y_value_old) { test = 1; } if (tr_value_arch != csv_array.tr_value_old) { test = 1; } if (time_x_arch != csv_array.time_x_old) { test = 1; } if (csv_array.time_x_old > csv_array.time_x) { test = 1; } } start = false; Serial.print("["); Serial.print(csv_array.y_value); Serial.print(","); Serial.print(csv_array.time_x); Serial.print(","); Serial.print(csv_array.tr_value); Serial.print(","); Serial.print(csv_array.y_value_old); Serial.print(","); Serial.print(csv_array.time_x_old); Serial.print(","); Serial.print(csv_array.tr_value_old); Serial.print(","); Serial.print(time_x_arch); Serial.print(","); Serial.print(test); Serial.print("]"); Serial.flush(); y_value_arch = csv_array.y_value; tr_value_arch = csv_array.tr_value; time_x_arch = csv_array.time_x; } }
Grazie comunque a tutti, il codice QT in realtà è parte di un progetto più complesso e fare il debug di tutto , temendo di essere vittima di un errore annidiato in un ciclo if o di un vero e proprio errore di impostazione , beh , mi stava già facendo venire il mal di testa! ;-)