Die Antwort hast du schon gekriegt.
Ich sags dir noch mit begründung:
> char* line = malloc(sizeof(char) * length);
Reserviert Speicher, den musst du irgendwann freigeben.
Dieses vorgehen ist auf PCs durchaus üblich, aber auf einem
Mikrocontroller würde ich den Speicher nicht dynamisch verwalten,
sondern statisch.
Also du empfängst 16 Bytes, dann verarbeitest du die, dann wider 16
Bytes empfange etc.
Dann weisst du, du brauchst 16 Bytes, und du brauchst nie mehr, den du
sowieso nicht hast.
16 Bytes ist als Beispiel anzusehen.
mfg Andreas
Ich kann hier Andreas B. nur zustimmen.
Besonders bei kleinen Controllern ist es bedeutend einfacher und
effizienter, auf dynamische Arrays zu verzichten.
Irgendwo vergisst du mal ein free() und schon hast du Speicherbereiche,
die nicht mehr benutzt werden können. Das kann auf einem PC natürlich
auch passieren, da sind die Auswirkungen aber im Allgemeinen nicht so
gravierend.
Wenn Du auf einen AVR (od. einen anderen µC) programmierst, dann findest
Du z.B. in der Codesammlung genug Beispiele, wie man das löst.
Du hast nur eine gewisse Größe vom Speicher zur Verfügung. Dein Code
berücksichtigt das aber nicht. Iwie. ist es auch seltsam, dass Du immer
nur 1 Byte zusätzlich allokierst. Verwende halt einen Ringspeicher und
Interrupts, der bei Empfang eines Zeichens beschrieben wird. Ist dieser
voll (Überschreitung) bzw. wurde die Null-Termierung erkannt, so wird
ein Flag gesetzt.
Ringspeicher http://www.mikrocontroller.net/articles/FIFO
UART http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/Der_UART
UART + Ringspeicher Beitrag "AVR-GCC: UART mit FIFO"
Ganz abgesehen davon, ob du den Speicher statisch oder dynamisch
reservierst: Der Speicherüberlauf ist garantiert, wenn aus irgendeinem
Grund (Fehler in der Gegenseite oder Übertragungsfehler) das Endebyte
('\0') nicht empfangen wird.
In 99% aller Fälle kann die empfangene Nachricht Byte für Byte, ohne
Zwischenspeicherung der gesamten Nachricht verarbeitet werden. Das
solltest du dann auch tun. Wenn das nicht geht, musst du den Lesevorgang
ab einer bestimmten Byteanzahl (die einen Fehlerfall signalisiert)
abbrechen.
Der empfangene String darf maximal 128 Bytes groß sein. Realloc fordert
zuerst den neuen Speicher an, kopiert die Daten und gibt erst dann den
alten frei. Wenn du also bei Zeichen 127 bist, hast du 127 Bytes belegt
und dann werden zusätzlich die 128 Bytes für das letzte Zeichen
reserviert. Das führt zu einem Speicherverbrauch von 255 Bytes.
Und dein Program braucht anderweitig sicher auch noch Speicher und schon
wird es knapp.
Rufus Τ. Firefly schrieb:> Modern Embedde Design schrieb:>> Wir sind nicht mehr in der Steinzeit.>> Ja. Mach das mal auf einem µC mit 1 kiB RAM.>> Nur zu.
Funktioniert hier wunderbar. :-P
Hallo,
um nochmal auf das Ram Problem zurückzukommen:
Wenn der Microcontroller einige male etwas über Uart empfangen hat (ca
50-200) mal stürzt er ab. Dies zeigt sich darin, dass er immer an einem
bestimmten Punkt sich aufhängt. Ich würde mich sehr darüber freuen wenn
sich jemand mal meinen Code ansehen könnte und mir vielleicht ein paar
Probleme nennen könnte. Bedanke mich schon mal im Foraus.
Gruß Jonas
Jonas E. schrieb:> Ich würde mich sehr darüber freuen wenn
... die Leute endlich mal kapieren würden das .rar ein denkbar
unglückliches Format ist wenn man etwas einer breiten Öffentlichkeit zur
Verfügung stellen möchte.
Zip kann inzwischen nahezu jedes OS sogar nativ erstellen und lesen...
Seh ich das richtig, das du im RX interrupt blockierend liest?
Damit müllst du dir im blödestem Fall den Stack voll, du sollstest
wenigstens das Interrupt-Flag löschen, oder noch besser, ohne Interrupt
in der Main pollen...
Außerdem ist es extrem unschön das deine Funktion keinen Fehlerwert
zurückliefert wenn es einen Overflow gab.
Auch die Prüfung > 0 ist etwas unsinnig. Du hast ja nun gerade per
interrupt mitbekommen, das wenigstens ein Zeichen vorliegt.
Wie meinst du das, dass ich blockieren lese?
Könntest du das im Code einmal zetieren?
Das Interrupt-Flag wird doch automatisch gelöscht, wenn ich die Daten
aus dem UART Register lese?
Mit dem > 0 habe ich nun verbessert.
Gruß Jonas
rufst du doch die UART_gets Funktion auf, welche wiederum 20x
1
uint8_tUART_getc(void)
2
3
{
4
5
while(!(UCSRA&(1<<RXC)))// warten bis Zeichen verfuegbar
6
7
;
8
9
returnUDR;// Zeichen aus UDR an Aufrufer zurueckgeben
10
11
}
aufruft!
Jonas E. schrieb:> Das Interrupt-Flag wird doch automatisch gelöscht, wenn ich die Daten> aus dem UART Register lese?
Das kann sein, solltest du aber im Datenblatt des Prozessor
verifizieren, trotz allem ist das sehr unschön im Interrupt irgendwelche
länglichen UART Strings zu empfangen, das ginge in der Hauptschleife
sehr viel einfacher und stressfreier.
Im blödestem Falle wird nämlich der Interrupt sofort wieder aufgerufen,
du hast der Hauptschleife aber gerade signalisiert das sie lesen kann
und bretzelst die Daten im nächstem Moment wieder über...
Jonas E. schrieb:> Du würdest also ohne RXC Interrupt arbeiten?
Das nicht unbedingt, aber wenn dann holt man im Interrupt nur das eine
Zeichen, das ihn ausgelöst hat, und wartet nicht auf weitere.
Gruss Reinhard
Reinhard Kern schrieb:> Das nicht unbedingt, aber wenn dann holt man im Interrupt nur das eine> Zeichen, das ihn ausgelöst hat, und wartet nicht auf weitere.
Wie kann ich denn mit dieser Vorgehensweise einen String vernünftig
empfangen? Hättest du einen Beispielcode, mit dem ich mein Vorgehen
realisieren kann?
Gruß Jonas
Jonas E. schrieb:> Wie kann ich denn mit dieser Vorgehensweise einen String vernünftig> empfangen?
Man richtet einen Empfangspuffer ein (fest) und hängt immer das neueste
Zeichen hinten an, bis der String komplett ist - z.B. weil ein CR
gekommen ist. Dann setzt man ein Flag fürs Hauptprogramm, dass eine neue
Message vorliegt.
Gruss Reinhard
>Man richtet einen Empfangspuffer ein (fest)
ich würde mal behaupten, man richtet ZWEI ein..
wenn man nämlich nur:
>Dann setzt man ein Flag fürs Hauptprogramm,
macht, hat man ja weiterhin das Problem, dass weiterhin Daten auflaufen,
während das Hauptprogramm mit den "alten" Daten irgendwas macht..
PS: "PC-Programmierung" ist der falsche Forums-Bereich, oder ???
Robert L. schrieb:> ich würde mal behaupten, man richtet ZWEI ein..
das kommt halt drauf an, ob weiter Daten kommen können, oder ob der
Gegner erst mal auf Antwort wartet. Aber erst mal so einfach wie
möglich, wir wollen Jonas ja nicht gleich ganz verschrecken.
Gruss Reinhard