Serielle Schnittstelle im extra Thread

Alles rund um die Programmierung mit Qt
Antworten
lockerlicky
Beiträge: 3
Registriert: 14. August 2018 15:28

Serielle Schnittstelle im extra Thread

Beitrag von lockerlicky »

Hey Leute,
ich sitze schon eine Weile an dem Problem mit Qt ein Programm zu schreiben welches mir die Serielle Schnittstelle ausliest und die gelesenen Daten verarbeitet. Ich hab das ganze Programm in einem Thread gelöst allerdings hat das Programm ein paar Pakete verschluckt (wahrscheinlich beim erstellen der GUi und so).

Nun versuche ich es mit einem zweiten Thread zu lösen aber ich schaff es einfach nicht meine Variable aus Thread 1 dem 2. zu übergeben. Ich steh auf dem Schlauch kann mir bitte einer weiterhelfen und vllt Tipps geben was man an meinem Programm besser machen kann? Ich bin neu in der C++ und GUI Entwicklung.

Hier ist die Fehler Ausgabe:

Code: Alles auswählen

QObject::connect: No such signal QThread::dataRead() in ..\test_serial\mainwindow.cpp:15
QObject::connect:  (receiver name: 'MainWindow')
Danke für eure Hilfe!

main.cpp

Code: Alles auswählen

#include "mainwindow.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    MainWindow w;
    w.show();

    return a.exec();
}
mainwindow.cpp

Code: Alles auswählen

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include "worker.h"
#include <QDebug>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    worker *mWorker = new worker;
    mWorker->moveToThread(&mThread);
    mWorker->initPort();
    connect(&mThread,SIGNAL(finished()),mWorker,SLOT(deleteLater()));
    connect(&mThread,SIGNAL(dataRead()),this,SLOT(protokoll())); // Ich glaube hier liegt mein Fehler??
    mThread.start();
}

MainWindow::~MainWindow()
{
    mThread.quit();
    mThread.wait();
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{

}

void MainWindow::protokoll(QByteArray datas){
    qDebug() << datas; // Hier kommt nichts an...
}
worker.cpp

Code: Alles auswählen

#include "worker.h"
#include <QDebug>


worker::worker(QObject *parent) : QObject(parent){

}

worker::~worker()
{
    delete portCom;
    portCom=NULL;
}

void worker::initPort()
{
    if(portCom==NULL){
        portCom = new QSerialPort;
        portCom->setBaudRate(QSerialPort::Baud115200);
        portCom->setDataBits(QSerialPort::Data8);
        portCom->setParity(QSerialPort::NoParity);
        portCom->setStopBits(QSerialPort::OneStop);
        portCom->setFlowControl(QSerialPort::NoFlowControl);
    }
    if(portCom->isOpen()) portCom->close();
    portCom->setPortName("COM6");
    if(portCom->open(QSerialPort::ReadWrite)){
        connect(portCom, &QSerialPort::readyRead, this, &worker::readData);
    }
    else
        qDebug() << "Port Open Failure";
}

void worker::readData()
{
    datas=(portCom->readAll().toHex());
    emit dataRead(datas);
    qDebug() << datas.mid(2,2).toInt(0,16);  //Counter - Position
}
mainwindow.h

Code: Alles auswählen

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QThread>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT
    QThread mThread;

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

public slots:
    void on_pushButton_clicked();
    void protokoll(QByteArray);

private:
    Ui::MainWindow *ui;
};

#endif // MAINWINDOW_H
worker.h

Code: Alles auswählen

#ifndef WORKER_H
#define WORKER_H

#include <QObject>
#include <QThread>
#include <QtSerialPort/QSerialPort>

class worker : public QObject
{
    Q_OBJECT
    QSerialPort* portCom=NULL;
public:
    explicit worker(QObject *parent = 0);
    ~worker();

signals:
    void dataRead(QByteArray);

public slots:
    void initPort();
    void readData();

private:
    QByteArray datas;
};

#endif // WORKER_H
Zuletzt geändert von lockerlicky am 6. September 2018 18:33, insgesamt 1-mal geändert.
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: Serielle Schnittstelle im extra Thread

Beitrag von Christian81 »

Ich sehe hier absolut keinen Grund einen Thread zu benutzen - er macht ja im Grunde gar nichts...
Außerdem hast Du nicht gesagt was genau für ein Problem Du jetzt hast. initPort() sollte m.E. im Thread-Kontext passieren und nicht im Main-Thread aber das sollte hier nicht das Problem sein.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
lockerlicky
Beiträge: 3
Registriert: 14. August 2018 15:28

Re: Serielle Schnittstelle im extra Thread

Beitrag von lockerlicky »

Entschuldige! Hier ist die Ausgabe hab ich vergessen:

Code: Alles auswählen

QObject::connect: No such signal QThread::dataRead() in ..\test_serial\mainwindow.cpp:15
QObject::connect:  (receiver name: 'MainWindow')
Diese Funktion wird leider nicht aufgerufen:

Code: Alles auswählen

void MainWindow::protokoll(QByteArray datas){
    qDebug() << datas; // Hier kommt nichts an...
}
Ich sehe hier absolut keinen Grund einen Thread zu benutzen - er macht ja im Grunde gar nichts...
Die Daten über die Serielle Schnittstelle kommen andauernd in einer Schleife und die Idee war: das Auslesen in einen Thread zu packen und einen zweiten der die Daten verarbeitet. Wenn ich alles in einem erledige werden ein paar Pakete verschluckt. Die Pakete haben einen Zähler daran erkenn ich gut welche Pakete verloren gehen.
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: Serielle Schnittstelle im extra Thread

Beitrag von Christian81 »

Das Signal ist ja auch in worker, nicht in QThread ...
Wenn die Verarbeitung wirklich lange dauert dann würde ich es verstehen aber zum einen liest Du in dem Thread die Daten nur aus und die Verarbeitung ist immer noch im Main-Thread und zum anderen puffert QSerialPort auch noch - so schnell kann an einem seriellen Port gar nichts ankommen als dass man es nicht verarbeiten kann. Da muss was anderes faul sein.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
lockerlicky
Beiträge: 3
Registriert: 14. August 2018 15:28

Re: Serielle Schnittstelle im extra Thread

Beitrag von lockerlicky »

Christian81 hat geschrieben: 6. September 2018 20:23 Das Signal ist ja auch in worker, nicht in QThread ...
Wenn die Verarbeitung wirklich lange dauert dann würde ich es verstehen aber zum einen liest Du in dem Thread die Daten nur aus und die Verarbeitung ist immer noch im Main-Thread und zum anderen puffert QSerialPort auch noch - so schnell kann an einem seriellen Port gar nichts ankommen als dass man es nicht verarbeiten kann. Da muss was anderes faul sein.
Hey vielen Dank für deine Antwort @Christian81 sie hat mir weitergeholfen!
Ich konnte den Fehler beheben. Ich hab das ganze jetzt mal in 3 Threads aufgeteilt in einen Worker-Thread (zum Auslesen der Schnittstelle), einen Protokoll-Thread (der die Verarbeitung der Daten übernimmt) und den main/gui Thread. Diese Threads lass ich jeweils den Zähler ausgeben der in den empfangen Daten steht. Hier sieht man gut das der Worker-Thread jedes Datenpaket empfängt aber der Protokoll-Thread bzw die GUI nicht mehr nach kommen (zb. 17 und 19). Mit einem anderen Programm hab ich mir nur mal die Daten anzeigen lassen und manchmal kommen in weniger als einer Millisekunde 8 Datenpakete an.
Habt ihr eine Idee wie ich das Protokoll beschleunige damit es bei meiner GUi ankommt?
Ich habe schon überlegt den Worker in eine Liste schreiben zu lassen und dann den Protokoll Thread diese Liste abarbeiten zu lassen. Damit wenigstens die Werte nicht verloren gehen.

Hier ist eine Ausgabe:

Code: Alles auswählen

16 WORK
16 PROTOKOLL
17 WORK
"16" GUI - 2
18 WORK
18 PROTOKOLL
19 WORK
"18" GUI - 2
20 WORK
20 PROTOKOLL
21 WORK
"20" GUI - 2
22 WORK
"22" GUI - 1
23 WORK
23 PROTOKOLL
24 WORK
"23" GUI - 2
mainwindow.cpp

Code: Alles auswählen

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QSerialPort>
#include "worker.h"
#include <QString>
#include "protokoll.h"

QSerialPort *serial;

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);
//Worker und Protokoll Thread Init...
    worker *mWorker = new worker;
    mWorker->moveToThread(&serial);
    mWorker->initPort();
    protokoll *mProtokoll = new protokoll;
    mProtokoll->moveToThread(&parser);

    connect(&serial,SIGNAL(finished()),mWorker,SLOT(deleteLater()));
    connect(mWorker,SIGNAL(dataRead(QByteArray)),mProtokoll,SLOT(parsingData(QByteArray)));

    connect(&parser,SIGNAL(finished()),mProtokoll,SLOT(deleteLater()));
    connect(mProtokoll,SIGNAL(vParsed(QString, QString, QString, QString, QString)),this,SLOT(vDaten(QString, QString, QString, QString, QString)));
    connect(mProtokoll,SIGNAL(grammParsed(QByteArray, QString)),this,SLOT(grammDaten(QByteArray, QString)));
    serial.start();
    parser.start();

//QtCustomPlot Initialisierung
    ui->plot->addGraph();
    ui->plot->graph(0)->setPen(QPen(QColor(40,110,255)));
    ui->plot->yAxis->setRange(0, 255); //255
    ui->plot->xAxis->setRange(0, 300); //300
}

MainWindow::~MainWindow(){
    serial.quit();
    serial.wait();
    parser.quit();
    parser.wait();
    delete ui;
}

void MainWindow::vDaten(QString v1,QString v2,QString v3,QString v4, QString counter){

    ui->label_v1->setText(v1);
    ui->label_v2->setText(v2);
    ui->label_v3->setText(v3);
    ui->label_v4->setText(v4);
    qDebug() << counter << "GUI - 1";

}

void MainWindow::grammDaten(QByteArray datas, QString counter){
    for(int i = 0; i < 15; i++){
        qv_x.append(qv_x.length());
        qv_y.append(datas.mid((8 + i*2), 2).toInt(0, 16));
        ui->plot->xAxis->setRange(qv_x.length(), 100, Qt::AlignRight);
        plot();
    }
    qDebug() << counter << "GUI - 2";
}

void MainWindow::clearData(){
    qv_x.clear();
    qv_y.clear();
}

void MainWindow::plot(){
    ui->plot->graph(0)->setData(qv_x, qv_y);
    ui->plot->replot();
    ui->plot->update();
}


void MainWindow::on_btm_clear_clicked(){
    clearData();
    plot();
}
protokoll.cpp

Code: Alles auswählen

#include "protokoll.h"
#include <QDebug>
#include "mainwindow.h"

protokoll::protokoll(QObject *parent) : QObject(parent){
}

protokoll::~protokoll(){
}

void protokoll::parsingData(QByteArray datas){

    counter = QString::number(datas.mid(2,2).toInt(0,16));

    if(datas.mid(7,1).toInt(0,16) == 4){
            if(datas.mid(8,2).toInt(0,16) <= 100)
            {
                v1 = (QString::number(datas.mid(8,2).toInt(0,16)));
            }
            else
            {
                v1 = "---";
            }

            if(datas.mid(10,4).toInt(0,16) <= 300)
            {
                v2 = (QString::number(datas.mid(10,4).toInt(0,16)));

            }
            else
            {
                v2 = "---";
            }
            if(datas.mid(14,4).toInt(0,16) <= 200)
            {
                double number = datas.mid(14,4).toInt(0,16);
                v3 = QString("%1").arg(number/10,0,'f',1);

            }
            else
            {
                v3 = "---";
            }
            if(datas.mid(18,2).toInt(0,16) <= 100)
            {
                v4 = QString::number(datas.mid(18,2).toInt(0,16));

            }
            else
            {
                v4 = "---";
            }
            emit vParsed(v1, v2, v3, v4, counter);
    }

    if( datas.mid(7,1).toInt(0,16) == 2){
        emit grammParsed(datas, counter);
        qDebug() << datas.mid(2,2).toInt(0,16) << "PROTOKOLL";  //Counter - Position
    }
}
worker.cpp

Code: Alles auswählen

#include "worker.h"
#include <QDebug>
#include "mainwindow.h"


worker::worker(QObject *parent) : QObject(parent){

}

worker::~worker()
{
    delete portCom;
    portCom=NULL;
}

void worker::initPort()
{
    if(portCom==NULL){
        portCom = new QSerialPort;
        portCom->setBaudRate(QSerialPort::Baud115200);
        portCom->setDataBits(QSerialPort::Data8);
        portCom->setParity(QSerialPort::NoParity);
        portCom->setStopBits(QSerialPort::OneStop);
        portCom->setFlowControl(QSerialPort::NoFlowControl);
    }
    if(portCom->isOpen()) portCom->close();
    portCom->setPortName("COM6");
    if(portCom->open(QSerialPort::ReadWrite)){
        connect(portCom, &QSerialPort::readyRead, this, &worker::readData);
    }
    else
        qDebug() << "Port Open Failure";
}

void worker::readData()
{
    datas=(portCom->readAll().toHex());
    emit dataRead(datas);
    qDebug() << datas.mid(2,2).toInt(0,16) << "WORK";  //Counter - Position
}
mainwindow.h

Code: Alles auswählen

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QThread>

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

    QThread serial;
    QThread parser;

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

    void clearData();
    void plot();

private slots:
    void serialReceived();
    void on_btm_clear_clicked();

    void vDaten(QString, QString, QString, QString, QString);
    void grammDaten(QByteArray, QString);

private:
    Ui::MainWindow *ui;

    QVector<double> qv_x, qv_y;
};

#endif // MAINWINDOW_H
protokoll.h

Code: Alles auswählen

#ifndef PROTOKOLL_H
#define PROTOKOLL_H

#include <QObject>
#include <QThread>

class protokoll : public QObject{
    Q_OBJECT

public:
    explicit protokoll(QObject *parent = 0);
    ~protokoll();
signals:
    void vParsed(QString, QString, QString, QString, QString);
    void grammParsed(QByteArray, QString);

public slots:
    void parsingData(QByteArray);

private:
    QString counter;
    QByteArray datas;
    QString v1;
    QString v2;
    QString v3;
    QString v4;
};

#endif // PROTOKOLL_H
worker.h

Code: Alles auswählen

#ifndef WORKER_H
#define WORKER_H

#include <QObject>
#include <QThread>
#include <QtSerialPort/QSerialPort>

class worker : public QObject
{
    Q_OBJECT
    QSerialPort* portCom=NULL;

public:
    explicit worker(QObject *parent = 0);
    ~worker();

signals:
    void dataRead(QByteArray);

public slots:
    void initPort();
    void readData();

private:
    QByteArray datas;
};

#endif // WORKER_H
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Re: Serielle Schnittstelle im extra Thread

Beitrag von Christian81 »

Da bei Signals/Slots keine Daten verloren gehen können und schon gar nicht bei dieser geringen Datenrate muss es es anderes Problem sein.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Antworten