Das sind die ganzen Variablen die genutzt werden um diesen zu
Realisieren.
Jedes empfangenes Zeichen kann ich mit der Funktion "uart_getc();"
auslesen.
Der Index muss ja jedes mal neu berechnet werden.
Aktuell kopiere ich die ganzen Empfangengen Zeichen so..
1
for(uint8_tx=0;x<UART_RX_BUFFER_SIZE;x++)
2
{
3
tmpBuff[x]=uart_getc();
4
}
Das dass sch**** ist, weiß ich selber.
Gibt es die Möglichkeit auf "UART_RxBuf[UART_RX_BUFFER_SIZE]" zu zu
greifen?
Vielen Dank.
Hallo,
die for Schleife ist der falsche Ansatz. Sobald ein Zeichen zum abholen
bereit liegt, holste das per uart_getc und schiebst das in deinen index
basierten tmpBuff. Ohne for, wenn man mit if.
Es muss doch eine Möglichkeit geben, auf den Hauptpuffer direkt drauf zu
zu greifen oder?
Das Ding ist, ich suche den ganzen Buffer nach einem String ab.
@Jan H. (janiiix3)
>Es muss doch eine Möglichkeit geben, auf den Hauptpuffer direkt drauf zu>zu greifen oder?
Sicher.
Die häßliche Version greift direkt auf die Variable bzw. das Array zu.
Die schöne schreibt eine passende Funktion innerhalb der Bibliothek.
>Das Ding ist, ich suche den ganzen Buffer nach einem String ab.
Das geht so einfach nicht, denn der Puffer ist ein logischer Ringpuffer.
D.h. dein String kann irgendwo in der Mitte des Arrays anfangen, über
das Ende hinausgehen und dann wieder am Anfang weiter gehen. Alle
normalen Stringfunktion kommen damit NICHT klar. Du mußt wohl oder übel
einen Teil des FIFOs in ein normales Array kopieren und dann darin
suchen. Das kann man natürlich performanter machen, als für jedes
Zeichen die Funktion uart_getc() aufzurufen. Wie das geht sieht man
hier.
https://www.mikrocontroller.net/articles/FIFO#FIFO_als_Bibliothek
Also wenns sehr Resourcenschonend sein muss, dann musst Du halt
massgeschneidert für Deine Aufgabe etwas entwickeln, welches die
empfangenen Zeichen gleich beim Empfang verarbeitet. Dies geht recht gut
mit einer kleinen State-Machine. Je nach dem sogar direkt im
Empfangsinterrupt die gewünschten Zeichen einlesen und die anderen
gleich verwerfen.
Falk B. schrieb:> @Jan H. (janiiix3)>>>Es muss doch eine Möglichkeit geben, auf den Hauptpuffer direkt drauf zu>>zu greifen oder?>> Sicher.>> Die häßliche Version greift direkt auf die Variable bzw. das Array zu.> Die schöne schreibt eine passende Funktion innerhalb der Bibliothek.
Wie würde das aussehen??
Falk B. schrieb:> Die häßliche Version greift direkt auf die Variable bzw. das Array zu.
Dazu muss "nur" das Schlüsselwort static entfernt und eine
korrespondierende /extern/-Deklaration in die zugehörige Headerdatei
eingefügt werden.
Das aber macht den Pfusch nicht besser.
Wenn man ein Protokoll wie z.B. das AT-Protokoll von
Modems/BT-Modulen/ESP8266 etc. interpretieren will, ist es sinnvoll, die
logische Struktur zur Hilfe zu nehmen - so ein Protokoll enthält oft
etwas, womit man "Telegramme", d.h. komplette Protokollblöcke
voneinander separieren kann.
Im Falle des AT-Protokolls ist's CR bzw. LF, da das Protokoll
zeilenorientiert ist.
Und damit holt man sich mit getc() solange Zeichen und trägt sie in
einen Zeilenpuffer ein, bis ein Zeilenendezeichen (CR bzw. LF)
auftritt bzw. eine vereinbarte maximale Zeilenlänge überschritten wird.
Diesen Puffer kann man dann nach irgendwelchen Strings durchsuchen.
Und das ganze macht man schön separat vom Interrupthandler und dessen
Empfangsfifo, weil ja durchaus weiterhin Daten eintrudeln könnten.
Ein Gefummel direkt am Empfangsfifo würde das Konzept des
Interrupthandlers irgendwie ziemlich ad absurdum führen.
Rufus Τ. F. schrieb:> Und damit holt man sich mit getc() solange Zeichen und trägt sie in> einen Zeilenpuffer ein, bis ein Zeilenendezeichen (CR bzw. LF)> auftritt bzw. eine vereinbarte maximale Zeilenlänge überschritten wird.>> Diesen Puffer kann man dann nach irgendwelchen Strings durchsuchen.>> Und das ganze macht man schön separat vom Interrupthandler und dessen> Empfangsfifo, weil ja durchaus weiterhin Daten eintrudeln könnten.>> Ein Gefummel direkt am Empfangsfifo würde das Konzept des> Interrupthandlers irgendwie ziemlich ad absurdum führen.
Du meinst so?
@Jan H. (janiiix3)
>Wieso kann ich durch das Schlüsselwort "static" nicht den Inhalt>auslesen?
Schon mal ein C-Buch konsultiert?
Wenn globale Variablen als static deklariert/definiert werden, sind sie
nur in der jeweiligen Datei sichtbar, nicht außerhalb.
Falk B. schrieb:> @Jan H. (janiiix3)>>>Wieso kann ich durch das Schlüsselwort "static" nicht den Inhalt>>auslesen?>> Schon mal ein C-Buch konsultiert?>> Wenn globale Variablen als static deklariert/definiert werden, sind sie> nur in der jeweiligen Datei sichtbar, nicht außerhalb.
Ja schon. Ich dachte static sorgt dafür das die Variable immer den
gleichen Speicherbereich hat?
Jan H. schrieb:> Ja schon. Ich dachte static sorgt dafür das die Variable immer den> gleichen Speicherbereich hat?
C-Buch also nicht gelesen. Nachholen.
Hallo,
die Lib bringt ein Bsp. mit, schau dir das mal genau an.
Du brauchst einen Buffer nochmal extra womit du vom Ringbuffer in den
eigenen Buffer einliest. Direkten Zugriff auf den Ringbuffer hast du
nicht und brauchst du auch nicht.
Ich habe meinen Code mal stark eingekürzt, weil da Sachen drin sind die
du nicht brauchst oder noch nicht brauchst, das Prinzip muss erstmal
verstanden werden. Dauert eben immer eine Weile. Ist normal. Ich rufe
aus dem Hauptprogramm immer nur handle_Serial() auf. Sobald die
Übertragung komplett empfangen wurde kommt ein true zurück und die
eigentliche Auswertung kann in dieser Funktion starten. Ohne
Fehlerbehandlung reicht auch ein Byte für c zum einlesen. Muss erstmal
kein int sein.
Die Byte kommen automatisch per USART Interrupt Nutzung in den
Ringbuffer.
getc fragt den nur ab ob ein neues Byte da ist, wenn ja kopierst du dir
das in deinen Buffer. Wenn die Übertragung komplett ist, kannst du
deinen Buffer behandeln. Meinetwegen auf Strings durchsuchen wie du
möchtest. Das machst du aber alles nur mit deinem Buffer. Der
eigentliche Ringbuffer bleibt verborgen. Defaultmäßig hat der Platz für
32 Bytes wenn mich nicht alles täuscht. Jeweils für senden und
empfangen.
Das enthaltene Bsp. der Lib musst du auch anschauen, weil das
funktioniert so wie es ist.
wie gesagt der Codeauszug kompiliert jetzt nicht, nur zur
Prinzipdarstellung meinerseits. Durch die if Abfrage(n) blockiert der
Code nicht und macht nur etwas wenn es wirklich etwas zu tun gibt. In
der Lib sind jedenfalls paar Gimmicks eingebaut, die ist wirklich gut.
1
boolread_Ringbuffer()
2
{
3
staticuint8_tindex=0;
4
uint8_tlength=sizeof(Nachricht)-1;
5
6
uint16_tc=uart0_getc();// nächstes Zeichen vom Ringbuffer holen
Veit D. schrieb:> uint8_t length = sizeof(Nachricht)-1;
Moin.
Vielen Dank, dass du dir die Zeit nimmst.
Was jedoch ist "Nachricht"? soll das etwa die 32 Bits vom Buffer sein?
Oder soll da die Länge, von dem drin stehen was ich erwarte? Also die
Länge meiner unterschiedlich langen Strings?
Rufus Τ. F. schrieb:> Ein Gefummel direkt am Empfangsfifo würde das Konzept des> Interrupthandlers irgendwie ziemlich ad absurdum führen.
Nein, nicht, wenn es richtig implementiert ist. Der Bereich zwischen
outptr und inptr gehört ja schliesslich dem Fifo-Reader, ihn anders zu
nutzen, als immer nur einzelne Chars in der Reihenfolge ihres Eingangs
daraus zu entnehmen, ändert am Konzept des Interrupthandlers absolut
garnix.
Es ändert allerdings etwas am Fifo-Konzept, es ist dann eben kein Fifo,
sondern nur noch ein allgemeiner Ringpuffer. Mit den entsprechenden
Zugriffsfunktionen ist es völlig legitim, einen wahlfreien Zugriff auf
dessen Pufferinhalt zu realisieren.
Das kann sehr gut für die Performance sein (das hängt von der Struktur
und der Nutzung der übermittelten Daten ab), spart aber leider keinen
Speicher, wie man vielleicht annehmen könnte, weil ja ein zusätzlicher
Buffer auf der Empfängerseite entfällt.
Nö, um genau die Größe des dort eingesparten Buffers muss nämlich der
Ringpuffer größer werden, um weiterhin im gleichen Umfang die Rolle
spielen zu können, für die er gedacht war.
In einem Projekt hab ich auch ein FIFO im UART drin. Die
Empfangs-Interruptroutone empfängt die Zeichen und schreibt sie in den
FIFO. Gleichzeitig prüft sie, ob ein Stringendezeichen empfangen wurde
('\r'). Das wird durch '\0' ersetzt und in den FIFO geschrieben.
Gleichzeitig wird ein Zähler (globale, volatile Variable) um 1 erhöht.
Damit weiß das Hauptprogramm immer, wieviele, vollständige Strings im
FIFO liegen und ausgelesen werden können. Das kann eine normale Funktion
machen. Wenn es etwas performanter sein soll, packt man die in die
FLeury-Lib und greift direkt und intelligent auf das FIFO-Array zu. Das
ist dann eine saubere Lösung.
Kloppt blockierende Kommunikationsroutinen in die Tonne. Sowas ist kaum
zu debuggen.
Falls man auf etwas wartet, sollte man eher mit einer Zustandsmaschine
Arbeiten und sich repetitives durchsuchen und kopieren sparen.
>> Nachricht ist der Name meiner Datenstruktur zum senden und empfangen.> Hier kannst du den Namen deines Empfangsarrays eintragen. Also deinen> Buffer.
Das heißt, du erwartest so viele bytes wie die Struktur groß ist? Dann
hast du immer eine feste Breite an Kommandos oder etc.?
Hallo,
@ Falk:
die uart Lib vom Peter schreibt auch den Null-Terminator in den
Ringbuffer, sodass man beim auslesen bei einem String auch nur bis zum
nächsten '\0' liest. Wollte das nur einmal nebenbei anmerken.
@ Jan:
muss wohl doch weiter ausholen. Seinen Buffer bzw. bei mir die
Datenstruktur, legt man nur so groß an wie man benötigt + 1 Byte
Reserve. Mach ich jedenfalls so. Man muss natürlich ein klares
Übertragungsprotokoll für sich vorher festlegen. Ob das nur mit fester
Länge ist, also die Anzahl der übertragenen Bytes, oder mit klarer Start
und Endekennung oder beides zusammen ist erstmal egal. Nur muss man
irgendwas haben zur Wiedererkennung. Sonst liest man ja nur wild mit und
weiß gar nicht was man eigentlich gerade eingelesen hat. Wie beim
Autorennen. Ohne Startnummern weiß niemand wer gerade führt, also wer
die nächste Runde eingeleutet hat und wer dann damit als erster über die
Linie fährt. Ohne Nummern würden nur irgendwelche Autos ihre Runden
drehen. Der Zuschauer und die Rennleitung wüßte nicht wer wer ist.
Genauso ginge es dir wenn du einfach nur einleist was gerade reinkommt.
Zurück zum Buffer und der Überprüfung der Bufferlänge. Das dient mit zum
Überlaufschutz. Damit nicht über den Buffer hinaus ins Nirwana,
geschrieben wird. Ansonsten landen die Daten unkontrolliert irgendwo im
SRAM was unvorhersehbare Folgen haben kann. Bufferüberlauf eben. Davon
liest man häufig wenn Sicherheitslücken von Programmen ausgenutzt wurden
in der PC Netzwerkwelt u.ä.
Auf meinem µC habe ich eine klare Start und Endekennung die ich
mitschicke, damit ich weiß wann was neues kommt und wann es zu Ende ist.
Im Normfall sollte das ausreichend sein. Wenn aber bei der Übertragung
was schief geht, kann ja sein durch Störungen oder was weiß ich, dann
müssen Fangnetze herhalten. Wie eben zum Bsp. die Längenüberprüfung.
Nochmal zum Unterschied. Ich lese also nicht solange ein bis mein Buffer
voll ist, sondern ich lese zwischen Start und Endekennung ein. Das der
Buffer nur so groß ist wie maximal benötigt sollte klar sein, alles
andere wäre Speicherverschwendung.
Wenn du nur Strings übertragen möchtest, dann reicht ein NL oder CR
erstmal aus für den Anfang. Dann weiß dein Einlesecode das Ende ist
erreicht und kann auswerten. Jedes Byte danach wäre dann wieder der
Anfang einer neuen Übertragung.
Der Ringbuffer hat default übrigens nicht 32 Bit sondern 32 Byte. :-)