Hallo,
ich nutze den STM32. In den Beispielen habe ich keine funktion gefunden,
mehrere Bytes oder strings zu empfangen. Senden geht wunderbar.
Ich wuerde naemlich gerne ein byte[] array vom pc welcher aufgebaut ist
wie folgt an dem stm32 empfangen und in variablen schreiben.
myPCbyte[40]
int32 myint1 = 12345678;
...
..
int16 myint2 = 128;
uint16 myint3 = 244;
...
auf dem STM32 benutze ich momentan folgenden code zum empfangen
einzelner bytes (uint16_t)
Ich habe keinen STM32-spezifischen Code, aber im Prinzip könte das so
funktionieren wie bei mir mit MSP430-Code.
In der Interrupt-Empfangsroutine wird nach dem Empfang eines Zeichens
über den UART ein Timeout gesetzt, innerhalb dem ein weiteres Zeichen
eempfangen werden kann, und danach wieder, ...
Ist der Timeout ohne den Empfangs eines neuen Zeichens abgelaufen, löst
das einen Timer-Interrupt aus und der empfangene String wird
zurückgegeben und ausgewertet.
interrupt (UART0RX_VECTOR) usart0_rx(void) // Interrupt_Empfangsroutine
{
...
if (uart0_RX_anz < RX0_BUFFER_SIZE) // Um Pufferüberlauf zu vermeiden
{
UART0_RX_Buffer[uart0_RX_anz] = RX0IN_CHAR; // Empfangenes
Zeichen in Buffer abspeichern
uart0_RX_anz++;
}
// Timeout für Zeichenempfang über UART setzen
set_UART0_rcv_Timeout(24576); // Einheit für "l_timeout" sind
Taktzyklen (0<=l_timeout < 32767), f=32768 Hz
}
Stell den Code für den STM32 doch ein, wenn er funktioniert.
Ne sorry dein Code macht was ganz anderes aber trotzdem vielen dank!!
bei mir gehts darum die Funktion
ReceivedData = USART_ReceiveData(USART2);
so umzubauen das es nicht nur ein byte empfaengt sondern mehrere.
Gruss
Karl
Wie schon gesagt : am besten mit eine ISR die jeden empfangen Zeichen
abspeichert in eine Array. Beim empfangen von eine \r wird dan in main
diese String weiter verarbeitet.
nunja...der Code ist schon nicht ganz unpassend.
Dort wird in einem Interrupt ein Puffer befüllt...das benötigst du auch.
Definitionsgemäss werden bei UART immer 8 Datenbits übertragen. Wie du
diese dann interpretierst, bleibt Dir überlassen.
Nehmen wir an, du willst eine Int16 Zahl übertragen, dann musst du diese
Zahl vorm Senden in zwei 8bit Werte aufsplitten.
z.b. mit
int16 send = 0x4321;
unsigned char hi_byte = send >> 8; //enthält dann 0x43
unsigned char lo_byte = (unisgned char)(send & 0x00ff); //enthält 0x21
diese beiden Bytes sendest du nun mit deiner Sende-Routine an den
Empfänger.
Der Empfänger liest die beiden Werte ein, und hat nun zwei Byte
Variablen mit deinem hi_byte und deinem lo_byte Werten, und bastelt
daraus wieder eine int16 Variable
int16 receive = (hi_byte << 8) | lo_byte;
Danke jungs!
Ja, man kann das mit Interrupts machen aber ich brauch den USART2
handler eigentlich nicht weil die abfrage eh in meiner loop lauft und
der DR beim empfang geschrieben wird. (oder irre ich mich da?)
Stellt euch einfach eine UART-Loopback-Funktion vor.
Ich sende per HTERM bspw. : 00 AA FF EE 0B
und das gleiche soll wieder zurueck kommen.
so wie ich das gemacht habe klappt das nicht:
was hat der DMA nun damit zu tun(Geschwindigkeit ist hier ja eher nicht
das Problem) und was hat die echo Funktion nun mit der ursprünglichen
Zahlenfrage zu tun???
>while(USART_GetFlagStatus(USART2, USART_FLAG_RXNE) == RESET);>{}
Zufälligerweise nicht falsch, aber der ";" gehört da nicht hin...
> RXBUFF[j++] = USART_ReceiveData(USART2);
Hier wird der Index inkrementiert...
> if (j >= buflgth)
Soll wahrsch eher j < buflgth heissen
> j = 0;>>> //Bytes Zuruecksenden ( RXBUFF[248] )> while ( j>= buflgth)
hier auch.
Wenn Du den KOMPLETTEN, bis dahin empfangenen String
ausgeben willst, solltest Du Dir eine weitere
Indexvariable gönnen.
Eine for-Schleife hätte auch was für sich.
> {> USART_SendData(USART2, RXBUFF[j]);
....und hier greifst Du in's Leere
> j++;
...und vielleicht noch mehr...
Falls die Code-Formatierung nicht durch die Forensoftware verursacht
wird, solltest Du da dringend nachbessern.
Im Grunde ist Dein Code nicht völlig falsch, aber man kann schwer in
Worte fassen, was zu ändern wäre. Daher hier ein konkreter Vorschlag,
wie es funktionieren könnte. Der Punkt ist, dass zu jeder Zeit beide
UARTs überwacht werden müssen, um einen UART-Overrun zu verhindern.
Damit dürfen im Rahmen der Puffergröße die UARTs auch mit
unterschiedlichen Baudraten arbeiten.
Hi Eddy,
ich wuerde gerne deine Funktion so umschreiben, das sie genau 50bytes in
den buffer empfaengt und sich dann beendet.
Was muss ich dazu tun ?
irgendwie rast bei mir die schleife durch bevor ich was senden konnte.
MfG
Sven
Ich hab das jetzt per DMA und Interrupt gemacht ;)
War bissl arbeit, weil ich nicht gewusst hatte das der DMA für jeden
Transferkanal neu erzeugt werden musste. (Danke an dieser stelle an das
Errata sheet von ST!)
Ich mach das jetzt noch bissl schön und dan poste ich den code.
Sven S. schrieb:> ich wuerde gerne deine Funktion so umschreiben, das sie genau 50bytes in> den buffer empfaengt und sich dann beendet.
Das geht nicht.
Die UART kann nicht wissen, welches das erste und welches das 50-te Byte
ist. Die UART schmeißt alle Bytes in die FIFO.
Erst durch ein Protokoll kannst Du sicher sein, daß die Bytes die
richtige Position haben.
Z.B. ist es ein Text, dann kannst Du ihn mit CR,LF abschließen.
Deine Parser weiß also, daß alle Bytes nach CR,LF zum nächsten Paket
gehören.
Ein Byte nach CR,LF ist also immer das erste Byte eines Pakets.
Für Binärdaten braucht man ein anderes Protokoll. Z.B. durch ein
Escape-Zeichen (z.B. 0xA5) werden Protokoll und Daten unterschieden.
Ohne Protokoll reicht es, wenn einmal ein Byte gestört ist oder eine
Station ein Reset macht und Du bist für alle Zeit asynchron und
empfängst nur Mumpitz.
Mit Protokoll ist nur das fehlerhafte Paket gestört, das nächste ist
wieder synchron.
Peter
Ja, genau bspw. mit einem End-Identifier etc.
Ich habe aber bereits eine andere Lösung gefunden. Denn wenn bekannt
ist, das bspw. dein Datenframe auf den du wartest 50bytes lang ist, dann
kann man sich da mit einer einfachen Schleife helfen:
Der Code ist getestet und funktioniert
Sven S. schrieb:> Denn wenn bekannt> ist, das bspw. dein Datenframe auf den du wartest 50bytes lang ist, dann> kann man sich da mit einer einfachen Schleife helfen:
Aber nur äußerst notbehelfen.
Das geht nur solange gut, wie beide Gerät immer zugleich eingeschaltet
werden, nie resettet werden und nie jemand über das Kabel stolpert und
es wieder reinsteckt.
Schon wenn ein Gerät mal später angeschaltet wird, das andere aber
gerade 1 .. 49 Byte rausgerotzt hat, ists Essig.
Oder der Empfänger ist früher eingeschaltet und das Power-On des Senders
erzeugt ne Startflanke und wird damit als 1.Byte gewertet.
Sowas ist eine reine Edelbastlerlösung nur für Dich zuhause.
In der Praxis haut Dir jeder sowas um die Ohren.
Peter
Peter Dannegger schrieb:> Sowas ist eine reine Edelbastlerlösung nur für Dich zuhause.> In der Praxis haut Dir jeder sowas um die Ohren.
Ganz genau.
Ganz abgesehen davon, das das hier
1
intcnt=0;
2
while(cnt<=50-1)//zu erwartende bytes -1
3
{
4
...
5
cnt++;
6
...
7
}
maximalkryptisch für
1
intcnt=0;
2
3
for(cnt=0;cnt<50;cnt++)
4
{
5
...
6
}
ist.
Wenn etwas eine Zählschleife ist, dann realisiere es auch als
Zählschleife. Dann muss sich ein späterer Leser des Codes nicht die
Frage stellen "Was zum Kuckuck hatte er da eigentlich vor? Warum hat er
nicht einfach eine for-Schleife benutzt? Wäre das etwa zu simpel
gewesen? Da steckt doch was dahinter - nur was?"
Ja du hast recht - aber solange es eine definierte Übertragung zu einem
definerten Zustand ist --- lass ich mir nicht sagen das es eine
Edelbastlerlösung ist!
Hier in diesem Falle ist der Empfangsablauf folgendermaßen:
1. Controller geht in Empfangsmodus und wartet auf exakt 50 bytes
2. Client sendet nach erhalt der Information, dass die Gegenstelle im
Empfangsmodus ist, die Daten
3. Controller empfängt und speichert die Daten.
4. Prüft ob die ersten 2 bytes 47-11 ergeben und die letzen ebenfalls
-Falls ja ist das Datentelegramm i.O.
5. Ende der Übermittlung
man könnte jedes Datenpaar mit einer crc prüfsumme versehen. das wäre
eine Maßnahme um die Datensicherheit zu erhöhen.
Edit: Karl, das ist der IP-Schutz :) ... kein umständlich
ausgedrückter code.
Und wenn du schon ... dann bitte so:
Sven S. schrieb:> 4. Prüft ob die ersten 2 bytes 47-11 ergeben und die letzen ebenfalls> -Falls ja ist das Datentelegramm i.O.
Und genau hier hast du dein Problem.
Sobald du aus irgendeinem Grund unsychron wirst, hast du keine Garantie
mehr, dass das was du (als Empfänger) als die ersten beiden Bytes
ansiehst auch aus Sicht des Senders die ersten beiden Bytes waren.
Ab da geht, wenn die Übertragung unsynchron wird, alles den Bach runter.
Und was noch viel schlimmer ist: es fängt sich auch nicht mehr von
alleine. Die Asynchronität bleibt bis zum Strom-abdrehen bestehen.
Bei einem guten Protokoll kannst du den RS232 Stecker ziehen und wieder
anstecken. Beliebig oft. Zu beliebigen Zeiten.
Die beiden Partner mögen ein wenig 'husten' und ein paar Üertragungen
als ungültig im Log-File vermerken aber danach regelt das Protokoll
wieder alles und die beiden arbeiten korrekt weiter als sie nie
irgendwas geschehen.
Karl,
wenn ich 50 bytes empfangen habe ... egal wie und ich validieren kann ob
das Telegramm plausibel ist oder nicht, dann ist doch der Fisch wieder
ins Wasser geworfen. In dem Fall, wie soll da die asynchronität
stattfinden?
Es wird ja byte für byte empfangen , die empfangsschleife läuft ja nicht
weiter wenn nichts gesendet wird sondern wartet jedes byte ab.
Ich will dir nicht wiedersprechen da du vollkommen recht hast! Nichts
geht über ein gutes Protokoll. Ich selbst komme aus Socketprogrammierung
und TCP/UDP Ecke. Ich weiß das zu schätzen. Das wird die leider beim
Controller nicht geschenkt! Gute Transmissionsprotokolle sind schwer zu
finden und nur anstrengend nachzutippen.
Für die Übermittlung von den paar Daten war es aus meiner sicht nicht
nötig, da es keine Sicherheitskritische Anwendung ist.
Aber wenn du lust hast können wir gerne ein Github Projekt eröffnen und
wir schreiben den Benutzern das schönste Protokoll der Welt ;)
ODER man benutzt einfach CAN oder TCP/IP und wir vergraben die RS232!
Sven S. schrieb:> Karl,>> wenn ich 50 bytes empfangen habe ... egal wie und ich validieren kann ob> das Telegramm plausibel ist oder nicht, dann ist doch der Fisch wieder> ins Wasser geworfen.
Der springende Punkt ist, dass ab dem ersten Fehler ALLE weiteren
Telegramme nicht mehr plausibel werden. ALLE!
Die beiden sind dann zeitversetzt.
Der Sender sendet (am Beispiel mit einer Telegramgröße von 8)
Frame Frame
+-------------+ +-------------+ +--- Frame
| | | | |
0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 ...
und der Empfänger versteht
+----- Frame --+ +-- Frame -----+ +---
| | | | |
2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 ...
und diesen Versatz wirst du auch nie wieder los. Der Sender sendet
jeweils 8 Byte, der Empfänger wartet jeweils auf 8 Bytes. Aber er fängt
an einer anderen Stelle im Datenstrom mit dem zählen bis 8 an!
Und alles nur, weil der Empfänger die ersten beiden Bytes nicht richtig
mitbekommen hat (aus welchem Grund auch immer. Kabel abgefallen, zu spät
eingeschaltet, Funkstörung, im Reset ein klein wenig zu lange gebraucht,
...)
Sven S. schrieb:> und TCP/UDP Ecke. Ich weiß das zu schätzen. Das wird die leider beim> Controller nicht geschenkt! Gute Transmissionsprotokolle sind schwer zu> finden und nur anstrengend nachzutippen.
Übertreib nicht. So schwer ist das auch wieder nicht.
Wenn man sich (zur Not mittels Escaping) 2 definierte Bytewerte
freischaufelt, hat man schon mal den ersten Schritt.
Sven S. schrieb:> Ok, so meinst du das.>> In diesem Falle werden bei mir aber die Daten solange wiederholt> gesendet, bis es richtig ankommt.
Du hast es immer noch nicht.
Die werden NIE mehr richtig ankommen! Den Versatz wirst du bis zum St.
Nimmerleinstag nicht mehr los. Das renkt sich NIE WIEDER von selber ein.
Karl Heinz Buchegger schrieb:> Die werden NIE mehr richtig ankommen! Den Versatz wirst du bis zum St.> Nimmerleinstag nicht mehr los. Das renkt sich NIE WIEDER von selber ein.
Doch das werden Sie da ja die Gegenstelle weiß wann empfangen wurde und
wann gesendet wurde und wieviel gesenet wurde und ob die daten richtig
angekommen sind und dem entsprechend wir der buffer auf der
empfängerseite wieder geleert.
Und die Empfängerseite wartet und wartet bis die 50 da sind und wenn ein
versatz da ist, dann stimmen die daten nicht und dann geht die show von
neuem los!
Sven S. schrieb:> Karl Heinz Buchegger schrieb:>> Die werden NIE mehr richtig ankommen! Den Versatz wirst du bis zum St.>> Nimmerleinstag nicht mehr los. Das renkt sich NIE WIEDER von selber ein.>> Doch das werden Sie da ja die Gegenstelle weiß wann empfangen wurde und> wann gesendet wurde und wieviel gesenet wurde und ob die daten richtig> angekommen sind und dem entsprechend wir der buffer auf der> empfängerseite wieder geleert.>> Und die Empfängerseite wartet und wartet bis die 50 da sind und wenn ein> versatz da ist, dann stimmen die daten nicht und dann geht die show von> neuem los!
Und die nächsten 50 Bytes sind wieder falsch.
Und die darauf folgenden 50 Bytes sind wieder falsch.
ad infinitum.
Aber was solls:
Wenn du meinst. Ist ja nicht mein Bier.
Der Rest der Welt verwendet ein dezidiertes Startbyte und/oder ein
dezidiertes Endbyte und synchronisiert jedes Telegramm darauf erneut
ein.