USB-Lesegerät über COM-Port ansteuern.



  • Hallo,
    ich habe ein Transponderlesegerät (HTTR DESK) das über USB mit meinem PC verbunden ist. Das Gerät wurde nach dem ersten anstecken an den PC erkannt und der Treiber autom. installiert.

    Das Gerät öffne ich an COM9 wie folgt:

    bool __fastcall TFMain::OpenPort()
    {
    AnsiString Device;
    
    		Device = "COM9";
    		hSerial  = CreateFile( Device.c_str(),
    							   GENERIC_READ | GENERIC_WRITE,
    							   0,
    							   0,
    							   OPEN_EXISTING,
    							   0,
    							   0 );
    		if (hSerial == INVALID_HANDLE_VALUE)
    		{
    			return false;
    		}
    		else
    		{
    			return true;
    		}
    }
    

    Er gibt mir auch ein Handle auf dieses Gerät zurück. Soweit so gut.

    Jetzt steht in der Doku, dass alle Befehle aus Klartext bestehen und mit dem Zeichen CR, dem Zeichen LF oder der Zeichenfolge CR LF abgeschlossen werden. Es gibt den Befehl "OUT <n><z>", mit dem man die einzelnen LEDs schalten kann. Ich habe das wie folgt umgesetzt:

    void __fastcall TFMain::BBeepClick(TObject *Sender)
    {
    char Ausgang[8] = "OUT C1F0";
    	float len = 8;
    	DWORD dwBytesWritten;
    	WriteFile(hSerial, Ausgang, len, &dwBytesWritten, NULL);
    }
    

    Doch leider tut sich am Gerät nichts. Kann mir da jemand helfen???

    SG
    Torsten



  • Du hast den Befehl nicht mit CR abgeschlossen. Das müsste irgendwie so aussehen:

    char CR_Zeichen = 13;
    Ausgang[n] = CR_Zeichen;  // n muss bei dir das letzte Zeichen des Arrays sein
    

    Es kann auch sein, dass zwischen dem "OUT" und dem "C1F0" kein Leerzeichen sein darf.



  • AnsiString Befehl = "OUT C1F0\r\n";
    WriteFile(hSerial, Befehl.c_str(), Befehl.Length(), &dwBytesWritten, NULL);
    

    \r ist CR
    \n ist LF

    Mal eine Anmerkung:
    COM in Windows IMMER mit: "\\\.\\COM9" öffnen, ansonsten ist bei COM9 Schluss und COM10 oder höher geht nicht mehr.



  • Hi,
    ich habe jetzt den Code etwas angepasst:

    bool __fastcall TFMain::OpenPort()
    {
    AnsiString Device;
    
    		Device = "\\\\.\\COM9";
    		hSerial  = CreateFile( Device.c_str(),
    							   GENERIC_READ | GENERIC_WRITE,
    							   0,
    							   NULL,
    							   OPEN_EXISTING,
    							   0,
    							   NULL );
    		if (hSerial == INVALID_HANDLE_VALUE)
    		{
    			return false;
    		}
    		else
    		{
    			return true;
    		}
    }
    
    void __fastcall TFMain::BBeepClick(TObject *Sender)
    {
    AnsiString Befehl = "OUT C1F0\r\n";
    	DWORD dwBytesWritten;
    	WriteFile(hSerial, Befehl.c_str(), Befehl.Length(), &dwBytesWritten, NULL);
    }
    

    Doch leider tut sich an den Status-LEDs noch immer nix! Ich bekomme auch keinen Fehler!

    Was nun ???

    Gruß Torsten



  • Kennst du das Tool "Hercules" von HW-group.com?

    Das ist ein einfaches kostenloses Tool, womit es möglich ist manuell Daten über ein COM-Port zu senden. Versuch doch dein Gerät damit anzusprechen. So kannst du feststellen, ob es grundsätzlich funktioniert.



  • Hallo torsten,

    hast Du es vorher mal mit einem Terminal-Programm versucht um zu sehen, ob Du überhaupt die richtigen Befehl-Codes hast?

    Richtest Du Deinen COM Port auch ein? oder tatsächlich nur das was Du gepostet hast? Du musst auch die Baudrate, Parity, etc. noch einstellen, bevor Du was rausschreiben kannst. Schau Dir mal die folgenden WinAPI Befehle an, ich fürchte die wirst Du brauchen.

    SetCommState(hComPort,&dcb);
    GetCommState(hComPort,&dcb);
    


  • @sonic_1233
    Danke für den Tip. Werde ich mal testen...

    @matze555
    Der Befehlscode ist korrekt. Dazu gibt es vom Hersteller eine Doku über den Befehlssatz.
    Den COM-Port richte ich mit meinem Tool nicht ein 😕 Ich war der Meinung, dass es aureichend ist die Baudrate etc. direkt in WIN einzurichten. Wenn das nicht ausreichen sollte, werde ich das natürlich noch in meinem Tool machen.

    Danke und Gruß
    Torsten



  • So, ich habe das Tool "Hercules" getestet und kann sagen, dass damit das Lesegerät das macht, was es soll. Die LEDs können geschaltet werden.

    Ich werde mich dann mal an die Parametereinstellung für den COM-Port mittels meinem Tool machen.

    Bericht folgt....



  • Juhuuu, ich hab's.
    Die Schnittstelle musste noch aus der Software heraus initialisiert werden. Das habe ich wie folgt gemacht:

    bool __fastcall TFMain::Initialisieren(HANDLE hPort)
    {
    bool y = false;
    DCB dcb;
    		dcb.BaudRate = 19200;
    		dcb.Parity = NOPARITY;
    		dcb.StopBits = ONESTOPBIT;
    		dcb.ByteSize = (BYTE)8;
    			y = SetCommState(hPort,&dcb);
    return y;
    

    So nimmt das Gerät nun jeden Befehl der Referenz an.

    VIELEN Dank 👍 👍 👍
    Torsten



  • Hi ich möchte einen ZigBee USB stick über denn C++Builder ansprechen.

    Habe mir hier den Code aus dem Thema kopiert. und es hat auch funktioniert. jedoch funktioniert es nur bei jedem 2 Versuch und wenn ich mehrere Befehler (Mit den Auskommentierten) in Folge mache geht es garnicht mehr.

    Ich glaube das das Problem liegt darin das ich die Baudrate nicht wirklich mit meinem Handel (hSerial) verknüpft habe. Wenn ihr meint das es daran liegt, könnt ihr mir sagen wie das geht.

    Bzw. hab jemand ne Idee woran das sonst liegen könnte.

    Hier der Code

    __fastcall TForm1::TForm1(TComponent* Owner)
    	: TForm(Owner)
    {
    
    //Conect to COM5
    AnsiString Device;
    
    		Device = "\\\\.\\COM5";
    		HANDLE hSerial  = CreateFile( Device.c_str(),
    							   GENERIC_READ | GENERIC_WRITE,
    							   0,
    							   NULL,
    							   OPEN_EXISTING,
    							   0,
    							   NULL );
    		if (hSerial == INVALID_HANDLE_VALUE)
    		{
    			Label1->Caption = "False";
    		}
    		else
    		{
    			Label1->Caption = "True";
    		}
    //Settings
    bool y = false;
    DCB dcb;
    		dcb.BaudRate = 19200;
    		dcb.Parity = NOPARITY;
    		dcb.StopBits = ONESTOPBIT;
    		dcb.ByteSize = (BYTE)8;
    		y = SetCommState(hSerial,&dcb);
    		if (y)
    		{
    			Label2->Caption = "True";
    		}
    		else
    		{
    			Label2->Caption = "False";
    		}
    
    //Commends
    AnsiString Antwort = "";
    DWORD dwBytesWritten;
    DWORD dwBytesRead;
    
    //ATI
    AnsiString Befehl0 = "ati\r";
    	WriteFile(hSerial, Befehl0.c_str(), Befehl0.Length(), &dwBytesWritten, NULL);
    	ReadFile(hSerial, Antwort.c_str(), 100, &dwBytesWritten, NULL);
    	Label3->Caption = Antwort.c_str();
    /*
    //JOIN PAN
    AnsiString Befehl1 ="at+jn\r";
    	WriteFile(hSerial, Befehl1.c_str(), Befehl1.Length(), &dwBytesWritten, NULL);
    	ReadFile(hSerial, Antwort.c_str(), 1000, &dwBytesWritten, NULL);
    	Label3->Caption = Antwort.c_str();
    
    //CONFIGURE
    AnsiString Befehl2 ="at+sn\r";
    	WriteFile(hSerial, Befehl2.c_str(), Befehl2.Length(), &dwBytesWritten, NULL);
    	ReadFile(hSerial, Antwort.c_str(), 1000, &dwBytesWritten, NULL);
    	Label3->Caption = Antwort.c_str();
    
    //SEND BROADCAST
    AnsiString Befehl9 ="at+bcast:01,Test_01\r";
    	WriteFile(hSerial, Befehl2.c_str(), Befehl9.Length(), &dwBytesWritten, NULL);
    	ReadFile(hSerial, Antwort.c_str(), 1000, &dwBytesWritten, NULL);
    	Label3->Caption = Antwort.c_str();
    */
    
    }
    

    MFG
    Anthony



  • An dem Code ist ziemlich viel falsch.

    z.B. werden nie die Rückgabewerte der Funktionen geprüft, das Programm macht einfach weiter.

    Die Initialisierung des DCB ist unvollständig, die Schnittstelle könnte mit zufälligen Einstellungen konfiguriert werden, deshalb sollte ein DCB immer vollständig initialisiert werden.

    Kleines Beispiel:
    http://members.inode.at/anton.zechner/az/Seriell.htm
    Da sieht man auch die Verwendung der Funktion SetCommTimeouts, wenn man etwas lesen will, sollte man da vernünftige Werte setzen.

    ReadFile(hSerial, Antwort.c_str(), 100, &dwBytesWritten, NULL);
    

    Überschreibt eventuell Speicher ausserhalb des AnsiStrings. Meines Wissens nach kann man den von .c_str() gelieferten Zeiger nur zum Lesen verwenden.


Anmelden zum Antworten