Hallo zusammen,
ich verbringe nun schon ungefähr eine Woche damit, von einem "serial
device" mit Hilfe der Qt Klasse <QSerialPort> Daten zu empfangen.
Das Gerät hat einen Loopback Modus und sendet das empfangene Byte
einfach wieder zurück.
Diese Funktion habe ich mit einer Konsole (putty) getestet,
funktioniert. :-)
Ich versuche mal das Problem kurz und anschaulich zu erklären:
Ich schreibe ein "abcdefg" auf den seriellen Bus, dies geschieht in der
main function mit arty.writeCharacter("abcdefg");, siehe:
1
#include<QCoreApplication>
2
#include<QDebug>
3
#include"serial.h"
4
5
intmain(intargc,char*argv[])
6
{
7
QCoreApplicationa(argc,argv);
8
SerialPortarty;
9
10
// Open serial port
11
if(arty.openSerialPort()==false)
12
{
13
qDebug()<<"Could not open serial port";
14
return0;
15
}
16
17
18
for(inti=0;i<10;i++)
19
{
20
arty.writeCharacter("abcdefg");
21
}
22
23
qDebug()<<"End application!";
24
returna.exec();
25
}
Die Ausgabe in der Konsole sieht wie folgt aus: (siehe console.PNG)
Und zu guter letzt die Implementierung:
Ich habe mit diversen Delays und Parametern (FlowControl)
herumexperimentiert, leider ohne Erfolg.
Über Ratschläge und Denkanstöße wäre ich sehr dankbar! :-)
QtNewbie87
Hallo Kai,
es handelt sich um ein Arty Board von Digilent mit einem Xilinx Artix
FPGA drauf.
Ich habe lediglich RX mit TX gekreuzt um eine Loopback zu bekommen.
Diese habe ich mit putty verifiziert.
Unter Qt habe ich Schwierigkeiten. Irgendwo scheint da ein Denkfehler zu
sein. Ich sehe ihn nur nicht.
Gruß,
QtNewbie87
Putty funktioniert? Hast du schon mal geschaut, wie putty das Device
konfiguriert?
Während der Terminalemulator läuft die Device-Parameter auslesen,
beenden, Device-Parameter wieder setzen und das eigene Programm starten.
Hi,
ja, ich habe die Parameter genauso gesetzt wie putty (FlowControl,
Parity, Stop-Bit, etc.)
Mir kam schon der Gedanke, ob man für gleichzeitige Lese- und
Schreibzugriffe wohl besser einen Thread verwendet, allerdings habe ich
das in dem dazugehörigen "terminal" example von Qt nicht gesehen.
Das funktioniert übrigens auch tadellos ...
Mein Beispiel ist davon abgeleitet.
Du benutzt 2 Threads?
Hatte unter Linux einen ähnlichen Effekt - Mit 2 getrennten Programmen
für Ein- und Ausgabe würden die gelesenen Zeichen endlos wiederholt.
Mit dem readyRead() Signal kannst du doch in ein paar Minuten einen Test
mit einem Thread schreiben.
Vielleicht braucht QSerialPort eine Eventloop, um richtig zu
funktionieren. Die startest du ja erst, nachdem du alle deine
Sendeversuche schon abgeschlossen hast.
Hallo zusammen,
danke für eure zahlreichen Antworten und Denkanstöße.
Die Idee mit einem Thread Schreib- und Lesevorgänge zu regeln hört sich
gut an. Ich werde das gleich morgen versuchen.
Der Vorschlag mit der Eventloop geht ja denke ich auch in diese
Richtung.
Falls Jemand weiß, wo man sich ein Beispiel für eine Implementierung
anschauen kann, freue ich mich natürlich :-)
Vielen Dank euch allen!
Sobald ich eine funktionierende Lösung habe, lasse ich euch daran
selbstverständlich teilhaben.
Kleiner Tip:
Das "a.exec();" startet die "Eventloop", die so lange läuft, wie die
QApplication nicht beendet wird!
Da braucht man keine anderen Threads. Die "Signals" werden ebenfalls in
der Eventloop abgehandelt. Daher kann auch kein Datenempfang
funktionieren, solange die nicht läuft.
Setz die "Schreibschleife" in einen Slot, der mit dem "timeout()" von
einem QTimer verbunden ist und konfigurier den auf z.B. 1000ms
SingleShot.
Den startetst Du vor dem Aufruf von "a.exec()". Dann sollte der String
vollständig durchgehen.
Das mit der Eventloop und den Signals ist ein wenig knifflig.
(Weil nicht offensichtlich)
Da ist auch mein Kollege schon drüber gestolpert ;-)
Die Abhandlung über QTHreads kann u.U. hilfreich sein:
http://blog.debao.me/2013/08/how-to-use-qthread-in-the-right-way-part-1/
Das "a.exec()" startet den "MainThread"mit der Eventloop, die dann alle
Events und "Signals" (zumindest die, welche im Hintergrundüber Events
laufen) bearbeitet.
Matthias schrieb:> Da braucht man keine anderen Threads. Die "Signals" werden ebenfalls in> der Eventloop abgehandelt.
Nur bei "queued connection", die man braucht, wenn man über
Thread-Grenzen hinweg Signale mit Slots verbinden will. Innerhalb eines
Thread hat die Eventloop per Default nichts mit der Verbindung zu tun.
> Setz die "Schreibschleife" in einen Slot
Falls trotzdem die Schreibpuffer überlaufen: QSerialPort erbt auch ein
bytesWritten() Signal.
>Die Abhandlung über QTHreads kann u.U. hilfreich sein
Würde ich eher von abraten. Alles im "MainThread" mit der Eventloop
machen und nur wenn ein Slot den MainThread zu lange blockiert über
Threads nachdenken.
>Nur bei "queued connection"
Mit Hilfe eines QTimer kann man auch innerhalb des selben Threads ein
Signal über den Eventloop senden. Bzw. an das Ende der Eventqueue
stellen.
>Nur bei "queued connection", die man braucht, wenn man über
Ich gehe auch davon aus, dass bei QSerialPort in der Backend-Library der
Datenempfang über einen RX-Thread abgehandelt wird. Und dann muss das
"ReadyRead()"-Signal zwangsläufig über eine Queued-Connection und die
EventLoop behandelt werden.
>Würde ich eher von abraten. Alles im "MainThread" mit der Eventloop
Ich meinte eigentlich nicht, dass er weitere Threads aufmachen soll.
In der verlinkten Doku wird das Thema Threads nur etwas erläutert und
auch das Thema "MainThread" erwähnt. Ich hoffe das der TO das nicht
so wie Du verstanden hat.
>Falls trotzdem die Schreibpuffer überlaufen: QSerialPort erbt auch ein>bytesWritten() Signal.
Die Buffer sind per Default auf einem Wert um die 1024..2048 Byte. Die
kleine Schleife schreibt da gerade mal 70 Bytes rein. Der TO möchte ja
auch erstmal was zum Laufen bringen. Er sollte sich natürlich auch
Gedanken machen, was da effektiv an Bytes pro Sekunde über die Leitung
geht (Sicherheitsmarge nicht vergessen) und einen möglichen
Buffer-Overflow im Vorfeld vermeiden.
Hallo,
die eventqeue kann man auch manuell in main.c triggern (also vor a.exec)
a->processEvents();
das vorweg.
Ich mache nach einem write() immer ein flush() (am einfachsten bei Dir
in der routine serialport::writedata())
speziell bei Windows bewirkte das manchmal Wunder. Nach flush() schrieb
er wirklich auf den serialport, sonst nur in irgendeinen Buffer.
Grüße
-Martin
Vielen Dank für die vielen Ratschläge! :-)
Leider kam ich zeitlich noch nicht dazu an meinem Projekt großartig
weiterzuarbeiten. Immer mal wieder ein bisschen eben. Ich werde die
Lösung hier vorstellen, sobald sie ordentlich funktioniert.
Grüße,
QtNewbie87