Ich benötige eine UART Datenübertragung zwischen uC (STM32G031K6T6) und meinem Windows Rechner. Dazu habe ich ein cpp Programm geschrieben welches einen 16 Bit Wert aufteilt in ein höherwertiges und ein niederwertiges Byte. Diese werden beide über UART an den PC gesendet. Um am PC eine Struktur zu erkennen, werden zwischendurch bestimmte Zeichen übertragen.
Nur leider werden manche Zahlen nicht korrekt übermittelt, sondern an stelle dieser einfach der Wert 63 (sechs aufeinanderfolgende 1-Bits).
STM32 MDK Arm Code:
char input,output;
bool test = 0;
bool change = 0;
uint32_t run = 0;
uint16_t tx_value = 12340;
1
voidTask1(uint32_tT_ms){
2
3
output=NULL;
4
if(run==1)tx_value=0b0000010100000101;
5
//else if(run==2)tx_value='a';
6
/*else if(run<=26)
7
{
8
if(change==0){
9
tx_value = ((run << 8) | (run+1));
10
}
11
else tx_value = 'n';
12
run++;
13
} */
14
elseif(run==2){
15
tx_value='a';
16
}
17
elseif(run==3){
18
tx_value=(1872);
19
}
20
elseif(run==4){
21
tx_value='n';
22
}
23
elseif(run==5){
24
tx_value=(1234);
25
}
26
elseif(run==6){
27
tx_value='n';
28
}
29
elseif(run==7){
30
tx_value=(50);
31
}
32
elseif(run==8){
33
tx_value='n';
34
}
35
elseif(run==9){
36
tx_value=(255);
37
}
38
else{
39
tx_value='z';
40
run=0;
41
}
42
43
send16Bit(tx_value);
44
run++;
45
46
}
47
uint8_tlower_byte;
48
uint8_tupper_byte;
49
50
voidsend16Bit(uint16_tdata){
51
lower_byte=data&0xFF;
52
upper_byte=data>>8;//(data >> 8) & 0xFF;
53
sendByte(lower_byte);
54
sendByte(upper_byte);
55
}
56
57
voidsendByte(uint8_tdata){
58
while(!(USART1->ISR&(1<<7)));// warten, bis Übertragungsbuffers bereit ist
59
USART1->TDR=data;// Daten in Übertragungsbuffer schreiben
Die Ausgabe auf der Konsole sieht wie folgt aus (Bild im Anhang):
Der zweite Zahlenwert sollte wie aus dem cpp Programm zu entnehmen 1234 (highByte 4, lowByte 210) sein, jedoch ist dieser 1087 ((highByte 4, lowByte 63).
Ähnliches beim letzten Wert 255.
Etwas wie ein Protokoll duerft's schon sein. Auf einem Tisch, dh zwischen Board und PC sollte man ja schon keine Uebertragungsfehler auflesen. Kann aber dank EMV trotzdem geschehen. Und wie unterscheidest du dann low byte und high byte ?
Nur leider werden manche Zahlen nicht korrekt übermittelt
Da frage ich mich sofort ob denn die Baudrate ausreichend genau
stimmt. Wenn man im Controller einen internen Oszillator als
Zeitbasis verwendet kann das schon mal schiefgehen.
Ich schliesse dann immer ein Scope an, und schaue, was wirklich auf der Leitung versendet wird.
Dann braucht man nur im Sender oder nur im Empfänger schauen.
Etwas wie ein Protokoll duerft's schon sein. Auf einem Tisch, dh
zwischen Board und PC sollte man ja schon keine Uebertragungsfehler
auflesen. Kann aber dank EMV trotzdem geschehen. Und wie unterscheidest
du dann low byte und high byte ?
Übertragungsfehler habe ich bereits ausgeschlossen, der Fehler passiert nur bei manchen bestimmten Zahlenwerten. Ich habe schon >1000 Übertragungen ohne Fehler hintereinander, wenn ich eben nicht die paar besonderen Werte übertrage.
Ich schliesse dann immer ein Scope an, und schaue, was wirklich auf der
Leitung versendet wird.
Dann braucht man nur im Sender oder nur im Empfänger schauen.
Odd parity soll so sein? Ich lass die immer weg.
Odd parity hab ich dann aus Verzweiflung probiert, normal mach ichs auch ohne.
Zugang zu einem Osci habe ich aktuell leider nicht.
Kann es sein, dass Werte größer 127 schiefgehen - irgendwas mit
7-bit-Übertragung?
Hab es grad getestet und scheint so korrekt zu sein, die 8 Bit Werte 125, 126 und 127 werden korrekt übertragen. Ab 128 ist es lediglich 63.
Weiß jemand woran das liegen könnte?
Im Bild im Anhang ist meine uC UART Konfiguration zu sehen.
So sieht die Empfängerseite Port Config aus:
1
SerialPort port = new SerialPort("COM8", 115200, Parity.Odd, 8, StopBits.One);
Ab 128 ist es lediglich 63.
Weiß jemand woran das liegen könnte?
Da gibt es mehrere Ansätze: du kannst mangels eines Oszis/LA nur den einen probieren und kontrollieren, was der Compiler da tatsächlich ins TX-Register schreibt. Nicht, dass das ein trivialer singed/unsigned-Effekt ist.
Nimm mal für den Test einfache Bitmuster wie 0x55aa und 0xaa55 und 0xcc33 oder so...
[Low Byte & High-Byte]...
Diese werden beide über UART an den PC gesendet.
Sobald ein kleiner Übertragungsfehler passiert, wird der PC das nachfolgende High-Byte als Low-Byte (und umgekehrt) interpretieren. Du hast keine Chance, dass die beiden überhaupt noch einmal zueinander finden - außer durch einen weiteren Übertragungsfehler.
Von daher ist Dein Konzept unbrauchbar. Ich empfehle, die beiden zu übertragenen Bytes in einen gesicherten, eindeutigen Frame zu betten, z.B. durch ETX, STX und Checksum, wobei ETX und STX selbst innerhalb des Frames "escaped" werden.
Andere (einfachere) Möglichkeit: Du verteilst die 16 Bit auf 3 oder 4 Bytes (24 bit oder 32 bit), wobei Du die höherwertigen Bits als Index benutzt z.B. so:
1
01XXXXXX
2
100XXXXX
3
110XXXXX
Durch Plausibilitätsprüfungen lassen sich Übertragungsfehler zumindest erkennen, aber nicht ausmerzen.
Du brauchst ein richtiges Protokoll und nicht was selber ausgedachtes und ungeprüftes.
Daten müssen sich eindeutig von Steuercodes unterscheiden lassen, auch bei Synchronisationsverlust. Eine CRC zur Fehlererkennung ist heutzutage auch Standard.
Nimm mal für den Test einfache Bitmuster wie 0x55aa und 0xaa55 und
0xcc33 oder so...
Eventuell ist es auch sinnvoll, auf der Senderseite die Anzahl der Stoppbits auf 1.5 oder 2 zu erhöhen. Dann werden bei andauernder Befeuerung ohne irgendeine Pause die einzelnen Bytes auf Empfängerseite eher als solche erkannt.
Du brauchst ein richtiges Protokoll und nicht was selber ausgedachtes
und ungeprüftes.
Daten müssen sich eindeutig von Steuercodes unterscheiden lassen, auch
bei Synchronisationsverlust. Eine CRC zur Fehlererkennung ist heutzutage
auch Standard.
Bevor ich ein vernünftiges Protokoll implementiere, benötige ich erstmal eine funktionierende Schnittstelle.
Nicht, dass das ein trivialer
singed/unsigned-Effekt ist.
Scheint tatsächlich so zu sein.
Da ich kein Osci zur verfügung habe, habe ich einen Arduino Nano parallel an de Schnittstelle gehängt und mitprotokolliert.
Hier sind die Daten korrekt (siehe Bild im Anhang).
Hier hatte ich anfangs auch eigenartige Werte, teils mit minus. Durch Verwendung von unsigned jedoch nicht mehr.
Arduino Code:
1
#include<SoftwareSerial.h>
2
3
SoftwareSerialmySerial(2,3);// RX, TX
4
5
voidsetup(){
6
Serial.begin(115200);
7
mySerial.begin(115200);
8
}
9
10
voidloop(){
11
if(mySerial.available()){
12
unsignedinti=mySerial.read();
13
if(i=='a'||i=='n'||i=='z'){
14
Serial.println((char)i);
15
}else{
16
Serial.println(i);
17
}
18
}
19
}
Also liegt das Problem an der Empfängerseite, jedoch finde ich nicht an welcher Stelle sich der Fehler verbergen könnte.
Bevor ich ein vernünftiges Protokoll implementiere, benötige ich erstmal
eine funktionierende Schnittstelle.
Mit der Schnittstelle ist alles in Ordnung.
Der Takt + max Fehler bei 115Kbps beim STM32 ist unklar.
Da kein Protokoll vorhanden ist sondern nur ein undurchdachter Wust der fullspeed Daten raushaut, fliegt es Dir eben auseinander.
So danke für die Hilfe an alle.
Es lag nicht an falschen werten die übermittelt wurden, der einzige Fehler war die Verwendung der Funktion
1
rx_value=Convert.ToByte(port.ReadChar())
in meinem C# Programm.
Wenn ich
1
Convert.ToByte(ReadChar())
durch
1
Convert.ToByte(ReadByte())
ersetze funktionert es einwandfrei.
Anscheinend macht die Funktion Convert.ToByte etwas seltsames mit allen Char werten über 127.
Convert.ToByte ist trotz der verwendung von ReadByte noch notwendig, aber dann funktionierts.