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
Vielleicht mal die Suchfunktion benutzen... www.codeguru.com www.codeproject.com
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!
Wenn für Win: http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnfiles/html/msdn_serial.asp
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!)
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
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
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
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
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?
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
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
Und wo kriegt man da mal ein Beispiel her ? CloseHandle fehlt nicht, wird ausgeführt wenn das Fenster geschlossen wird.
Probier doch einfach mal vor dem Read eine Pause einzuifügen, nur als proof-of-concept, ob es wirklich damit dann behoben ist
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
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 ?
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.ä
Anyway, dank eurer Hilfe habe ich eine grundlegende Kommunikation nun laufen, den Rest krieg ich schon gebacken. 1000Dank Jungs Greets Karlheinz
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
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 !!! }
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
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
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
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
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
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++?
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