Interrupt von ComPort wenn Daten empfangen wurden



  • Hallo

    Ich habe eine Frage bezüglich des Com Portes. Ich benutze den Com1 um mit meinem yController zu kommunizieren und möchte in bestimmten Zeitabständen vom yC Daten zum PC senden und weil ich es nicht mit polling machen will würde ich dies gerne über einen Interrupt realisieren.
    Ich verwende createfile um den Port zu öffnen und habe bis jetzt immer mit readfile vom yC Daten gelesen aber das geht ja nur wenn schon Daten geschickt wurden.
    Jetzt meine Frage wie ich das ganze mit c++ und Interrupts elegant lösen kann..?
    Wenn dies noch von belang ist ich habe auch eine grafische Oberfläche welche ich mit wxWidgets erstellt habe.

    Schon mal danke für die Infos 😉

    mfg Micky



  • Ich würde auf jeden Fall eine Library für die Kommunikation über den seriellen Port benutzen:
    z.B. http://www.codeproject.com/Articles/992/Serial-library-for-C

    Oder die Implementierung aus Boost.Asio.

    Diese Libraries vereinfachen das ganze enorm, sind getestet und es gibt einigermassen gute Dokumentaion dazu.



  • Du kannst es nicht direkt mit Interrupts machen, aber so ungefähr sieht das per Winapi aus:

    HANDLE comporthandle = CreateFile(_T("\\\\.\\COM1"),
                        GENERIC_READ | GENERIC_WRITE,
                        0,
                        0,
                        OPEN_EXISTING,
                        FILE_FLAG_OVERLAPPED, //wichtig! overlapped
                        0);
    
    OVERLAPPED ovr, ovw; //die overlapped strukturen sorgen für die Synchronisation
    	//windows macht das alleine, wichtig ist aber, dass du 2 verschiedene für lesen und schreiben nimmst
    //eigener thread hier
    for (;;){
    	TCHAR buffer[1024];
    	ReadFile(comporthandle, &buffer, sizeof buffer / sizeof *buffer, 0, &ovr); //lies was
    	GetOverlappedResult(comporthandle, &ovr, &transactionsize, 1); //hole resultat (blockiert)
    	SendMessage(window, WM_COMDATA, (WPARAM)buffer, (LPARAM)transactionsize); //sende ergebnis an HWND window
    }
    

    Der Thread blockiert bei GetOverlappedResult, ist also praktisch immer inaktiv, außer wenn es was zu empfangen gibt, dann reicht er es an ein Fenster weiter. Du kannst dem Thread auch noch Realtime-Priorität geben oder ein paar Sleep(0) in deinen mainthread einbauen, damit du die Daten sofort bekommst.
    Es fehlen noch Fehlerbehandlung und vielleicht möchtest du mit den Einstellungen von SetCommState und SetCommTimeouts spielen.



  • Micky002 schrieb:

    Hallo

    Ich habe eine Frage bezüglich des Com Portes. Ich benutze den Com1 um mit meinem yController zu kommunizieren und möchte in bestimmten Zeitabständen vom yC Daten zum PC senden und weil ich es nicht mit polling machen will würde ich dies gerne über einen Interrupt realisieren.
    Ich verwende createfile um den Port zu öffnen und habe bis jetzt immer mit readfile vom yC Daten gelesen aber das geht ja nur wenn schon Daten geschickt wurden.

    Nö, mit ReadFile kannst du auch warten bis was ankommt.

    Aber mal von Anfang an. COM Schnittstellen haben üblicherweise einen Empfangspuffer (FIFO). Der UART Baustein schreibt erstmal in die FIFO rein, und wenn ein bestimmter Schwellwert erreicht ist (also z.B. 12 von 16 Bytes schon belegt sind), dann löst er einen Interrupt aus.
    Dass nicht immer gleich sofort ein Interrupt ausgelöst wird hat den Zweck CPU-Zeit zu sparen. Bei hohen Baudraten könnte sonst mächtig viel Zeit dabei draufgehen die Daten Byteweise abzuholen.
    Wenn die Baudrate allerdings recht niedrig ist, und nur ein paar wenige Bytes daherkommen, dann führt das zu einer Verzögerung.
    Der UART wartet natürlich nicht bis in alle Ewigkeit bis er einen Interrupt auslöst, auch wenn der Schwellwert nie überschritten wird, aber es entsteht eine Verzögerung.
    Wenn du das geringst-mögliche Delay haben willst, könnte es sich auszahlen diesen Schwellwert herunterzusetzen.
    (Machen kann man das im Device-Manager in den Device-Properties - wie man es programmatisch macht weiss ich nicht. Dürfte nicht ganz einfach sein, denn die Einstellung ist hardwarespezifisch).

    Nachdem das geklärt ist, kannst du mit SetCommTimeouts die Timeouts konfigurieren.

    Und dann kannst du ganz normal mit ReadFile lesen, was dann so lange blockiert bis 'was angekommen ist, oder eben das Timeout abgelaufen.
    FILE_FLAG_OVERLAPPED und GetOverlappedResult kann man dabei verwenden, muss man aber nicht.



  • @nwp3
    Wenn du schon empfiehlst overlapped IO mit getrennten OVERLAPPED structs für Lesen und Schreiben zu verwenden, dann solltest du das auch nicht unterschlagen:

    http://msdn.microsoft.com/en-us/library/windows/desktop/ms683209(v=vs.85).aspx

    MSDN schrieb:

    If the hEvent member of the OVERLAPPED structure is NULL, the system uses the state of the hFile handle to signal when the operation has been completed. Use of file, named pipe, or communications-device handles for this purpose is discouraged. It is safer to use an event object because of the confusion that can occur when multiple simultaneous overlapped operations are performed on the same file, named pipe, or communications device. In this situation, there is no way to know which operation caused the object's state to be signaled.



  • Es gibt verdammt viele Tutorials yu Com Ports im Netz.Auch Microsoft hat ein sehr umfangreiches TTY Beispiel in seinen Samples enthalten: http://msdn.microsoft.com/en-us/library/ff802693.aspx . Dort werden keine Interrupts benutzt, sondern Eventobjekte. Mittels WaitCommEvent kann dann auf beispielsweise eingehende Chars gewartet werden.



  • Dankeschön für die schnelle Antwort 🙂
    hab mich jetzt mal ein wenig dahinter gesetzt und ich hab das Problem jetzt so gelöst das ich einfach neben meinem Window einen zweiten Thread erstellt hab und diesen dann einfach die com Schnittstelle überprüfen lasse und wenn was kommt dann schickt er mir das an mein Window und ich kanns wunderbar verarbeiten 🙂

    mfg micky



  • WaitCommEvent
    http://msdn.microsoft.com/en-us/library/windows/desktop/aa363424%28v=vs.85%29.aspx
    Falls Du das nicht schon in Deinem Thread verbaut hast



  • Man kann laut MSDN-Doku notfalls auch auf einzelne chars warten:

    EV_RXFLAG
    A new character was received and placed in the input buffer. See the "Caveat" section.

    The code does not work correctly without setting the proper time-outs.

    DWORD dwCommEvent;
    DWORD dwRead;
    char  chRead;
    
    if (!SetCommMask(hComm, EV_RXCHAR))
       // Error setting communications event mask
    
    for ( ; ; ) {
       if (WaitCommEvent(hComm, &dwCommEvent, NULL)) {
          do {
             if (ReadFile(hComm, &chRead, 1, &dwRead, NULL))
                // A byte has been read; process it.
             else
                // An error occurred in the ReadFile call.
                break;
          } while (dwRead);
       }
       else
          // Error in WaitCommEvent
          break;
    }
    

    http://msdn.microsoft.com/en-us/library/ms810467.aspx



  • Ja wenn Ihr wollt kann ich euch den Teil der Kommunikation online stellen.?
    Nur erste ab Montag bin nämlich grad in Urlaub 😉


Anmelden zum Antworten