mikrocontroller.net

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


Autor: Alex K. (alexk99123)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht 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.
int serialCommunication::serialInit(void){

//non overlapped communication
hComm = CreateFile( gszPort.c_str(),
                    GENERIC_READ | GENERIC_WRITE,
                    0,
                    0,
                    OPEN_EXISTING,
                    0,
                    0);

if (hComm == INVALID_HANDLE_VALUE){
    cout << "Error opening port." << endl;
    return 0;
}
else{
    cout << "Opened Port successfully." << endl;
}

if (SetCommMask(hComm, EV_RXCHAR) == FALSE){
    cout << "Error setting communications mask." << endl;
    return 0;
}
else{
    SetCommMask(hComm, EV_RXCHAR);
    cout << "Communications mask set successfully." << endl;
}

if (GetCommState(hComm, &dcbSerialParams) == FALSE){
    cout << "Error getting CommState." << endl;
    return 0;
}
else{
    GetCommState(hComm, &dcbSerialParams);
    cout << "CommState retrieved successfully" << endl;
}

dcbSerialParams.BaudRate = CBR_115200;    // Setting BaudRate = 115200
dcbSerialParams.ByteSize = 8;             // Setting ByteSize = 8
dcbSerialParams.StopBits = ONESTOPBIT;    // Setting StopBits = 1
dcbSerialParams.Parity = NOPARITY;        // Setting Parity = None

if (SetCommState(hComm, &dcbSerialParams) == FALSE){
    cout << "Error setting CommState" << endl;
    return 0;
}
else{
    SetCommState(hComm, &dcbSerialParams);
    cout << "CommState set successfully" << endl << endl;
    cout << "+---CommState Parameters---+" << endl;
    cout << "Baudrate = " << dcbSerialParams.BaudRate << endl;
    cout << "ByteSize = " << static_cast<int>(dcbSerialParams.ByteSize) << endl; //static Cast, um int auszugeben und kein char
    cout << "StopBits = " << static_cast<int>(dcbSerialParams.StopBits) << endl; //static Cast, um int auszugeben und kein char
    cout << "Parity = " << static_cast<int>(dcbSerialParams.Parity) << endl; //static Cast, um int auszugeben und kein char
    cout << "+--------------------------+" << endl;
}

/*------------------------------------ Setting Timeouts --------------------------------------------------*/

timeouts.ReadIntervalTimeout         = 50;
timeouts.ReadTotalTimeoutConstant    = 50;
timeouts.ReadTotalTimeoutMultiplier  = 10;
timeouts.WriteTotalTimeoutConstant   = 50;
timeouts.WriteTotalTimeoutMultiplier = 10;

if (SetCommTimeouts(hComm, &timeouts) == FALSE){
    cout << "Error setting timeouts" << endl;
    return 0;
}
else{
    SetCommTimeouts(hComm, &timeouts);
    cout << "Timeouts set successfully." << endl;
    cout << "+--------------------------+" << endl;
    return 1;
}

Außerdem hier noch meine Read Funktion
void serialCommunication::serialRead(void){
bool readStatus;
bool purgeStatus = 0;
bool correctData = 0;

cout << "Waiting for Data..." << endl; // Programm waits and blocks Port (like Polling)
readStatus = WaitCommEvent(hComm, &dwEventMask, 0);
if (readStatus == FALSE){
    cout << "Error in setting WaitCommEvent." << endl;
}
else{
    cout << "Data received." << endl;
    do{
        readStatus = ReadFile(hComm, &TempChar, sizeof(TempChar), &NoBytesRead, 0);
        SerialBuffer += TempChar; // add tempchar to the string
    }while (NoBytesRead > 0);
SerialBuffer.pop_back(); // Delete last sign in buffer, otherwise one "0" too much shows up, for example "23900" instead of "2390"
cout << endl << SerialBuffer << endl;
SerialBuffer = ""; // Reset string
}

: Bearbeitet durch User
Autor: m.n. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nimm mal einen anderen STM32.

Autor: Martin (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie sieht denn der Code aufm dem Controller aus?
Funktioniert ein Loopback?

Autor: Lothar M. (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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
Autor: Alex K. (alexk99123)
Datum:

Bewertung
0 lesenswert
nicht 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.
RS485_SendString(COM2, "Init complete...!\r\n", CRLF);
  buf[0] = '\0'; //Inhalt des Buffers löschen

  // While schleife für Kalibrierung, Increment und Dekrement um "increment"
  while (stopCalibration != 1){
    check = RS485_ReceiveString(COM2, buf);
    if(check == RX_READY){  // Test, ob Daten am Port anliegen
      if(strstr(buf, "stopCalibration")){
        stopCalibration = 1;
        incrementValue = incrementValue - (2 * increment); // nach Endbedingung 2x Decrement
        hvAntwort = transmit_apd(channelNumber, 0b1000, incrementValue);
        RS485_SendString(COM2, "Kalibrierung gestoppt. 2x Dekrement durchgefuehrt.", CRLF);
        buf[0] = '\0'; //Inhalt des Buffers löschen
      }
      else if(strstr(buf, "increment")){
        incrementValue = incrementValue + increment;
        hvAntwort = transmit_apd(channelNumber, 0b1000, incrementValue);
        RS485_SendString(COM2, itoa(incrementValue, ausgangsBuffer, 10), CRLF);
        buf[0] = '\0'; //Inhalt des Buffers löschen
      }
      else if(strstr(buf, "decrement")){
        incrementValue = incrementValue - increment;
        hvAntwort = transmit_apd(channelNumber, 0b1000, incrementValue);
        RS485_SendString(COM2, itoa(incrementValue, ausgangsBuffer, 10), CRLF);
        buf[0] = '\0'; //Inhalt des Buffers löschen
      }
    }
  }

Autor: Alex K. (alexk99123)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: r c (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Lothar M. (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie ist der ausgangsBuffer definiert?

Autor: Nico W. (nico_w)
Datum:

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

: Bearbeitet durch User
Autor: m.n. (Gast)
Datum:

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

Autor: Alex K. (alexk99123)
Datum:

Bewertung
1 lesenswert
nicht 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.

Autor: Alex K. (alexk99123)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Joachim B. (jar)
Datum:

Bewertung
0 lesenswert
nicht 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
Autor: Alex K. (alexk99123)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Joachim B. (jar)
Datum:

Bewertung
0 lesenswert
nicht 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 :)

Autor: Lothar M. (lkmiller) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht 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...

Autor: Alex K. (alexk99123)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wieder was gelernt, dankeschön!

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.