Hier soll beschreiben werden wie die serielle Schnittstelle via C/C++
angesteuert wird.
Am Ende habe ich einen Quellcode mit den Com-Tools
für Windows angehängt. Darin ist ein kleines Demoprogramm
enthalten das zeigt wie zwei Computer mit einander verbunden werden können. Ein
weiteres Beispiel zeigt wie alle COM-Schnittellen aufgelistet
werden können, und bestimmt werden kann welche Ports von USB-Geräten stammen.
Die Schnittstelle besteht aus mindestens 3 Leitungen. (GND RxD und TxD). GND
ist die Masseverbindung, über TxD werden die Daten gesendet und bei RxD
empfangen. Die Daten werden asynchron übertragen. Das heißt zwischen Sender
und Empfänger gibt es kein Synchronisationssignal. Der Beginn der
Datenübertragung wird durch ein Startbit auf der TxD Leitung eingeleitet. Dieses
Bit ist immer 0 (low). Ein logisches 0 Signal entspricht einem Pegel von +15 bis
+3 Volt. Ein logisches 1 Signal entspricht einem Pegel von -15 bis -3 Volt. Nach
dem Startbit folgen die Datenbits, beginnend mit dem niederwertigsten Bit. Es
können 5 bis 8 Datenbits übertragen werden, üblich sind aber 7 oder 8 Datenbits. Nach
den Datenbits kann ein Paritybit folgen. Dieses kann auf vier Arten
erfolgen. Gerade Parität dann wird das Paritybit auf 1 gesetzt wenn eine
ungerade Anzahl an logischen 1'en in den Datenbits vorhanden war. Ungerade
Parität dann wird das Paritybit auf 1 gesetzt wenn eine gerade Anzahl an
logischen 1'en in den Datenbits vorhanden war. Außerdem kann das Paritybit
immer auf 1 oder auf 0 gesetzt werden. Die Übertragung wird durch ein Stopbit
beendet. Dieses ist immer 1 und ist ein, ein-ein-halb oder zwei Bits lang. Die
Baudrate bestimmt wie viele Bits je Sekunde ausgegeben werden.
Durch setzen der RTS (ready to send) Leitung auf 1 wird signalisiert das die Schnittstelle bereit zum senden ist. Über CTS (clear to send) wird empfangen ob die Gegenseite bereit zum senden ist. Durch setzen der DTR (date terminal ready) Leitung auf 1 wird signalisiert das die Schnittstelle betriebsbereit ist. Über DSR (data set ready) wird empfangen ob die Gegenseite bereit ist. Für eine Verbindung zwischen zwei PC's braucht man ein 7-poliges Null-Modem Kabel. Die 3 polige Variante ist die Sparversion und funktioniert in den meisten Fällen auch:
Programmierung der seriellen Schnittstelle
Auf die serielle Schnittstelle kann man unter Windows zugreifen über die Datei-IO Funktionen:
- CreateFile
- CloseHandle
- WriteFile
- ReadFile
Die Einstellungen der serielle Schnittstelle erfolgen über die API-Funktionen:
- SetCommState
- SetCommTimeouts
So öffnet man die Schnittstelle:
DCB sDcb;
HANDLE hFile;
COMMTIMEOUTS sTo;
hFile=CreateFile("\\\\.\\COM1",GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
if(hFile==INVALID_HANDLE_VALUE)return0;
memset(&sDcb,0,sizeof(sDcb));
sDcb.DCBlength = sizeof(sDcb);
sDcb.BaudRate = 9600; // Baudrate
sDcb.fParity = FALSE;
sDcb.fBinary = TRUE;
sDcb.Parity = NOPARITY;// Kein Paritybit
sDcb.StopBits = ONESTOPBIT;
sDcb.fOutxCtsFlow = FALSE;
sDcb.fOutxDsrFlow = FALSE;
sDcb.fDtrControl = DTR_CONTROL_ENABLE;
sDcb.fRtsControl = RTS_CONTROL_ENABLE;
sDcb.fDsrSensitivity = FALSE;
sDcb.fAbortOnError = FALSE;
sDcb.ByteSize = 8; // 8 Datenbits
if(!SetCommState(hFile,&sDcb))
{
CloseHandle(hFile);
return
0;
}
sTo.ReadIntervalTimeout = MAXDWORD; // 0 ms Read-Tomeout
sTo.ReadTotalTimeoutMultiplier = 0;
sTo.ReadTotalTimeoutConstant = 0;
sTo.WriteTotalTimeoutMultiplier= 1; // 1*2 ms Write Timeout
sTo.WriteTotalTimeoutConstant = 2;
if(!SetCommTimeouts((HANDLE)hFile,&sTo))
{
CloseHandle(hFile);
return
0;
}
So liest und schreibt man auf die Schnittstelle:
DWORD dwCount;
char cData[16];
ReadFile (hFile,cData,16,&dwCount,0);
WriteFile(hFile,cData,16,&dwCount,0);
Die Pegel auf der RTS und DTR Leitung können beliebig gesetzt werden, es sind dazu nur die Variabelen bDtrOn und bRtsOn im folgenden Beispiel richtig zu setzen:
...
bool bDtrOn=1, bRdsOn=1;memset
(&sDcb, 0 ,sizeof(sDcb)); sDcb.DCBlength = sizeof(sDcb);
GetCommState(hFile,&sDcb); sDcb.fDtrControl = (bDtrOn)? DTR_CONTROL_ENABLE:DTR_CONTROL_DISABLE; sDcb.fRtsControl = (bRdsOn)? RTS_CONTROL_ENABLE:RTS_CONTROL_DISABLE; SetCommState(hFile,&sDcb); ...
Die Tools bestehen aus acht Funktionen:
ComInit Initialisieren
ComExit Deinitialisieren
ComOpen Schnittstelle öffnen
ComClose Schnittstelle schließen
ComRead Daten lesen
ComWrite Daten schreiben
ComGetReadCount Abfragen wieviele Bytes im Empfangspuffer sind
ComGetWriteCount Abfragen wieviele Bytes im Sendepuffer sind
Um ein COM-Port ansprechen zu können muss mit ComInit den Treiber zuerst initialisiert werden. Anschließend öffnet man mit ComOpen das COM-Port. Mit ComRead und ComWrite können jetzt Daten einlesen und ausgeben werden.
Hier ist ein kleines Beispiel wie man die Com-Tools anwendet:
#include
"ComTools.h"
#define COM2 1
intmain()
{
char cData[16]="Hallo";
int i;
ComInit (); // Initialisierung
ComOpen (
COM2
,19200); // COM2 öffnen
ComWrite(
COM2
,cData,5); // 5 Byte schreiben
i=
ComRead (
COM2
,cData,16); // 16 Byte lesen
ComClose(
COM2
); // COM2 schließen
ComExit ();
// Deinitialisierung
printf
("\nEs wurden %i Zeichen empfangen.\n",i
);
return 0;
}
Download der Com-Tools Com-Tools samt einem kleinen Demo-Programm das zeigt wie man zwei PC's mit einem Null-Modem-Kabel verbindet.
Hier sind ist eine Funktionen mit der man die seriellen Schnittstellen auflisten kann. Dabei wird auch angezeigt ob die COM-Schnittstelle von einem USB-Grerät stammt. Außerdem werden die Device-Namen und Beschreibungen angezeigt. Das ganze läuft über die Funktion ComEnumPorts. Hier ein Beispiel:
#include "ComEnumPorts.h" #include <conio.h> #include <stdio.h> #include <stdlib.h> #include <string.h> int main(int argc, char* argv[]) { int i,iCount; ComInfo *pInfo; iCount = ComEnumPorts(NULL,0); // Zählen der Ports if(!iCount) { printf("\n\nNo Ports found.\n\n"); getch(); return -1; } pInfo = new ComInfo[iCount]; // Port Informationen holen iCount = ComEnumPorts(pInfo,iCount); for(i=0;i<iCount;i++) { printf("\nPort %i",i); printf("\n\tPort = %s",pInfo[i].cPortName); printf("\n\tName = %s",pInfo[i].cFriendlyName); printf("\n\tPath = %s",pInfo[i].cDevPath); printf("\n\tDesk = %s",pInfo[i].cPortDesc); printf("\n\tUSB = %i",pInfo[i].bUsbDevice); printf("\n"); } delete pInfo; getch(); return 0; }
Dieser Source-Code funktioniert unter WinXP,Win2000,WinNT und Win98. Er erzeugt eine solche Ausgabe:
Port 0 Port = COM1 Name = Kommunikationsanschluss (COM1) Path = \\?\acpi#pnp0501#1#{86e0d1e0-8089-11d0-9ce4-08003e301f73} Desk = Kommunikationsanschluss USB = 0 Port 1 Port = COM2 Name = Kommunikationsanschluss (COM2) Path = \\?\acpi#pnp0501#2#{86e0d1e0-8089-11d0-9ce4-08003e301f73} Desk = Kommunikationsanschluss USB = 0 Port 2 Port = COM3 Name = Prolific USB-to-Serial Comm Port (COM3) Path = \\?\usb#vid_067b&pid_2303#5&29c90e1d&0&2#{86e0d1e0-8089-11d0-9c Desk = Prolific USB-to-Serial Comm Port USB = 1Unter Port wird der Name der Schnittstelle ausgegeben. Unter Name wird eine Beschreibung des Ports angezeigt. Path ist jener Pfad mit dem über CreateFile die Schnittstelle geöffnet werden kann. Desk ist eine allgemeine Beschreibung ohne der Angabe des Portnamens. Hier kann man den Source-Code downloaden.