Hypercell ein ] Hypercell aus ] Zeige Navigation ] Verstecke Navigation ]
c++.net  
   

Die mobilen Seiten von c++.net:
https://m.c-plusplus.net

  
C++ Forum :: WinAPI ::  Probleme mit empfangen von Daten (Serielle Schnittstelle)     Zeige alle Beiträge auf einer Seite Auf Beitrag antworten
Autor Nachricht
domenc
Unregistrierter




Beitrag domenc Unregistrierter 15:27:19 12.09.2017   Titel:   Probleme mit empfangen von Daten (Serielle Schnittstelle)            Zitieren

Ich schreibe ein Programm, wo der Rechner mit einem Microcontroller über eine serielle Schnittstelle kommunizieren soll. Dabei sollen zwei Funktionen realisiert werden:
- ich schicke ihm Daten auf die er dann antwortet
- er sendet mir daten, auf welche ich dann reagiere (z.B. ein Timer ist im Microcontroller abgelaufen und er schickt mir zu: Timer End)

Den "Warteteil" (WaitCommEvent) hab ich mit einem Thread realisiert:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//Thread um auf ein Event/eine Nachricht vom Microcontroller zu warten, währrend das Programm normal weiter laufen kann und der PC weiter mit dem MC kommunizieren kann
DWORD WINAPI WaitForEventThread(PVOID lpParam)
{                  
    while (TRUE) {
            dwEventMask = NULL;
            //Wait for the character to be received
            SetCommMask(hComm, EV_RXCHAR);
            dataReceived = WaitCommEvent(hComm, &dwEventMask, NULL); // Es wird auf Daten vom Microcontroller gewartet
            if (dataReceived) {
                if (dwEventMask && EV_RXCHAR) {
                    ReadBuffer = ComRead();
 
                    if (...)
                        //Vergleiche empfangene Nachricht in ReadBuffer mit eigenen Werten/eigener Nachricht und mache damit etwas...
                    else ...
                }
            }
        }
}


Das Senden funktioniert eigentlich ganz gut
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
bool ComWrite(char* TxBuffer, int telegramSize)
...
    overlappedWrite.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
 
    // Issue write.
    if (!WriteFile(hComm, TxBuffer, telegramSize, &dNoOfBytesWritten, &overlappedWrite)) {
        if (GetLastError() != ERROR_IO_PENDING)
            // WriteFile failed, but isn't delayed. Report error and abort.
            writeSuccess = FALSE;
 
        else
            // Write is pending.
            dwRes = WaitForSingleObject(overlappedWrite.hEvent, INFINITE);
 
        switch (dwRes)
        {
            // OVERLAPPED structure's event has been signaled.
        case WAIT_OBJECT_0:
            if (!GetOverlappedResult(hComm, &overlappedWrite, &dwWritten, FALSE))
                writeSuccess = FALSE;
            else
                writeSuccess = TRUE;
 
            break;
 
        default:
            // An error has occurred in WaitForSingleObject.
            // This usually indicates a problem with the
            // OVERLAPPED structure's event handle.
            writeSuccess = FALSE;
            break;
        }
    }
...


Allerdings das Empfangen bereitet mir Kopfzerbrechen :confused: , da er mir ein paar Daten "abschneidet oder vergisst zu senden".
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
char* ComRead()
{
...
    overlappedRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
 
    do {
            Status = ReadFile(hComm, &TempChar, sizeof(TempChar), &NoBytesRead, &overlappedRead);
            SerialBuffer[recvSize] = TempChar;
            recvSize++;
       
    } while (NoBytesRead > 0);
 
       
    if (fWaitingOnRead) {
        dwRes = WaitForSingleObject(overlappedRead.hEvent, READ_TIMEOUT);
        switch (dwRes)
        {
            case WAIT_OBJECT_0:
                if (!GetOverlappedResult(hComm, &overlappedRead, &NoBytesRead, FALSE))
                    ReadSuccess = FALSE;
                else
                    ReadSuccess = TRUE;
                    fWaitingOnRead = FALSE;
                break;
 
            default:
                ReadSuccess = FALSE;
                break;
        }
    }
    return SerialBuffer
}


Ich stell die Verbindung beim Programmstart in einer Dialog-Hauptfunktion her:

C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
//=========== Dialog-Hauptfunktion ==============
...
/*---------------------------------- Opening the Serial Port -------------------------------------------*/     
    switch (msg) {
 
        case WM_INITDIALOG:
 
            hComm = CreateFile(ComPortName,   // Name of the Port to be Opened
                GENERIC_READ | GENERIC_WRITE, // Read/Write Access
                0,                            // No Sharing, ports cant be shared
                NULL,                         // No Security
                OPEN_EXISTING,                // Open existing port only
                FILE_FLAG_OVERLAPPED,         // Non Overlapped I/O
                NULL);                        // Null for Comm Devices
 
            /*------------------------------- Setting the Parameters for the SerialPort ------------------------------*/
            if (hComm != INVALID_HANDLE_VALUE) {
                DCB dcbSerialParams = { 0 };                         // Initializing DCB structure
                dcbSerialParams.DCBlength = sizeof(dcbSerialParams);
 
                Status = GetCommState(hComm, &dcbSerialParams);      //retreives  the current settings
                dcbSerialParams.BaudRate = CBR_9600;      // Setting BaudRate = 9600
                dcbSerialParams.ByteSize = 8;             // Setting ByteSize = 8
                dcbSerialParams.StopBits = ONESTOPBIT;    // Setting StopBits = 1
                dcbSerialParams.Parity = NOPARITY;        // Setting Parity = None
                Status = SetCommState(hComm, &dcbSerialParams);  //Configuring the port according to settings in DCB
 
                /*------------------------------------ Setting Timeouts --------------------------------------------------*/
 
                COMMTIMEOUTS timeouts = { 0 };
                timeouts.ReadIntervalTimeout = 50;
                timeouts.ReadTotalTimeoutConstant = 50;
                timeouts.ReadTotalTimeoutMultiplier = 10;
                timeouts.WriteTotalTimeoutConstant = 50;
                timeouts.WriteTotalTimeoutMultiplier = 10;
 
                /*------------------------------------ Setting Receive Mask ----------------------------------------------*/
 
                SetCommMask(hComm, EV_RXCHAR); //Configure Windows to Monitor the serial device for Character Reception
 
                // ==== einmal Status abfragen, damit MC angesprochen wird
                writeSuccess = ComWrite(NachrichtAnMicrocontroller, sizeof(NachrichtAnMicrocontroller));
                WaitForEventHwnd = CreateThread(NULL, 0L, WaitForEventThread, NULL, 0L, &dwWaitForEvent);
 
...


Mein Problem genauer:
Beim Programmstart sende ich eine Nachricht an den Microcontroller um diesen anzusprechen. Wenn ich danach wieder eine Nachricht an Ihn sende, bekomme ich die Antwort nicht vollständig von ihm.
Als Beispiel:
ich sende ihm: 0x01 0x02 0x03 0x04 0x05
und erwarte als Antwort: 0x05 0x04 0x03 0x02 0x01.
Allerdings bekomme ich von ihm: 0x03 0x02 0x01. :eek:

Was mich jetzt verwirrt ist, dass er beim Programmstart wenn es zum ersten mal ausgeführt wird (Siehe im Code->Hauptdialog
C:
ComWrite(NachrichtAnMicrocontroller, sizeof(NachrichtAnMicrocontroller));

mir die richtige Anwort/Nachricht zusendet und jede weitere Kommunikation danach nicht mehr stimmt. Das Senden funktioniert, allerdings beim Empfangen hab ich ein wenig Probleme :rolleyes:
Hatte schon jemand mal so ein Problem? Kann mir da jemand helfen? :D

p.s. ich hoffe das ist jetzt nichz zu viel code auf einmal :rolleyes:
Mox
Unregistrierter




Beitrag Mox Unregistrierter 16:08:59 12.09.2017   Titel:              Zitieren

Deine ComRead-Funktion ist ein klein wenig zu sehr reduziert. So ist mir z.B. nicht klar, wann und wie Du das Flag fWaitingOnRead setzt. Wenn ich aber davon ausgehe, dass Du dieses dann auf TRUE setzt, wenn "Status" von ReadFile auf FALSE gesetzt wird und GetLastError den Wert ERROR_IO_PENDING liefert.

Wenn dem so ist, hat ReadFile noch nichts in den übergebenen Buffer geschrieben (Parameter 2, &TempChar). Das passiert dann, wenn GetOverlappedResult mit TRUE zurückgekehrt ist. Allerdings kopierst Du das gelesene Byte in diesem Falle nicht in Deinen SerialBuffer.

Kann das schon das Problem sein?
domenc
Unregistrierter




Beitrag domenc Unregistrierter 10:59:41 13.09.2017   Titel:              Zitieren

Hallo Mox,

danke für die schnelle Antwort. Leider hat das auch nicht geklappt.
Ich habe jetzt einfach noch eine "reduzierte" Variante versucht, die wieder den Buffer ließt aber nicht vollständig.
Der Fehler ist der gleiche, dass einige Zeichen aus dem Buffer nicht aufgenommen werden :confused:

Ich habe es jetzt so versucht:
C:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
    overlappedRead.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
 
    do {
            // Issue read operation.
            if (!ReadFile(hComm, &TempChar, sizeof(TempChar), &NoBytesRead, &overlappedRead)) {
                if (GetLastError() != ERROR_IO_PENDING)     // read not delayed?
                    MessageBox(NULL, "FAIL Read", "ERROR_IO_PENDING", MB_OK); // Error in communications; report it.
                //else
                //  dwRes = WaitForSingleObject(overlappedRead.hEvent, READ_TIMEOUT);
            }
            else
                writeInSerialBuf = TRUE;
           
            dwRes = WaitForSingleObject(overlappedRead.hEvent, READ_TIMEOUT);
            switch (dwRes)
            {
                // Read completed.
            case WAIT_OBJECT_0:
                if (!GetOverlappedResult(hComm, &overlappedRead, &NoBytesRead, FALSE))
                    MessageBox(NULL, "FAIL Read", "GetOverlappedResult", MB_OK);
                else
                    writeInSerialBuf = TRUE;
 
                break;
               
            case WAIT_TIMEOUT :
                Sleep(1); //Sleep nur drinnen damit "etwas getan wird"
                break;
                       
            default:
                writeInSerialBuf = FALSE;
                break;
            }
 
            if (writeInSerialBuf)
            {
                writeInSerialBuf = FALSE;
                SerialBuffer[recvSize] = TempChar;
                recvSize++;
            }
    } while (NoBytesRead > 0);


Bin leider noch ein Laie in dem Gebiet der seriellen Kommunikation :rolleyes:
hustbaer
Mitglied

Benutzerprofil
Anmeldungsdatum: 27.10.2006
Beiträge: 23589
Beitrag hustbaer Mitglied 11:13:02 13.09.2017   Titel:              Zitieren

Ich würde dir empfehlen statt WaitForSingleObject mit Timeout SetCommTimeouts zu verwenden. Und kein Overlapped IO. Dein Overlapped-Handling sieht nämlich etwas ... funky aus.

_________________
Until every person can enjoy all their human rights, we will not stop. I support Amnesty International. Will you?
https://www.amnesty.org / https://www.amnesty.de / https://www.amnesty.at
domenc
Unregistrierter




Beitrag domenc Unregistrierter 13:31:42 13.09.2017   Titel:              Zitieren

Danke hustbaer,

Dein Tipp mit dem SetCommTimeouts hat geholfen :)
Hab das vergessen zu setzen. Auch mit meiner Funky Overlapped Lösung funktioniert es dank dem SetCommTimeouts :D
C++ Forum :: WinAPI ::  Probleme mit empfangen von Daten (Serielle Schnittstelle)   Auf Beitrag antworten

Zeige alle Beiträge auf einer Seite




Nächstes Thema anzeigen
Vorheriges Thema anzeigen
Sie können Beiträge in dieses Forum schreiben.
Sie können auf Beiträge in diesem Forum antworten.
Sie können Ihre Beiträge in diesem Forum nicht bearbeiten.
Sie können Ihre Beiträge in diesem Forum nicht löschen.
Sie können an Umfragen in diesem Forum nicht mitmachen.

Powered by phpBB © 2001, 2002 phpBB Group :: FI Theme

c++.net ist Teilnehmer des Partnerprogramms von Amazon Europe S.à.r.l. und Partner des Werbeprogramms, das zur Bereitstellung eines Mediums für Websites konzipiert wurde, mittels dessen durch die Platzierung von Werbeanzeigen und Links zu amazon.de Werbekostenerstattung verdient werden kann.

Die Vervielfältigung der auf den Seiten www.c-plusplus.de, www.c-plusplus.info und www.c-plusplus.net enthaltenen Informationen ohne eine schriftliche Genehmigung des Seitenbetreibers ist untersagt (vgl. §4 Urheberrechtsgesetz). Die Nutzung und Änderung der vorgestellten Strukturen und Verfahren in privaten und kommerziellen Softwareanwendungen ist ausdrücklich erlaubt, soweit keine Rechte Dritter verletzt werden. Der Seitenbetreiber übernimmt keine Gewähr für die Funktion einzelner Beiträge oder Programmfragmente, insbesondere übernimmt er keine Haftung für eventuelle aus dem Gebrauch entstehenden Folgeschäden.