www.mikrocontroller.net

Forum: PC-Programmierung RS232 auf PC Seite


Autor: Carsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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)?
int SendData(char Data[],int n)
{
DWORD NumberOfBytesWritten; //Anzahl der gesendeten Bytes
  bool b=WriteFile(hComSend, // handle des Com-Ports
     Data, // Adresse der Daten
     n, // Anzahl der zu sendenden Bytes
     &NumberOfBytesWritten, // Adresse übergeben
     0); // kein overlapped I/O
  if (!b) ShowLastError("WriteFile");
return NumberOfBytesWritten;
}

DWORD ReceiveData(char* Data,int n)
{
DWORD NumberOfBytesRead; // Anzahl der gelesenen Bytes
   bool b=ReadFile(hComReceive, // handle des Com-Ports
     Data, // Adresse des Datenpuffers
     n, // Anzahl der zu lesenden Bytes
     &NumberOfBytesRead, // Adresse übergeben
     0); // kein overlapped I/O
   if (!b) ShowLastError("ReadFile");
return NumberOfBytesRead;
}
void __fastcall TForm1::ButtonEmpfang(TObject *Sender)
{
const int BufSize = 100;
int i;
char Buffer[BufSize]; // Puffer für die empfangenen Daten
  DWORD NumberOfBytesRead=ReceiveData(Buffer,BufSize);
  if (NumberOfBytesRead > 0)
    {
    for (DWORD i=0;i<NumberOfBytesRead;i++)
      {
        s=s+Buffer[i];      // Ausgabe in ASCII
      }  
    Memo1->Lines->Add(s);
    }
  else
    Memo1->Lines->Add("Nichts empfangen");
}

vielen Dank

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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/0...

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

Autor: Carsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Stefan,

Danke genau das hab ich gesucht. Super.

Autor: Blackbird (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
/**********************************************************************
** Testprogramm: Wartet auf eine Pegeländerung an DSR, CTS, ... an COM1
**
** Getestet: OK ab 12/2002!
**********************************************************************/

#include <windows.h>
#include <stdio.h>

#define TIMELIMIT 100000   // Programm läuft 100 Sekunden

// zusätzliche Events (DDK)
#define SERIAL_EV_RXCHAR           0x0001  // Any Character received
#define SERIAL_EV_RXFLAG           0x0002  // Received certain character
#define SERIAL_EV_TXEMPTY          0x0004  // Transmitt Queue Empty
#define SERIAL_EV_CTS              0x0008  // CTS changed state
#define SERIAL_EV_DSR              0x0010  // DSR changed state
#define SERIAL_EV_RLSD             0x0020  // RLSD changed state
#define SERIAL_EV_BREAK            0x0040  // BREAK received
#define SERIAL_EV_ERR              0x0080  // Line status error occurred
#define SERIAL_EV_RING             0x0100  // Ring signal detected
#define SERIAL_EV_PERR             0x0200  // Printer error occured
#define SERIAL_EV_RX80FULL         0x0400  // Receive buffer is 80 percent full
#define SERIAL_EV_EVENT1           0x0800  // Provider specific event 1
#define SERIAL_EV_EVENT2           0x1000  // Provider specific event 2

// Prototypes
const char* decimalToBinary (const long value, 
                             const unsigned length,
                             char* pszBuffer);

/********************************************************************
** DOS32-programm läuft TIMELIMIT / 1000 Sekunden und zeigt alle
** Pegeländerungen an COM 1 an
********************************************************************/
int main (void)
{
  HANDLE hCom;
  OVERLAPPED o;
  DWORD dwStart;
  DWORD dwEvtMaskIn = EV_CTS | EV_DSR | EV_BREAK | EV_RING | EV_RXCHAR | 
                      EV_RLSD | EV_ERR | EV_RXFLAG | EV_TXEMPTY |
                      SERIAL_EV_PERR | SERIAL_EV_RX80FULL |
                      SERIAL_EV_EVENT1 | SERIAL_EV_EVENT2;
  DWORD dwEvtMask = 0;
  char szString[] = ("\r\nWarte auf Events (Pegelaenderungen) an COM 1:\r\n\
EV_RXCHAR  =0x%04x\r\nEV_RXFLAG  =0x%04x\r\nEV_TXEMPTY =0x%04x\r\n\
EV_CTS     =0x%04x\r\nEV_DSR     =0x%04x\r\nEV_RLSD    =0x%04x\r\n\
EV_BREAK   =0x%04x\r\nEV_ERR     =0x%04x\r\nEV_RING    =0x%04x\r\n\
EV_PERR    =0x%04x\r\nEV_RX80FULL=0x%04x\r\nEV_EVENT1  =0x%04x\r\n\
EV_EVENT2  =0x%04x");
  char szBuf[sizeof (DWORD) * 8] = "";  // für decimalToBinary-Funktion
  SYSTEMTIME    SystemTime;   // system time
  TCHAR         lpszMsg[127] = "";


  printf (szString, EV_RXCHAR, EV_RXFLAG, EV_TXEMPTY, 
      EV_CTS, EV_DSR, EV_RLSD, EV_BREAK, EV_ERR, EV_RING, SERIAL_EV_PERR,
      SERIAL_EV_RX80FULL, SERIAL_EV_EVENT1, SERIAL_EV_EVENT2);
        
  hCom = CreateFile ("COM1",
    GENERIC_READ | GENERIC_WRITE,
    0,    // exclusive access 
    NULL, // no security attributes 
    OPEN_EXISTING,
    FILE_FLAG_OVERLAPPED,
    NULL);
  
  if (hCom == INVALID_HANDLE_VALUE) 
    return printf ("\r\nCOM1 kann nicht geöffnet werden"); 

  if (!SetCommMask (hCom, dwEvtMaskIn)) 
    return printf ("\r\nSetCommMask fehlgeschlagen"); 
  
  // Create an event object for use in WaitCommEvent. 
  o.hEvent = CreateEvent (
    NULL,   // no security attributes 
    FALSE,  // auto reset event 
    FALSE,  // not signaled 
    NULL);  // no name 
    
  dwStart = GetTickCount ();

  while (GetTickCount () - dwStart < TIMELIMIT)
  {
    WaitCommEvent (hCom, &dwEvtMask, &o);
    
    if (WAIT_OBJECT_0 == WaitForSingleObject (o.hEvent, INFINITE))
    {
      GetLocalTime (&SystemTime);
      printf ("\r\nEvents: %s - ", decimalToBinary (dwEvtMask, sizeof (DWORD) * 8, szBuf));

      if (dwEvtMask & EV_DSR) 
        printf ("DSR "); 
      
      if (dwEvtMask & EV_CTS) 
        printf ("CTS "); 
      
      if (dwEvtMask & EV_BREAK) 
        printf ("BREAK "); 
      
      if (dwEvtMask & EV_RING) 
        printf ("RING "); 
      
      if (dwEvtMask & EV_RXCHAR)
        //printf ("RXCHAR "); 
      if (dwEvtMask & EV_RLSD) 
        printf ("RLSD "); 
      
      if (dwEvtMask & EV_ERR) 
        printf ("ERR "); 
      
      if (dwEvtMask & EV_RXFLAG) 
        printf ("RXFLAG "); 
      
      if (dwEvtMask & EV_TXEMPTY) 
        printf ("TXEMPTY "); 
      
      if (dwEvtMask & SERIAL_EV_PERR) 
        printf ("PERR "); 
      
      if (dwEvtMask & SERIAL_EV_RX80FULL) 
        printf ("RX80FULL "); 
      
      if (dwEvtMask & SERIAL_EV_EVENT1) 
        printf ("EVENT1 "); 
      
      if (dwEvtMask & SERIAL_EV_EVENT2) 
        printf ("EVENT2 "); 

      wsprintf (lpszMsg, "%s, den %02d.%02d.%04d um %d:%d Uhr %d,%d Sek.",
        SystemTime.wDayOfWeek == 1 ? "Mo" : 
        (SystemTime.wDayOfWeek == 2 ? "Di" : 
        (SystemTime.wDayOfWeek == 3 ? "Mi" : 
        (SystemTime.wDayOfWeek == 4 ? "Do" : 
        (SystemTime.wDayOfWeek == 5 ? "Fr" : 
        (SystemTime.wDayOfWeek == 6 ? "Sa" : 
        (SystemTime.wDayOfWeek == 7 ? "So" : "Heute")))))), 
        SystemTime.wDay, SystemTime.wMonth, SystemTime.wYear,
        SystemTime.wHour, SystemTime.wMinute, SystemTime.wSecond, 
        SystemTime.wMilliseconds);
      printf (": %s", lpszMsg); 
    }
  }

  CloseHandle (o.hEvent);
  CloseHandle (hCom);

  return printf ("\r\n!ENDE! %d Sekunden sind um!\r\n", TIMELIMIT / 1000);
}


/*****************************************************************************
** Umwandlung: Dezimal zu Binär
**
** 1. Param: die Zahl
** 2. Param: Anzahl der Binärstellen (von 1..32)
** 3. Param: Zeiger auf ein char-Array, das den String aufnehmen kann
*****************************************************************************/
const char* decimalToBinary (const long value, 
                             const unsigned length,
                             char* pszBuffer)
{
  if ((length == 0) || (length > 32))
  {
    pszBuffer = '\0';
    return pszBuffer;
  }
  
  unsigned digit = 1 << (length - 1);
  char* pszCurrent = pszBuffer;
  
  do
  {
    if (value & digit)
      *pszCurrent = '1';
    else
      *pszCurrent = '0';
    pszCurrent++;
    digit /= 2;
  } while (digit != 0);
  
  *pszCurrent = '\0';
  
  return pszBuffer;
}




Blackbird

Autor: Carsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Blackbird,

dankeschön, das funktioniert.Klasse!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.