Forum: PC-Programmierung RS232 auf PC Seite


von Carsten (Gast)


Lesenswert?

Hallo,

wie funktioniert die RS232 Schnittstelle auf PC Seite. Gibt es dort 
einen Puffer der die Daten entgegennimmt(vielleicht in Hardware)? Gibt 
es eine Art Interrupt für Byte empfangen und gesendet? Ich benutze den 
Borland C++ Builder. Den Comport öffne ich über Create File. Verstehe 
das ganze aber noch nicht so richtig. Bitte nicht über diese Frage 
meckern, ich habe gesucht aber nichts passendes gefunden.

Diese Funktionen benutze ich zum senden und empfangen:
Bei der ReceiveData Funktion wird ein Array Buffer[BufferSize] 
übergeben.
Wo werden diese Daten hergeholt? Ich lege die BufferSize erst bei Aufruf 
der Receive Funktion fest(ButtonEmpfang)?
1
int SendData(char Data[],int n)
2
{
3
DWORD NumberOfBytesWritten; //Anzahl der gesendeten Bytes
4
  bool b=WriteFile(hComSend, // handle des Com-Ports
5
     Data, // Adresse der Daten
6
     n, // Anzahl der zu sendenden Bytes
7
     &NumberOfBytesWritten, // Adresse übergeben
8
     0); // kein overlapped I/O
9
  if (!b) ShowLastError("WriteFile");
10
return NumberOfBytesWritten;
11
}
12
13
DWORD ReceiveData(char* Data,int n)
14
{
15
DWORD NumberOfBytesRead; // Anzahl der gelesenen Bytes
16
   bool b=ReadFile(hComReceive, // handle des Com-Ports
17
     Data, // Adresse des Datenpuffers
18
     n, // Anzahl der zu lesenden Bytes
19
     &NumberOfBytesRead, // Adresse übergeben
20
     0); // kein overlapped I/O
21
   if (!b) ShowLastError("ReadFile");
22
return NumberOfBytesRead;
23
}
1
void __fastcall TForm1::ButtonEmpfang(TObject *Sender)
2
{
3
const int BufSize = 100;
4
int i;
5
char Buffer[BufSize]; // Puffer für die empfangenen Daten
6
  DWORD NumberOfBytesRead=ReceiveData(Buffer,BufSize);
7
  if (NumberOfBytesRead > 0)
8
    {
9
    for (DWORD i=0;i<NumberOfBytesRead;i++)
10
      {
11
        s=s+Buffer[i];      // Ausgabe in ASCII
12
      }  
13
    Memo1->Lines->Add(s);
14
    }
15
  else
16
    Memo1->Lines->Add("Nichts empfangen");
17
}

vielen Dank

von Stefan B. (stefan) Benutzerseite


Lesenswert?

Du musst mit dem Puffer Data aufpassen. Der muss bestimmte Bedingungen 
erfüllen. http://msdn2.microsoft.com/en-us/library/aa365467.aspx

Und mit den anderen Parametern auch aufpassen. 
http://blogs.msdn.com/larryosterman/archive/2007/01/12/software-contracts-part-3-documentation.aspx

Auf Lowest-Level Ebene hast du mit einem FiFo-UART Baustein im PC einen 
kleinen Hardwarepuffer.

Auf Windows OS-Ebene gibt es im seriellen Treiber interne IO-Puffer. 
Deren Grösse kannst du über SetupComm() beeinflussen.
http://msdn2.microsoft.com/en-us/library/aa363439.aspx

von Carsten (Gast)


Lesenswert?

Hallo Stefan,

Danke genau das hab ich gesucht. Super.

von Blackbird (Gast)


Lesenswert?

"... Gibt es eine Art Interrupt für Byte empfangen und gesendet? ..."

Ja, gibt es. Man erstellt einen Event, verknüpft ihn mit der 
Schnittstelle und wartet dann in einer Endlos-Schleife darauf. Die 
Schnittstelle sollte aber OVERLAPPED geöffnet werden und die 
Endlos-Schleife in einem eigenen Thread laufen. Sonst blockiert man sich 
das eigene Programm.

Hier ein Beispiel. Du kannst alle Events rauswerfen, die Du nicht 
benötigst. Das Ganze kann in einem eigenen Thread laufen und statt der 
printf() kann dann Deine Ausgabe laufen. Sollte aber so kurz wie möglich 
sein, am Besten nur ein PostThreadMessage zu Deinen anderen 
Programmteilen.
1
/**********************************************************************
2
** Testprogramm: Wartet auf eine Pegeländerung an DSR, CTS, ... an COM1
3
**
4
** Getestet: OK ab 12/2002!
5
**********************************************************************/
6
7
#include <windows.h>
8
#include <stdio.h>
9
10
#define TIMELIMIT 100000   // Programm läuft 100 Sekunden
11
12
// zusätzliche Events (DDK)
13
#define SERIAL_EV_RXCHAR           0x0001  // Any Character received
14
#define SERIAL_EV_RXFLAG           0x0002  // Received certain character
15
#define SERIAL_EV_TXEMPTY          0x0004  // Transmitt Queue Empty
16
#define SERIAL_EV_CTS              0x0008  // CTS changed state
17
#define SERIAL_EV_DSR              0x0010  // DSR changed state
18
#define SERIAL_EV_RLSD             0x0020  // RLSD changed state
19
#define SERIAL_EV_BREAK            0x0040  // BREAK received
20
#define SERIAL_EV_ERR              0x0080  // Line status error occurred
21
#define SERIAL_EV_RING             0x0100  // Ring signal detected
22
#define SERIAL_EV_PERR             0x0200  // Printer error occured
23
#define SERIAL_EV_RX80FULL         0x0400  // Receive buffer is 80 percent full
24
#define SERIAL_EV_EVENT1           0x0800  // Provider specific event 1
25
#define SERIAL_EV_EVENT2           0x1000  // Provider specific event 2
26
27
// Prototypes
28
const char* decimalToBinary (const long value, 
29
                             const unsigned length,
30
                             char* pszBuffer);
31
32
/********************************************************************
33
** DOS32-programm läuft TIMELIMIT / 1000 Sekunden und zeigt alle
34
** Pegeländerungen an COM 1 an
35
********************************************************************/
36
int main (void)
37
{
38
  HANDLE hCom;
39
  OVERLAPPED o;
40
  DWORD dwStart;
41
  DWORD dwEvtMaskIn = EV_CTS | EV_DSR | EV_BREAK | EV_RING | EV_RXCHAR | 
42
                      EV_RLSD | EV_ERR | EV_RXFLAG | EV_TXEMPTY |
43
                      SERIAL_EV_PERR | SERIAL_EV_RX80FULL |
44
                      SERIAL_EV_EVENT1 | SERIAL_EV_EVENT2;
45
  DWORD dwEvtMask = 0;
46
  char szString[] = ("\r\nWarte auf Events (Pegelaenderungen) an COM 1:\r\n\
47
EV_RXCHAR  =0x%04x\r\nEV_RXFLAG  =0x%04x\r\nEV_TXEMPTY =0x%04x\r\n\
48
EV_CTS     =0x%04x\r\nEV_DSR     =0x%04x\r\nEV_RLSD    =0x%04x\r\n\
49
EV_BREAK   =0x%04x\r\nEV_ERR     =0x%04x\r\nEV_RING    =0x%04x\r\n\
50
EV_PERR    =0x%04x\r\nEV_RX80FULL=0x%04x\r\nEV_EVENT1  =0x%04x\r\n\
51
EV_EVENT2  =0x%04x");
52
  char szBuf[sizeof (DWORD) * 8] = "";  // für decimalToBinary-Funktion
53
  SYSTEMTIME    SystemTime;   // system time
54
  TCHAR         lpszMsg[127] = "";
55
56
57
  printf (szString, EV_RXCHAR, EV_RXFLAG, EV_TXEMPTY, 
58
      EV_CTS, EV_DSR, EV_RLSD, EV_BREAK, EV_ERR, EV_RING, SERIAL_EV_PERR,
59
      SERIAL_EV_RX80FULL, SERIAL_EV_EVENT1, SERIAL_EV_EVENT2);
60
        
61
  hCom = CreateFile ("COM1",
62
    GENERIC_READ | GENERIC_WRITE,
63
    0,    // exclusive access 
64
    NULL, // no security attributes 
65
    OPEN_EXISTING,
66
    FILE_FLAG_OVERLAPPED,
67
    NULL);
68
  
69
  if (hCom == INVALID_HANDLE_VALUE) 
70
    return printf ("\r\nCOM1 kann nicht geöffnet werden"); 
71
72
  if (!SetCommMask (hCom, dwEvtMaskIn)) 
73
    return printf ("\r\nSetCommMask fehlgeschlagen"); 
74
  
75
  // Create an event object for use in WaitCommEvent. 
76
  o.hEvent = CreateEvent (
77
    NULL,   // no security attributes 
78
    FALSE,  // auto reset event 
79
    FALSE,  // not signaled 
80
    NULL);  // no name 
81
    
82
  dwStart = GetTickCount ();
83
84
  while (GetTickCount () - dwStart < TIMELIMIT)
85
  {
86
    WaitCommEvent (hCom, &dwEvtMask, &o);
87
    
88
    if (WAIT_OBJECT_0 == WaitForSingleObject (o.hEvent, INFINITE))
89
    {
90
      GetLocalTime (&SystemTime);
91
      printf ("\r\nEvents: %s - ", decimalToBinary (dwEvtMask, sizeof (DWORD) * 8, szBuf));
92
93
      if (dwEvtMask & EV_DSR) 
94
        printf ("DSR "); 
95
      
96
      if (dwEvtMask & EV_CTS) 
97
        printf ("CTS "); 
98
      
99
      if (dwEvtMask & EV_BREAK) 
100
        printf ("BREAK "); 
101
      
102
      if (dwEvtMask & EV_RING) 
103
        printf ("RING "); 
104
      
105
      if (dwEvtMask & EV_RXCHAR)
106
        //printf ("RXCHAR "); 
107
      if (dwEvtMask & EV_RLSD) 
108
        printf ("RLSD "); 
109
      
110
      if (dwEvtMask & EV_ERR) 
111
        printf ("ERR "); 
112
      
113
      if (dwEvtMask & EV_RXFLAG) 
114
        printf ("RXFLAG "); 
115
      
116
      if (dwEvtMask & EV_TXEMPTY) 
117
        printf ("TXEMPTY "); 
118
      
119
      if (dwEvtMask & SERIAL_EV_PERR) 
120
        printf ("PERR "); 
121
      
122
      if (dwEvtMask & SERIAL_EV_RX80FULL) 
123
        printf ("RX80FULL "); 
124
      
125
      if (dwEvtMask & SERIAL_EV_EVENT1) 
126
        printf ("EVENT1 "); 
127
      
128
      if (dwEvtMask & SERIAL_EV_EVENT2) 
129
        printf ("EVENT2 "); 
130
131
      wsprintf (lpszMsg, "%s, den %02d.%02d.%04d um %d:%d Uhr %d,%d Sek.",
132
        SystemTime.wDayOfWeek == 1 ? "Mo" : 
133
        (SystemTime.wDayOfWeek == 2 ? "Di" : 
134
        (SystemTime.wDayOfWeek == 3 ? "Mi" : 
135
        (SystemTime.wDayOfWeek == 4 ? "Do" : 
136
        (SystemTime.wDayOfWeek == 5 ? "Fr" : 
137
        (SystemTime.wDayOfWeek == 6 ? "Sa" : 
138
        (SystemTime.wDayOfWeek == 7 ? "So" : "Heute")))))), 
139
        SystemTime.wDay, SystemTime.wMonth, SystemTime.wYear,
140
        SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, 
141
        SystemTime.wMilliseconds);
142
      printf (": %s", lpszMsg); 
143
    }
144
  }
145
146
  CloseHandle (o.hEvent);
147
  CloseHandle (hCom);
148
149
  return printf ("\r\n!ENDE! %d Sekunden sind um!\r\n", TIMELIMIT / 1000);
150
}
151
152
153
/*****************************************************************************
154
** Umwandlung: Dezimal zu Binär
155
**
156
** 1. Param: die Zahl
157
** 2. Param: Anzahl der Binärstellen (von 1..32)
158
** 3. Param: Zeiger auf ein char-Array, das den String aufnehmen kann
159
*****************************************************************************/
160
const char* decimalToBinary (const long value, 
161
                             const unsigned length,
162
                             char* pszBuffer)
163
{
164
  if ((length == 0) || (length > 32))
165
  {
166
    pszBuffer = '\0';
167
    return pszBuffer;
168
  }
169
  
170
  unsigned digit = 1 << (length - 1);
171
  char* pszCurrent = pszBuffer;
172
  
173
  do
174
  {
175
    if (value & digit)
176
      *pszCurrent = '1';
177
    else
178
      *pszCurrent = '0';
179
    pszCurrent++;
180
    digit /= 2;
181
  } while (digit != 0);
182
  
183
  *pszCurrent = '\0';
184
  
185
  return pszBuffer;
186
}


Blackbird

von Carsten (Gast)


Lesenswert?

Hallo Blackbird,

dankeschön, das funktioniert.Klasse!

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.