Forum: PC-Programmierung RS232 lcc-win32 WinXp


von micro1 (Gast)


Lesenswert?

Ich möchte gerne unter Windows XP daten über COM1  schicken.
outp ist ja nicht mehr. Jetzt möchte ich aber nicht ie ganzen utils
benutzen die im netz rumschwirren damit das wieder geht.
Weis jemand wie man richtig mit dem lcc-win32 c compiler
auf einfachste weise dir serielle schnittstelle COM1 öffnet und einfach
1 byte darüber schickt. Ich habe mich jetzt schin durch tausende web
sites geklickt wurde aber nicht schlau daraus

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Das geht mit den Systemfunktionen CreateFile, WriteFile/ReadFile etc.
und noch ein paar anderen, mit denen Baudrate etc. konfiguriert
werden.

Ein Tutorial, das zumindest einen Anhaltspunkt liefern dürfte, ist
http://www.luxoncreations.com/tutorials/serial_read/

Mit direkten Portzugriffen (outp etc.) wärest Du bei einer seriellen
Schnittstelle übrigens schon unter Windows 3.0 (ja, dem 16-Bit-Relikt)
auf die Schnauze gefallen; von Hardware, die Interrupts auslösen kann
und vom Betriebssystem auch dafür konfiguriert ist, sollte man
tunlichst die Finger lassen.

Es geht aber auch ohne Programmieren:

In der Kommandozeile ("Eingabeaufforderung", von manchen Leuten
fälschlicherweise "DOS-Box" genannt) tippst Du folgendes ein:

copy con com1:

dann drückst Du die Eingabetaste, tippst die zu sendenden Zeichen ein
und schließt die Eingabe mit Ctrl+Z ("Strg+Z") ab.

Konfigurieren kannst Du die Schnittstelle in der Kommandozeile mit dem
Mode-Befehl:

   MODE COMm[:] [BAUD=b] [PARITY=p] [DATA=d] [STOP=s]
   [to=on|off] [xon=on|off] [odsr=on|off]
   [octs=on|off] [dtr=on|off|hs]
   [rts=on|off|hs|tg] [idsr=on|off]

Ausführlicher:
baud=b
  Baudrate, kennt folgende Abkürzungen:
   11 110 Baud
   15 150 Baud
   30 300 Baud
   60 600 Baud
   12 1200 Baud
   24 2400 Baud
   48 4800 Baud
   96 9600 Baud
   19 19.200 Baud

parity=p
  Bestimmt, wie das System das Paritätsbit verwendet, um
  Übertragungsfehler zu überprüfen. In der folgenden Tabelle sind
  gültige Werte für p aufgeführt.
  n,e,o,m,s = none, even, odd, mark, space
  Der Standardwert ist e. Die Werte m und s werden nicht auf
  allen Computern unterstützt.
data=d
  Gibt die Anzahl der Datenbits pro Zeichen an. Gültige Werte
  für d liegen im Bereich von 5 bis 8. Der Standardwert ist 7.
  Nicht alle Computer unterstützen die Werte 5 und 6.
stop=s
  Gibt die Anzahl der Stoppbits an, die das Ende eines
  Zeichens definieren: 1; 1,5 oder 2. Wenn die Übertragungsrate
  110 eingestellt wurde, werden standardmäßig 2 Stoppbits
  verwendet; andernfalls ist 1 der Standardwert.
  Nicht alle Computer unterstützen den Wert 1,5.
to={on|off}
  Bestimmt, ob die Verarbeitung der endlosen Zeitüberschreitung
  ein- oder ausgeschaltet ist. Der Standardwert ist off.
xon={on|off}
  Bestimmt, ob das xon- oder xoff-Protokoll für die
  Datenflusssteuerung ein- oder ausgeschaltet ist.
odsr={on|off}
  Bestimmt, ob der Ausgabehandshake, der das DSR (Data Set
  Ready)-Signal verwendet, ein- oder ausgeschaltet ist.
octs={on|off}
  Bestimmt, ob der Ausgabehandshake, der das CTS (Clear To
  Send)-Signal verwendet, ein- oder ausgeschaltet ist.
dtr={on|off|hs}
  Bestimmt, ob das DTR (Data Terminal Ready)-Signal ein-
  (on) bzw. ausgeschaltet (off) ist oder auf Handshake (hs)
  gesetzt bzw. umschaltbar (tg) ist.
rts={on|off|hs|tg}
  Bestimmt, ob das RTS (Request To Send)-Signal ein- (on)
  bzw. ausgeschaltet (off) ist oder auf Handshake (hs) gesetzt
  bzw. umschaltbar (tg) ist.
idsr={on|off}
  Bestimmt, ob das DSR-Signal verwendet wird oder nicht.




also beispielsweise

   Mode com1: Baud=19200 Parity=n Data=8 Stop=1

von Blackbird (Gast)


Lesenswert?

Wenn es C sein soll:

// 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[] = {0x41, 0x42, 0x20, 0x43}; // (4)
  //unsigned char ucMsg = 'C';    // zu sendendes Zeichen (1)

  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, 4, &iBytesWritten, NULL); // Senden von 4
Bytes
  WriteFile (hCom, &ucMsg, sizeof (ucMsg), &iBytesWritten, NULL); //
Senden von 4 Bytes
  // oder:
  //WriteFile (hCom, &ucMsg, 1, &iBytesWritten, NULL); // Senden eines
Bytes

  CloseHandle (hCom); // COM1 schließen

  return (0);
}


Blackbird

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Pedanterie:

Das ist kein "Dos32"-Programm, sondern ein ganz normales
32-Bit-Konsolenprogramm.

Bitte keine unnötigen Termini für bereits definiertes erfinden, das
schafft nur Verwirrung.

von micro1 (Gast)


Lesenswert?

@Blackbird

Ich bin absolut begeistert es funktioniert vielen Dank endlich mal eine
klare leicht verständliche Antwort die wirklich funktioniert.

Jetzt habe ich nur noch eine andere Frage.
Ich möchte jetzt noch daten Empfangen. Wie geht das?
Da ich nämlich über dir RS232 eine Datenstrom empfange und diesen
mchteich dann in einem File abspeichern. Wie das mit dem File geht
weis. Ich müsste nur wissen wie ich halt Daten uner win Xp in einem
eigenem C Programm empfangen kann

von Tobi H. (tobi-) Benutzerseite


Lesenswert?

Lesen geht mit ReadFile
Falls du nicht ewig warten willst, bis etwas kommt am einfachsten
vorher einen Timeout mit SetCommTimeout setzen

von Blackbird (Gast)


Lesenswert?

Lesen ist auch nicht kompliziert:


// 32-Bit-Konsolen-Programm zum Senden/Empfangen von Bytes über COM
(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 256       // Read- und Write-Buffer-Size
#define BD_RATE         CBR_9600 // 9600 Baud
#define HELP_STRING TEXT("Aufruf mit: progname
<COM-Port-Nummer>\r\n")


// Hauptprogramm: Aufruf mit: progname <COM-Port-Nummer>
int main (int argc, char **argv)
{
  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];
  TCHAR         szCOM[6];


  if (argc == 2 &&                              // progname +
COM-Port-Nummer ?
      atoi (argv[1]) > 0 && atoi (argv[1]) < 5) // COM1 ... COM4?
    wsprintf (szCOM, TEXT("COM%s"), argv[1]);   // String "basteln"
...
  else
  {
    printf (TEXT("\r\nERROR:\t %s"), HELP_STRING);
    return (1); // und tschüß ...
  }

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

  HANDLE hCom = CreateFile (szCOM, GENERIC_WRITE | GENERIC_READ, 0,
NULL,
                            OPEN_EXISTING, 0, NULL);


  if (hCom == INVALID_HANDLE_VALUE)
  { // 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: CreateFile", MB_OK |
MB_ICONINFORMATION);
    LocalFree (lpMsgBuf);
    return (1); // und tschüß ...
  }

  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'; // in "zero-ended"-String
verwandeln
          printf (TEXT("\r\n\tRxD (%d Byte(s)): %s"), dwRead,
InString);
          WriteFile (hCom, &InString, dwRead, &iBytesWritten, NULL); //
Senden der 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);
}

Statt (oder zusaetzlich zum) Zuruecksenden der empfangenen Bytes kann
auch das Speichern in ein File eingebaut sein.
Wenn Dein Programm noch mehr machen soll, ist es besser, das
COM-Port-Einlesen in einen eigenen Thread zu legen.
Mit Windows-GUI gehts fast genauso, nur die GUI zwingt zu einer
Aufteilung in mehrere Funktionen.

Blackbird

von Blackbird (Gast)


Lesenswert?

Die zusaetzlichen Zeilenumbrueche versauen das ganze Layout - vor dem
Compilieren diese also noch entfernen. Sonst meckert der Compiler.

Blackbird

von micro1 (Gast)


Lesenswert?

Mal ne dumme Frage.
Gibt es für so etws kein Interrupt wie z.B bei einem µC.
Wo kann man eigentlich in einem Buch solche sachen nachlesen.
In den ganzen Büchern werden immer nur die grundlagen vermittelt.

Gibt es eigentlich etwas wo z.B richtig drinn steht wie man Interrupts
programmiert Timer auswertet Schnittstellen steuert usw usw

Oder ist die einzige Quelle MSDN?

von Tobi H. (tobi-) Benutzerseite


Lesenswert?

Heutzutage programmiert man nicht mehr direkt an der Hardware. Dadurch
fallen Interrupts und direkte Nutzung von Schnittstellen weg. Kein
aktuelles System lässt dich da mehr ran. Als Programmierer ist man nur
noch auf die Schnittstellen des OS angewiesen.
Aber etwas ähnliches wie Interrupts gibt es auch bei aktuellen Systemen
in Form von Callbacks oder Events. Dazu gibts in der MSDN auch sehr gute
Artikel, z.B
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnfiles/html/msdn_serial.asp

von micro1 (Gast)


Lesenswert?

Thanks at Tobi.

Die Seite ist auch sehr hilfreich. Dort steht ja auch die behnadlung
der serillen Schnittstelle drin.

Aber wieso hat man keinen Timer.

Ich müsste jetzt noch wiesen wie man in C eben alle 100 ms beschied
bekommt weil ich dann eine Funktion aufrufen möchte

von Tobi H. (tobi-) Benutzerseite


Lesenswert?

Timer gibt es auch.

Ich benutz bei mir die recht präzisen Multimedia-Timer mit
timeSetEvent, timeKillEvent

Der ersten Funktion gibt man eine Callback-Routine mit, wie oft und,
dass es periodisch aufgerufen werden soll. Am Ende mit der 2. Funktion
den Timer wieder löschen und fertig

von micro1 (Gast)


Lesenswert?

Kannst du ein Codebeispiel posten bitte ?

von Selim M. (trooper81vs18)


Lesenswert?

hallo balckbird!

ich habe deinen Programmierungstext kopiert und es über den Compiler
geschickt!



:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 
::::::::::::::::::::::::

// 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[] = {0x41, 0x42, 0x20, 0x43}; // (4)
  //unsigned char ucMsg = 'C';    // zu sendendes Zeichen (1)

  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, 4, &iBytesWritten, NULL); // Senden von 4
Bytes
  WriteFile (hCom, &ucMsg, sizeof (ucMsg), &iBytesWritten, NULL); //
Senden von 4 Bytes
  // oder:
  //WriteFile (hCom, &ucMsg, 1, &iBytesWritten, NULL); // Senden eines
Bytes

  CloseHandle (hCom); // COM1 schließen

  return (0);
}

:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 
:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: 
::::::::::::::::::::::::



über welche pins des rs 232 werden die 4 byts geschickt?

würde die glühbirne (siehe anhang) mit diesem programm leuchten? die
glühbirne schließe ich an RTS oder TxD und an einem GND!

von Selim M. (trooper81vs18)


Angehängte Dateien:

Lesenswert?

hier das bild zu meinem text von vorhin

von Tobi H. (tobi-) Benutzerseite


Lesenswert?

Ich würde dir Empfehlen, dich zumindest grundlegend mit der seriellen
Schnitstelle auseinander zu setzen. In deinem Schaltplan steht nicht
umsonst etwas von RTS. Schau dir mal die Pins einer solchen
Schnittstelle an und lies dir in den oben schon angegebenen Links
durch, wie man diese Pins ansteuert. Ich kann dir gleich sagen, dass
der Code, den du dort unnötigerweise noch einmal gepostet hast nicht
funktionieren wird.

von Weinga-Unity (Gast)


Lesenswert?

Schau dir mal das an:
http://pvbrowser.org/pvbrowser/sf/manual/rllib/html/classrlSerial.html

hab die Library selber in Verwendung, funktioniert supi, nur unter
Linux hab ich sie net zum Laufen gebracht (jemand Erfahrung?)

mfg W.K.

von Blackbird (Gast)


Lesenswert?

@Weinga-Unity - snaky.1gmx.at:

loest der Link, den Du angegeben hast, das Problem des Threaderstellers
oder das von Selim Mut (trooper81vs18) ?

Blackbird

von Weinga-Unity (Gast)


Lesenswert?

Ich denke, es löst das Problem des Threadstellers. Mit der angegebenen
Bibliothek (einfach die benötigen CPP und H Files in das eigene Projekt
beifügen) bekommt man auf einfachste Weise zugriff auf die serielle
Schnittstelle und man kann so sehr einfach ein Byte schicken.

mfg W.K.

von Blackbird (Gast)


Lesenswert?

Was ist bei meiner Loesung nicht (Zitat:) "einfachste Weise " (siehe
Post vom 10.08. ?
Und ist das Problem damit nicht schon geloest gewesen, einschliesslich
des Lesens vom COM-Port?

Selim Mut (trooper81vs18) hat ein ganz anderes Problem, die Hardware.

Blackbird

von Kartoffel S. (kartoffelsalat)


Lesenswert?

@blackbird

das von dir gepostete c-programm mit welchem bytes gesendet und 
empfangen werden können über den com funktioniert bei mir nicht. fliegt 
immer raus nach dem ersten return. neben bei mekert der compiler bei:

BOOL bRet = true

was mache ich falsch?

dei c-routine nur fürs senden, am anfang des thread funkt probklemlos!

gruss raphael

von Bratensosse (Gast)


Lesenswert?

Hi ihr

Ich erstelle gerade ne dialogbox und habe dazu den oben genannten code 
testweise übernommen.

die baudrade habe ich auf 110 gestellt, damit ich mit meinem uralt oszi 
noch was messen kann (dachte ich mir zumindest so)

wenn ich jetzt am Pin RTS messe, dann messe ich ca -12V

wenn ich dann die 4 Bytes übertrage (also auf meinen button klicke) dann 
reagier des programm 4 sekunden lang nicht, und der pegel springt von 
-12V auf +10V nach den 4 sekunden springt er dann wieder auf -12V....

Sollte der Pegel an RTS nicht aber "wild" hin und her zappeln?

Mache mit der RS232 erst so meine anfänge.... und bin jetzt erstmal 
total verunsichert....

vielen dank schonmal

gruß#
ich

von Blackbird (Gast)


Lesenswert?

"... wenn ich jetzt am Pin RTS messe, dann messe ich ca -12V ..."

RTS ist aktiv - ist in Ordnung.

"... wenn ich dann die 4 Bytes übertrage (also auf meinen button klicke) 
dann
reagier des programm 4 sekunden lang nicht, und der pegel springt von
-12V auf +10V nach den 4 sekunden springt er dann wieder auf -12V...."

i.O.: R(eady)-T(o)-S(end) ist solange inaktiv, wie gesendet wird.

"Sollte der Pegel an RTS nicht aber "wild" hin und her zappeln?"

Nein, TxD (Pin3) sollte aber "zappeln". Vorher und nachher sollten 
-8V...-12V anliegen.


Mal http://www.beyondlogic.org/serial/serial.htm#1 besuchen.

Blackbird

von Bratensosse (Gast)


Lesenswert?

Oh weia.... danke backbird

wer misst misst mist..... bin da jetzt nochmal ruhig ran gegangen und 
siehe da.... am TxD zappelt was, des ist mir gestern gar nicht 
aufgefallen, und dann hat mich der post mit dem RTS nur noch verwirrt

herzlichen dank;-)


juhu


danke

gruß
ich

von Wolfsblut (Gast)


Lesenswert?

@Blackbird:

Du hast am 10.08.2006 einen Code zur Ansteuerung der seriellen 
Schnittstelle unter C online gestellt. Dieser lässt sich bei mir auch 
problemlos kompilieren. Allerdings muss ich ein RDS Gerät, welches am 
Com Port hängt, ansprechen. Der Befehlssatz ändert sich laufend und auch 
die Länge. Um nun als Beispiel einen dieser Befehle zu schicken habe ich 
Deinen Code abgeändert. Folgendes soll laut Herstellerfirma des Geräts 
als Command übertragen werden:

STX + 0x02 + 0x00 + ASCII1 + ETX + CHK

Wobei ASCII1 = '1' für gesetztes Bit ist.

Folgenden Code habe ich geschrieben:

#include <windows.h>

int main ()
{
  DCB           dcb;
  DWORD         iBytesWritten;

  int laenge = 3;

  unsigned char *output; // Liste mit x-Einträgen

  output = (unsigned char*) malloc(sizeof(int)*laenge);

  output[0] = 0x02;
  output[1] = 0x02;
  output[2] = '1';
  output[3] = 0x03;

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

  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, &output, sizeof (output), &iBytesWritten, NULL);
  // Senden von output mit oben defenierter Größe

  CloseHandle (hCom); // COM1 schließen

  return(0);
}

Wie gesagt: Der Code lässt sich ohne Probleme bei mir kompilieren und 
ausführen. Aber das angeschlossene Gerät reagiert nicht drauf (an dem 
Gerät liegt es nicht, da es mit der Steuersoftware vom Hersteller 
klappt. Da aber ein automatisierter Protzess ablaufen soll, soll das 
ansprechen des RDS Coder mittels eines Programmteils in C geschehen).

Ich wäre Dir und auch jedem anderen für ein wenig Hilfe sehr dankbar. 
:-)

Ich hoffe, dass mir einer helfen kann. Verzweifel daran schon.

Ich habe auch meine Email Adresse angegeben und bin für jeden Vorschlag 
und Hilfe auch per email unendlich dankbar.

Hoffe bald weiter zu kommen.

Gruß

Wolfsblut

von Wolfsblut (Gast)


Lesenswert?

Ohje... Gepennt...

Hier noch meine Email Adresse, wo man mich erreichen kann:
wolfsblut@wolfspride.com

Sorry für die erneute Störung.

Gruß
Wolfsblut

von ... (Gast)


Lesenswert?

Hi Wolfsblut,

mal einige Sachen, die mir aufgefallen sind:
  "STX + 0x02 + 0x00 + ASCII1 + ETX + CHK"
sieht irgendwie nach 6 Bytes aus. (btw. was ist CHK, eventuell irgendein 
Prüfbyte; wenn ja, wie berechnet?)
In Deinen Code ist "laenge=3" ?!?!?
Dann "... malloc(sizeof(int)*laenge)", warum multiplizierst Du hier mit 
sizeof(int) und nicht mit sizeof(char) bzw. sizeof(unsigned char) ?
Anschließend schreibts Du da 4 Bytes rein! Sollten das nicht 6 sein?
Und zum Schluß benutzt Du "sizeof (output)" für die Anzahl der zu 
übertragenden Byte. Das ist definitiv auch nicht das, was Du willst! Das 
liefert Dir die Größe des Pointers, aber nicht die Anzahl der Bytes auf 
die dieser zeigt!

CU

von Blackbird (Gast)


Lesenswert?

Hallo @Wolfsblut,

zum geposteten Code von Dir:
- siehe Hinweise von @...(Gast), der Poster vor mir
- ein feste Zeichenfolge kannst Du auch so setzen:
1
#define ETX 0x05
2
    unsigned char msg[] = {0x03, 0x02, 0, '1', ETX, 12};
3
4
    BOOl bRet = WriteFile (hCom, &msg, sizeof(msg), &iBytesWritten, NULL);

- eine variable Zeichenfolge, gemischt mit festen Zeichenfolgen mit 
structs
- überprüfe die return codes Deiner aufgerufenen Funktionen, z.b: so:
1
if(!bRet)
2
{
3
    LPVOID lpMsgBuf;
4
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
5
        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
6
        NULL, GetLastError(),
7
        MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
8
        (LPTSTR) &lpMsgBuf, 0, NULL);
9
        MessageBox(NULL, (LPCTSTR)lpMsgBuf, TEXT("Error WriteFile:"), 
10
        MB_OK | MB_ICONSTOP);
11
    LocalFree(lpMsgBuf);
12
}


Blackbird

von Blackbird (Gast)


Lesenswert?

Noch was.
Wenn Du nicht sicher bist, was an der seriellen Schnittstelle geschieht, 
so verbinde sie einfach mit einer weiteren seriellen Schnittstelle und 
lasse dort ein Terminalprogram drauf laufen, welches auch hexadezimal 
darstellen kann, z.B. "SerialWatcher.exe".


Blackbird

von Wolfsblut (Gast)


Lesenswert?

Erstmal vielen Dank für Eure Hilfe und Unterstüztung. Das hilft mir echt 
weiter und ich sehe meine Fehler nun leider auch...

Ouch... Das tut weh!

@... :
Vielen Dank für Deine Anmerkungen. Es ist schon ziemlich doof was ich da 
für "Flüchtigkeitsfehler" eingebaut habe.
Also:
- laenge = 3; :
  Was ich hier gepostet habe wird später ja nur ein Unterprogramm. Und 
in diesem soll die Laenge des Vektors ( da dieser bei verschiedenen 
Befehl verschieden lang sein wird) variiert werden. Zum testen wollte 
ich die Länge auf einen festen Wert setzen. Dabei sollte ich aber auch 
einen Wert nehmen, der dem ganzen angemessen ist... Ist bereits 
geändert.

- CHK:
  Nun ja. Wenn ich schon sowas schreibe sollte ich auch angeben, was CHK 
ist. Hier mal die Aufschlüsselung:
CHK = STX .XOR. CODE (hier: 0x02) .XOR. Pointer (hier: nicht vorhanden, 
aber in anderen Befehlen) .XOR. ASCII1 .XOR. ASCII2 .XOR. ... (weitere 
ASCII Codes bei anderen Befehlen, hier nur ein einziger) .XOR. ETX

- Ähm... :
  Was mir noch aufgefallen ist: Selbst wenn ich die Prüfsumme CHK am 
Ende weglassen würde, so muss ich doch die 0x00, die ich beim Command 
erwähnt habe,  mit einbauen. Das tat ich nicht. Klar, dass es dann auch 
schon mal nicht geht...

- sizeof(int):
  OK. Da sollte sizeof(unsigned char) stehen... Schon geändert.

- sizeof(output):
  Hier hatte ich mich auf den Code von Blackbird bezogen.... Für mich 
klang es logisch, dass ich die Anzahl der auszugebenden Bytes angeben 
muss.

@ Blackbird:
Danke für Deine Zeit und Deine Anregungen.
Es ist eine sehr gute Idee eine feste Zeichenfolge zu verwenden. Aber 
leider ändert sich Länge der Zeichenfolge von Command zu Command. STX 
und ETX habe ich allerdings laut Deinem Vorschlag vordefiniert und sie 
werden am Ende einfach einfügen.

Mit der Überprüfung des Return codes.... Da trau ich mich noch nicht 
ran. Verstehe den Code, um ehrlich zu sein, noch nicht 100pro... Muss 
mich da noch tierisch einarbeiten.

Danke auch für Deine Anregung mit der Verbindung zwischen zwei 
Computern. Kann so wenigstens ja mal testen, ob da überhaupt was 
kommuniziert.


Danke euch beiden für eure schnellen und für mich wichtigen Antworten. 
Werde versuchen alles umzusetzen und am Montag in der Firma zu testen. 
:-)

CU soon

Liebe Gürße

Wolfsblut

von Wolfsblut (Gast)


Lesenswert?

Hallo nochmals!

Also: Ich habe es mit der Zeit nun doch hinbekommen, dass ich einen Com 
Port öffnen, schreiben und lesen kann.
Vielen vielen Dank an dieser Stelle an euch und eure Hilfe!!! Und vor 
allem auch an eure Geduld mit Quereinsteigern wie mir ;-)

Aber: Ich habe immer noch ein Problem.
Ich kann den Com Port nicht mehr schliessen...
Wenn ich das Programm das erste Mal starte, läuft alles scheinbar 
tadelos. Starte ich es dann ein zweites Mal, so hängt es sich in der 
ersten do-while- Schleife auf bei "WaitCommEvent". Und ich kann nicht 
verstehen warum.
Das Programm dient der Steuerung eines externen Gerätes, welches später 
Teil eines großen Programms zur Automation wird. Bei dem Gerät liegt 
eine eigene Software bei. Mit dieser funktioniert alles, also auch nach 
mehrmaligem Starten. Wenn ich aber meinen eigenen Code verwende um das 
Gerät anzusprechen, und nach einem Erfolgreichen lauf das Hersteller 
eigene Programm starte, dann bekomme ich von dem Tool die Fehlermeldung 
"Serial Port timeout".
Schliesst mein Programm den Port nicht? Oder habe ich timeout Probleme? 
Ich komme damit leider nicht weiter und auch ein Kollege von mir ist 
ratlos, obwohl er einige Jahre mehr Erfahrung hat.

Bitte helft mir!!! Ich weiss gerade nicht weiter.

Vielen Dank!

Viele Grüße

Wolfsblut

von Blackbird (Gast)


Lesenswert?

Naja, lasse Dir doch die return codes (bzw. die lesbare Entsprechung) 
von Programm in einer MessageBox anzeigen. Von allen Funktionen, auch 
von CloseHandle.
1
if(!CloseHandle(hCom))
2
{
3
    LPVOID lpMsgBuf;
4
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
5
        FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
6
        NULL, GetLastError(),
7
        MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
8
        (LPTSTR) &lpMsgBuf, 0, NULL);
9
        MessageBox(NULL, (LPCTSTR)lpMsgBuf, TEXT("Error CloseHandle:"), 
10
        MB_OK | MB_ICONSTOP);
11
    LocalFree(lpMsgBuf);
12
}

Blackbird

von Wolfsblut (Gast)


Lesenswert?

@ Blackbird:

Sorry. Ich hatte vergessen zu erwähnen, dass ich mir die Codes schon mal 
habe ausgeben lassen. Dabei kam "Das Handle ist ungültig" heraus.
Das macht mich auch so ratlos. Warum soll CloseHandle ungültig sein?

(Hatte nur danach den Codeteil für return codes wieder rausgeschmissen, 
da ich mir mehr Übersicht verschaffen wollte)

von Blackbird (Gast)


Lesenswert?

Wenn das Handle (nicht die Funktion CloseHandle!) ungültig war, hast Du 
entweder auf eine nicht initialisierte Variable zurückgegriffen (kann 
bei der Parameter-Übergabe an andere Funktionen passieren) oder es war 
schon  freigegeben.
Wahrscheinlich ersteres.


Blackbird

von Wolfsblut (Gast)


Lesenswert?

@ Blackbird

Auch wenn ich kein Freund von so langen Posts mit Code und allem bin, so 
mache ich es diesmal doch. Leider kann ich nur keine Datei anhängen... 
seufz
Ich habe HANDLE hCom... und damit arbeite ich die ganze Zeit 
(CreateFile, ReadFile, WriteFile) Und immer frage ich ab, ob auch der 
Com Port geöffnet ist ( if(hCom == INVALID_HANDLE_VALUE) ). Aber dennoch 
klappt es nicht wie ich möchte. Aber ich brauche den Code dringend...
1
#include <windows.h>
2
#include <stdio.h>
3
#include <conio.h>
4
#include <stdlib.h>
5
#include <iostream.h>
6
7
8
#define COM_BUFFER_SIZE 256         
9
10
#define STX 0x02          
11
#define ETX 0x03          
12
#define Pointer 0x00        
13
#define CHK 0x3E;    
14
15
char check(int groesse, char vektor[]);
16
17
18
int main()            
19
{
20
  DCB          dcb;      
21
  DWORD        iBytesWritten;  
22
  BOOL    bRet  = TRUE;
23
  DWORD    dwRead  = 0;
24
  DWORD    dwSetMask = EV_RXCHAR | EV_ERR;
25
  DWORD    dwEvtMask;
26
27
  OVERLAPPED  o;
28
29
  COMMTIMEOUTS ct;
30
31
  int laenge = 6;      
32
              
33
  int i = 0;        
34
35
  char ENQ[] = {0x05};
36
  char InString[COM_BUFFER_SIZE + 1];
37
  char output[COM_BUFFER_SIZE];
38
39
  output[0] = STX;        
40
  output[1] = 0x0E;        
41
  output[2] = Pointer;      
42
  output[3] = '1';        
43
  output[4] = ETX;        
44
  output[5] = CHK;        
45
46
47
  memset (&o, 0, sizeof (OVERLAPPED)); 
48
  o.hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); 
49
  
50
  hCom = CreateFile("COM1", GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);  
51
52
53
  if (hCom == INVALID_HANDLE_VALUE)
54
  {                    
55
    MessageBox (NULL, "Not able to open Com1!\nCable connected?", "Error: CreateFile", MB_OK |
56
    MB_ICONINFORMATION);
57
    return (1);          
58
  }
59
60
61
  dcb.DCBlength = sizeof(DCB);  
62
  GetCommState (hCom, &dcb);    
63
  dcb.BaudRate  = 9600;      
64
  dcb.ByteSize  = 8;        
65
  dcb.Parity    = NOPARITY;    
66
  dcb.StopBits  = TWOSTOPBITS;  
67
  SetCommState (hCom, &dcb);    
68
69
  GetCommTimeouts (hCom, &ct);   
70
  ct.ReadIntervalTimeout         = 50;
71
  ct.ReadTotalTimeoutMultiplier  = 0; 
72
  ct.ReadTotalTimeoutConstant    = 50;
73
  ct.WriteTotalTimeoutMultiplier = 0;
74
  ct.WriteTotalTimeoutConstant   = 0;
75
  SetCommTimeouts (hCom, &ct);
76
77
78
  SetupComm (hCom, COM_BUFFER_SIZE, COM_BUFFER_SIZE);
79
  SetCommMask (hCom, dwSetMask);          
80
81
82
   if (hCom == INVALID_HANDLE_VALUE)  
83
  {                    
84
    MessageBox (NULL, "Not able to open Com1!\nCable connected?", "Error: CreateFile", MB_OK |
85
    MB_ICONINFORMATION);
86
    return (1);    
87
  }
88
  
89
  
90
  WriteFile(hCom, &ENQ, sizeof(ENQ), &iBytesWritten, NULL); 
91
  
92
  do
93
  {
94
    printf("\nWait for event\n");
95
    WaitCommEvent (hCom, &dwEvtMask, &o); 
96
97
    if (WAIT_OBJECT_0 == WaitForSingleObject (o.hEvent, INFINITE)) //warten bis Event
98
    {
99
      if (dwEvtMask & EV_RXCHAR) 
100
      {
101
        bRet = ReadFile (hCom, &InString, sizeof (InString), &dwRead, NULL);
102
          if (!bRet)  
103
        {        
104
          MessageBox (NULL, "Not able to read Data!", "Error: ReadFile",
105
            MB_OK | MB_ICONINFORMATION);
106
        }
107
        else      
108
        { 
109
          InString[dwRead] = '\0';  
110
          printf (TEXT("\r\n\tRxD (%d Byte(s)): 0x%x"), dwRead, InString[0]);
111
          break;
112
        }
113
      }
114
      if (dwEvtMask & EV_ERR)
115
      {
116
        MessageBox (NULL, "Error empfangen", "Error: ReadFile", MB_OK);
117
          break; // Schleifen-Abbruch
118
      }
119
120
    }
121
  }
122
  while (1);
123
124
  
125
  WriteFile(hCom, &output, laenge, &iBytesWritten, NULL); // Senden der Bytes
126
127
  do  
128
  {
129
    printf("\nWait for event\n");
130
    WaitCommEvent (hCom, &dwEvtMask, &o);
131
132
    if (WAIT_OBJECT_0 == WaitForSingleObject (o.hEvent, INFINITE)) 
133
    {
134
      if (dwEvtMask & EV_RXCHAR) 
135
      {
136
        bRet = ReadFile (hCom, &InString, sizeof (InString), &dwRead, NULL);
137
          if (!bRet)  
138
        {        
139
          MessageBox (NULL, "Not able to read Data!", "Error: ReadFile",
140
            MB_OK | MB_ICONINFORMATION);
141
        }
142
        else      
143
        { 
144
          InString[dwRead] = '\0';  // in "zero-ended"-String verwandeln
145
          printf (TEXT("\r\n\tRxD (%d Byte(s)): 0x%x"), dwRead, InString[0]);
146
            break;
147
        }
148
      }
149
      if (dwEvtMask & EV_ERR)
150
      {
151
        MessageBox (NULL, "Error empfangen", "Error: ReadFile", MB_OK);
152
          break; 
153
      }
154
    }
155
  }
156
  while (1);
157
158
159
  WriteFile(hCom, &ENQ, sizeof(ENQ), &iBytesWritten, NULL); 
160
  
161
  do  
162
  {
163
    printf("\nWait for event\n");
164
    WaitCommEvent (hCom, &dwEvtMask, &o); 
165
166
    if (WAIT_OBJECT_0 == WaitForSingleObject (o.hEvent, INFINITE)) 
167
    {
168
      if (dwEvtMask & EV_RXCHAR) 
169
      {
170
        bRet = ReadFile (hCom, &InString, sizeof (InString), &dwRead, NULL);
171
          if (!bRet)  
172
        {        
173
          MessageBox (NULL, "Not able to read Data!", "Error: ReadFile",
174
            MB_OK | MB_ICONINFORMATION);
175
        }
176
        else      
177
        { 
178
          InString[dwRead] = '\0';  
179
          printf (TEXT("\r\n\tRxD (%d Byte(s)): 0x%x"), dwRead, InString[0]);
180
          
181
          CloseHandle(hCom);
182
          if(!CloseHandle(hCom))
183
          {
184
            LPVOID lpMsgBuf;
185
              FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
186
              FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
187
              NULL, GetLastError(),
188
              MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), 
189
              (LPTSTR) &lpMsgBuf, 0, NULL);
190
            MessageBox(NULL, (LPCTSTR)lpMsgBuf, TEXT("Error CloseHandle:"), 
191
              MB_OK | MB_ICONSTOP);
192
            LocalFree(lpMsgBuf);
193
          }
194
          hCom = INVALID_HANDLE_VALUE;
195
            break;
196
        }
197
      }
198
      if (dwEvtMask & EV_ERR)
199
      {
200
        MessageBox (NULL, "Error empfangen", "Error: ReadFile", MB_OK);
201
          break;
202
      }
203
    }
204
  }
205
  while (1);
206
207
  CloseHandle (o.hEvent);  
208
  
209
  printf("\n\nTest erfolgreich?\n");
210
  return(0);
211
}

  

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Deine Fehlerauswertung ist ... merkwürdig.

Beim Fehlschlagen von CreateFile solltest Du GetLastError aufrufen und 
dessen Ergebnis ausgeben, das hilft bei der Diagnose.

Nach SetupComm und SetCommMask ist es völlig nutzlos, das Handle auf 
Gültigkeit zu überprüfen - diese Funktionen verändern das Handle nicht, 
sondern haben einen Rückgabewert, und den solltest Du auswerten.

Und das auch bei allen anderen Funktionen, wie beispielsweise WriteFile.

Wenn Du mit Overlapped I/O arbeiten willst, dann musst Du das auch beim 
Aufruf von CreateFile machen - Du solltest Dir dringend die 
Dokumentation der von Dir verwendeten API-Funktionen ansehen.

von Blackbird (Gast)


Lesenswert?

Das erste, was mir auffällt ist:
1
 hCom = CreateFile("COM1", GENERIC_WRITE | GENERIC_READ, 0, 0, OPEN_EXISTING, 0, 0);
es muß so geöffnet werden:
1
 hCom = CreateFile("COM1", GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL);
Das "FILE_FLAG_OVERLAPPED" ist wichtig.

Vor dem ersten Öffnen des COM-Ports kannst Du auch schreiben:
1
 CloseHandle (hCom);       // "alten" COM-Port schließen

Das sollte helfen.
Die anderen Kleinigkeiten sind nicht so wichtig.

Blackbird

von Blackbird (Gast)


Lesenswert?

Uups, 2 Minuten zu spät ...

Blackbird

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Vor dem ersten Öffnen des COM-Ports kannst Du auch schreiben:
>
>  CloseHandle (hCom);       // "alten" COM-Port schließen

Davon würde ich abraten. Wie kommt der "alte" COM-Port in die nicht 
initialisierte Variable hCom? Eben.

von Wolfsblut (Gast)


Lesenswert?

@ Rufus

Ich gebe zu, dass meine Auswertung der Fehler ein wenig merkwürdig ist. 
Aber ich habe einfach nur eine schnelle Ausgabe gemacht, die einfach bei 
einem Fehler mir diesen anzeigt. Und ich bekomme keinen Fehler bis zu 
dem Punkt, wo er das CloseHandle umsetzen soll.
Dokumentation von der API Funktion ist ein gutes Stichwort. Die gibt es 
nicht. Zumindest steht sie mir nicht zur Verfügung. Alles was ich habe 
ist ein fertiges Programm des Geräteherstellers und eine Liste der 
Befehle, die das Gerät akzeptiert. Eigentlich ist es dazu gedacht über 
die Bedienoberfläche der mitgelieferten Software bedient zu werden. Nur 
kann ich diese Bedienoberfläche für meine Automation nicht nutzen. Somit 
muss ich alles alleine herausfinden. Ich kann das Gerät ja ansprechen 
und bekomme die richtigen "Antworten" zurück. Das sagt mir der serial 
monitor. Aber am Ende will er den Port nicht schliessen.

@ Blackbird

FILE_FLAG_OVERLAPPED habe ich versuchsweise in CreateFile eingebaut... 
Dann endet der gesamte Lauf schon in der ersten do-while -Schleife bei:
1
printf("\nWait for event\n");
2
WaitCommEvent (hCom, &dwEvtMask, &o);
Ich habe auch mal die gesamte do-while-Schleife weggelassen, also auch 
"WaitCommEvent"  nicht ausgeführt und nach
1
 WriteFile(hCom, &ENQ, sizeof(ENQ), &iBytesWritten, NULL);
,
1
 WriteFile(hCom, &output, laenge, &iBytesWritten, NULL);
und
1
 WriteFile(hCom, &ENQ, sizeof(ENQ), &iBytesWritten, NULL);
jeweils direkt eingelesen. Funktioniert ebenso gut oder eben schlecht. 
Wie oben schon erwähnt: Ich habe keine Dokumentation über die API. Ich 
muss trial and error machen. Und bisher macht es ja fast das was ich 
will...

Gruß

Wolfsblut

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Dokumentation von der API Funktion ist ein gutes Stichwort.
> Die gibt es nicht. Zumindest steht sie mir nicht zur Verfügung.

Das ist einfach nicht wahr. Offensichtlich steht Dir ein Internetzugang 
zur Verfügung, also kommst Du auch an die Dokumentation der 
Win32-API-Funktionen 'ran:

CreateFile:
http://msdn.microsoft.com/library/en-us/fileio/fs/createfile.asp

WriteFile:
http://msdn.microsoft.com/library/en-us/fileio/fs/writefile.asp

SetupComm:
http://msdn2.microsoft.com/en-us/library/aa363439.aspx


etc.

Für weiteres kann dort die Suchfunktion verwendet werden.

von Wolfsblut (Gast)


Lesenswert?

@ Rufus

Oh... Da habe ich etwas falsch verstanden. Klar. Die MSDN habe ich auch 
auf dem PC installiert und verwende sie regelmäßig.
Ich dachte es war die Rede von der genauen Schnittstellenbeschreibung 
des Gerätes, also die API Funktionen meines Endgerätes, sprich eine 
Treiberschnittstelle, die ich nutzen kann.
Aber wer zu schnell liest, der versteht eben nur die Hälfte. Sorry.
(Und ja: Manchmal drücke ich mich einfach zu kompliziert aus, wenn ich 
nicht weiss wie und ob ich es richtig beschreibe ;-) )

von Blackbird (Gast)


Lesenswert?

Hier ist eine einfache Lösung:
1
#include <windows.h>
2
#include <stdio.h>
3
4
#define COM_BUFFER_SIZE 256    
5
#define RECVBYTES       5      // max. recv. bytes per transmission     
6
#define STX             0x02          
7
#define ETX             0x03          
8
#define Pointer         0x00   // ?? Pointer sind 4 Byte lang?    
9
#define CHK             0x3E
10
#define ENQ             0x05
11
12
const char * dump(const unsigned char *ucHex, const size_t length, char *pszBuffer);
13
14
int main(void)            
15
{
16
  DCB           dcb;      
17
  DWORD         iBytesWritten, dwRead = 0;
18
  DWORD         dwEvtMask, dwSetMask = EV_RXCHAR | EV_ERR;
19
  HANDLE        hCom;
20
  BOOL          bRet = TRUE;
21
  OVERLAPPED    o;
22
  COMMTIMEOUTS  ct;
23
  int           part = 3; // do-while stop
24
  char          flag[] = {ENQ};
25
  char          InString[COM_BUFFER_SIZE + 1];
26
  unsigned char          output[] = {STX, 0x0E, Pointer, '1', ETX, CHK};
27
28
  int           laenge = sizeof(output);
29
  char          *Buf;
30
31
  Buf = (char*)malloc(laenge * 5 + 1);
32
33
  memset(&o, 0, sizeof(OVERLAPPED)); 
34
  o.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); 
35
36
  if(!(hCom = CreateFile("COM1", GENERIC_WRITE | GENERIC_READ, 0, NULL, 
37
                        OPEN_EXISTING, 0, NULL)))
38
  {
39
    LPVOID lpMsgBuf;
40
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 
41
                    FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
42
                    MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
43
    MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error: CreateFile", MB_OK | MB_ICONINFORMATION);
44
    LocalFree(lpMsgBuf);
45
  return 1; // no action
46
  }
47
48
  dcb.DCBlength = sizeof(DCB);  
49
  GetCommState(hCom, &dcb);    
50
  dcb.BaudRate  = 9600;      
51
  dcb.ByteSize  = 8;        
52
  dcb.Parity    = NOPARITY;    
53
  dcb.StopBits  = TWOSTOPBITS;  
54
  SetCommState(hCom, &dcb);    
55
56
  GetCommTimeouts(hCom, &ct);   
57
  //ct.ReadIntervalTimeout         = 50;
58
  ct.ReadIntervalTimeout         = 100000 / 9600 * (dcb.ByteSize + 
59
                                                 (dcb.Parity == NOPARITY ? 0 : 1) + 
60
                                                 (dcb.StopBits == ONESTOPBIT ? 1 : 2)) * RECVBYTES;
61
  ct.ReadTotalTimeoutMultiplier  = 0; 
62
  ct.ReadTotalTimeoutConstant    = 50;
63
  ct.WriteTotalTimeoutMultiplier = 0;
64
  ct.WriteTotalTimeoutConstant   = 0;
65
  SetCommTimeouts(hCom, &ct);
66
67
  SetupComm(hCom, COM_BUFFER_SIZE, COM_BUFFER_SIZE);
68
  SetCommMask(hCom, dwSetMask);          
69
70
  if(!WriteFile(hCom, &flag, 1, &iBytesWritten, NULL))
71
  {
72
    LPVOID lpMsgBuf;
73
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 
74
                  FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
75
                  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
76
    MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error: WriteFile", MB_OK | MB_ICONINFORMATION);
77
    LocalFree(lpMsgBuf);
78
  }
79
  else
80
    printf(TEXT("\r\n\tTxD (%3d Byte(s)) written: 0x%x"), iBytesWritten, *flag);
81
82
  do
83
  {
84
    WaitCommEvent(hCom, &dwEvtMask, &o); 
85
    if(WAIT_OBJECT_0 == WaitForSingleObject(o.hEvent, INFINITE)) //warten bis Event
86
    {
87
      if(dwEvtMask & EV_RXCHAR) 
88
      {
89
        bRet = ReadFile(hCom, &InString, sizeof(InString), &dwRead, NULL);
90
        if(!bRet)  
91
        {        
92
          LPVOID lpMsgBuf;
93
          FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 
94
                        FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
95
                        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
96
          MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error: ReadFile", MB_OK | MB_ICONINFORMATION);
97
          LocalFree(lpMsgBuf);
98
        }
99
        else      
100
        { 
101
          InString[dwRead] = '\0';  
102
          printf(TEXT("\r\n\tRxD (%3d Byte(s)) read   : %s"), dwRead, InString);
103
          switch(part)
104
          {
105
          case 3:
106
            if(!WriteFile(hCom, &output, laenge, &iBytesWritten, NULL))  
107
      {        
108
              LPVOID lpMsgBuf;
109
              FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 
110
                            FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
111
                            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
112
              MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error: WriteFile", MB_OK | MB_ICONINFORMATION);
113
              LocalFree(lpMsgBuf);
114
      }
115
            else
116
              printf(TEXT("\r\n\tTxD (%3d Byte(s)) written: %s"), iBytesWritten, dump(output, laenge, Buf));
117
      break;
118
          case 2:
119
            if(!WriteFile(hCom, &flag, 1, &iBytesWritten, NULL))  
120
      {        
121
              LPVOID lpMsgBuf;
122
              FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 
123
                            FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
124
                            MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
125
              MessageBox(NULL, (LPCTSTR)lpMsgBuf, "Error: WriteFile", MB_OK | MB_ICONINFORMATION);
126
              LocalFree(lpMsgBuf);
127
      }
128
            else
129
              printf(TEXT("\r\n\tTxD (%3d Byte(s)) written: 0x%x"), iBytesWritten, *flag);
130
      break;
131
          }
132
      --part;
133
        }
134
      }
135
      if(dwEvtMask & EV_ERR)
136
      {
137
        MessageBox(NULL, "Error empfangen", "Error: ReadFile", MB_OK);
138
      }
139
    }
140
  }
141
  while(part > 0);
142
143
  if(!CloseHandle(hCom))
144
  {
145
    LPVOID lpMsgBuf;
146
    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | 
147
                  FORMAT_MESSAGE_IGNORE_INSERTS, NULL, GetLastError(),
148
                  MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL);
149
    MessageBox(NULL, (LPCTSTR)lpMsgBuf, TEXT("Error CloseHandle:"), MB_OK | MB_ICONSTOP);
150
    LocalFree(lpMsgBuf);
151
  }
152
153
  CloseHandle(o.hEvent);  
154
  free(Buf);
155
156
  printf("\n\nTest erfolgreich?\n");
157
  return(0);
158
}
159
160
161
const char * dump(const unsigned char *ucHex, const size_t length, char *pszBuffer)
162
{
163
  if((length == 0) || (length > strlen(pszBuffer) / 5))
164
  {
165
    pszBuffer = '\0';
166
    return pszBuffer;
167
  }  
168
  pszBuffer[0] = '\0';
169
  char buf[5] = "";
170
  for(size_t i = 0; i < length; ++i)
171
  {
172
    sprintf(buf, "0x%02x ", ucHex[i]);
173
    strcat(pszBuffer, buf);
174
  }
175
176
  return pszBuffer;
177
}


Die Anzahl der empfangenen Bytes kenne ich nicht, auch die Abstände der 
Datagramme nicht.

Blackbird

von Wolfsblut (Gast)


Lesenswert?

@ Blackbird

Vielen Dank für die große Hilfe. Leider kann ich das erst am Montag 
testen, da mir dann erst wieder die Hardware zur Verfügung steht :-( . 
Hätte es gerne sofort gemacht.
Und glücklicherweise verstehe ich auch fast jeden Schritt. Allerdings 
ist mir leider nicht soooo ganz klar, was der Pointer Buf macht... 
Sorry, wenn die Frage dumm klingt. Aber leider sehe ich das nicht so 
direkt. Vielleicht sehe ich auch vor lauter Codes das Programm nicht 
mehr. So langsam raucht mein Kopf weil ich fast jeden Tag alles 
umschreibe und versuche zu verbessern. grins
Aber hab vielen Dank. Ich werde es testen. ;-) Ist auf jeden Fall 
einfacher als mein Durcheinander.

von Blackbird (Gast)


Lesenswert?

Buf ist ein Pointer auf ein char-Array, welches mit malloc erst zur 
Laufzeit erstellt wird (und der "allokierte" Speicher muß auch mit 
free(Buf) wieder freigegeben werden!). Das Array wird von der Funktion 
dump benutzt weil diese Funktion dort ihr Ergebnis reinschreibt.
Die Funktion dump habe ich nur wegen der Anzeige der hex-Werte 
geschrieben, sie ist nicht notwendig für die Gesamtfunktion. Buf ebenso.

Den Ablauf kannst Du nach Belieben optimieren, Fehlerbehandlung, 
Datenwiederholungen usw. sollten auch implementiert sein.
Für solche Abläufe bietet sich eine State-Event-Maschine an.
Die meisten Aktionen und Fehler können auch in eine Log-Datei 
geschrieben werden statt per MessageBox aufzupoppen.

Viel Spaß beim Testen,

Blackbird.


von Wolfsblut (Gast)


Lesenswert?

@ Blackbird:

WOW! Es funktioniert endlich wie es soll!!!! Danke!
Habe erstmal Deine Programmierung probiert. Natürlich 1A! Und dann hab 
ich mal geschaut, woran es bei mir gescheitert sein könnte. Habe die 
Blöcke ausgetauscht (Ja, es war ein Fehler, den ich mir bei 
CloseHandle(hCom) selber eingebaut habe) und siehe da... ES KLAPPT!
Nun bin ich nicht nur sehr erleichtert, sondern auch wieder ein ganzes 
Stück weiter. Selbst nach dem Umschreiben und einbauen in das 
eigentliche Programm gab es keine Schwierigkeiten. Und nun kann ich die 
restlichen 10 oder 15 Funktionen noch schreiben, ohne dass ich mich mit 
solchen dummen Fehlern zwei Wochen aufhalte. (So hoffe ich doch grins) 
Aber das sind die kleineren Übel... mehr so Standard Funktionen, die man 
in den ersten Grundkursen lernt. ;-)

Nochmals vielen Dank!
Auch für die wertvollen Tips von Rufus! ;-)

Viele Grüße aus dem Bergischen!

Wolfsblut

von Lanjan (Gast)


Lesenswert?

Tach, sorry dass ich diesen alten Thread ausgrabe, aber ich bin mir 
sicher ihr könnt mir helfen.

Ich programmiere nur selten und auch nur simple Dinge, daher versteh ich 
recht wenig von WinAPI und komme nicht so ganz damit zu recht.

Im Rahmen einer Projektarbeit will ich ein Programm schreiben, mit dem 
man eine "programmierbare" Steuerungen mit einfachen Positionen füttern 
kann. Das erstellen der Positionen klappt und wenn ich die erzeugte 
TxT-Datei mit Copy&Paste in die Hyperterminalsitzung kopiere und somit 
an die Steuerung übertrage funktioniert auch alles prima.

Nun sollte der Anwender die erzeugte TxT-Datei direkt im Programm an die 
Steuerung übertragen (damit die sich nicht erst mit Hyperterminal 
auseinander setzen müssen und die richtigen COM-Einstellungen raussuchen 
müssen). Eigentlich muss ich nur Zeile für Zeile an die Steuerung 
übertragen, Rückgabe brauche ich keine...ich geh davon aus, dass alles 
klappt :-)

Ich habe Blackbirds kleines Programm geschnappt, kompliliert und 
ausgeführt. Scheint ok zu sein. Leider kann ich an meinen Arbeitsplatz 
nicht prüfen, was die COM-Schnittstelle wirklich ausspuckt (kein 
Nullmodemkabel).

Also meine zwei Fragen:

1) Wie sende ich ein "Return" oder wird nach dem Write-Befehl 
automatisch ein Return eingefügt?
2) Wie aktiviere ich die FlowControl "Xon/Xoff" ?
Laut Microsoft muss fOutX auf TRUE sein. Macht man das dann so?:

dcb.DCBlength = sizeof(DCB);
    GetCommState (hCom, &dcb);
    dcb.BaudRate  = 9600;
    dcb.ByteSize  = 8;
    dcb.Parity    = NOPARITY;
    dcb.StopBits  = ONESTOPBIT;
  dcb.fOutX    = 1; //Flowcontrol Xon/Xoff für Ausgabe auf TRUE?
    SetCommState (hCom, &dcb);


Danke schon mal für Eure Hilfe!

von Lanjan (Gast)


Lesenswert?

Hmm aaaalso ich habe schon neue Erkenntnisse:

"Return" sollte 0x13 sein, sollte also so tun (die restlichen 3 
Buchstaben jucken mal nicht):
   unsigned char ucMsg[] = {0x13, 0x42, 0x20, 0x43}; // (4)

und ich sollte wohl lieber die Terminalsitzung beenden um auf den Port 
zugreifen zu können :-)

Aber bisher reagiert der Antrieb meiner Steuerung nicht. Wenn ich ein 
"Return" erfolgreich versende, dann bewegt sich der Antrieb und das 
bedeutet für mich "JUHU".

von Lanjan (Gast)


Lesenswert?

Sorry, dass ich soviel schreibe, aber man kann ja leider die Beiträge 
(jedenfalls als nicht-registrieter Benutzer) nicht ändern.

Welche Hexzahl nun "Return" darstellt ist wohl nicht immer eindeutig und 
abhängig vom Zeichensatz (logisch). Mit einem kleinem Programm habe ich 
ein "Return" als hex zurückgegeben und das meinte "0x0A" bzw. 
"10"-dezimal ist ein Return.

Beim Senden von "ucMsg[] = {0x6D, 0x73, 0x30, 0x0A};" passiert am 
Antrieb nichts.
Statt nur ein Return möchte ich ein nun den Befehl "ms0" (msNULL) und 
Return senden.

von Blackbird (Gast)


Lesenswert?

Wenn die "Return" aus einer Textdatei kamen, können die auch 0x0D + 0x0A 
lauten. Oder als String "\r\n".

Blackbird

von Lanjan (Gast)


Lesenswert?

Das übertragen der Textdatei ist ja mein finales Ziel, erst einmal wäre 
ich glücklich nur "ms0" mit einem anschließenden Return zuversenden.

Ist der Ansatz mit "ucMsg[] = {0x6D, 0x73, 0x30, 0x0A};" richtig, oder 
sollte man lieber einen anderen Arraytyp (int, char, etc.) nehmen, oder 
vielleicht die Sache ganz anders angehen?

Ich würde sooo gerne mal ne COM-Schnittstelle ansteueren :-)

PS: mit Portmon von Sysinternals soll man seine COM-Schnittstellen 
belauschen können, aber bei zwei PCs wo ich es nun getestet habe, bleibt 
das Tool leer und zeigt nichts an. Gibts ne Alternative zu Portmon?

von Blackbird (Gast)


Lesenswert?

0x0A ist Line Feed (LF) - "eine Zeile runterrücken"
0x0D ist Carriage Return (CR) - "Wagen zurückfahren"

Die ASCII codes kommen noch aus der Fernschreibertechnik.

Versuche es mal so:
1
ucMsg[] = {0x6D, 0x73, 0x30, 0x0D};
statt so:
1
ucMsg[] = {0x6D, 0x73, 0x30, 0x0A};

oder so:
1
ucMsg[] = {0x6D, 0x73, 0x30, 0x0A, 0x0D};


Blackbird
PS: Bei mir funktioniert Portmon. Hyperterminal auch. SerialWatcher 
ebenso. Liegt sicherlich an der Einstellung oder am Anschluß.

von Blackbird (Gast)


Lesenswert?

Und nicht vergessen beim Senden mit Writefile() auch ALLE Zeichen zu 
senden!
Z.B. mit strlen(ucMsg) oder einfach Nachzählen.

Blackbird

von Lanjan (Gast)


Lesenswert?

Juhu,

es tut.
Einen Zeilenumbruch  Return  Enter sendet man mit "\r\n" und nicht nur 
mit "\n"...bis ich das raus hatte.

Beispiel:
WriteFile( hCom, "ms0\r\n", 4, &iBytesWritten, NULL);
Sendet:
"ms0"+Zeilenumbruch

Schönen Tag noch und danke euch für die schnell Hilfe. Nun muss ich 
schnell mal schauen, dass ich auch anderen Text übertragen kann.

von Blackbird (Gast)


Lesenswert?

Weißt Du eigentlich, was Du tust?
Hast Du auch verstanden, was ich geschrieben habe?
1
WriteFile( hCom, "ms0\r\n", 4, &iBytesWritten, NULL);

sendet genau 4 Zeichen: m, s, 0 und \r

Das \n wird nicht gesendet.

Da \r aber Carriage Return (also CR = 0x0D) ist, hast Du zufällig das 
richtige Zeichen gesendet. Sonst sah der String ja so aus "ms0\n".

Anmerkung:
\n wird von den meisten Programmen/"Maschinen" als \r\n interpretiert, 
aber eben nicht von allen.

Blackbird

von Blackbird (Gast)


Lesenswert?

PS als Nachtrag:

Es freut mich trotzdem, dass ich Dir helfen konnte.


Blackbird

von user (Gast)


Lesenswert?

Hallo Blackbird,

ich muss ein Programm in c Sprache unter Windows schreiben, das auf die
serielle Schnittstelle zugreift, um Daten (GPS_Daten)auszulesen. Die
serielle Schnittstelle ist mit einem GPS-Terminal (xt75 von Firma
MC)angeschlossen. Die Daten kann ich ansehen mit Hyper-Terminal. Ich
gebe bestimmte AT-Commands ein und dann bekomme ich die Daten (NMEA
Protokoll). Nun mein Professor will dass ich ein Programm schreibe das
direkt diesen Daten ausliest. Ich muss bis Ende diesen Monat eine Lösung
finden. Ich habe keine Ahnung wie das geht!
weiß du vielleicht wie ich es mache?

Danke

Die sind die drei Commandos die ich Hyper-Terminal eingebe:
ati
at^sgpss=1,0
at^sgpsp=2

von zwieblum (Gast)


Lesenswert?

das hab' ich doch schon mal gelesen ...

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Und das Thema wurde bereits ad nauseam diskutiert. Und fertige 
Code-Beispiele gibt es ebenfalls ad nauseam.

von user (Gast)


Lesenswert?

Hallo Rufus,

was meinst du mit "ad nauseam"

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Bis zum Erbrechen.

Damit will ich ausdrücken, daß das Thema "Wie programmiere ich die 
serielle Schnittstelle unter Windows in C" in diesem Forum verdammt 
oft diskutiert und ausreichend besprochen wurde. Die Forensuchfunktion 
sollte helfen.

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.