PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : serielle Schnittstelle



Devil Ray
08.09.2004, 16:45
Hallo, ich möchte durch ein C++ Programm über die serielle Schnittstelle kommunizieren. Wie kann ich diesen Port öffnen und darauf zugreifen bzw. abfragen?
Ich möchte auf einer Platine an einen definierten Port einen bestimmten Wert senden. Wie schreibe ich das in C? Weiß da jemand was oder kennt ein paar gute Links?

08.09.2004, 19:14
Entweder hier Forensuche (da laufen noch Diskussionen) oder auf www.mikrocontroller.net das Forum PC-Programmierung.
Unterm Strich kommt bei allen Sachen raus, dass es keine einfache Lösung gibt und man schon etwas tiefergehende Programmierkenntnisse haben sollte.

Gruss, Alex

Blackbird
09.09.2004, 07:50
// DOS32-Programm zum Senden eines Bytes über COM1 (9600-8N1)
// OS: W95, W98, W98SE, WinME, WinNT, Win2000, WinXP
// Note: Keine Fehlerbehandlung implementiert!
#include <windows.h>

int main (void)
{
DCB dcb;
DWORD iBytesWritten;
unsigned char ucMsg = 'C'; // zu sendendes Zeichen

HANDLE hCom = CreateFile ("COM1", GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);

dcb.DCBlength = sizeof(DCB); // Laenge des Blockes MUSS gesetzt sein!
GetCommState (hCom, &dcb); // COM-Einstellungen holen und aendern
dcb.BaudRate = 9600; // Baudrate
dcb.ByteSize = 8; // Datenbits
dcb.Parity = NOPARITY; // Parität
dcb.StopBits = ONESTOPBIT; // Stopbits
SetCommState (hCom, &dcb); // COM-Einstellungen speichern

WriteFile (hCom, &ucMsg, 1, &iBytesWritten, NULL); // Senden eines Bytes

CloseHandle (hCom); // COM1 schließen

return (0);
}


Blackbird

Hessibaby
09.09.2004, 08:29
Hi Devil Ray,

leider ist es seit WIN NT4.0 nicht mehr ganz so trivial direct auf eine Schnittstelle zuzugreifen da die Resourcen vom Betriebssystem per DLL-Function Call verwaltet werden. In einem DOS-Fenster geht´s da hier alle betriebssysteminternen Sicherheitsmechanismen ausgehebelt werden. Die entsprechenden DLL-Einsprungpunkte für Serviceroutinen sind in einigen Foren dokumentiert. Du hast allerdings die Möglichkeit z.B. auf Hyperterm aufzusetzen.

Gruß Hartmut

Blackbird
09.09.2004, 11:45
@Hessibaby,
weißt Du auch, wovon Du schreibst?

Die altbekannten Funktionen inport(...) und outport(...) funktionieren nur unter 16Bit-OS wie eben DOS, Win3.1 und unter W95 und W98, W98SE. Die "neuen" Funktionen (siehe Code-Beispiel) sind ab W95 aufwärts bis zum letzten aktuellen OS, einschließlich der darauf laufenden DOS32-Box vorgesehen.
Das in einem Dos(32)-Fenster in WinNT, Win2000 oder WinXP die "betriebssysteminternen Sicherheitsmechanismen ausgehebelt " werden ist Quatsch.

Der Zugriff auf die seriellen Ports ist unter WinNT, Win2000 oder WinXP genauso einfach wie unter DOS. Komplizierter wird es erst, wenn die Zugriffe interruptgesteuert und im Hintergrund laufen. Aber das war unter DOS auch nicht einfacher.

Blackbird

Hessibaby
09.09.2004, 12:21
Hi Blackbird,

wenn Du meinst. OK. Aber lösche mal in einem DOS Fenster eine Datei und schau anschließend mal ob Du diese im Papierkorb wiederfindest.
Die Im-/Export-funktionen greifen auf die zugeordneten DLL´s zu. Und anders geht´s auch nicht weil sonst das ganze Taskmanagment auf den Bauch fällt -da kommen auch die geliebten Blue-Screens her.

Gruß Hartmut

Blackbird
09.09.2004, 16:40
Das "DOS-Fenster" unter W95, W98 (und WinME?) hat noch den Direktzugriff auf das "unter" dem Windows liegende DOS. Und nur da umgeht es also die W95++ -"Schutzmechanismen".
Aber unter WinNT aufwärts ist das DOS32-Fenster nur ein Windowsprogramm wie alle anderen auch. Und es bedient sich auch der gleichen Funktionen, DLLs, Treiber, etc. Deshalb funktionieren ja auch von dort die Portzugriffe, nicht nur in einem Windowsprogramm.

Was ich mit dem Beispielcode zeigen wollte, war die einfach Ansteuerung von seriellen Ports unter ("geschützten") W32-Systemen, die aber auch unter den alten Windows-OS funktioniert. Als "Rahmen" habe ich das Consolenprogramm mit int main (void) {} gewählt, weil ein Windowsprogramm zu viel (verwirrenden) overhead hat. Geht aber genauso, den Code kann ich auch noch posten, ist aber viel länger.

Die SerialPort-Ansteuerung ist von MS in den Compilerhilfen nicht besonders hervorgehoben und etwas tricky. Deshalb haben eine Reihe Programmierer diese Funktionen in einem Treiber, einer DLL zusammengefaßt und veröffentlicht. Kann man auch benutzen, warum nicht? Programmieren muß man aber trotzdem noch, da kann man auch die paar Zeilen Code selber schreiben, wenn man nicht den vollen Funktionsumfang braucht.

Blackbird

NumberFive
11.09.2004, 13:41
Hallo,

Blackbird du hast recht dein Code tut ob alles Dosfenster und als windows prg. Nur das man mit den Code nur schreiben kann und nix empfangen.
Wenn man mit so code empfangen will muß man leider ein thread bauen.
da son zeichen verloren gehen.

Das einzige was ich noch ein bauen würde ist Purgecom um bei starten den serial buffer zu löschen. Irgenwo hier im forum hatte ich mal den Source gepostet aber ich finde ihn nicht wieder war für VC 6 und ATL

ach jetzt habe ich es doch gefunden

https://www.roboternetz.de/phpBB2/viewtopic.php?t=1259

Gruß

Blackbird
13.09.2004, 07:28
@NumberFive;

die Frage war:


Ich möchte auf einer Platine an einen definierten Port einen bestimmten Wert senden. Wie schreibe ich das in C?

Buffer löschen und Schnittstelle zurücksetzten (CLRDTR) fehlen genauso wie das Abfangen von Fehlern.

Ich gehe aber mal davon aus, dass @Devil Ray programmieren kann.

Bytes empfangen sollte man immer in einem eigenen Thread. Das funktioniert dann auch ab W95 aufwärts. Damit sich nichts stört, öffnet man die COM-Schnittstelle noch im Modus OVERLAPPED.

Blackbird

NumberFive
14.09.2004, 07:22
Ok hab dann dasvielleicht was mis verstanden.

Auf ein port zuzugreifen geht aber auch.Im ddk von ms gibt es ein beispiel
damit kann mann sich port adressen blockieren(als treiber installiert makieren) dann kann aus ein prg auf den treiber direckt zu greifen und daten an die adresse schreiben. Habe im mal programmiern für die Paralle schnistelle um ein lauf licht zu bauen. also wenn so gesucht wird kann ich mit source und programm dienen also aber für c++ von ms.

Nachteil dieser metode man kann die Paralle schnistelle nicht mehr im normalen windows verwenden. installation ist nicht gar so einfach.

Gruß Numberfive

NumberFive
14.09.2004, 07:27
Oder geht es vielleicht um den c code fürden AVR ?

24.09.2004, 23:12
Hallo Blackbird

Ich habe fast den selben code wie du zusammengestellt zum senden.
Bekomme es aber nicht hin die Schnittstelle auszulesen.

konntest du mir da vieleicht helfen??

Gruß Stefan

Blackbird
28.09.2004, 12:16
Hier ist ein funktionierender Code zum Empfangen und Senden von zeichen über die serielle Schnittstelle. Die einzelnen Code-Teile (Initialisieren, Empfangen, Senden und Schließen) sind je nach Programm/Aufgabenstelleung in einem anderen Kontext zu verwenden.
Das Proggi hier ist nur ein Beispiel, wie man das macht.


// DOS32-Programm zum Senden/Empfangen von Bytes über COM2 (9600-8N1)
// Alle empfangenen Bytes werden zurückgesendet.
// OS: W95, W98, W98SE, WinME, WinNT, Win2000, WinXP
// Note: Keine Fehlerbehandlung implementiert!
#include <windows.h>
#include <stdio.h>

#define COM_BUFFER_SIZE 16 // Read- und Write-Buffer-Size
#define BD_RATE CBR_9600 // 9600 Baud


int main (void)
{
DCB dcb;
DWORD iBytesWritten;
BOOL bRet = true;
DWORD dwRead = 0;
DWORD dwSetMask = EV_RXCHAR | EV_ERR;
DWORD dwEvtMask;
OVERLAPPED o;
COMMTIMEOUTS ct;
unsigned char InString[COM_BUFFER_SIZE + 1];

memset (&o, 0, sizeof (OVERLAPPED)); // Struktur mit 0en füllen
o.hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); // einen Event setzten

HANDLE hCom = CreateFile ("COM2", GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, &o);

dcb.DCBlength = sizeof(DCB); // Laenge des Blockes MUSS gesetzt sein!
GetCommState (hCom, &dcb); // COM-Einstellungen holen und aendern
dcb.BaudRate = BD_RATE; // Baudrate
dcb.ByteSize = 8; // Datenbits
dcb.Parity = NOPARITY; // Parität
dcb.StopBits = ONESTOPBIT; // Stopbits
SetCommState (hCom, &dcb); // COM-Einstellungen speichern

GetCommTimeouts (hCom, &ct);
// Warte-Zeit [ms] vom Beginn eines Bytes bis zum Beginn des nächsten Bytes
ct.ReadIntervalTimeout = 1000 / BD_RATE * (dcb.ByteSize +
(dcb.Parity == NOPARITY ? 0 : 1) +
(dcb.StopBits == ONESTOPBIT ? 1 : 2)) * 2;
ct.ReadTotalTimeoutMultiplier = 0; // [ms] wird mit Read-Buffer-Size multipliziert
ct.ReadTotalTimeoutConstant = 50; // wird an ReadTotalTimeoutMultiplier angehängt
ct.WriteTotalTimeoutMultiplier = 0;
ct.WriteTotalTimeoutConstant = 0;
SetCommTimeouts (hCom, &ct);

// Zwischenspeicher des serial-Drivers einstellen (für read und write):
SetupComm (hCom, COM_BUFFER_SIZE, COM_BUFFER_SIZE);

SetCommMask (hCom, dwSetMask); // Empfangssignale definieren

do // in Endlos-Schleife auf Empfangssignale warten:
{
WaitCommEvent (hCom, &dwEvtMask, &o); // Event mit Empfangssignalen verknüpfen

if (WAIT_OBJECT_0 == WaitForSingleObject (o.hEvent, INFINITE)) // warten bis Event
{
if (dwEvtMask & EV_RXCHAR) // Zeichen an RxD empfangen:
{
bRet = ReadFile (hCom, &InString, sizeof (InString), &dwRead, NULL);

if (!bRet)
{ // Fehlerausgabe:
LPVOID lpMsgBuf;
FormatMessage (FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(),
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
(LPTSTR) &lpMsgBuf, 0, NULL);
MessageBox (NULL, (LPCTSTR)lpMsgBuf, "Error: ReadFile",
MB_OK | MB_ICONINFORMATION);
LocalFree (lpMsgBuf);
}
else
{ // Ausgabe (oder Verarbeitung) der empfangenen Bytes:
InString[dwRead] = '\0';
printf (TEXT("\r\n\tRxD (%d Byte(s)): %s"), dwRead, InString);
WriteFile (hCom, &InString, dwRead, &iBytesWritten, &o); // Senden eines Bytes
}
}

if (dwEvtMask & EV_ERR)
{
MessageBox (NULL, "Error empfangen", "Error: ReadFile", MB_OK);
break; // Schleifen-Abbruch
}
}
}
while (1);

CloseHandle (hCom); // COM schließen
CloseHandle (o.hEvent); // Event-Handle zurückgeben

return (0);
}

Viel Spaß beim proggen.


Blackbird

04.10.2004, 13:26
Hallo Blackbird
Vielen dank für deine Hilfe!!!!!!!!!!!!!!!!!!!!!!