Fehlersuche: serielle schnittstelle nur auslesen



  • Hallo1
    Ich weiß nicht mehr weiter, ich möchte Daten, die von einem Datenlogger an die serielle Schnittstelle gesendet werden, aufnehmen. Mein Programmcode zeigt aber wieder mal Fehler anb und ich weiß nicht wo der Haken liegt. Vielleicht kann mir ja jemand dabei helfen. Vielen Dank.
    Hier der Code von mir:

    #include <windows.h>
    int main (void)
    {
    DCB dcb;
    DWORD iBytesReceived;
    int nRead;
    unsigned char bBuffer[1000];

    HANDLE hCom = CreateFile ("COM1", GENERIC_WRITE|GENERIC_READ, 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

    nRead = 1;
    ReadFile (hCom, &bBuffer, nRead, &iBytesReceived, NULL);

    CloseHandle (hCom); // COM1 schließen

    return (0);
    }



  • Benutze bitte die C++ Tags, damit man deinen Code auch lesen kann.

    #include <windows.h>
    int main (void)
    {
    DCB dcb;
    DWORD iBytesReceived;
    int nRead;
    unsigned char bBuffer[1000];
    
    HANDLE hCom = CreateFile ("COM1", GENERIC_WRITE|GENERIC_READ, 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
    
    nRead = 1;
    ReadFile (hCom, &bBuffer, nRead, &iBytesReceived, NULL);
    
    CloseHandle (hCom); // COM1 schließen
    
    return (0);
    }
    

    Schon viel besser, gell?



  • @portfan,

    dieses Code-Schnipsel war nur fürs Senden geeignet, einfach WriteFile durch ReadFile (und die paar Parameter) ersetzten, geht nicht. Senden geht ja zu jedem Zeitpunkt, beim Empfangen muß man WARTEN. Du wartest nicht, sondern versuchst, ein Zeichen auszulesen und beendest das Programm. Hier ist das passende Empfangsprogramm zu dem von Dir veränderten Beispiel:

    // DOS32-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);
    }
    

    Das Zurücksenden kannst Du ja durch Speichern o.ä. ersetzten.

    Blackbird

    PS: Marc++us, was ist denn mit den Userdaten passiert?



  • Danke erst mal für die Fehlerbeseitigungen!
    Aber wie wird es gemacht, damit sich kein DOS-Fenster öffnet, sondern ein Windows-Fenster, wo dann die eingelesenen Werte dastehen? Da bin ich total unkundig drin. Ich weiß, dass wenn ich eine WIN32-Anwendung erstelle und dort die Einstellung "MFC in einer gemeinsam genutzten DLL verwenden" vornehme, dann die Windows-Fenster erzeugen kann, aber dann hört es auch schon auf.

    mfg portfan (oder auch nicht fan)



  • MFC? Dann wäre das hier das falsche Board.
    Außerdem ist das ja in Deiner Eingangsfrage so nicht rauszulesen gewesen.

    Mit VC++6.0:
    - einfach ein Projekt mit "WIN32_Anwendung" erstellen,
    - eine WinMain-Funktion einbauen, die eine Callback-Funktion hat,
    - die Callback-Funktion schreiben,
    - ein Edit-Fenster erstellen,
    - einen COM-Read-Thread schreiben und alle Zeichen an das Edit-Fenster senden.

    In der MSDN gibt es zu allen schon Beispiele, kombinieren mußt Du es dann so, wie Du es brauchst.

    Aber das hat fast alles nichts mit serieller Communications zu tun.

    Blackbird


Anmelden zum Antworten