Forum: PC-Programmierung Seriellport im PC lesen/ schreiben


von D.M (Gast)


Lesenswert?

Hallo.

Ich weiß nicht wie ich unter C den RS232 Port lesen/schreiben soll.
Ich hab keine Ahnung was es da für Befehle gibt und was die machen.

Ich hab vor Daten von meinem Atmega16 an den PC zu senden.

Kann mir da jemand helfen?

von Jan H. (zool)


Lesenswert?

Der Reihe nach

CreateFile("COM1:",...    // Port öffnen

GetCommState    // vorbereiten der Schnittstellenparameter, spart den 
kompletten DCB selbst zu bauen

SetCommState    // angepasste Werte aktivieren (Baudrate, Stopbits,...)

ReadFile / WriteFile    // die eigentliche Datenübertragung

CloseHandle   // das wars  ;-)


Hoffe Du hast die MSDN-CD's installiert. Da gibts dann nähere Infos zu. 
Falls nicht: http://msdn.microsoft.com

von Jan H. (zool)


Lesenswert?

Ach so, schon Windows, oder??  ;-)

von Weinga-Unity (Gast)


Lesenswert?

Hi!

Kuck mal hier:
http://pvbrowser.org/pvbrowser/sf/manual/rllib/html/classrlSerial.html

Download des Ganzen:
http://pvbrowser.de/pvbrowser/tar/rllib.tar.gz

Funktioniert super. Musst halt all jene Dateien mit in dein Projekt 
mitnehmen, nach denen der Compiler schreit.

mfg W.K.

von D.M (Gast)


Lesenswert?

@ Jan H.

Könntest du mir vielleicht ein beispiel geben?

von Frank (Gast)


Lesenswert?

Jo Jan, schon schlimm einfach so ein paar Brocken hinzuwerfen wo der 
Kumpel doch gern ein komplettes Programm gehabt hätte...

von Jan H. (zool)


Lesenswert?

Du wolltest doch die Befehle wissen, die man für serielle Kommunikation 
unter Windows braucht?! Das sind sie - mehr ist da nicht (ok, ein, zwei 
Sachen gibts da noch, aber für Deinen Zweck reicht das).
Du brauchst im einfachsten Fall genau diese Funktionen in dieser 
Reihenfolge.

Mach MSDN auf, lokal oder online und schau Dir die genaue Syntax an. Ein 
komplettes Beispiel kann ich Dir nicht geben - und würde Dir auch nicht 
viel bringen, weil der eigentliche Kommunikationsteil ja nur einen 
kleinen Teil der Programme ausmacht.

Ach ja, Get-/SetCommTimeouts hatte ich noch vergessen. Ist wichtig um 
ein definiertes Timing zu erhalten.

von Blackbird (Gast)


Lesenswert?

Und ReadFile sollte in einem eigenen Thread stehen und mit WaitCommEvent 
und WaitForSingleObject auf ein Read- oder sonstiges Ereignis am Port 
warten.
Sonst hilft nur pollen im main thread.

HyperTerminal tut's aber auch, ganz ohne programmieren.

Blackbird

von Feadi F. (feadi)


Lesenswert?

@ Blackbird:
WaitForSingleObject kenn ich, aber welche Funktionen braucht man dafür:
> Sonst hilft nur pollen im main thread.
?

Gruß, Feadi

von Blackbird (Gast)


Lesenswert?

Pollen:
Am Anfang die Timeouts einstellen, z.B.: so:
1
  COMMTIMEOUTS  ct;
2
  GetCommTimeouts (hCom, &ct);
3
  // Warte-Zeit [ms] vom Beginn eines Bytes bis zum Beginn des nächsten Bytes 
4
  ct.ReadIntervalTimeout         = 1000 / BAUDRATE * (dcb.ByteSize + 
5
                                                     (dcb.Parity == NOPARITY ? 0 : 1) + 
6
                                                     (dcb.StopBits == ONESTOPBIT ? 1 : 2)) * 2;
7
  ct.ReadTotalTimeoutMultiplier  = 0;  // [ms] wird mit Read-Buffer-Size multipliziert
8
  ct.ReadTotalTimeoutConstant    = 50; // wird an ReadTotalTimeoutMultiplier angehängt
9
  ct.WriteTotalTimeoutMultiplier = 0;
10
  ct.WriteTotalTimeoutConstant   = 0;
11
  SetCommTimeouts (hCom, &ct);

Ja, und dann in einer Schleife immer ReadFile aufrufen.

Das ist aber die schlechteste Variante, besser ist ein eigener Thread 
(CreateThread), in dem man auf ein Read-Ereignis am Port wartet und dann 
erst ReadFile aufruft. Weil ja dann auch ein Byte angekommen ist.

Zuerst wird eine Overlapped-Struct erstellt und mit einem Event 
verknüpft.
1
  OVERLAPPED    o;
2
  memset (&o, 0, sizeof (OVERLAPPED)); // Struktur mit 0en füllen
3
  o.hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); // einen Event setzten

dann eine Maske mit den Events, af die man warten möchte und eine, die 
die eintreffenden Events aufnimmt, erstellt:
1
  DWORD         dwSetMask = EV_RXCHAR | EV_ERR; 
2
  DWORD         dwEvtMask;

und dann wird in einer Endlosschleife auf die Events gewartet:
1
  do  // in Endlos-Schleife auf Empfangssignale warten:
2
  {
3
    WaitCommEvent (hCom, &dwEvtMask, &o); // Event mit Empfangssignalen verknüpfen
4
5
    if (WAIT_OBJECT_0 == WaitForSingleObject (o.hEvent, INFINITE)) // warten bis Event
6
    {
7
      if (dwEvtMask & EV_RXCHAR) // Zeichen an RxD empfangen:
8
      {
9
        bRet = ReadFile (hCom, &InString, sizeof (InString), &dwRead, NULL);
10
...
11
      if (dwEvtMask & EV_ERR) // Zeichen an RxD empfangen:
12
      {
13
     ...

Naja, das Übliche mit DCB, Fehlerauswerten, Sende- und Empfangspuffer 
setzen, Schließen von Thread und COm und Event usw. nicht vergessen.

Schreiben kann man aus jedem Thread heraus, sollte nicht im 
Empfangsthread sein und wenn möglich, in einem eigenen Thread ablaufen, 
wel man so ganz bequem feststellen kann, ob die Zeichen auch wirklich 
raus sind (an den Treiber) und nicht der Puffer noch voll ist und man 
Zeichen überschreibt.

Für das Öffnen, Schließen und Setzen der seriellen Ports und der 
einzelnen Pins gibts es massig C/C++ -Code-Schnipsel und -Klassen. Aber 
keine mir bekannte behandelt das Empfangen in einem Thread. Es wird 
immer nur eine schön eingepackte ReadFile-Routine vorgestellt, aber wo 
soll man die aufrufen?


Blackbird

von Blackbird (Gast)


Lesenswert?

Vor Aufruf der do-while-Schleife kommt noch das Setzen der Maske:
1
  SetCommMask (hCom, dwSetMask); // Empfangssignale definieren

Hatte ich vergessen.

Blackbird

von Blackbird (Gast)


Lesenswert?

Noch'n Zusatz, zum Pollen:

Den Code für den Empfangsthread kann man auch in den main-Thread packen 
und statt INFINITE in WaitForSingleObject eine Wartezeit angeben. Auf 
einen Event braucht man dann aber nicht warten.

Blackbird

von Feadi F. (feadi)


Lesenswert?

Vielen Danke für die Erklärung!
Das probiere ich bei Gelegenheit gleich mal aus.

Gruß, Feadi

von Christian R. (supachris)


Lesenswert?

Blackbird wrote:

> Für das Öffnen, Schließen und Setzen der seriellen Ports und der
> einzelnen Pins gibts es massig C/C++ -Code-Schnipsel und -Klassen. Aber
> keine mir bekannte behandelt das Empfangen in einem Thread. Es wird
> immer nur eine schön eingepackte ReadFile-Routine vorgestellt, aber wo
> soll man die aufrufen?

Doch, bei CodeGuru: 
http://www.codeguru.com/Cpp/I-N/network/serialcommunications/article.php/c2483

Funktioniert wunderbar, nehme ich in leicht erweiterter Form auch immer. 
Ich hab mir noch Binärdatentransfer und das ordentliche Schließen der 
Schnittstelle sowie Behandlung der COM bis 255 hinzugefügt.

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.