Forum: PC-Programmierung UART PC Interrupt Empfang VC++


von Michael (Gast)


Lesenswert?

Hallo,

sorry für das ewig gleiche Thema. Meine selbst geschriebene Klassen für
das Senden und Empfangen über UART funktionieren einwandfrei.

Das Empfangen möchte jetzt aber optimieren. Bisher sieht das
Empfangsprotokoll in etwa so aus:

PC --> uC: Anfrage auf Informationen
uC --> PC: uC sendet genaue Anzahl von BYTES. (Empfang)

Ich möchte nun aber gerne, das meine PC-Software Daten empfängt die
irgenwann auf den Bus gelegt werden. In einer while(1)-Schleife in
meiner PC-Software möchte und kann ich nicht ewig auf einen Empfang
warten.

Wie kann ich ohne dieser while-Schleife das machen??????????????

Bin dankbar für jeden Vorschlag,
Michael

von Tobi H. (tobi-) Benutzerseite


Lesenswert?

Entweder per Thread, da ist eine while-Schleife kein Problem, oder mit
dem Overlapped-Modus, der blockiert das programm nicht, so dass man
regelmässig nachfragen kann, ob was da ist. Zu guter letzt wäre da noch
readfileex, das eine Callback-Routine aufruft, wenn es fertig ist, aber
damit habe ich noch nichts gemacht vondaher keine Ahnung, wie das genau
funktioniert

von Michael (Gast)


Lesenswert?

Hi Tobi,

was ist Deiner Meinung nach leichter zu programmieren. Die Thread- oder
die Overlappedvariante.

Und vielleicht hast Du noch ein paar gute Infolinks. Bei der
MSN-Library verstehe ich meistens nur Bahnhof. Bin halt doch mehr der
uC-Programmierer.

Michael

von Tobi H. (tobi-) Benutzerseite


Lesenswert?

Hier ist eine sehr gute Beschreibung aus der MSDN:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnfiles/html/msdn_serial.asp

Ich denke, wenn du noch wie was mit Threads gemacht hast ist die
Overlapped-Version einfacher. Aber schau dir den Link mal an, dann
solltest du das selbst einschätzen können

von Michael (Gast)


Lesenswert?

Hallo Tobi,

danke für die Quelle ich komme damit ziemlich gut zurecht. Ich habe
noch eine brauchbare Info gefunden, vorallem für die Einsteiger auf
Multi-Thread.

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndllpro/html/msdn_threads.asp

MfG,
Michael

von Michael (Gast)


Lesenswert?

Hallo,

ich bin ein gutes Stück weiter mit dem Multithreading. In C ist das ja
relativ einfach. Ich habe allerdings echte Probleme wenn ich das ganze
im VC++ Code versuche zu implementieren.

Ich möchte eine Memberfunktion von CTestboxDlg als BackgroundTread
laufen lassen. Diese Memberfunktion soll mir in ein Ausgabefeld die
asynchron empfangenen Zeichen (vom UART-Port) schreiben.

Meine Fragen:
Kann ich überhaupt eine Memberfunktion einer Klasse separat in einem
Thread laufen lassen?

Wenn ja wie?

_beginthread( CTestboxDlg.MyMultiThread, 0, NULL );

funktioniert nicht... Ich hab' auch schon ein paar ander Funktionen
auspropiert. Aber ich habe immer Ärger mit dem ersten Parameter. Der
wird nie akzeptiert.

Danke,
Michael

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

.
   Kann ich überhaupt eine Memberfunktion einer Klasse
   separat in einem Thread laufen lassen?

Das geht schon, nur muss diese Funktion eine statische Memberfunktion
sein.
Das bedeutet, daß es in der Funktion keinen this-Pointer gibt, sondern
der, wenn benötig, als getrennter Parameter an
_beginthread/CreateThread zu übergeben ist und der Funktion bei Aufruf
entsprechend übergeben wird.

von Michael (Gast)


Lesenswert?

@ Rufus
Danke für Deine schnelle Antwort. Ich bin leider nicht so sattelfest in
C++. Kannst Du vielleicht mal einen Code Snippet von der statischen
Funktion und der anschließenden Parameterüberger für _beginthread
posten.
Damit könntest Du mir wirklich weiterhelfen.

Michael

von Karl H. (kbuchegg)


Angehängte Dateien:

Lesenswert?

Eine statische Member-Funktion ist im Grunde wie
eine einzelne, freistehende Funktion. Nur dass sie
halt aus welchen Gruenden auch immer, im Namensraum
einer Klasse definiert wird.
D.h. Du kannst genauso gut auch eine freistehende
Funktion machen, die Du in den beginthread hineinstopfts.

Schau Dir mal das angehaengte Beispiel an.
Die ThreadFunktion bekommt eine globale Variable,
die als Window-Handle zum Dialog fungiert. Die Thread-
Funktion selbst kommuniziert mit dem Dialog Objekt
indem es ihm Messages schickt. Dadurch vermeide ich, daß
ich Funktionen des Dialog-Objektes aufrufe, wenn dieses
in einem falschen Zustand ist.

Die entscheidende Source ist in ThreadDlg.cpp / ThreadDlg.h

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Nun, das ist schon noch ein Unterschied.
Eine statische Memberfunktion kann über einen ihr übergebenen
this-Pointer auf private und protected-Membervariablen ihrer Klasse
zugreifen und über den this-Pointer auch nichtstatische
Memberfunktionen ihrer Klasse aufrufen; eine alleinstehende
nicht-Memberfunktion kann das nicht.

von Karl H. (kbuchegg)


Lesenswert?

Sag ich ja: sie ist im Namensraum der Klasse definiert.

von Michael (Gast)


Lesenswert?

Hallo,
Danke für Eure Untersützung. Ich bin jetzt ein gutes Stück weiter.Mein
Thread (globale Funktion) läuft. Jetzt muss ich nur noch an ein
"Ein-Ausbgabe"-Feld meines Hauptfensters die Daten schicken, die über
 die UART empfangen wurden .

Ich habe es mir so gedacht.

static BYTE hMemberVar; // Handle zu meiner AusgabeVariable global
static HWND hDlg;       // ...

void CTestboxDlg::OnStartCatch()
{
  ...
  hMemberVar = this->m_bCatchResult;
  hDlg = this->GetSafeHwnd();
}

void NewMultiThread(void *pvParam)
{
     BYTE bCatchUART = 34;      // Hier empfang über UART
     *hMemberVar = bCatchUART;  // ????????? Funktioniert nicht
     UpdateData(FALSE);         // ????????? Hier hDlg Updaten
     while(1);
}

Nochmals Danke für Euren Support...
Michael

von Michael (Gast)


Lesenswert?

Sorry muss natürlich ein Zeiger sein.

static BYTE *hMemberVar; // Handle zu meiner AusgabeVariable global

von Michael (Gast)


Lesenswert?

Nochmals Sorry,
manchmal steht man auf dem Schlauch. Lösung...

static BYTE * hMemberVar;

hMemberVar = & m_bCatchResult;

*hMemberVar = bCatchUART;

Allerdings habe ich noch immer das UpdateData(FALSE) Problem.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

UpdateData solltest Du auf gar keinen Fall aus einem anderen Thread
heraus aufrufen.

Besser ist es in diesem Fall mit PostThreadMessage dem GUI-Thread der
Applikation eine Nachricht zu senden, die vom Nachrichtenhandler Deines
Dialoges ausgewertet wird und an dieser Stelle UpdateData aufruft.

von Karl H. (kbuchegg)


Lesenswert?

:-)

Genau so, wie ich es ihm in der Demo gezeigt habe.

von Michael (Gast)


Lesenswert?

Ok, Danke Leute. Ich hab's kapiert und zum laufen gebracht :-)

:-)  :-)  :-)  :-)  :-)  :-)  :-)  :-)  :-)

Michael

von Michael (Gast)


Lesenswert?

Hallo,

wie schon gesagt alles funktioniert so wie ich es mir vorstelle.
Allerdings möchte ich jetzt noch meinen erzeugten Background-Thread:

while (1){ USART Dauerempfang; SendMessage zu Main;}

aus dem Bedienfenster wieder beenden. Ich kann das mit Hilfe ein
globalen Variable "EndThreadFlg".

while (EndThreadFlg == 0){ USART Dauerempfang; SendMessage zu Main;}

Es würde mir aber viel besser gefallen, wenn ich eine Message an meinen
Background-Thread schicken könnte und dann auf diese Message gezielt
reagieren. Mein Backgroundprozess ist aber eine primitive globale
Funktion.

long WINAPI AsynUsartThread (long *pvParam)
{
  Öffne Port;
  while (EndThreadFlg == 0){ USART Dauerempfang; SendMessage zu Main;}
  return 0;
}

Ist es sehr aufwendig meine AsynUsartThread-Funktion über Messages zu
steuern???
Und wie kann man es ungefähr bewerkstelligen. Muss ich für meinen
Thread einen großen Overhead anlegen zum Message-Empfang?????

Danke für Eure Antworten,
Michael

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Statt ein Flag auszuwerten kannst Du auch ein Event verwenden.
So etwas wird mit CreateEvent erzeugt und mit SetEvent signalisiert.

Deine "Dauerempfangsfunktion" wird, sofern sie overlapped I/O
verwendet, bereits irgendwo ein WaitForSingleObject verwenden.
Wird das durch ein WaitForMultipleObjects ersetzt, kann die
Wartefunktion im Thread sowohl eintreffende Zeichen als auch die
Signalisierung des Events mitbekommen.

Windows-Nachrichten sind für die Kommunikation mit Background-Threads
ein eher ungeeignetes Mittel.

von Hans (Gast)


Lesenswert?

das mit den CEvent dingern ist nicht inbedingt notwendig.. wenns nur 1
thread ist geht das mit nem flag auch problemlos..

im übrigen solltest du möglichst NICHTS was einem CWnd gehört in einen
thread reintun.. mach dir einen struct mit den daten die du drinnen
haben willst, hol dir speicher dafür und gibt den pointer drauf in den
thread.. der muss dann am schluss den speicher selbst wieder frei
geben... alles andere ist schrott..

also im prinzip sowas...

SMeineDaten *MeineDaten=new SMeineDate;
MeineDate->m_hWindowToUpdate=<der handle auf das fenster was daten tun
soll ;)
MeineDate->wasauchimmer

dann machst ein AfxBeginThread(....); oder wie auch immer du das
erledigen willst...

im thread schickst du dann einfach eine window-message and das fenster,
von dem du den handle hast und schon rutschen die daten dort hin... (z.b
SetWindowText-message)

wie gesagt MESSAGE schicken.. nicht funktion aufrufen !!! das ist sonst
alles NICHT Threadsafe!!!

immer wenn dein fenster nachrichten verarbeitet(also sich neu zeichnet
beim verschieben,...) dann wirds auch die box updaten...

es gibt aber noch eine variante die ein grober hack ist.. du kannst in
einem thread eine eigene message-queue aufbaun und dann das gesamt
fenster im thread handlen... aber das ist böse.. tu lieber nachrichten
schicken.. das ist unkompliziert und funktioniert gut ;)

73

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.