serielle Schnittstelle mit ReadFile() auslesen



  • Hallo,

    ich habe ein Programm, welches einen Antrieb steuert.
    Ich möchte den Antrieb Nummer 1 in die absolute Position 6500 µm bringen.
    Also: Unit=1, Command=20 (für abolute Position), Data = 6500
    Dann sende ich diesen Befehl über die serielle Schnittstelle und der Antrieb begibt sich auch in die Position.
    Der Rückgabewert dieseds Aufrufs ist die Endposition. Meine Frage ist nun wie kann ich die serielle Schnittstelle mit ReadFile() auslesen, um an den Wert der Position zu gelangen?
    Vielen Dank im Voraus

    void PSerial_send(unsigned char Unit, unsigned char Command, long Data)
    {
    OutBuffer[0] = Unit;
    OutBuffer[1] = Command;
    
    	cout <<"Unit"<<Unit << endl;
    	cout <<"Command"<<Command << endl;
    
    // Umrechung laut Hersteller
    if(Data<0)
    {
    
    	Data = 256*256*256*256 + Data;
    }
    
    float scale;
    
    scale=0;
    
    scale = 256*256*256;
    OutBuffer[5] = floor (Data/scale);
    Data = Data-OutBuffer[5]* scale;
    
    scale = 256*256;
    OutBuffer[4] = floor(Data/scale);
    Data = Data-OutBuffer[4] * scale;
    
    scale = 256;
    OutBuffer[3] = floor(Data/scale);
    Data = Data-OutBuffer[3] * scale;
    
    OutBuffer[2] = Data;
    cout <<"Out Buffer 5 "<<OutBuffer[5]<< endl;
    cout <<"Out Buffer 4"<<OutBuffer[4]<< endl;
    cout <<"Out Buffer 3"<<OutBuffer[3]<< endl;
    cout <<"Out Buffer 2"<<OutBuffer[2]<< endl;
    
    WriteFile(PortHandle, OutBuffer, PSerial_Packetsize, &bytes_written, NULL);
    

    Bis hier hin funktioniert alles, der Actuator bewegt sich zu der gewollten Position. Die Frage ist nun, wie kann ich den Rückgabewert, in diesem Fall die Endposition, aus der seriellen Schnittstelle auslesen?
    Mein Ansatz ist folgendermaßen:

    unsigned char TempByte;
    
    	if ( timeGetTime() - RxTimeStamp > RXTIMEOUT )
    	{
    		RxCount = 0;
    		RxTimeStamp = timeGetTime();
    	}
    
    	for (int i=0; i < PSerial_Packetsize; i++)
    	{
    
    		ReadFile(	PortHandle,
    				&TempByte,     // Where to put the byte read
    				1,             // read one byte at a time
    				&BytesRead,    // Bytes actually read
    				NULL );
    
    	RxCount=i;	// Increment counter
    
    	if ( BytesRead > 0 ) // A byte is read
    	{
    
    		RxBuffer[RxCount] = TempByte; // Store the byte                   
    		RxTimeStamp = timeGetTime();  // reload timestamp
    
    	 }
    
    	}
    
    	cout <<"Rx count"<<RxCount << endl;
    
    	if ( PSerial_Packetsize == (RxCount+1) ) // A full buffer
    	{
    
     // A packet is ready to be used
    	unsigned char Unit_1 = RxBuffer[0];
    	unsigned char Command_1 = RxBuffer[1];
    
    		cout <<"Return Unit"<<Unit_1<< endl;
    		cout <<"Return Command"<<Command_1 << endl;
    
    	         // Umrechnung laut Hersteller, zaber.com
    		double Reply_Data;
    
    		Reply_Data = (256*256*256)*RxBuffer[5] + (256*256)*RxBuffer[4] +  256*RxBuffer[3] + RxBuffer[2];
    
    		if (RxBuffer[5]>127)
    			{
    				Reply_Data = Reply_Data - (256*256*256*256); 
    				cout <<"buffer bigger than 127 "<< endl;
    			}
    


  • Dieser Thread wurde von Moderator/in Jochen Kalmbach aus dem Forum C++/CLI mit .NET in das Forum WinAPI verschoben.

    Im Zweifelsfall bitte auch folgende Hinweise beachten:
    C/C++ Forum :: FAQ - Sonstiges :: Wohin mit meiner Frage?

    Dieses Posting wurde automatisch erzeugt.



  • Die serielle Schnittstelle ist nicht trivial. Deshalb würde ich eine fertige Klasse verwenden... z.B.:
    http://www.codeproject.com/Articles/992/Serial-library-for-C



  • Die Frage ist nun, wie kann ich den Rückgabewert, in diesem Fall die Endposition, aus der seriellen Schnittstelle auslesen?
    Mein Ansatz ist folgendermaßen:

    Und was ist das Problem? Funktioniert es oder nicht? Kommt eine Fehlermeldung? ...

    2 Dinge fallen mir auf: Rueckgabewert von ReadFile nicht ausgewertet. Man kann mehr als 1 Byte auf einmal auslesen.

    Jochen Kalmbach schrieb:

    Die serielle Schnittstelle ist nicht trivial. Deshalb würde ich eine fertige Klasse verwenden... z.B.:
    http://www.codeproject.com/Articles/992/Serial-library-for-C

    Naja, geht so. Man muss nicht unbedingt overlapped io verwenden.


  • Mod

    knivil schrieb:

    Jochen Kalmbach schrieb:

    Die serielle Schnittstelle ist nicht trivial. Deshalb würde ich eine fertige Klasse verwenden... z.B.:
    http://www.codeproject.com/Articles/992/Serial-library-for-C

    Naja, geht so. Man muss nicht unbedingt overlapped io verwenden.

    Aber man kann die Klasse verwenden, die das tut.
    Zudem ist dann die Anwendnung nicht blockierend und man muss nicht pollen.



  • Ja. 🙂



  • Hallo,

    danke für die Antworten. Es funktioniert ohne Fehlermeldung, es gibt allerdings immer den gleichen Wert für ReplyData zurück. Immer 128.

    @knivil: Hier wird der Rückgabewert von ReadFile ausgewertet, oder nicht ?

    if ( BytesRead > 0 ) // A byte is read
        {
    
            RxBuffer[RxCount] = TempByte; // Store the byte                   
            RxTimeStamp = timeGetTime();  // reload timestamp
    
         }
    

    Ich lese immer nur 1 byte aus und speichere es dann im Vector.

    Vielen Dank!



  • Nein, dort wertest du einen InOut-Parameter aus. Ansosnten: Baue ein Minimalbeispiel, hier sind noch viele Sachen unbekannt, beispielsweise welchen Wert hat PSerial_Packetsize, welche Packetgroesse sendet dein Motor, wie ist das Paketformat, ... und: Hast du schon die verlinkte Klasse ausprobiert?



  • ich probiere gerade die fertige Klasse aus....
    Falls das nicht funktioniert, melde ich mich wieder!
    Danke 😉



  • starter88 schrieb:

    @knivil: Hier wird der Rückgabewert von ReadFile ausgewertet, oder nicht ?

    if ( BytesRead > 0 ) // A byte is read
        {
            
            RxBuffer[RxCount] = TempByte; // Store the byte                   
            RxTimeStamp = timeGetTime();  // reload timestamp
            
         }
    

    Nein, ReadFile hat noch einen "direkten" Rückgabewert vom Typ BOOL. Den wertest du gar nicht aus.

    Und es fehlt der Else-Zweig.
    Deine Schleife geht davon aus, dass in jedem Durchlauf ein Byte gelesen wird. Dann hast du das "if (hats_denn_wirklich_funktioniert)", aber kein "else". D.h. wenn in einem Durchlauf nix gelesen wird, dann wird das Byte in RxBuffer einfach übergangen. Nicht gerade sehr robust.

    Besser wäre eine Schleife ala

    while (not timeout and not message complete)
    {
        try to read something
        if (read was successful)
            append read data to message buffer
    }
    if (not message complete)
        handle error
    

    Und natürlich müsste man wissen welche Timeout Einstellungen du verwendest (SetCommTimeouts).

    Eine fertige Klasse zu verwenden ist aber vermutlich die bessere Lösung. Speziell wenn man noch nicht mehrere Jahre Windows Systemprogrammierung auf dem Buckel hat.



  • Ich habe nun eine fertige Klasse verwendet. Das Schreiben funktioniert wunderbar, allerdings bekomme ich beim Lesen keine vernünftigen Werte heraus.
    Hier ist mein Code

    bool Init_Port_and_Zaber(CString port_name)
    {
    
    	if (!port.OpenPort(port_name))
    		{
    			printf("Cannot open port.\n");
    			printf("Please check that you typed in the correct name,\n");
    			printf("and check that the requested port is not currently being used.\n");
    			printf("press any key to exit...");
    			return 0;
    		}
    
    	else if  (!port.ConfigurePort(CBR_9600, 8, false, NOPARITY, ONESTOPBIT))
    			 // Baudrate 9600, data byte=8, parity=false, NOPARITY, stopbit=1
    
    			{
    				printf("Cannot configure port.\n");
    				return 0;
    			}
    
    	//else if (!port.SetCommunicationTimeouts(MAXWORD,0,0,0,0)) 
    		else if (!port.SetCommunicationTimeouts(50,10,50,10,50)) 
    
    		{
    				printf("Set Communication not successful.\n");
    				return 0;
    
    		}
    
    		port.send_command(0,2,0); // renumber actuators
    		Sleep(800);
    
                    Command = 1;
    		port.send_command(0,Command,0); // send all actuators to home position
    
    		return 1;
    
    	}
    

    Und hier die Funktion zum Senden und Empfangen der Bytes. Das Senden funktioniert einwandfrei.

    BOOL CSerialPort::send_command(unsigned char Unit, unsigned char Command, long Data)
    {
    	static unsigned char OutBuffer[6]; 
    	static unsigned char ReadBuffer[6]; 
    
    	OutBuffer[0] = Unit;
    	OutBuffer[1] = Command;
    
    	cout <<"Unit  "<<OutBuffer[0]<< endl;
    	cout <<"Command"<<OutBuffer[1]<< endl;
    
    	if(Data<0)
    	{
    
    		Data = 256*256*256*256 + Data;
    	}
    
    	float scale;
    
    	scale=0;
    
    	scale = 256*256*256;
    	OutBuffer[5] = floor (Data/scale);
    	Data = Data-OutBuffer[5]* scale;
    
    	scale = 256*256;
    	OutBuffer[4] = floor(Data/scale);
    	Data = Data-OutBuffer[4] * scale;
    
    	scale = 256;
    	OutBuffer[3] = floor(Data/scale);
    	Data = Data-OutBuffer[3] * scale;
    
    	OutBuffer[2] = Data;
    	cout <<"Out Buffer 5 "<<OutBuffer[5]<< endl;
    	cout <<"Out Buffer 4"<<OutBuffer[4]<< endl;
    	cout <<"Out Buffer 3"<<OutBuffer[3]<< endl;
    	cout <<"Out Buffer 2"<<OutBuffer[2]<< endl;
    
    	//iBytesWritten=0;
    	//if(WriteFile(hComm,OutBuffer,6,&iBytesWritten,NULL)==0)
    	//return false;
    	//else return true;
    
    	for (int i=0; i<6; i++)
    		{
    			WriteByte(OutBuffer[i]);
    		}
    
    	for (int i=0; i < 6; i++)
    		{
    
    			ReadByte(ReadBuffer[i]);
    
    	}
    
    	unsigned char Unit_1 = ReadBuffer[0];
    	unsigned char Command_1 = ReadBuffer[1];
    
    		cout <<"Return Unit"<<Unit_1<< endl;
    		cout <<"Return Command"<<Command_1 << endl;
    
    		double Reply_Data;
    
    		Reply_Data = (256*256*256)*ReadBuffer[5] + (256*256)*ReadBuffer[4] + 256*ReadBuffer[3] + ReadBuffer[2];
    
    		if (ReadBuffer[5]>127)
    			{
    				Reply_Data = Reply_Data - (256*256*256*256); 
    				cout <<"buffer bigger than 127 "<< endl;
    			}
    
    	return true;
    }
    

    Ich vermute ich mache irgendetwas falsch, beim setzen der Timeouts. Über Tipps wäre ich sehr dankbar!



  • Hi Leute,

    hier ist ein Link zu einer sehr guten Toolbox für die COM Schnittstelle:

    http://members.inode.at/anton.zechner/az/ComTools.zip

    MfG


  • Mod

    Siehe auch www.codeproject.com...



  • Wie stellst du fest, dass Senden funktioniert und Empfangen nicht?


Anmelden zum Antworten