Problem Mit Qextserialport und Qt

Alles rund um die Programmierung mit Qt
Manax
Beiträge: 10
Registriert: 19. März 2010 12:07

Problem Mit Qextserialport und Qt

Beitrag von Manax »

Hallo Qt-Gemeinde

Ich hoffe ihr könnt mir weiterhelfen.

Erstmal die Umgebung

Windows XP aktuelle Updates
Qt aktuelle Version
QextserialPort 1.2 und 1.1

Mit folgender Code funktioniert einfach nicht so wie er soll. Die Variable erg wird nicht inkrementiert obwohl sie das theoretisch mit ablauf des Porttimers machen sollte. Der Port kann nicht per Hyperterminal angesprochen werden, daher ist er scheinbar korrekt vom Programm erkannt und auch belegt.

Hier der Code
serialport.cpp

Code: Alles auswählen

#include <serialport.h>
//******************************************************************************
SerialPort::SerialPort(QWidget *parent)
{
   erg=0;
   timerPort=new QTimer(this);
   connect(timerPort, SIGNAL(timeout()), this, SLOT(fetchData()));
   serialPort = new QextSerialPort();
}
//******************************************************************************
void SerialPort::changeParas(QString &name, PortSettings &para)
{
   serialPort->setPortName(name);
   serialPort->setBaudRate(para.BaudRate);   
   serialPort->setFlowControl(FLOW_OFF);
   serialPort->setParity(PAR_NONE);
   serialPort->setDataBits(DATA_8);
   serialPort->setStopBits(STOP_1);
}
//******************************************************************************
void SerialPort::openPort()
{
   serialPort->open(QIODevice::ReadWrite);
   timerPort->start(30);
   emit(portOpened());
}
//******************************************************************************
void SerialPort::closePort()
{
   serialPort->close();
   timerPort->stop();
   emit(portClosed());
}
//******************************************************************************
void SerialPort::fetchData(void)
{
  char buff[1024];
  int numBytes;
  erg++;
  numBytes = serialPort->bytesAvailable();
	
  if(numBytes > 0) 
  {
    if(numBytes > 1024) numBytes = 1024;
    while(serialPort->bytesAvailable()>12){     //readLine macht nicht exklusiv beim \n Stopp
      serialPort->readLine(buff, numBytes);
      QString msg = buff;
      erg++;
      if(msg=="t"){
      erg++;
      }
     }
  }
  emit(dataReady());
}
//******************************************************************************
double SerialPort::giveValue()
{
   return erg;
}


//******************************************************************************
void SerialPort::clearerg()
{
    erg=0;
}

//******************************************************************************
void SerialPort::sendData(QByteArray befehl)
{
  if(serialPort->isOpen()){
    serialPort->write(befehl, 1);   //Steuerung soll nur ein Char sein
  }
}
//******************************************************************************



Hier die Headerdatei serialport.h

Code: Alles auswählen

#ifndef SERIALPORT_H
#define SERIALPORT_H

#include <qextserialport.h>
#include <QTimer.h>

class SerialPort  : public QextSerialPort
 {
     Q_OBJECT
  private:
    QextSerialPort* serialPort;
    QTimer *timerPort;
    double erg;

 public:
    SerialPort(QWidget *parent = 0);
    void changeParas(QString &name, PortSettings &para);    
    double giveValue(void);
    void sendData(QByteArray befehl);
    void clearerg(void);

 private slots:
    void fetchData(void);

public slots:
    void openPort();
    void closePort();

 signals:
	void portOpened();
	void portClosed();
	void dataReady();
 };

#endif

hier meine Datei mit der aufrufenden Funktion

kartgui.cpp

Code: Alles auswählen

#include "kartgui.h"
#include "ui_kartgui.h"
#include "SerialPort.h"


MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
ui->setupUi(this);
timerLCD=new QTimer(this);
timerZZP=new QTimer(this);
timerRPM=new QTimer(this);
port=new SerialPort();

verbunden = "Verbindung wurde hergestellt";
getrennt = "Verbindung wurde getrennt";

connect(timerLCD, SIGNAL(timeout()), this, SLOT(updatedrehzahl_LCD()));
connect(timerZZP, SIGNAL(timeout()), this, SLOT(updatezzp_LCD()));
connect(timerZZP, SIGNAL(timeout()), this, SLOT(updatevorz_LCD()));
connect(timerRPM, SIGNAL(timeout()), this, SLOT(drehzahl()));

connect(ui->pushButtonTrennen, SIGNAL(clicked(bool)), this, SLOT(trennenButtonClicked()));
connect(ui->pushButtonVerbinden, SIGNAL(clicked(bool)), this, SLOT(verbindenButtonClicked()));
connect(ui->spinBox, SIGNAL(valueChanged(int)), this, SLOT(maxdrehzahl()));

connect(port, SIGNAL(portOpened()), this, SLOT(connected()));
connect(port, SIGNAL(portClosed()), this, SLOT(disconnected()));

maxrpm=ui->spinBox->value()+100;

ui->progressBar->setMaximum(maxrpm);
ui->progressBar->setMinimum(0);
ui->statusBar->showMessage(getrennt);
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::changeEvent(QEvent *e)
{
    QMainWindow::changeEvent(e);
    switch (e->type()) {
    case QEvent::LanguageChange:
        ui->retranslateUi(this);
        break;
    default:
        break;
    }
}
void MainWindow::updatedrehzahl_LCD(void)
{
ui->drehzahlLCD->display(rpm);
ui->progressBar->setValue(rpm);
}

void MainWindow::updatezzp_LCD(void)
{

}

void MainWindow::updatevorz_LCD(void)
{

}

void MainWindow::verbindenButtonClicked(void)
{
ui->drehzahlLCD->display(rpm);
ui->progressBar->setValue(rpm);
timerRPM->start(100);
timerLCD->start(13);
timerZZP->start(500);
port->closePort();

PortSettings para;
QString name;
name=ui->comboBox->currentText();

switch(ui->comboBox_2->currentIndex())
     {
             case 0:
                     para.BaudRate=(BAUD300);
                     break;
             case 1:
                     para.BaudRate=(BAUD600);
                     break;
             case 2:
                     para.BaudRate=(BAUD1200);
                     break;
             case 3:
                     para.BaudRate=(BAUD2400);
                     break;
             case 4:
                     para.BaudRate=(BAUD4800);
                     break;
             case 5:
                     para.BaudRate=(BAUD9600);
                     break;
             case 6:
                     para.BaudRate=(BAUD14400);
                     break;
             case 7:
                     para.BaudRate=(BAUD19200);
                     break;
             case 8:
                     para.BaudRate=(BAUD38400);
                     break;
             case 9:
                     para.BaudRate=(BAUD56000);
                     break;
             case 10:
                     para.BaudRate=(BAUD57600);
                     break;
             case 11:
                     para.BaudRate=(BAUD76800);
                     break;
             case 12:
                     para.BaudRate=(BAUD115200);
                     break;
             case 13:
                     para.BaudRate=(BAUD128000);
                     break;
             case 14:
                     para.BaudRate=(BAUD256000);
     }

    para.Timeout_Millisec=100;
    para.Timeout_Sec=0;
    port->changeParas(name, para);

port->openPort();
}

void MainWindow::trennenButtonClicked(void)
{
rpm=0;
timerRPM->stop();
port->closePort();
}



void MainWindow::connected()
{
ui->statusBar->showMessage(verbunden);
}

void MainWindow::disconnected()
{
ui->statusBar->showMessage(getrennt);
}

void MainWindow::maxdrehzahl(void)
{
maxrpm=ui->spinBox->value();
ui->progressBar->setMaximum(maxrpm);
ui->progressBar->reset();
}

void MainWindow::drehzahl(void)
{
int zzp_wert,vorz=125;
float zzp;
double tick;
zzp=rpm*3/400;
vorz=vorz/5;
zzp_wert=vorz+(zzp/5);
tick=port->giveValue();
rpm=tick*114.285714286;
//port->clearerg();
ui->vorzuendungLCD->display(vorz);
    ui->zzpLCD->display(vorz+(zzp/5));
}

Theretisch sollte ja jetzt nach dem connecten die Funktion fetchdata alle paar ms ausgeführt werden und der angezeigte Wert in der Progressbar und dem Drehzahl LCD sollte sich verändern.
Leider passiert das aber nur wenn ERG direkt in givevalue gesetzt wird ( return erg+10)
Nicht aber über den Timer ( erg++ in fetchData)

Wie kommt es dazu?
Ich hoffe ihr könnt mir helfen.

mfg Manax
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Warum leitest Du von QExtSerialPort ab und hast auch einen Klassenmember QExtSerialPort??
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Manax
Beiträge: 10
Registriert: 19. März 2010 12:07

Beitrag von Manax »

Danke für deine Antwort
Ich habe Serialport als Klasse von Qextserialport weil die auf die Qextserialport zugreift ( routinen sind aus einem Beispiel entnommen) die Qextserialport::QextSerialport wird ja in der include datei von Qextserialport sein.

mfg Jan

p.s. Wenn ich giveValue benutze kommt ja der Wert aus der Funktion zurück nur wenn ich ihn in fetchData inkrementiere dann passiert irgendwie nixs. obwohl ja fetchData theoretisch alle 30 ms aufgerufen wird.
Manax
Beiträge: 10
Registriert: 19. März 2010 12:07

Beitrag von Manax »

Hmm ich bin jetzt vorangekommen.
Der Fehler
QObject: Cannot create children for a parent that is in a different thread.
legt nahe das er das timeout signal nicht bekommt weil der Timer im falschen Thread läuft.
QObject::moveToThread() soll hier angeblich abhilfe schaffen leider weiß ich trotz der Dokumentation nicht wie genau ich das jetzt benutzen soll und finde leider keine Beispiele.

Könnte mir jmd von euch helfen?
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

1. Sehe ich in Deinem Code keine threads
2. Hast du immer och nicht gesagt warum du einmal von QextSerialPort ableitest und einmal einen Member QextSerialPort hast. Du hast somit 2 QextSerialPort - Objekte...
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Manax
Beiträge: 10
Registriert: 19. März 2010 12:07

Beitrag von Manax »

Könntest du mir bitte erklären was du meinst ?

Ich erstelle doch nur ein neues Objekt Serialport von Qextserialport
serialPort = new QextSerialPort();

und serialport ist ne klasse von Qextserialport

class SerialPort : public QextSerialPort

oder hab ich da jetzt was ganz falsch verstanden

beide sind doch bei serialPort im selben thread nämlich QextSerialPort
moggi
Beiträge: 7
Registriert: 7. März 2010 02:36

Beitrag von moggi »

Hi manax,

das Problem auf das Christian hinweisen will, ist das dadurch das deine Klasse von QextSerialPort ableitet, diese alle Funktionen und Eigenschaften dieser Klasse übernimmt. Daher wenn du ein Objekt vom Typ SerialPort erstellst, hast du alle Eigenschaften und Funktionen die du bräuchtest in deinem Objekt.
Durch das erzeugen von einem QextSerialPort Objekt im Konstruktor hast du eigentlich die gleichen Eigenschaften und Funktionen noch mal, auf die du durch deinen privaten Zeiger serialPort zugreifen kannst.

Soweit das Problem, jetzt zur einfachsten Möglichkeit um es zu lösen:

Soweit ich es überblicke musst du deine Klasse SerialPort nicht von QextSerialPort ableiten, da du nicht auf die abgeleiteten Funktionen zugreifst.
Manax
Beiträge: 10
Registriert: 19. März 2010 12:07

Beitrag von Manax »

Danke für eure Hilfe ich hoffe ich habe es richtig umgesetzt. Leider scheint die Veränderung nixs gebracht zu haben.
Hier nochmal die serialport.cpp

Code: Alles auswählen

#include <serialport.h>
//******************************************************************************
SerialPort::SerialPort(QWidget *parent)
{
   erg=0;
   timerPort=new QTimer(this);
   connect(timerPort, SIGNAL(timeout()), this, SLOT(fetchData()));
   //serialPort = new QextSerialPort();
}
//******************************************************************************
void SerialPort::changeParas(QString &name, PortSettings &para)
{
   /*serialPort->setPortName(name);
   serialPort->setBaudRate(para.BaudRate);   
   serialPort->setFlowControl(FLOW_OFF);
   serialPort->setParity(PAR_NONE);
   serialPort->setDataBits(DATA_8);
   serialPort->setStopBits(STOP_1);*/
   setPortName(name);
   setBaudRate(para.BaudRate);
   setFlowControl(FLOW_OFF);
   setParity(PAR_NONE);
   setDataBits(DATA_8);
   setStopBits(STOP_1);
}
//******************************************************************************
void SerialPort::openPort()
{
   //serialPort->open(QIODevice::ReadWrite);
   open(QIODevice::ReadWrite);
   timerPort->start(30);
   emit(portOpened());
}
//******************************************************************************
void SerialPort::closePort()
{
   //serialPort->close();
   close();
   timerPort->stop();
   emit(portClosed());
}
//******************************************************************************
void SerialPort::fetchData(void)
{
  char buff[1024];
  int numBytes;

  numBytes = bytesAvailable();
  //numBytes = serialPort->bytesAvailable();
  erg=erg+1;
  if(numBytes > 0) 
  {
    if(numBytes > 1024) numBytes = 1024;
    //while(serialPort->bytesAvailable()>12){     //readLine macht nicht exklusiv beim \n Stopp
     // serialPort->readLine(buff, numBytes);
      while(bytesAvailable()>12){     //readLine macht nicht exklusiv beim \n Stopp
        readLine(buff, numBytes);
      QString msg = buff;
      if(msg=="t"){
      erg++;
      }
     }
  }
  emit(dataReady());
}
//******************************************************************************
double SerialPort::giveValue()
{
  //  fetchData();
    return erg+10;
}


//******************************************************************************
void SerialPort::clearerg()
{
    erg=0;
}

//******************************************************************************
void SerialPort::sendData(QByteArray befehl)
{
  //if(serialPort->isOpen()){
    //serialPort->write(befehl, 1);   //Steuerung soll nur ein Char sein
    if(isOpen()){
      write(befehl, 1);   //Steuerung soll nur ein Char sein
    }
}
//******************************************************************************
und die Serialport.h

Code: Alles auswählen

#ifndef SERIALPORT_H
#define SERIALPORT_H

#include <qextserialport.h>
#include <QTimer.h>

class SerialPort  : public QextSerialPort
 {
     Q_OBJECT
  private:
    //QextSerialPort* serialPort;
    QTimer *timerPort;
    double erg;

 public:
    SerialPort(QWidget *parent = 0);
    void changeParas(QString &name, PortSettings &para);    
    double giveValue(void);
    void sendData(QByteArray befehl);
    void clearerg(void);

private slots:
    void fetchData(void);

public slots:
    void openPort();
    void closePort();

 signals:
	void portOpened();
	void portClosed();
	void dataReady();
 };

#endif

Leider triggert der timer immer noch nicht die entsprechende Funktion

Wodran hakt es denn jetzt noch

mfg Jan
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

und rufst Du auch openPort() auf?
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Manax
Beiträge: 10
Registriert: 19. März 2010 12:07

Beitrag von Manax »

wird doch im Kartgui beim klicken des Verbinden buttons aufgerufen


Fehlermeldungen im Kompiler sind

Das ist ja i.O.
QObject::connect: Connecting from COMPAT signal (QAction::activated())

Aber was ist hiermit

QObject: Cannot create children for a parent that is in a different thread.
(Parent is SerialPort(0xa8b1cf8), parent's thread is QThread(0xa8aeac8), current thread is QThread(0xa880930)
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Benutzt Du irgendwo Threads?
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Manax
Beiträge: 10
Registriert: 19. März 2010 12:07

Beitrag von Manax »

Na klar den Main Qthread und der Fehlermeldung nach nehme ich mal an Qextserialport hat auch einen in meinem Source steht ja sonst keiner. Aber wie gesagt ich bin anfänger.


Schonmal im vorraus vielen dank für deine Hilfe

timerPort=new QTimer(this);
in der Serialport.cpp hat durch das this den zeiger auf den aktuellen thread ( Qthread) obwohl es Serialport bzw Qextserialport sein sollte oder ?

mfg Jan
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

Wenn Du wirklich keine Threads verwendest weiß ich nicht was noch falsch sein sollte.
In QExtSerialPort Sourcecode habe ich keinen QThread gesehen. Aber vielleicht wissen die mehr...
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
Manax
Beiträge: 10
Registriert: 19. März 2010 12:07

Beitrag von Manax »

trotzdem scheint er ja Fetchdata über den timer net aufzurufen ich kontrolliere das indem ich immer erg abfrage das ja um 1 im takt des timers größer werden müsste.

Oder wird das immer wieder genullt ?
Wann wird denn eigentlich immer Serialport::SerialPort aufgerufen ?

und was bedueten diese fehlermeldungen beim Simulieren ( ausführen in qt umgebung ) ?

mfg Jan
moggi
Beiträge: 7
Registriert: 7. März 2010 02:36

Beitrag von moggi »

Hi,

auch wenn ich nicht verstehe warum SerialPort in einem neuen Thread gestartet wird, könntest du mal versuchen deine Klasse nicht abzuleiten sondern ein Member vom Typ QExtSerialPort zu erstellen und mit diesem zu arbeiten.

Und SerialPort::SerialPort ist der Konstruktor und wird nur bei der Erzeugung einer Instanz aufgerufen.
Antworten