Forum: PC-Programmierung RS232 über C++ auslesen


von Johannes (Gast)


Lesenswert?

Hallo!
Folgendes Problem:

Ich sende mit einzelne Byte's mit meinem µC über RS232 an den PC. Ich
möchte die Daten der RS232 mit einem C++  auslesen und im Programm
damit weiterrechnen.
Ich hab im Internet schon verzweifelt nach brauchbaren Infos gesucht,
leider ohne Erfolg. Entweder, der Code ist fehlerhaft oder in einzelne
Stücke zerhackt und schlecht erklärt.
Ich habe bisher keine Erfrahrung über Schnittstellenprogrammierung in
C++.

Was nützlich wäre:
-Links  wo dieses Thema ausführlich erklärt wird
-Bücher " "
- Quellcode der funktioniert und erklärt ist

MfG
Johannes

: Gesperrt durch User
von Hubert (Gast)


Lesenswert?

Vielleicht mal die Suchfunktion benutzen...
www.codeguru.com
www.codeproject.com

von Helge Dietert (Gast)


Lesenswert?

Naja mit Linux kannst du einfach das entsprechende Device ( meist
/dev/ttySx ) öffenen und es dann wie eine normale Datei behandeln.
Musst natürlich die Rechte und so passend setzen!

von Tobi H. (tobi-) Benutzerseite


Lesenswert?


von Kai Klenovsek (Gast)


Lesenswert?

Ferig und leicht zu nutzen:
http://kk.elektronik-4u.de/index.php?Sid=14

von Tobi H. (tobi-) Benutzerseite


Lesenswert?

Fertig zum nutzen und nicht nur als DLL verfügbar:
http://www.iftools.com/ctb.de.html

(so ziemlich die beste Lib, die ich kenne. Sogar für Win und Linux
geeignet!)

von Karlheinz Druschel (Gast)


Lesenswert?

Hi Leuts, ich habe auch mal ne Frage dazu, will aber nicht den 100.
Thread dazu beginnen :-)

Mein PC soll via RS232C mit einem Gerät kommunizieren.
Beispielsweise schicke ich den String "R0.29.0 + <CR>".
Das Teil antwortet mit "<CR><LF>V29.1234<CR<>LF>

Problem:
Via Hyperterminal funzt das alles (9600,n,8,1, kein Handshake).
Via C++ (Beispiele aus dem Net, aus den genannten Verweisen...) wird
IMMER nur ein "r" gelesen
Woran kann das liegen ?

Greets
Karlheinz

von Karlheinz Druschel (Gast)


Lesenswert?

Klar, woran es liegt weiss ich jetzt:
Das gerät sendet ja jedes empfangene Zeichen als Echo zurück!
Das kann ich auch nicht abschalten, ist ja nicht mein Gerät.
Wie programmiert man sowas ? Zeichen für Zeichen ausgeben, zurücklesen,
vergleichen und dann nächstes Zeichen schicken ?

Wer hat denn Erfahrung bei sowas ?


Greets
Karlheinz

von Tobi H. (tobi-) Benutzerseite


Lesenswert?

Oder gleich den ganzen String ausgeben und danach die Anzahl der
gesendeten Zeichen wieder einleisen, bei Bedarf kann man auch
vergleichen, wenn das wirklich nötig ist. Zeichen für Zeichen halt ich
für übertrieben. Die Schnittstelle am PC hat grosse Puffer

von Karlheinz Druschel (Gast)


Lesenswert?

Genau hier sitzt mein Problem:
Wennich 10 Zeichen schreibe und versuche dann was zu lesen, dann
behauptet er nur ein Zeichen gelesen zu haben.Nämlich das erste.
Wenn ich 1 Byte schreibe, dann lese, dann schreibe.... funzt es.
Ein Terminalprogramm macht ja auch genau das.
Aus mir unerklärlichen Gründen kriege ich immer nur ein Zeichen
ausgelesen

von Tobi H. (tobi-) Benutzerseite


Lesenswert?

Nein, ein Terminalprogramm liest meines Wissens nach auch blockweise,
schon der Geschwindigkeit wegen (macht meins zumindest so).

Die Frage wäre also, wo gehen die anderen Empfangenen verloren. Kannst
du den relevanten Codeblock hier mal reinstellen?

von Karlheinz Druschel (Gast)


Angehängte Dateien:

Lesenswert?

Klar, die Funktion ist im beigefügten Textfile.
Lt. Doku des angeschlossenen Gerätes muss der Vefehlsstring mit CR
abgeschlossen sein, wobei das CR nicht geechot wird.
Daraufhin antwortet das Gerät mit CR+LF+"V....."+CR+LF
Mit Hyperterminal gehts einwandfrei, mit CPP krieg ich immert nur das
erste Zeichen

von Blackbird (Gast)


Lesenswert?

Schreiben und gleich darauf einlesen - was ist, wenn das externe Gerät
etwas langsam ist? Dann rattert der PC über die if-Abfrage hinweg.
WaitForSingeObject(...) ist hier die Lösung.

Außerdem fehlt CloseHandle.

Blackbird

von Karlheinz Druschel (Gast)


Lesenswert?

Und wo kriegt man da mal ein Beispiel her ?

CloseHandle fehlt nicht, wird ausgeführt wenn das Fenster geschlossen
wird.

von Tobi H. (tobi-) Benutzerseite


Lesenswert?

Probier doch einfach mal vor dem Read eine Pause einzuifügen, nur als
proof-of-concept, ob es wirklich damit dann behoben ist

von Blackbird (Gast)


Angehängte Dateien:

Lesenswert?

Im Anhang ist ein kleines kommentiertes Beispiel. Ohne Threads. D.h.,
das Programm wartet auf ein Ereignis am COM-Port. Wenn jedoch während
des Wartens weitergearbeitet werden soll, so muß mit Threads gearbeitet
werden.

Blackbird

von Karlheinz Druschel (Gast)


Lesenswert?

Da habe ich wenigstens einen Anhaltspunkt, 1000 Dank


Greets
Karlheinz

von Karlheinz Druschel (Gast)


Lesenswert?

Na also, irgendwie klappts ja jetzt sogar.
Nur eine Frage hätte ich noch:
Die Werte für Timeouts werden ja gesetzt, aber nie irgendwie abefragt.
Wird ein Timeout durch ein EV_ERR signalisiert ?

von Tobi H. (tobi-) Benutzerseite


Lesenswert?

Nein, nach der eingestellten Timeout-Zeit bricht der Schreib/Leseversuch
nur ab. Da sorgt dafür, dass die Fnktionen nicht blockieren. EV_ERR
signalisiert Pufferüberläufe, Parity/Frame-Error u.ä

von Karlheinz Druschel (Gast)


Lesenswert?

Anyway, dank eurer Hilfe habe ich eine grundlegende Kommunikation nun
laufen, den Rest krieg ich schon gebacken.
1000Dank Jungs




Greets
Karlheinz

von Chrisi (Gast)


Angehängte Dateien:

Lesenswert?

Sers Johannes,
ich hatte vor ein paar Wochen in etwa das gleiche Problem. Viele Leute,
die dir antworten und es gut meinen, jedoch nichts dabei, was dir
wirklcih weiter hilft. Nach etwas Einarbeitung habe ich den Einstieg
geschafft.
Ich würde dir empfehlen auf die MSDN Homepage zu schauen:
Schaue dir dort drei Dinge an: DCB, ReadFile, WriteFile
Mehr brauchst du voerst nicht.
Lies dir diese drei Themen durch und dann kannst du mal den angehängten
Quellcode anschauen.
Damit dieser Sinn macht, verbinde TxD und RxD Leitung und das Programm
wird 5 Bytes senden und 5 Bytes empfangen und sie dir anzeigen. Somit
sollte das wichtigste für dich geschafft sein: Der Einstieg !!!
Anmerkung: Der SourceCode ist sehr kurz gehalten, damit du auch alles
nachvollziehen kannst.
Bitte gib hier kurz bescheid, ob du den Einstieg geschafft hast.
Gruß Christian

von cooper3210 (Gast)


Lesenswert?

Hi
Leider Hänge ich am gleichen Problem und komme nicht weiter!!
könnt Ihr mir helfen ?

//////////////////////////////////////////////////////////////
  /////////////include für serial aus dem Internet//////////////
  #include <iostream>
  #include <cstdio>
  #include <fstream>
  #include <sstream>
  #include <cstdlib>
  #include <stdio.h> /* Standard input/output definitions */
  #include <string.h> /* String function definitions */
  #include <unistd.h> /* UNIX standard function definitions */
  #include <fcntl.h> /* File control definitions */
  #include <errno.h> /* Error number definitions */
  #include <termios.h> /* POSIX terminal control definitions */
   /////////////////////////////////////////////////////////////
   using namespace std;
  /////////////////////////////////////////////////////////////
   int fd; // File descriptor Serial
   struct termios options;
   int open_port(void)
  {
      /*                         SETINGS
*/
      /* set raw input, 1 second timeout
       * Set the baud rates to 9600...
       * /dev/ttyS0, UART: 16550A, Port: 0x03f8, IRQ: 4
       * /dev/ttyS1, UART: 16550A, Port: 0x02f8, IRQ: 3
       * einstellungen mit minicom auf  No parity (8N1): meine
einstellungen
       * UNIX 8N1 meine serial einstellung */
     tcsetattr(fd, TCSANOW, &options);
     options.c_cflag &= ~CRTSCTS;
     cfsetispeed(&options, B9600);// bits pro sek
     options.c_cflag &= ~PARENB;  // noch kein Plan ?
     options.c_cflag &= ~CSTOPB;  // noch kein Plan
     options.c_cflag &= ~CSIZE;   // noch kein Plan
     options.c_cflag |= CS8;      // stop Bits
     options.c_cc[VMIN]  = 0;
     options.c_cc[VTIME] = 10;
    /*                     VERBINDEN
*/
    /* dev/ttyS0  fuer com1    dev/ttyS1 fuer com2 */
      fd = open("/dev/ttyS0", O_RDWR | O_NOCTTY | O_NDELAY);//
öffne()' -  port1
      fcntl(fd, F_SETFL, FNDELAY);
      tcgetattr(fd, &options);

  if (fd == -1)
      {
           // wenn ich denn port nicht öffnen kann
           perror("\nCOM1: ERROR kann Port nicht Öffnen!! /dev/ttyS0
- ");
           printf("\n ACHTUNG PROGRAMM BITTE ALS ROOT
AUSFÜHREN!!\n\n");
      }
       else
      {
           printf("\nVerbindung wurde erfolgreich hergestelle");
           }
            return (fd);
           }

       /*   void close_port()
           {
                close(fd);          //schliesst port soll aber nicht
           }
       */



 ///////////////////// Hauptprogramm //////////////////////////
  int main(int argc, char* argv[])
  {
         int status;
         char retval;
         char buffer[255];
         ssize_t size;
         status=open_port();
         if (status != -1) {
         fcntl(status, F_SETFL, FNDELAY);
             cout << "\n vor while        " << buffer ;//test
             while (size > 0)
                     //oder so !!!!!!!
                     // while(retval!=-1)
                     {
                         cout << "\nvor size     " << buffer ;//test

                         size = read(status, buffer,255);//buffer
leider nur 255 zeichen im mom
                         if (size > 0)
                         {
                                 buffer[size] = '\0';
                                 printf("\n%c", buffer);
                                 cout << "\n nach \n%c         " <<
buffer ;//test
                         }
                       }
             /*close_port();     // port schliessen hört auf zu loogen

               printf("\n\nVerbindung wurde getrennt\n"); */
         }
         ///////////////////////////Ausgabe/in log
datei/////////////////////////
         /* erstellen der log datei */
             ofstream
output("/home/cooper3210/Documents/logger.txt");
             if (!output)
             // Fehler abfangen
             {
                 cout << "Fehler beim Erstellen der Datei!\n";
                 exit (1);
             }
         cout << buffer;  // test
         cout << "\n\n";
         cout << "LOGGER Daten in eine Datei schreiben!!! \n" <<
buffer;
         output << " LOGGER COM 1 " << endl;
         output << buffer << endl;  // buffer in datei schreiben
      ////////////////// Programm ENDE
////////////////////////////////////
         retval=getchar();            // warten auf enter !!!
 }

von Blackbird (Gast)


Lesenswert?

Martin Graefe: "C und Linux", ISBN 3-446-22055-0 im Carl Hanser-Verlag
Muenchen.

Leider ist es nicht damit getan, einfach in einem Programm einmal oder
laufend den COM-Port abzufragen. Der Prozess blockiert dann den ganzen
PC. Auch ein Sleep oder usleep oder Timer hilft nicht, weil in der
Wartezeit zwar andere Prozesse drankommen koennen, aber inzwischen auch
der Empfangspuffer ueberlaufen kann.

Deshalb wird unter Windows mit Events gearbeitet (geht auf Interrupts
zurueck) und unter Linux direkt mit Interrupts. Root-Rechte muss nur
das Programm besitzen, nicht gleich der User.

Overlapped braucht man bei Windows nur, wenn man gleichzeitig empfangen
und senden will, denn das Senden kann aus jedem anderen Thread
unabhaengig erfolgen.

Blackbird

von Karlheinz Druschel (Gast)


Lesenswert?

Also bei mir wars definitiv die Geschwindigkleit.
Das externe Gerät sendet und empfängt zwar mit 9600 baud, aber die Zeit
zwischen den Zeichen war zu kurz.
Da das Messgerät aber die Eigenschaft hat jedes empfangene Zeichen als
Echo zu senden, warte ich einfach nach jedem Byte bis ich das gleiche
Byte wieder empfange.
Nun funzt es.


Greets
Karlheinz

von cooper3210 (Gast)


Lesenswert?

Hallo
Also sorry ich sehe nun überhaupt nicht mehr durch ;-)
Ich wollte unter linux nur ein serial monitor haben mit 9600 bis/sek.
Das ganze von mir tut ja schon mal was nur ist dort ein fehler drin
denn ich nicht finden kann.
meine ausgabe  logger.txt schaut meist so aus.
 LOGGER COM 1
R @p  XR @? @

ist nicht viel oder lol!!!!
Das gleiche unter root!
ich denke mal das ist ein problem  bei options.c aber ich komme dort
nicht klar !
laut
http://www.easysw.com/~mike/serial/serial.html#2_5
sollte ich mit minicom mal meine orginal einstellung prüfen was ich
auch habe!
No parity (8N1):
options.c_cflag &= ~PARENB
options.c_cflag &= ~CSTOPB
options.c_cflag &= ~CSIZE;
options.c_cflag |= CS8;
wäre für mich zutreffent ! und ich denke mal da habe ich doch alles
richtig.
Selbst wenn es duch das abfragen mein rechner blockiert sollte in der
ausgabe mehr sein oder ?
cooper<<< nicht mehr klar kommen
DAnke für Eure Hilfe

von cooper3210 (Gast)


Lesenswert?

noch mal ich also ich habe eben gesehen
(((((((""Blackbird """
Root-Rechte muss nur
das Programm besitzen, nicht gleich der User.))))))))

wie soll denn das gehen ??????????
mfg cooper

von Blackbird (Gast)


Lesenswert?

Das Programm mit chmod mit den Zugriffsrechten R, X und S versehen und
mit chown den Benutzer "root" eintragen (alles als root natuerlich).
Dann werden beim Ausfuehren Root-Rechte dem Prozess mitgegeben, auch
wenn man es als Nicht-"root" user ausfuehrt.

Blackbird

von cooper3210 (Gast)


Lesenswert?

Danke für diesen Tipp, ist gut das mal zu wissen !!!!!
Cu mfg Cooper

von guest (Gast)


Lesenswert?

Also ich hab auch ein problem mit Zugriff auf RS232 über C++. Würde gern 
die einzelnen Ausgäne setzen/rücksätze so wie die Eingänge auslesen.
Ich hab im Netzt eine Delphi API gefunden, aber ich will mit Delphi und 
Borland, ich weis die heisen jetzt anders, irgend was zu tun haben. Auf 
jeden Fall hat diese Delphi API z.B. ne Funktion DTR(int), RTS(int) und 
TXD(int) mit der man den jeweiligen Ausgang auf 1 (setzen) und 0 
(rücksätzen) ändern kann. Gibts wircklich nix vergleichbares für C/C++?

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Stell doch Deine Frage bitte in einem neuen Thread und exhumiere keinen 
13 Jahre alten Thread.

Und überprüf' mal Deine Rechtschreibung, das erzeugt ja schon leichte 
Pickel.

Die Handshakeleitungen der seriellen Schnittstelle kann man sogar mit 
der stinknormalen Win32-API setzen/löschen, dafür gibt's die Funktion 
EscapeCommFunction.

https://docs.microsoft.com/en-us/windows/desktop/api/Winbase/nf-winbase-escapecommfunction

Dieser Beitrag ist gesperrt und kann nicht beantwortet werden.