Forum: Mikrocontroller und Digitale Elektronik Serielle Kommunikation zwischen PC(Windows) und µC (STM32)


von Alex K. (alexk99123)


Angehängte Dateien:

Lesenswert?

Hallo zusammen,

ich habe ein Problem, was die serielle Kommunikation zwischen den beiden 
o.g. Devices angeht. Es geht darum, eine (zuverlässige) Kommunikation 
zwischen PC und µC herzustellen.

Generell scheint die Kommunikation auch recht gut zu funktionieren. Ich 
teste das ganze mit Hilfe von Abfragen und Reaktionen darauf. Z.B: µC 
wartet auf Daten. Ich kann quasi 2 Befehle vom PC auf den µC senden. Die 
Befehle heißen "increment" und "decrement". Je nach Befehl führt der µC 
dann unterschiedliche Anweisungen durch und sendet einen aktuellen Wert 
an den PC zurück, z.B. "2000". Mein Problem ist, dass an dem Port immer 
komische Daten anliegen.
Lustigerweise scheinen immer dieselben falschen Datenstrings anzukommen, 
wenn ich einen gewissen Befehl verwende. Das erste Bild zeigt die 
Fehlerhaften Daten, die ankommen, wenn ich den Befehl "increment" zum µC 
schicke.
Wenn ich den Befehl "decrement" sende, erscheinen die fehlerhaften Daten 
im 2. Bild.

Ich verstehe nicht, woher diese fehlerhaften Daten kommen. Meine Idee 
war, dass der PC sich irgendwie selbst Daten sendet??
Die Befehle "increment" und "decrement" werden tatsächlich richtig vom 
µC verarbeitet, das konnte ich beim Debuggen feststellen.

Aber woher kommen diese komischen Daten? Die Frage konnte ich mir bisher 
nicht erklären. Die Parameter zur seriellen Kommunikation sind auf PC 
und µC identisch.
//EDIT: Vielleicht noch als wichtige Info: Nach einem Neustart des µC 
wird dieser neu initialisiert und sendet am Ende der Initialisierung die 
Information "Init complete". Diese Daten werden immer richtig gelesen. 
Die fehlerhaften Daten treten erst danach auf.
//

Ich hänge mal meinen Code zum initialisieren des Ports auf dem PC an.
1
int serialCommunication::serialInit(void){
2
3
//non overlapped communication
4
hComm = CreateFile( gszPort.c_str(),
5
                    GENERIC_READ | GENERIC_WRITE,
6
                    0,
7
                    0,
8
                    OPEN_EXISTING,
9
                    0,
10
                    0);
11
12
if (hComm == INVALID_HANDLE_VALUE){
13
    cout << "Error opening port." << endl;
14
    return 0;
15
}
16
else{
17
    cout << "Opened Port successfully." << endl;
18
}
19
20
if (SetCommMask(hComm, EV_RXCHAR) == FALSE){
21
    cout << "Error setting communications mask." << endl;
22
    return 0;
23
}
24
else{
25
    SetCommMask(hComm, EV_RXCHAR);
26
    cout << "Communications mask set successfully." << endl;
27
}
28
29
if (GetCommState(hComm, &dcbSerialParams) == FALSE){
30
    cout << "Error getting CommState." << endl;
31
    return 0;
32
}
33
else{
34
    GetCommState(hComm, &dcbSerialParams);
35
    cout << "CommState retrieved successfully" << endl;
36
}
37
38
dcbSerialParams.BaudRate = CBR_115200;    // Setting BaudRate = 115200
39
dcbSerialParams.ByteSize = 8;             // Setting ByteSize = 8
40
dcbSerialParams.StopBits = ONESTOPBIT;    // Setting StopBits = 1
41
dcbSerialParams.Parity = NOPARITY;        // Setting Parity = None
42
43
if (SetCommState(hComm, &dcbSerialParams) == FALSE){
44
    cout << "Error setting CommState" << endl;
45
    return 0;
46
}
47
else{
48
    SetCommState(hComm, &dcbSerialParams);
49
    cout << "CommState set successfully" << endl << endl;
50
    cout << "+---CommState Parameters---+" << endl;
51
    cout << "Baudrate = " << dcbSerialParams.BaudRate << endl;
52
    cout << "ByteSize = " << static_cast<int>(dcbSerialParams.ByteSize) << endl; //static Cast, um int auszugeben und kein char
53
    cout << "StopBits = " << static_cast<int>(dcbSerialParams.StopBits) << endl; //static Cast, um int auszugeben und kein char
54
    cout << "Parity = " << static_cast<int>(dcbSerialParams.Parity) << endl; //static Cast, um int auszugeben und kein char
55
    cout << "+--------------------------+" << endl;
56
}
57
58
/*------------------------------------ Setting Timeouts --------------------------------------------------*/
59
60
timeouts.ReadIntervalTimeout         = 50;
61
timeouts.ReadTotalTimeoutConstant    = 50;
62
timeouts.ReadTotalTimeoutMultiplier  = 10;
63
timeouts.WriteTotalTimeoutConstant   = 50;
64
timeouts.WriteTotalTimeoutMultiplier = 10;
65
66
if (SetCommTimeouts(hComm, &timeouts) == FALSE){
67
    cout << "Error setting timeouts" << endl;
68
    return 0;
69
}
70
else{
71
    SetCommTimeouts(hComm, &timeouts);
72
    cout << "Timeouts set successfully." << endl;
73
    cout << "+--------------------------+" << endl;
74
    return 1;
75
}

Außerdem hier noch meine Read Funktion
1
void serialCommunication::serialRead(void){
2
bool readStatus;
3
bool purgeStatus = 0;
4
bool correctData = 0;
5
6
cout << "Waiting for Data..." << endl; // Programm waits and blocks Port (like Polling)
7
readStatus = WaitCommEvent(hComm, &dwEventMask, 0);
8
if (readStatus == FALSE){
9
    cout << "Error in setting WaitCommEvent." << endl;
10
}
11
else{
12
    cout << "Data received." << endl;
13
    do{
14
        readStatus = ReadFile(hComm, &TempChar, sizeof(TempChar), &NoBytesRead, 0);
15
        SerialBuffer += TempChar; // add tempchar to the string
16
    }while (NoBytesRead > 0);
17
SerialBuffer.pop_back(); // Delete last sign in buffer, otherwise one "0" too much shows up, for example "23900" instead of "2390"
18
cout << endl << SerialBuffer << endl;
19
SerialBuffer = ""; // Reset string
20
}

: Bearbeitet durch User
von m.n. (Gast)


Lesenswert?

Nimm mal einen anderen STM32.

von Martin (Gast)


Lesenswert?

Wie sieht denn der Code aufm dem Controller aus?
Funktioniert ein Loopback?

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Alex K. schrieb:
> Aber woher kommen diese komischen Daten?
Wie sieht denn die Beschaltung und die Masseführung aus?

Dieser Kommentar im Code gibt mir zu denken:
> Delete last sign in buffer, otherwise one "0" too much shows up
Warum das?
Ein solcher "Workaround" ist immer ein Zeichen dafür, dass da noch was 
faul ist...

> Ich verstehe nicht, woher diese fehlerhaften Daten kommen.
Hast du ein Oszilloskop? Oder einen Logikanalyzer? Damit könntest du mal 
feststellen, ob die Bytes tatsächlich auf der RXD-Leitung des PC 
auftauchen.

: Bearbeitet durch Moderator
von Alex K. (alexk99123)


Lesenswert?

Martin schrieb:
> Wie sieht denn der Code aufm dem Controller aus?
> Funktioniert ein Loopback?


Die loop für die Abfrage der Daten ist folgende:
BEim Debuggen konnte ich wie schon erwähnt feststellen, dass der 
COntroller tatsächlich auch in die If- Schleifen von "increment" und 
"decrement" reinspringt und die Befehle ausführt.
1
RS485_SendString(COM2, "Init complete...!\r\n", CRLF);
2
  buf[0] = '\0'; //Inhalt des Buffers löschen
3
4
  // While schleife für Kalibrierung, Increment und Dekrement um "increment"
5
  while (stopCalibration != 1){
6
    check = RS485_ReceiveString(COM2, buf);
7
    if(check == RX_READY){  // Test, ob Daten am Port anliegen
8
      if(strstr(buf, "stopCalibration")){
9
        stopCalibration = 1;
10
        incrementValue = incrementValue - (2 * increment); // nach Endbedingung 2x Decrement
11
        hvAntwort = transmit_apd(channelNumber, 0b1000, incrementValue);
12
        RS485_SendString(COM2, "Kalibrierung gestoppt. 2x Dekrement durchgefuehrt.", CRLF);
13
        buf[0] = '\0'; //Inhalt des Buffers löschen
14
      }
15
      else if(strstr(buf, "increment")){
16
        incrementValue = incrementValue + increment;
17
        hvAntwort = transmit_apd(channelNumber, 0b1000, incrementValue);
18
        RS485_SendString(COM2, itoa(incrementValue, ausgangsBuffer, 10), CRLF);
19
        buf[0] = '\0'; //Inhalt des Buffers löschen
20
      }
21
      else if(strstr(buf, "decrement")){
22
        incrementValue = incrementValue - increment;
23
        hvAntwort = transmit_apd(channelNumber, 0b1000, incrementValue);
24
        RS485_SendString(COM2, itoa(incrementValue, ausgangsBuffer, 10), CRLF);
25
        buf[0] = '\0'; //Inhalt des Buffers löschen
26
      }
27
    }
28
  }

von Alex K. (alexk99123)


Lesenswert?

m.n. schrieb:
> Nimm mal einen anderen STM32.

Das Problem ist, dass es sich um ein ganzes, fest verbautes Board 
handelt. Mal sehen, ob ich eins auftreiben kann

von r c (Gast)


Lesenswert?

Auch wenn du sagst, die Paramter sind gleich, sieht das für mich rein 
optisch erstmal nach falscher Baudrate aus.
Vielleicht ist diese im Init ja noch anders, das seh ich hier nicht.

Lässt sich wohl zu 100% nur mit dem Oszi klären.

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Wie ist der ausgangsBuffer definiert?

von Nico W. (nico_w)


Lesenswert?

1
buf[0] = '\0';
Löscht sicher nicht den kompletten Buffer.

: Bearbeitet durch User
von m.n. (Gast)


Lesenswert?

Aha. Es geht um eine RS485 Verbindung. Vermutlich mit fehlender Pause 
bei der Umschaltung.
Die erste Scheibe Salami möchte ich bekommen!

von Alex K. (alexk99123)


Lesenswert?

Okay,

vielen Dank erstmal für eure Hilfe! Das Problem lag wirklich am µC.... 
Ich habe es an 2 anderen µC's ausprobiert und das Programm funktioniert 
bisher fehlerfrei. Vielleicht ist an dem einen Board intern was falsch 
verbunden gewesen. Sorry, dass ich das nicht zuerst probiert habe, bevor 
ich den Thread hier eröffnet habe.

von Alex K. (alexk99123)


Lesenswert?

Nico W. schrieb:
> buf[0] = '\0';
> Löscht sicher nicht den kompletten Buffer.

Könnte man das in diesem Zusammenhang vielleicht noch klären? Ich dachte 
mir das so, dass, falls mal irgendwelche Daten im Buffer übrig geblieben 
sind, ich den Buffer lieber nochmal nach jedem Befehl von Hand 
zurücksetze. Habe die Zeile, die du zitierst hast, jetzt mal 
auskommentiert und du hast Recht damit, dass das gar nicht den 
gewünschten Effekt hat. Bzw. scheint die Zeile vollkommen überflüssig zu 
sein

von Joachim B. (jar)


Lesenswert?

Alex K. schrieb:
> Generell scheint die Kommunikation auch recht gut zu funktionieren.
> Wenn ich den Befehl "decrement" sende, erscheinen die fehlerhaften Daten
> im 2. Bild.
>
> Ich verstehe nicht, woher diese fehlerhaften Daten kommen. Meine Idee
> war, dass der PC sich irgendwie selbst Daten sendet??
> Die Befehle "increment" und "decrement" werden tatsächlich richtig vom
> µC verarbeitet, das konnte ich beim Debuggen feststellen.
>
> Aber woher kommen diese komischen Daten?

es ist gut das zu ergründen (zu wollen) aber wenn man es nicht ergründen 
kann, und sonst alles funktioniert, wie wäre es mit einfach ignorieren?

Ich prüfe alles was kommt
1. auf isprint und/oder nach Bedarf
isalnum, isalpha, isascii, isblank, iscntrl, isdigit, isgraph, islower, 
isprint, ispunct, isspace, isupper, isxdigit

passt es nicht oder ich brauche es nicht wird es ignoriert, alles kann 
man nicht ergründen, solange es trotzdem fehlerfrei funktioniert was man 
möchte....

Die gezeigten Zeichen passen ja auch nicht zu "increment" und 
"decrement"
also unwichtig, ich vergleiche meine commands auch und was der µC nicht 
kennt wird verworfen

: Bearbeitet durch User
von Alex K. (alexk99123)


Lesenswert?

Joachim B. schrieb:
> also unwichtig, ich vergleiche meine commands auch und was der µC nicht
> kennt wird verworfen

Das wird für mich wohl auch der richtige Ansatz sein, da ich nicht zu 
100% durchblicke, was PC und µC zu welchem Zeitpunkt genau machen.

von Joachim B. (jar)


Lesenswert?

Alex K. schrieb:
> Joachim B. schrieb:
>> also unwichtig, ich vergleiche meine commands auch und was der µC nicht
>> kennt wird verworfen
>
> Das wird für mich wohl auch der richtige Ansatz sein, da ich nicht zu
> 100% durchblicke, was PC und µC zu welchem Zeitpunkt genau machen.

so auch bei meinem AVR Webserver NETIO, manchmal reagiert er nicht mehr, 
ABER
er ist immer ansprechbar per RS232, dann schicke ich "reset", er 
antwortet mit "eset" oder "unbekannter Befehl" es ist also was im Buffer 
angekommen was er nicht versteht!
wenn ich dann noch mal "reset" schicke startet er halt neu und ist 
wieder ansprechbar.

Ich sollte noch eine kill buffer Routine einbauen bei derlei Unsinn im 
Buffer, aber es eilt ja nicht :)

von Lothar M. (Firma: Titel) (lkmiller) (Moderator) Benutzerseite


Lesenswert?

Alex K. schrieb:
> Nico W. schrieb:
>> buf[0] = '\0';
>> Löscht sicher nicht den kompletten Buffer.
> Könnte man das in diesem Zusammenhang vielleicht noch klären? Ich dachte
> mir das so, dass, falls mal irgendwelche Daten im Buffer übrig geblieben
> sind, ich den Buffer lieber nochmal nach jedem Befehl von Hand
> zurücksetze.
Mit diesem Befehl "löschst" du nur das erste Zeichen vom Puffer (wobei 
"löchen" hier eigentlich auch falsch ist, denn da wird nur an die erste 
Zelle der Strinterminator 0 geschrieben).
Wenn du da im Puffer sonst nichts zurücksetzt (z.B. mit memset(buf,0);), 
dann muss nur irgendwer in diese erste Speicherzelle irgendwas ungleich 
0 reinschreiben und auf wunderbare Weise "erscheint" der gelöscht 
geglaubte Pufferinhalt wieder...

von Alex K. (alexk99123)


Lesenswert?

Wieder was gelernt, dankeschön!

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.