Forum: PC-Programmierung winapi com RS232 lesen und schreiben


von soso (Gast)


Lesenswert?

Hi,

ich möchte mit der Winapi auf die com schnittstelle lesen und schreiben.
Die initialisierung über createFile hab ich bereits hionter mir das 
funktioniert auch soweit. nur hab ich keinen schimmer wie ich nun 
schriebn und lesen kann.

ich bräuchte eine schreibfunktion, welche ein array mit bekannter laenge 
auf die com schnittstelle schreibt. (kein String, der bei null aufhöhrt, 
da durchaus auch nullen geschrieben werden sollen.)

des weiteren würde ich gerne aus dem eingangsbuffer lesen. weird die 
Funktion aufgerufen soll sie blockieren, bis ein Zeichen angekommen ist. 
das soll dann zurückgeliefert werden.


hier mal die Funktionen:
1
static void send_RS232(char *data, int length){
2
3
    DWORD temp, numbytes_ok;
4
    COMSTAT ComState;
5
6
7
    ClearCommError(hPort, &temp, &ComState);
8
9
    if(!temp)
10
    {
11
12
     if(!WriteFile(hPort, data, length, &numbytes_ok, NULL))
13
     {
14
       DWORD err = GetLastError();
15
       MessageBoxA(NULL, "FEHLER #06 schreiben auf Port fehlgeschlagen", "comPort", 0);
16
17
       printf("Letzter Fehler: %ld\r\n", (long int)err);
18
19
    return ;
20
     }
21
    }
22
23
24
}
25
26
27
/**
28
 * Diese Funktion empfaengt ein zeichen ueber den RS232 Buffer
29
 */
30
char receive(){
31
32
33
  unsigned long gelesen;
34
  char Buffer=0;
35
36
  DWORD dwEvtMask;
37
38
  gelesen = 0;
39
40
41
  SetCommMask (hPort, EV_RXCHAR);
42
43
  dwEvtMask = 0;
44
45
  OVERLAPPED o;
46
  o.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
47
  WaitCommEvent(hPort, &dwEvtMask, &o);
48
49
  while(WAIT_OBJECT_0 == WaitForSingleObject(o.hEvent, INFINITE))
50
  {
51
      if (dwEvtMask & EV_RXCHAR){
52
        if(!ReadFile(hPort,&Buffer,1,&gelesen,NULL)){
53
          printf("lesefehler\r\n");
54
        }else{
55
          break;
56
        }
57
      }
58
  }
59
60
61
  return Buffer;
62
}
63
64
65
/**
66
 * Diese Funktion initialisiert die RS232 Schnittstelle
67
 */
68
void init_rs232(){
69
70
  int baudrate = 9600;
71
72
73
  // Setze Baudrate und Comport
74
  printf("Initialisiere RS232 Schnittstelle\r\n\r\n");
75
  printf("Setze Port auf Com3\r\n");
76
  printf("Setze Baudrate auf %d\r\n", baudrate);
77
  printf("\r\n\r\n");
78
79
  hPort =  CreateFile("COM3", GENERIC_WRITE|GENERIC_READ, 0, NULL,
80
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
81
82
    if(!SetupComm(hPort, 512, 512))
83
    {
84
    MessageBoxA(NULL, "FEHLER #01 (Comport kann nicht geoeffnet werden)", "comPort", 0);
85
    return;
86
    }
87
88
    DCB dcb;
89
    ZeroMemory(&dcb, sizeof(DCB));
90
91
    char buffer[100];
92
    strcpy(buffer,"baud=9600 parity=N data=8 stop=1");
93
    if (BuildCommDCB((char*)&buffer, &dcb))
94
    {
95
    if (dcb.BaudRate != CBR_9600)
96
    {
97
      MessageBoxA(NULL, "FEHLER #02", "comPort", 0);
98
      return;
99
    }
100
    }
101
    else
102
    {
103
    MessageBoxA(NULL, "FEHLER #03", "comPort", 0);
104
    return;
105
    }
106
107
    if(GetCommState(hPort, &dcb))
108
    {
109
     dcb.BaudRate = CBR_9600;
110
     dcb.ByteSize = 8;
111
     dcb.Parity = 0;
112
     dcb.StopBits = 0;
113
     SetCommState(hPort, &dcb);
114
    }
115
    else
116
    {
117
    MessageBoxA(NULL, "FEHLER #04", "comPort", 0);
118
    return ;
119
    }
120
121
    if (hPort == INVALID_HANDLE_VALUE)
122
    {
123
    MessageBoxA(NULL, "FEHLER #05", "comPort", 0);
124
    return ;
125
    }
126
127
128
129
/*
130
    CloseHandle(hCom);
131
132
    MessageBoxA(NULL, "Alles im grünen Bereich!", "comPort", NULL);
133
*/
134
135
136
137
138
139
}

hat jemand ne idee warum sowohl das empfangen als auch das senden nicht 
geht? oder nen code wo ich sehen kann wie das auszusehen hat?

er wartet beim lesen immerhin auf ein zeichen. kommt dieses wird ein 
lesefehler geschmissen, warum auch immer

beim schreiben kommt auch immer ein fehler

danke und Gruß

von Peter (Gast)


Lesenswert?

warum zu komlpliziert mit WaitForSingleObject? Mach doch einfach ein 
Read. Wenn du schon den Fehler beim Read abfängst kann doch auch gleich 
den Fehler mit GetLastError ermitteln und anzeigen.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Da es Unmengen von fertigem Beispielcode für die Programmierung der 
seriellen Schnittstelle mit der Win32-API gibt, wüsste ich nicht, warum 
Du Dir nicht eines dieser funktionierenden Beispiele ansehen und die 
Unterschiede zu Deinem Code herausfinden können solltest.

Beispiele solltest Du auch mit der foreneigenen Suchfunktion finden 
können, das Thema taucht etwa wöchentlich hier auf.

von soso (Gast)


Lesenswert?

aber leider ohne funktionierende Beispiele. meines hab ich auch hier aus 
dem forum zusammengeschustert. könntet ihr mir vielleicht ein 
funktionierendes zeigen?

von Ralf (Gast)


Lesenswert?

Zu deinem Obigen Beispiel:

In der Routine "init_rs232" fehlt irgendwie
der Aufruf "SetCommState" mit der du auch
die RS 232 Parameter setzt. Du liest ja nur
die aktuellen Parameter aus. Schau mal bei
Microsoft nach, dort wird die Programmierung
der seriellen Schnittstelle eigentlich gut
beschrieben (In Google suchen nach z. B.
"GetCommState" o. ä., dann findest du den Link).

Gruß

Ralf

von Karl (Gast)


Lesenswert?

Kann jemand eine gute Library für die Serielle Schnittstelle empfehlen? 
Ich hatte jetzt eine von Code Guru. Ich habe das Programm unter Win7 
geschrieben, und musste es für XP wieder neu compilieren. Gibt es da 
etwas besseres?

von Karl (Gast)


Lesenswert?

ach ja eine C++ Klasse suche ich.

von Peter (Gast)


Lesenswert?

es sind doch dafür nur eine paar api aufrufe erforderlich, warum noch 
extra ein lib ringsrumschrauben die noch noch extra fehler mitbringt?

> Ich habe das Programm unter Win7
> geschrieben, und musste es für XP wieder neu compilieren. Gibt es da
> etwas besseres?
warum das denn, die api hat sich da nicht weiter geändert? Was gab es 
für ein Fehler?

von Karl H. (kbuchegg)


Lesenswert?

Peter schrieb:
> es sind doch dafür nur eine paar api aufrufe erforderlich, warum noch
> extra ein lib ringsrumschrauben die noch noch extra fehler mitbringt?

Na ja.
Das Einstellen der Parameter ist nicht der große Grund, warum die 
Serielle gekapselt wird.
Eher schon das Einrichten von Buffern, bzw. einer Queue in der 
Empfansgroutine.


Aber im Grunde zeigt die Fragestellung nur wieder mal, dass der 
Fragesteller nicht googeln und Links auswerten will. Libraries bzw. 
Kapselungen für die serielle Schnittstelle gibt es wie Sand am Meer. 
Auch Firmen überlassen einem gerne für einen Obulus ihre Sicht der 
Dinge.

von Karl (Gast)


Lesenswert?

So leicht ist es da gar nicht, etwas zu finden. Für die Meisten braucht 
man MFC.

von soso (Gast)


Lesenswert?

Was ich halt suche ist eine einfache möglichkeit.

man hat einen sende und einen empfangsbuffer, wo man liest / schreibt.

um alles andere sollte sich die libary kümmern.

ich finde so Aussagebn wie "kann nicht mit google umgehen" unangebracht, 
da ich immer vorher bei Google suche, aber bisher nichts gefunden habe. 
Daher die Frage, habt ihr da was?

Zu Microsoft, ich finde die API Dokumentation diesbezüglich schlecht, da 
hier kein Beispiel zu finden ist. für einen Neuling auf diesem Gebiet 
ist das nicht einfach so einzisteigen.

Nochmal zur Ausgangsfrage, Hat jemand ein Beispielprogramm oder eine 
Bibliothek (dll) wo man sich das mal angucken kann oder welche man frei 
benutzen darf?

Gruß

von Peter (Gast)


Lesenswert?

soso schrieb:
> man hat einen sende und einen empfangsbuffer, wo man liest / schreibt.

und genau das macht auch die Windows-Api, sie hat ein empfangspuffer und 
ein sendepuffer.

von Karl (Gast)


Lesenswert?

Also die boost Library sieht ja ganz nett aus. Die kann auch nen 
Serialport erstellen. Bloß mal sehen, ob ich damit zurecht komme.

von soso (Gast)


Lesenswert?

wie gesagt nen Beispiel wäre schön

von Karl (Gast)


Lesenswert?

Na ich probiere mal die boost. Wenn das damit gut geht könnte man auch 
einen Wiki Artikel daraus machen.

von Karl (Gast)


Lesenswert?

Also die Boost Lib ist irgendwie nicht sehr Anfänger freundlich.

http://www.boost.org/doc/libs/1_41_0/doc/html/boost_asio/overview/serial_ports.html

Also erst einmal braucht man ein IO Device, warum auch immer.

io_service io;
serial_port port( io, "COM1" );

Aber warum man jetzt nicht einfach.

Die Einstellungen sind auch total aufwendig:

port.set_option(boost::asio::serial_port_base::baud_rate(9600) );
Da braucht man erst einmal ein Baudraten Objekt, warum auch immer.

Aber warum ich jetzt nicht einfach port.open(); machen kann erschließt 
sich mir immer noch nicht.

von Blackbird (Gast)


Lesenswert?

>> ... So leicht ist es da gar nicht, etwas zu finden. ...

Naja, weil das Senden recht einfach, das Empfangen aber von der 
Anwendung abhängig ist.
Asynchron senden kann man immer. Soll doch der andere Empfänger selber 
zusehen, ob er die Daten auch zum richtigen Zeitpunkt abfragt, bevor sie 
verlorengehen.

Aber Empfangen kann man nicht eben so mal irgendwann, wenn man im 
Proramm gerade mal am Empfangspuffer vorbeikommt.

Das läßt man sich ANZEIGEN (per Event zum Beispiel) und reagiert darauf 
(mit der ReadFile-Funktion).
In einer Warteschleife auf Zeichen warten kann man auch (Polling), aber 
dann bleibt nicht genug zusammenhängende Zeit für den anderen Kram 
übrig. Oder man lagert das Polling oder das Event-Handling in einen 
eigenen Thread aus, der dann wiederum den Hauptthread informiert (und 
der auch eine Eingangs-Queue haben sollte).

Nun kannst Du ungefähr ermessen, warum es nur komplexe Libs und so'n 
Kram gibt, die das alles zuverlässig hinkriegen. So mal schnell einen 
Beispielcode aus einem größenen Projekt zu extrahieren - nee, wirklich 
nicht!


Blackbird

von Oliver R. (superberti)


Lesenswert?

Hi,

also den MSDN-Artikel

http://msdn.microsoft.com/en-us/library/ms810467.aspx

über serielle Kommunikation gibt es jetzt schon stolze 15 Jahre bei 
Microsoft. Mit jeder Menge Beispielcode, der unter JEDER Windowsversion 
ab '95 funktioniert. Keine zusätzlichen Libs nötig, jeder C-Compiler 
kann's kompilieren.
Nur durchlesen muss man es noch selbst.

Gruß,

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.