QextSerialPort

Alles rund um die Programmierung mit Qt
archon
Beiträge: 117
Registriert: 22. August 2006 12:01

QextSerialPort

Beitrag von archon »

Hallo Leute,

ich programmier grad zum ersten mal mit QextSerialPort und hab da so meine Probleme. Ich bin ziemlich sicher dass das senden von einem ASCII String schon funktioniert. Nur beim Empfangen vom port hab ich noch meine Probleme.

Ich möchte einfach Daten empfangen bloss wann weis ich wann daten kommen?

Code: Alles auswählen

#include "mainform.h"
#include <qextserialport.h>

mainform::mainform(QWidget *parent)
    : QMainWindow(parent), port(NULL)
{
	setupUi(this);
	
	port = new QextSerialPort("COM1");
        port->setBaudRate(BAUD9600);   
        port->setFlowControl(FLOW_OFF);
        port->setParity(PAR_NONE);
        port->setDataBits(DATA_8);
        port->setStopBits(STOP_1);
    
    
	connect(sendPushButton, SIGNAL(clicked()), this, SLOT(send_cmd()));
	
	connect(port, SIGNAL(readyRead()), this, SLOT(receiveMsg()));

    openPort();
}

mainform::~mainform()
{

}

void mainform::send_cmd()
{
	QString test = QString("message  \x0D\x0A");
	
	incomingTextEdit->insertPlainText(test);
	port->write(test.toAscii(),test.length());
	
}

void mainform::receiveMsg()
{
        cmdLineEdit->setText("incoming msg");	
	
	char buff[1024];
 	int numBytes;
  
	numBytes = port->bytesAvailable();
	if(numBytes > 0) 
	{
	    if(numBytes > 1024) numBytes = 1024;
	
	    int i = port->read(buff, numBytes);
	    buff[i] = '\0';
	    QString msg = buff;
	
	    incomingTextEdit->insertPlainText(msg);
        }
}

void mainform::closePort()
{
	port->close();
	qDebug("is open: %d", port->isOpen());
}

void mainform::openPort()
{
	port->open(QIODevice::ReadWrite);
	qDebug("is open: %d", port->isOpen());
}

das mit dem Signal readyread() funktioniert so nicht... d.h. er springt erst gar nicht in die receivemsg() funktion.

Weiss jemand Rat?
archon
Beiträge: 117
Registriert: 22. August 2006 12:01

Beitrag von archon »

hmm also eigentlich erbt ja port von qiodevice das readread signal nur wird dieses komischerweise nicht gesendet :?:
kuberka
Beiträge: 26
Registriert: 8. Februar 2006 09:17

Beitrag von kuberka »

Ich habe die read Funktion in ein Thread verpackt.

An sonsten must du die read Funktion über ein timer pollen glaube ich.

Code: Alles auswählen

 

void RS232ReadThread::run()
{


	for(;;)
	{
		
			int numBytes = m_CommPort->bytesAvailable();
			
			if(numBytes>0)
			{
				char buffer[1024];
				
				QByteArray RS232Buffer;
				
				if(numBytes > 1024)
				{
					numBytes = 1024;
				}

			
				m_CommPort->readData(buffer,numBytes);

				for(int k=0;k<numBytes;k++)
				{
					RS232Buffer.append(buffer[k]);
				}
				

				emit recivedBuffer(RS232Buffer,numBytes);
			}
			
			if(stopped)
			{
				stopped=false;
				break;
			}
		
	}
}
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

QExtSerialPort kann (soweit ich weiss) kein readyRead() emitten da die darunterliegende API (zumindest unter Windows) kein Event für Daten am Seriellen Port ausgeben kann. Deswegen ist kuberka's Lösung korrekt.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
archon
Beiträge: 117
Registriert: 22. August 2006 12:01

Beitrag von archon »

Vielen Dank schonmal!

Ok über timer ist die einfachste lösung, hab ich mir auch schon überlegt. Aber gibts da echt keine Alternative? Unter C-Sharp (mitgelieferte rs232 funktion) soll sowas möglich sein (vielleicht compiler abhängig?)... Ich weiss nicht warum aber irgendwie habe ich mit timer aufrufen so meine abneigung da die funktionen sehr oft aufgerufen werden auch wenn nichts im Puffer steht. Der Algorithmuss soll später in einem zertifizierten (zeitkritischen) System ablaufen... vielleicht gehe ich weg von qextserialport und schau nach eine ansi c lösung die ich dann ich qt reinschmeiss... Wie ist eure Meinung?
kuberka
Beiträge: 26
Registriert: 8. Februar 2006 09:17

Abneigung Timer

Beitrag von kuberka »

Genau Timer sind nicht so gut aus oben genanten Gründen.


Deshalb benutze Multithreading und mache es ähnlich wie ich es gemacht habe.

Habe in 2 Großprojekten wo ich dies so ein gesetzt habe und es funktioniert klasse.

Gruss

Torsten
Zuletzt geändert von kuberka am 28. Januar 2008 07:37, insgesamt 1-mal geändert.
methusalem
Beiträge: 186
Registriert: 11. August 2005 08:21

Beitrag von methusalem »

Moin,

bin auch gerade dabei qextserialport zu nutzen. Nun bin ich gerade dabei, auch eine Lösung mit dem Thread zu basteln. Und nun ist mir gerade folgendes aufgefallen.

In dem Beispiel von kuberka wird ja ein Objekt m_CommPort benutzt. Dies ist ja ein QextSerialPort, richtig?

Habt Ihr dieses Objekt in der Klasse RS232ReadThread erstellt? Wenn ja, dann kann ja nur diese Klasse darauf zugreifen.

Aber ich will ja evtl. auch zwischendurch mal auf den Port schreiben. Das kriege ich ja dann außerhalb des RS232ReadThread nicht hin.

Oder habt ihr den Port außerhalb des Threads erstellt und dann an den Thread übergeben?

Ist schon spät und mir raucht der Kopf ... habe bisher noch nicht viel mit Threads gemacht ...
Martin
methusalem
Beiträge: 186
Registriert: 11. August 2005 08:21

Beitrag von methusalem »

Da ich es allgemeiner fragen möchte und es eigentlich nichts mehr mit QextSerialPort zu tun hat, hab ich hier noch mal gefragt: http://qtforum.de/forum/viewtopic.php?p=29871
Martin
comer352l
Beiträge: 47
Registriert: 10. Juli 2007 18:10

Beitrag von comer352l »

Ich kenne QextSerialPort zu wenig, aber vielleicht helfen dir folgende Links zum Thema serielle Schnittstelle bzw. API-Funktionen weiter:

Linux/Unix:
http://www.easysw.com/~mike/serial/serial.html

Windows:
http://msdn2.microsoft.com/en-us/librar ... S.85).aspx

Wie du sehen wirst unterstützt auch die Windows-API mit den Funktionen SetCommMask, GetCommMask und WaitCommEvent events.
In der Praxis macht das aber kaum jemand. Ich beschäftige mich jetzt schon länger mit dem Thema und 95% aller Programme die auf die serielle Schnittstelle zugreifen machen das per Polling in einem separaten Thread... Kann man prima sehen, wenn man mal einen Port Monitor dazwischen klemmt. :wink: :D
kuberka
Beiträge: 26
Registriert: 8. Februar 2006 09:17

Beitrag von kuberka »

Hi methusalem,

m_CommPort ist nur ein Zeiger auf ein CommPortObjet meines Projektes.

Er wir mit dem Konstruktor dem Thread übergeben.

D.h. ich kann jeder Zeit auf mein ComPort im Projekt zugreifen.

Gruss

Torsten
methusalem
Beiträge: 186
Registriert: 11. August 2005 08:21

Beitrag von methusalem »

Hallo Thorsten,

Danke für deine Rückmeldung. Ich hab mir das schon fast so gedacht (das du m_CommPort übergibst).

Ich war am WE auch fleißig und mein kleines Projekt tut eigentlich auch das, was es soll. Nur habe ich ein Problem mit den Daten die ich hier bekomme.

Wenn ich später etwas Zeit habe, poste ich hier noch was dazu. Du scheinst die Klasse QextSerialPort ja einzusetzen. Vielleicht weißt du, was ich noch falsch mache ...
Martin
methusalem
Beiträge: 186
Registriert: 11. August 2005 08:21

Beitrag von methusalem »

so, nun ein paar Worte zu meinem Versuch ...

so sieht der Teil meines Threads aus, der die Daten ausließt:

Code: Alles auswählen

void ReadThread::run(){

        running = true;
        int j = 0;

        serPort->open(QIODevice::ReadOnly);

        while(running){

                int numBytes = serPort->bytesAvailable();
                
                if(numBytes > 0){

                        j++;
                        char buff[1024];
                       
                        if(numBytes > 1024){
                                numBytes = 1024;
                        }
                   
                        int i = serPort->read(buff, numBytes);
                        qDebug("%d out: %s", j, buff);

                        QString st_buff = QString(buff);
                        emit recivedBuffer(st_buff,j);
                }
        }
}
Wenn ich nun unter Windows mit HyperTerm auf diesem COM Port lausche, bekomme ich etwas in dieser Art. Es handelt sich um NMEA Daten eines GPS Empfängers.

Code: Alles auswählen

,,,,*1F
$GPRMC,061928.490,V,5232.1368,N,00810.3515,E,,,280108,,,N*7A
$GPGGA,061929.490,5232.1353,N,00810.3528,E,0,03,,36.1,M,46.8,M,,0000*46
$GPGSA,A,1,01,02,31,,,,,,,,,,,,*1F
$GPRMC,061929.490,V,5232.1353,N,00810.3528,E,,,280108,,,N*7D
$GPGSA,A,1,01,02,31,,,,,,,,,,,,*1F
$GPRMC,061930.490,V,5232.1309,N,00810.3606,E,,,280108,,,N*75
$GPRMC,061929.490,V,5232.1353,N,00810.3528,E,,,280108,,,N*7D
$GPGGA,061930.490,5232.1309,N,00810.3606,E,0,03,,36.1,M,46.8,M,,0000*4E
$GPGSA,A,1,01,02,31,,,,,,,,,,,,*1F
$GPRMC,061930.490,V,5232.1309,N,00810.3606,E,,,280108,,,N*75
Die Ausgabe des Threads hingegen sieht ziemlich geschrottet aus (ist ein anderer Part - kann nicht direkt mit der Ausgabe des HyperTerm verglichen werden):

Code: Alles auswählen

1 out: ,,,,*1F
$GPRMC,061928.490,V,5232.1368,N,00810.3515,E,,,280108,,,N*7A
$GPGGA,061929.490,5232.1353,N,00810.3528,E,0,03,,36.1,M,46.8,M,,0000*46
$GPGSA,A,1,01,02,31,,,,,,,,,,,,*1F
$GPRMC,061929.490,V,5232.1353,N,00810.3528,E,,,280108,,,N*7D
¡
2 out: $GPGGA,061930.490,5232.1309,N,00810.3606,E,0,03,,36.1,M,46.8,M,,0000*4E
$GPGSA,A,1,01,02,31,,,,,,,,,,,,*1F
$GPRMC,061930.490,V,5232.1309,N,00810.3606,E,,,280108,,,N*75
,,,,*1F
$GPRMC,061929.490,V,5232.1353,N,00810.3528,E,,,280108,,,N*7D
¡
3 out: $GPGGA,061930.490,5232.1309,N,00810.3606,E,0,03,,36.1,M,46.8,M,,0000*4E
$GPGSA,A,1,01,02,31,,,,,,,,,,,,*1F
$GPRMC,061930.490,V,5232.1309,N,00810.3606,E,,,280108,,,N*75
,,,,*1F
$GPRMC,061929.490,V,5232.1353,N,00810.3528,E,,,280108,,,N*7D
Ihr seht hier 3 Durchläufe der Schleife des ReadThred (3 mal "out:"). Was man erkennen kann, ist das die Zeilenumbrüche anders sind. Und es gehen offensichtlich Daten verloren. Z.B. sieht die zweitletzte Zeile (,,,,*1F) merkwürdig aus. Hier scheint zu Beginn etwas zu fehlen. Da die letzten 5 Zeilen aber alle aus dem gleichen buff sind und diese Stelle mitten drin liegt, wunder ich mich ein wenig. Wenn die Fehler am Ende wären, könnte ich mir das ja noch erklären.

Hat jemand ne Idee, woher die Unterschiede zwischen dem Thread und HyperTerm kommen?
Martin
archon
Beiträge: 117
Registriert: 22. August 2006 12:01

Beitrag von archon »

Ist ja interessant das du auch GNSS Empfänger serielle Daten auswertest. Genau dasselbe mach ich nämlich auch nur dass ich keine NMEA Daten auswerte.

Vielleicht liegt die Problematik darin das beim Polling der Buffer erst gelöscht werden muss bevor man neue Daten reinschreibt?

Was anderes noch: wenn du per Polling den Buffer abfrägst ...kannst du dann überhaupt sichergehen das die Abschliessende Null eines String sicherübertragen wird?

Wenn man den Befehl readline nutzt muss doch der auf die CR und LF detektieren? Oder nur CR? Vielleicht weiss das jemand?
methusalem
Beiträge: 186
Registriert: 11. August 2005 08:21

Beitrag von methusalem »

Hallo,

ja, ich wollte eigentlich nur schnell feststellen, wie sich bei mir "Static Navigation" auswirkt. Nun wirds wohl doch etwas mehr ...
archon hat geschrieben:...
Vielleicht liegt die Problematik darin das beim Polling der Buffer erst gelöscht werden muss bevor man neue Daten reinschreibt?
Ist das ne Frage oder eine Feststellung? :lol:
Was anderes noch: wenn du per Polling den Buffer abfrägst ...kannst du dann überhaupt sichergehen das die Abschliessende Null eines String sicherübertragen wird?
Ich muss zugeben, das meine Lösung eine "Schnell & Schmutzig" Version ist. Wie fragst du denn die Schnittstelle ab, wenn nicht über polling?
Martin
archon
Beiträge: 117
Registriert: 22. August 2006 12:01

Beitrag von archon »

methusalem hat geschrieben:Wie fragst du denn die Schnittstelle ab, wenn nicht über polling?
comer352l hat doch die Lösung vorgeschlagen mit Events (puffer wird nur immer dann ausgelesen wenn z.B. 1 Byte drinnen ist, ansonsten nicht). Ich bin immer noch der Meinung (auch wenns heisst das 95% mit Polling realisiert wird) dass dies die einzigste konsistente und sichere Lösung ist. Alles andere ist für Hobbyisten. Mal sehen ob das auch wirklich so klappt wie ich mir dass vorstelle. Vielleicht gibts ja noch andere Ansätze? Ich finds halt blöd das die ganze Serielle Anbindung von Qt nicht von Haus aus unterstützt wird. Zum beispiel dass das mit den Signalen nicht klappt find ich halt z.k....
archon hat geschrieben:...
Vielleicht liegt die Problematik darin das beim Polling der Buffer erst gelöscht werden muss bevor man neue Daten reinschreibt?
Probiers doch mal aus den Puffer zu flushen und zeig noch mal die Ergebnisse mit deinem Algorithmus
methusalem hat geschrieben: Ich muss zugeben, das meine Lösung eine "Schnell & Schmutzig" Version ist. Wie fragst du denn die Schnittstelle ab, wenn nicht über polling?
Das ist genau das Gegenteil was ich versuche :wink:
Antworten