Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. International
  3. Italian
  4. Aggiornare valori letti da seriale su una nuova finestra
QtWS25 Last Chance

Aggiornare valori letti da seriale su una nuova finestra

Scheduled Pinned Locked Moved Solved Italian
7 Posts 2 Posters 1.5k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • L Offline
    L Offline
    lagodolio
    wrote on 5 Nov 2018, 10:29 last edited by lagodolio 11 May 2018, 10:58
    #1

    Salve a tutti, ho un problema con la velocità di aggiornamento dei valori in una finestra.
    Partiamo dal principio: ho un microcontrollore STM32F7 che legge i dati provenienti da due encoder e da un sensore analogico e li invia tramite seriale (velocità 460800bps) al computer a 100hz circa.
    La struttura contenente i dati acquisiti (due valori uint32 -encoder1, encoder2- , un int32 -analog_in- e 8bit del carattere di controllo '$') accupa 104bit, che vengono "impacchettati" attraverso una union.
    Sul lato pc il mio programmino in ambiente QT si occupa di leggere i valori della seriale all'arrivo del readyRead() e li memorizza a sua volta in una union "gemella" (united_data.buffer_csv):

    QObject::connect(stm32_board, SIGNAL(readyRead()), this, SLOT(readSerial()));
    

    La porta seriale è "stm32_board", mentre la funzione readSerial() è quella che si occupa di leggere i dati:

    void Speak_Serial::readSerial()
    {
    
        uint32_t size = stm32_board->bytesAvailable();
        stm32_board->flush();
        if(size<SIZESTRUCT)
        {
            return;
        }
    
        stm32_board->read(temp_buffer, 1);
        while (temp_buffer[0]!='q')
        {
            stm32_board->read(temp_buffer, 1);
    
        }
    
            stm32_board->read(united_data.buffer_csv, SIZESTRUCT-1);
    
            QByteArray buffertemp;
            buffertemp = QByteArray(temp_buffer,1); //copio il carattere di controllo
            char tempo[SIZESTRUCT];
            memcpy(tempo,temp_buffer,1); //tempo e' una var temporanea
            memcpy(tempo+1,united_data.buffer_csv,(SIZESTRUCT-1)); 
    //ora in tempo è contenuto tutto united_data.buffer_csv
    
            memcpy(united_data.buffer_csv,tempo,SIZESTRUCT);
            count_frame++;  // contatore a scopo debug
    
        qDebug() << united_data.csv_array.start_char[0] << "," << united_data.csv_array.encoder1 <<","<<united_data.csv_array.encoder2-<<","<<united_data.csv_array.analog_in;
    }
    
    

    Se provo a stamparli a video attraverso un semplice qDebug() non ho alcun problema, i dati vengono mostrati senza alcun delay significativo e senza perdite.
    A questo punto ho provato ad integrare il codice in un programma più complesso e sono iniziati i dolori.
    La MainWindows() configura la porta e invia un segnale alla presenza di dati sulla seriale , chiamando una funzione che a sua volta -lette e organizzate le variabili- invia un altro segnale per aggiornare i valori (visualizzati attraverso QLCDNumber) in un' altra finestra.
    La cosa funziona ma con latenze mostruose (anche 20sec) e sembra che i valori non vengano aggiornati contemporaneamente: non riesco a capire se il problema può dipendere dai signal
    che forse non sono il sistema migliore per un sistema real time o se la velocità di aggiornamento dei valori in una finestra grafica ha delle limitazioni ....
    Grazie mille a tutti!

    1 Reply Last reply
    0
    • V Offline
      V Offline
      VRonin
      wrote on 5 Nov 2018, 10:56 last edited by
      #2

      Non capisco perche' tu abbia complicato a tal modo il programma, usi 3 buffer temporanei che sono probabilmente inutili.
      Ad ogni modo, per risolvere il problema aggiungi readSerial(); come ultima riga.

      in pratica tu stai implicitamente assumendo che stm32_board->bytesAvailable(); sia sempre <=SIZESTRUCT. Ma non e' cosi'. un singolo readyread puo' portare con se multipli segnali

      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
      ~Napoleon Bonaparte

      On a crusade to banish setIndexWidget() from the holy land of Qt

      1 Reply Last reply
      0
      • L Offline
        L Offline
        lagodolio
        wrote on 5 Nov 2018, 14:16 last edited by
        #3

        Forse la funzione "singola" non è chiarissima: se stm32_board->bytesAvailable() restituisce un valore inferiore a SIZESTRUCT , ovvero se non ci sono abbastanza dati per riempire la struttura, la funzione esce e aspetta un'altra chiamata .
        Se a questo punto i dati sono sufficienti a riempire la struttura (che in realtà viene inviata e ricevuta come flusso di dati non formattato attraverso una union) allora estrae i dati e li stampa.
        Quel brutto giro di memcpy e buffer temporanei c'è perchè in realtà il primo byte (il carattere di controllo $) non verrà archiviato nella struttura finale, quindi ci sarà solo:

        stm32_board->read(united_data.buffer_csv, SIZESTRUCT);
        

        con SIZESTRUCT lungo solo 12byte, quindi temp_buffer e tempo (che avevo usato x debug) andranno a sparire.
        Quello però che non mi convince è che, dopo aver effettuato la lettura, nel momento in cui vado a emettere un segnale per aggiornare i valori nella seconda finestra, il sistema si rallenta, come se la visualizzazione grafica e i due signal creassero delle eccessive latenze.

        1 Reply Last reply
        0
        • V Offline
          V Offline
          VRonin
          wrote on 5 Nov 2018, 15:15 last edited by VRonin 11 May 2018, 15:16
          #4

          Hai aggiunto readSerial(); come ultima riga?

          Il tuo problema e' qui:

          Se a questo punto i dati sono sufficienti a riempire la struttura

          Tu dai per scontato che i dati siano per 1 e 1 sola struttura ma ce ne possono essere multiple nel buffer

          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
          ~Napoleon Bonaparte

          On a crusade to banish setIndexWidget() from the holy land of Qt

          1 Reply Last reply
          0
          • L Offline
            L Offline
            lagodolio
            wrote on 5 Nov 2018, 17:58 last edited by lagodolio 11 May 2018, 18:00
            #5

            Attualmente non ho sottomano il "programmone" (è sul pc fisso, purtroppo mi sono dovuto allontanare dall'ufficio e ho solo il portatile...) quindi la possibilità di fare prove è un po' limitata.
            La logica della funzione readSerial (ma forse non è poi così logica :-) ) dovrebbe essere questa:

            • Lettura di quanti byte sono disponibili sulla seriale
              Se sono insufficienti al riempimento della struttura, il sistema esce e aspetta una nuova chiamata.
            • Se sono sufficienti, vengono letti un numero di byte pari a "SIZESTRUCT" (es 12byte delle 3 variabili int32) e riempite le variabili con i valori acquisiti. Fatto ciò, verranno liberati "SIZESTRUCT" byte sulla porta e questa ora conterrà "size-SIZESTRUCT"byte , con:
              size = stm32_board->bytesAvailable().
            • La funzione ,dopo aver stampato e fatto poco altro, termina e passa il controllo al main, che -grazie al readyRead()- emetterà ancora un segnale (dal momento che rileva dati sulla seriale) e la porta verrà ancora letta, riprendendo il ciclo di controllo dei byte presenti sulla porta e ricominciando l'intero ciclo.

            Bisogna tener conto che i dati vengono generati a circa 100Hz , quindi circa 9600bps teorici. Leggendo a 460800bps -per motivi tecnici- non ci dovrebbero essere problemi di progressivo "intasamento" del buffer.
            Potrei introdurre un ciclo for per far scaricare tutto il buffer all'interno della funzione readSerial(), ma visto che il sistema mi ha retto anche 1000 letture al secondo -che non mi servono!- , mi è sembrato inutile e meno "pulito". La funzione readSerial come riga finale dovrebbe fare la stessa cosa ,anche se in maniera più concisa e forse elegante.
            Domani , codice alla mano, proverò a fare qualche esperimento.
            Ero curioso di sapere se la tecnica SIGNAL/SLOT era utilizzabile , da qualche parte ho letto essere poco efficiente per chiamate continue ma volevo sentire altri pareri.
            Il problema potrebbe essere legato al meccanismo con cui vengono creati i valori QLCDNumber, esistono ad esempio widget più efficaci ?
            Grazie mille ancora

            1 Reply Last reply
            0
            • L Offline
              L Offline
              lagodolio
              wrote on 7 Nov 2018, 10:24 last edited by
              #6

              Risolto!
              Chiedo scusa se scrivo oggi ma ho potuto metter mano al codice solo ora.
              Inserendo un ciclo for che libera tutto il buffer PRIMA dell'uscita dalla funzione ( o , come consigliatomi da VRonin richiamando readSerial() alla fine della funzione readSerial()), il programma corre liscio, senza rallentamenti.
              In pratica prima succedeva questo:

              • Chiamata funzione readSerial() da parte del segnale (readyRead)

              • Verifica dati sufficienti a caricare la struttura

              • Se sì, caricamento dei dati nella struttura. Eventuali dati già disponibili saranno caricati al successivo passaggio.

              • Uscita dalla funzione

              • Nuova chiamata da readyRead in caso di nuovi dati sulla seriale ( o di dati ancora presenti).

              Adesso invece il ciclo è:

              • Chiamata funzione readSerial() da parte del segnale (readyRead)

              • Verifica dati sufficienti a caricare la struttura

              • Se sì, caricamento dei dati nella struttura.

              • Verifica di eventuali dati in grado ancora di riempire la stuttura.

              • Se sì, caricamento dei dati nella struttura in modo ciclico, fino a svuotare il buffer.

              • Uscita dalla funzione

              • Nuova chiamata da readyRead in caso di nuovi dati sulla seriale .

              In pratica nel secondo modo (sintetizzabile in una nuova chiamata di readSerial() alla fine della stessa readSerial(), come suggerito da VRonin) i dati già presenti sul buffer vengono scaricati dalla funzione stessa in modo autonomo, senza attendere nuove chiamate SIGNAL/SLOT.
              Grazie mille ancora a tutti e in particolare a VRonin!

              V 1 Reply Last reply 7 Nov 2018, 10:32
              0
              • L lagodolio
                7 Nov 2018, 10:24

                Risolto!
                Chiedo scusa se scrivo oggi ma ho potuto metter mano al codice solo ora.
                Inserendo un ciclo for che libera tutto il buffer PRIMA dell'uscita dalla funzione ( o , come consigliatomi da VRonin richiamando readSerial() alla fine della funzione readSerial()), il programma corre liscio, senza rallentamenti.
                In pratica prima succedeva questo:

                • Chiamata funzione readSerial() da parte del segnale (readyRead)

                • Verifica dati sufficienti a caricare la struttura

                • Se sì, caricamento dei dati nella struttura. Eventuali dati già disponibili saranno caricati al successivo passaggio.

                • Uscita dalla funzione

                • Nuova chiamata da readyRead in caso di nuovi dati sulla seriale ( o di dati ancora presenti).

                Adesso invece il ciclo è:

                • Chiamata funzione readSerial() da parte del segnale (readyRead)

                • Verifica dati sufficienti a caricare la struttura

                • Se sì, caricamento dei dati nella struttura.

                • Verifica di eventuali dati in grado ancora di riempire la stuttura.

                • Se sì, caricamento dei dati nella struttura in modo ciclico, fino a svuotare il buffer.

                • Uscita dalla funzione

                • Nuova chiamata da readyRead in caso di nuovi dati sulla seriale .

                In pratica nel secondo modo (sintetizzabile in una nuova chiamata di readSerial() alla fine della stessa readSerial(), come suggerito da VRonin) i dati già presenti sul buffer vengono scaricati dalla funzione stessa in modo autonomo, senza attendere nuove chiamate SIGNAL/SLOT.
                Grazie mille ancora a tutti e in particolare a VRonin!

                V Offline
                V Offline
                VRonin
                wrote on 7 Nov 2018, 10:32 last edited by
                #7

                @lagodolio said in Aggiornare valori letti da seriale su una nuova finestra:

                senza attendere nuove chiamate SIGNAL/SLOT.

                Chiarimento minore: readyRead non viene chiamata di nuovo solo perche' ci sono dati non letti, viene chamata solo se arrivano nuovi dati dalla seriale

                "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                ~Napoleon Bonaparte

                On a crusade to banish setIndexWidget() from the holy land of Qt

                1 Reply Last reply
                0

                5/7

                5 Nov 2018, 17:58

                • Login

                • Login or register to search.
                5 out of 7
                • First post
                  5/7
                  Last post
                0
                • Categories
                • Recent
                • Tags
                • Popular
                • Users
                • Groups
                • Search
                • Get Qt Extensions
                • Unsolved