Problem mit serieller Schnittstelle



  • Hallo,

    ich habe ein Gerät gebaut, das einen Sensor auswertet und das Ergebnis über die serielle Schnittstelle sendet.
    Eine Messung wird immer dann gestartet, wenn über die serielle Schnittstelle ein "a" empfangen wird.

    Mit einem Terminalprogramm (ich habe miniIde verwendet: http://www.mgtek.com/miniide/) funktioniert es auch perfekt.

    Da ich aber nicht immer auf die "a"-Taste drücken will und die Messergebnisse auch ausgewertet werden sollen, habe ich folgendes Testprogramm geschrieben:

    #include <iostream>
    #include <cstring>
    #include <windows.h>
    
    using namespace std;
    
    int main()
    {
        cout << "starting program... done" << endl;
    
        //Initialisierung
        cout << "initializing... ";
    
        LPCTSTR port = L"COM4";
        HANDLE hComm;
        hComm = CreateFile(port, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    
        if(hComm == INVALID_HANDLE_VALUE)
        {
            cout << "failure 1" << endl;
        }
        else
        {
            cout << "done" << endl;
        }
    
        //set timeout
        COMMTIMEOUTS timeout;
        timeout.ReadIntervalTimeout = 100;
        timeout.ReadTotalTimeoutConstant = 100;
        timeout.ReadTotalTimeoutMultiplier = 100;
        timeout.WriteTotalTimeoutConstant = 100;
        timeout.WriteTotalTimeoutMultiplier = 100;
    
        SetCommTimeouts(hComm, &timeout);
    
        //write one "a" to request data
        cout << "writing 'a'... ";
    
        if(!WriteFile(hComm, "a", 1, NULL, NULL))
        {
            cout << "failure 2" << endl;
        }
        else
        {
            cout << "done" << endl;
        }
    
        //receive
        cout << "receiving data... ";
    
        char result[5];
        long unsigned int size;
    
        if(!ReadFile(hComm, &result, 4, &size, NULL))
        {
            cout << "failure 3" << endl;
            cout << "errorcode: " << GetLastError() << endl;
        }
        else
        {
            cout << "done" << endl;
        }
    
        //converting
        string res;
        res = result;
        res.erase(size-1, res.length());
        int value = atoi(res.c_str());
    
        cout << endl << value << " : " << size << endl;
    
        system("pause");
    
        return 0;
    }
    

    Wenn ich jetzt meinen PC neustarte und das Program ausführe, dann funktioniert es nicht.
    Starte ich allerdings das Terminalprogramm und "teste" mein Gerät einmal (ich sende also ein "a" und erhalte dann den Wert zurück), dann kann ich das Terminalprogramm beenden und mein selbstgeschriebenes Programm funktioniert wie es soll bis zum nächsten Neustart.

    Woran kann das liegen?

    Über Tipps würde ich mich sehr freuen!

    Gruß und Danke,
    Marvin



  • utzer schrieb:

    LPCTSTR port = L"COM4";
    

    Das gibt früher oder später Probleme, siehe "HOWTO: Specify Serial Ports Larger than COM9". Schreib es lieber gleich so:

    LPCTSTR port = TEXT("\\\\.\\COM4");
    
    // *Oder* direkt in UNICODE
    LPCWSTR port = L"\\\\.\\COM4";
    

    Das ist aber in diesem speziellen Fall nicht das Problem. Das Problem ist, dass Du den Port nicht konfigurierst (Baudrate, Handshake usw.), und das musst Du per SetCommState erledigen.



  • Hallo,

    danke für die Antwort, das hilft schon mal weiter.

    Ich habe jetzt folgendes zu meinem Code hinzugefügt;

    DCB dcb;
        dcb.DCBlength =  sizeof(DCB);
        dcb.BaudRate = CBR_9600;
        dcb.fBinary = TRUE;
        dcb.fParity = TRUE;
        dcb.fOutxCtsFlow = FALSE;
        dcb.fOutxDsrFlow = FALSE;
        dcb.fDtrControl = DTR_CONTROL_DISABLE;
        dcb.fDsrSensitivity = TRUE;
        dcb.fTXContinueOnXoff = TRUE;
        dcb.fOutX = FALSE;
        dcb.fInX = FALSE;
        dcb.fErrorChar = TRUE;
        dcb.fNull = TRUE;
        dcb.fRtsControl = RTS_CONTROL_DISABLE;
        dcb.fAbortOnError = FALSE;
        dcb.XonLim = 1;
        dcb.XoffLim = 1;
        dcb.ByteSize = 8;
        dcb.Parity = NOPARITY;
        dcb.StopBits = ONESTOPBIT;
        //dcb.XonChar = ;           //?
        //dcb.XoffChar = ;          //?
        //dcb.ErrorChar = ;         //?
        dcb.EofChar = '\0';
        //dcb.EvtChar = ;           //?
    
        if(!SetCommState(hComm, &dcb))
    

    Leider erhalte ich jetzt ein "wirres Zeichen", und bei machen Einstellungen ist mir auch nicht klar, was damit gemeint ist.

    Kann mir irgendjemand Tipps geben, wie ich am besten den Port konfiguriere?

    Hier meine Einstellungen vom Terminalprogramm:

    http://imageshack.us/a/img94/9479/porteinstellungen.png

    Über Tipps würde ich mich sehr freuen!

    Gruß
    Marvin



  • Du willst scheinbar nicht wirklich Flusskontrolle, von daher musst Du fDsrSensitivity auf FALSE setzen. Parity hast Du im Terminal ebenfalls auf "None" gesetzt, fParity hingegen auf TRUE. Automatisches ersetzen von Bytes willst Du auch nicht, also ist auch fErrorChar falsch initialisiert. Das ganze Zeugs der Richtung Xon und Xoff kannst Du belassen wie es ist, da Dich das sowieso nicht interessiert.

    Mach es irgendwie so:

    DCB dcb = { };
    dcb.DCBlength = sizeof(dcb);
    GetCommState(hComm, &dcb);
    
    dcb.BaudRate            = CBR_9600;
    dcb.fBinary             = TRUE;
    dcb.fParity             = FALSE;
    dcb.fOutxCtsFlow        = FALSE;
    dcb.fOutxDsrFlow        = FALSE;
    dcb.fDtrControl         = DTR_CONTROL_DISABLE;
    dcb.fDsrSensitivity     = FALSE;
    dcb.fTXContinueOnXoff   = TRUE;
    dcb.fOutX               = FALSE;
    dcb.fInX                = FALSE;
    dcb.fErrorChar          = FALSE;
    dcb.fNull               = FALSE;
    dcb.fRtsControl         = RTS_CONTROL_ENABLE;
    dcb.fAbortOnError       = FALSE;
    dcb.ByteSize            = 8;
    dcb.Parity              = NOPARITY;
    dcb.StopBits            = ONESTOPBIT;
    if(!SetCommState(hComm, &dcb))
    


  • Hallo,

    cool, danke habe es jetzt nach Deinem Beispiel gemacht und es funkdtioniert jetzt super, auch nach dem Neustart 😃

    Eine Frage habe ich aber noch: Ich möchte nun dieses "Testprogramm" erweitern, weil es ja nur zum Testen war.
    Jetzt liegt der Port in einem std::string als "COM1" vor (z.B. es kann auch "COM14" sein.)
    Wie bringe ich das jetzt in die Form

    LPCWSTR port = L"\\\\.\\COM4";
    

    ? Wie mache ich das mit dem 'L' und den '\'?

    Gruß und Danke nochmals,
    Marvin



  • std::wstring port = L"\\\.\\COM14";
    CreateFileW(port.c_str(), ...);



  • Hallo,

    ok, aber mein Problem ist, dass ich am Anfang nur einen

    std::string eingabe = "COMx"
    

    (x = Portnummer) habe.
    Wie kann ich daraus dann einen LPCWSTR machen?
    einfach so:

    LPCWSTR port = L("\\\\.\\" + eingabe);
    

    😕

    Danke für die Tipps!

    Gruß
    Marvin



  • #include <string>
    
    int main()
    {
      // ...
      std::wstring eingabe = L"COM4";
      std::wstring port    = std::wstring(L"\\\\.\\") + eingabe;
      CreateFile(port.c_str(), ...);
    }
    


  • Hallo,

    danke, ich habe es geschafft 🙂
    So funktioniert es:

    #include "string2wstring.h"
    
    ...
    
    Widen<wchar_t> to_wstring;
    std::wstring port = std::wstring(L"\\\\.\\") + to_wstring(eingabe);;
    
    HANDLE hComm;
    hComm = CreateFile(port.c_str(), GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0);
    

    Und die string2wstring.h habe ich von hier: http://www.c-plusplus.net/forum/168607-full
    'eingabe' ist ein std::string mit dem Inhalt "COM4" (z.B.) (welchen Port weiß ich aber erst zur Laufzeit und dieser string wird dann von Benutzer eingegeben.)
    Funktioniert wie gesagt bestens!

    Gibt es eine einfachere Lösung?

    Gruß und Danke,
    Marvin



  • hier hab ich eine lib gepostet, die unter anderem auch eine liste mit verfügbaren Ports ausgibt.

    http://www.mikrocontroller.net/topic/251666

    um die neuen Versionen zu finden, von unten nach oben scrollen 😉



  • utzer schrieb:

    Gibt es eine einfachere Lösung?

    Zu was?


Anmelden zum Antworten