Hallo!
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.
Bitte um Hilfe und herzlichen Dank im Voraus!
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 ?
Thomas F. schrieb:> 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.
Odd parity soll so sein? Ich lass die immer weg.
Thomas F. schrieb:> C# Consolen Anwendung zum Auswerten der Daten:
Bitte Anhang lesen, verstehen, verinnerlichen und danach handeln.
"Längerer Sourcecode" ist es wenn man dauernd scrollen muss um
alles zu sehen.
Purzel H. schrieb:> 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.
Thomas F. schrieb:> Übertragungsfehler habe ich bereits ausgeschlossen
Na und? Sicherlich sind bei grösseren Baudraten-Abweichungen nicht
alle Bytes gleichmässig von Übertragungsfehlern betroffen.
PittyJ schrieb:> 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.
Thomas F. schrieb:> tx_value = 'z';
Was erwartest du denn beim Empfänger wenn du einen Character
über eine Funktion sendest die 16 Bit überträgt?
Thomas F. schrieb:> void send16Bit(uint16_t data) {
Wäre nett bzw. zuvorkommend gewesen, Soll- und Istwerte direkt
gegenüberzustellen, damit die Angesprochenen sich das nicht erst
zusammensuchen müssen.
Kann es sein, dass Werte größer 127 schiefgehen - irgendwas mit
7-bit-Übertragung?
S. Landolt schrieb:> 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);
Thomas F. schrieb:> Zugang zu einem Osci habe ich aktuell leider nicht.
Irgendwo hatte ich schon wiederholt mal was zur Inbetriebnahme von
seriellen Schnittstellen geschrieben.
Habs wieder gefunden, dort war es:
* Beitrag "Re: Atmega Uart - Falsche Byte Übertragung"
* Beitrag "Re: WS2812b flackern / 3600 LED Matrix"
Fazit: kauf dir wenigstens einen 10€ Logic-Analyzer, dann bist du
wenigstens nicht mehr völlig blind.
Thomas F. schrieb:> Nur leider werden manche Zahlen nicht korrekt übermittelt, sondern an> stelle dieser einfach der Wert 63 (sechs aufeinanderfolgende 1-Bits).
Da wird wohl fälschlicherweise ein Startbit erkannt.
mitlesa schrieb:> Was erwartest du denn beim Empfänger wenn du einen Character> über eine Funktion sendest die 16 Bit überträgt?
Hast du den Code dieser Funktion mit ihren beiden *sendByte()* auch
schon angeschaut?
Thomas F. schrieb:> Bild_2023-02-08_125144747.png
Text bitte **nicht** als Bild posten.
Wenn die Formatierung wichtig ist, dann gibt es (wie in den Zeilen über
jeder Textbox hier beschrieben) die [pre] Tags:
https://www.mikrocontroller.net/articles/Formatierung_im_Forum
Thomas F. schrieb:> 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...
Thomas F. schrieb:> [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.
Lothar M. schrieb:> 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.
Peter D. schrieb:> 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.
Lothar M. schrieb:> 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.
Thomas F. schrieb:> 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.
Funktioniert es bei 9600bps?
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.
Danke für eure mithilfe!
Thomas F. schrieb:> etwas seltsames mit allen Char werten über 127.
Es kommt drauf an, wie char definiert ist. Es ist nicht völlig abwegig,
dass das ein signed 8-Bit-Wert ist:
https://www.google.com/search?q=char+signed+unsigned
BTW: Mein Tipp mit dem 10€ Logicanalyzer gilt weiterhin ;-)
Wäre in diesem Fall also ein simples Terminalprogramm ein geeigneter
Logik-Analysator gewesen.
Übrigens - fand ich lustig (s. 3. Bedeutung):
> Nicht, dass das ein trivialer singed/unsigned-Effekt ist.