Hallo,
über die UART-Schnittstelle lese ich Daten von einem SD-Karten Modul
zurück,
dazu benutze ich diese Funktion:
void GetSDString0(uint8_t* BUF) // Bytes empfangen
{
uint8_t NextChar;
NextChar = UART0_getc(); // Warte auf das nächste Byte
while(NextChar != '.') // empfange Zeichen bis "." kommt
{
*BUF++ = NextChar;
NextChar = UART0_getc();
}
}
In einer Header-Datei steht:
uint8_t RetSD[30]; // Bytes vom SD-Card Modul
Funktions-Aufruf:
GetSDString0(RetSD);
Leider gehen die empfangenen Bytes verloren, sobald die Funktion
verlassen wird. In RetSD steht dann nur Müll.
Meine Frage: wie kann ich auf die Array-Daten von RetSD zugreifen?
Gast
#6476858
Wolfgang Z. schrieb: > In einer Header-Datei steht: > uint8_t RetSD[30]; // Bytes vom SD-Card Modul > > Funktions-Aufruf: > GetSDString0(RetSD); Frage dich bitte, ob hier ein Pointer steht und wie das überschreiben des Arrays abgefangen wird. Bzw. der Füllgrad mitgeteilt wird. für mich fehlen da noch vom Type size_t Angaben über die maximale Größe und die Anzahl der geschriebenen Zeichen als Rückgabewert einer Funktion.
Gast
#6476861
Das
1 | |
kommt mir komisch vor. Damit man es versteht, hätte ich es wie folgt gemacht (Wert an Adresse BUF schreiben, Adresse BUF erhöhen)
1 | |
2 | |
Ansonsten die Startadresse als
1 | |
Übergeben. Evtl noch die Zeichen zählen, dass du nicht über die Arraygrenzen schreibst.
Hallo Patrick, Danke für die schnelle Antwort. Habe ich, wie von Dir vorgeschlagen umgesetzt, leider ohne Erfolg. Bin für jeden Tip dankbar!!!
Gast
#6476892
Patrick schrieb: > Evtl noch die Zeichen zählen, dass du nicht über die Arraygrenzen > schreibst. Und noch eine nul ans Ende hängen
Gast
#6476893
Ich kenne die Funktion UART0_getc() nicht. Ich gehe mal davon aus, dass die dafür gedacht ist, nach Empfang eines Bytes aufgerufen zu werden (im Empfangsinterrupt zB). Wenn du die Funktion einfach in der while-Schleife runterratterst und diese dann am Ende nur stumpf das Empfangsregister ausliest, steht da freilich nur Unfug und du rauschst auch mit absoluter Sicherheit über die Arraygrenzen hinweg.
>*BUF++ = NextChar; und >*BUF= NextChar; >BUF++; sind identisch. Würde mich nicht wundern, wenn der Compiler aus beidem das Gleiche macht. Bist Du Dir sicher, dass der Datentyp "uint8_t", praktisch für alles, der Richtige ist? Theoretisch sollte es zwar gehen, aber...
Gast
#6476920
UART0_getc() liest einfach nur den von der UART-Bibliothek mitgebrachten Ringpuffer aus und setzt den Zeiger ein Element weiter. Im Highbyte liefert die Funktion eine Fehlerinformation mit. Du musst also auswerten, ob du überhaupt schon was empfangen hast, bevor du UART0_getc() aufrufst. Das ufert in deiner Funktion zu einem Polling - Massaker aus, oder du musst die umschreiben, dass du sie über mehrere Zyklen verteilen kannst. Alles in allem schätze ich, dass du dich erstmal bisschen mit der Bibliothek auseinandersetzen solltest.
Nachtrag: Natürlich MUSS sichergestellt sein, dass weniger (gleich) als 30 Zeichen vor dem Punkt kommen. Sonst wird es spannend. Wie Patrick geschrieben hat: Was passiert, wenn kein Zeichen empfangen wurde, oder Du zu schnell abfragst (noch kein Zeichen da)? Ich kenne die verwendete Funktion auch nicht.
>In einer Header-Datei steht: > uint8_t RetSD[30]; // Bytes vom SD-Card Modul Wenn Du die Variablen-Definition in die Header-Datei schreibst, wird für jede Datei, die die Header-Datei einbindet, eine Variable gleichen Namens angelegt. Das erklärt den beobachteten Effekt. Die Variablen-Definition gehört in die c-Datei und die Deklaration mit einem vorangestellten "extern" in die Header-Datei. Dann sollte es funktionieren.
Gast
#6476933
> In einer Header-Datei steht: > uint8_t RetSD[30]; // Bytes vom SD-Card Modul Ich vermute, du hast mehrere RetSD. In die .h-Datei gehört nur die Deklaration (mit einem "extern" davor), in einer .c-Datei dann die Definition so wie oben ohne "extern".
Danke für die zahlreichen Rückmeldungen dazu.
Habe jetzt folgende Änderungen vorgenommen:
1. alle Variablen Definitionen stehen jetzt in der C-Datei
2. in der h-Datei steht: extern void GetSDString0(uint8_t* BUF);
Leider ohne Erfolg!
Hier die Funktion zum Empfang von Zeichen (Bytes):
uint8_t UART0_getc(void) // Byte empfangen
{
while (!(UCSR0A & (1<<RXC0))); // warten bis Byte verfügbar
return UDR0; // Byte aus UDR zurückgegeben
}
Zur Kontrolle gebe ich den Array-Inhalt RetSD so über HTerm aus:
for(i = 1; i < 25; i++)
{
UART0_putc(RetSD[i]);
i++;
}
Vielleicht liegt der Fehler in der Ausgabe der Bytes?
void UART0_putc(uint8_t xB) // Byte senden
{
while (!(UCSR0A & (1<<UDRE0))); // warten bis Senden möglich
UDR0 = xB; // sende Byte
}
Gast
#6477095
Es könnte auch ganz trivial an einem Stack-Überlauf liegen. Ausgelöst durch zu viele verschachtelte Funktionsaufrufe bzw. Funktionen mit zu vielen lokalen Daten.
Hallo Stefan, okay, aber wie kann ich das feststellen?
Gast
#6477190
Wolfgang Z. schrieb: > okay, aber wie kann ich das feststellen? Es gibt zwei Zeiger, die sich aufeinander zu bewegen. Einer vom Stack und einer vom Heap. Wenn sie sich in der Mitte treffen, ist der Speicher voll. Dort erklärt das jemand im Detail: https://rn-wissen.de/wiki/index.php/Speicherverbrauch_bestimmen_mit_avr-gcc
1 | |
2 | |
Das Ergebnis könntest du innerhalb jeder Prozedur ausgeben.
Wolfgang Z. schrieb: > uint8_t UART0_getc(void) // Byte empfangen > { > while (!(UCSR0A & (1<<RXC0))); // warten bis Byte verfügbar return > UDR0; // Byte aus UDR zurückgegeben > } Ist das richtig, dass "return UDR0" im Kommentar steht, oder ist das ein Copy&Paste-Fehler? Das muss so aussehen:
1 | |
2 | |
3 | |
4 | |
5 | |
Hast Du hier auch alle Warnungen, die der Compiler ausgibt, hier mitgeteilt?
Gast
#6477201
Frank M. schrieb: > Ist das richtig, dass "return UDR0" im Kommentar steht, oder ist das ein > Copy&Paste-Fehler? Der Kommentar stammt wohl von einem anderen µC Modell das nur einen UART hat.
Stefan ⛄ F. schrieb: > Der Kommentar stammt wohl von einem anderen µC Modell das nur einen UART > hat. Häh? die UART0_getc-Funktion ist definiert als uint8_t, da hat sie auch gefälligst was zurückzuliefern. Tut sie aber nicht, da das return-Statement auskommentiert ist. Schließlich wird auch der Rückgabewert benutzt:
1 | |
Gast
#6477214
Frank M. schrieb: > die UART0_getc-Funktion ist definiert als uint8_t, da hat sie auch > gefälligst was zurückzuliefern. Tut sie aber nicht Da steht doch "return UDR0", nicht auskommentiert: Wolfgang Z. schrieb: > uint8_t UART0_getc(void) // Byte empfangen > { > while (!(UCSR0A & (1<<RXC0))); // warten bis Byte verfügbar > return UDR0; // Byte aus UDR zurückgegeben > } In deinem Zitat fehlt jedoch ein Zeilenumbruch. Vielleicht ein Darstellungsproblem im Web Browser?
Hallo Frank,
aber das ist nichts auskommentiert:
uint8_t UART0_getc(void) // Zeichen empfangen
{
while (!(UCSR0A & (1<<RXC0))); // warten bis Zeichen verfügbar
return UDR0; // Zeichen aus UDR0 zurückgegeben
}
Der Inhalt von UDR0 wird zurückgeliefert!
Der ATmega328 hat zwar nur einen UART, aber trotzdem heißt das Register
UDRn.
Hallo Stefan, jetzt zu dem Speicherverbrauch. Ich habe die Funktion eingesetzt und bekomme als Ergebnis eine 0. Also kein Speicher-Überlauf?
Stefan ⛄ F. schrieb: > In deinem Zitat fehlt jedoch ein Zeilenumbruch. Als Moderator kann ich Beiträge editieren. Da ist kein Zeilenumbruch drin. Aber so viele Leerzeichen, dass es in einer nicht-proportionalen Schrift so aussieht, als ob das Return-Statement darunter stände. Steht es aber nicht. Deshalb fragte ich den TO, ob das ein Copy&Paste-Fehler sei. Besser ist auch, C-Code in
1 | |
einzubetten.
Wolfgang Z. schrieb: > Der Inhalt von UDR0 wird zurückgeliefert! Das sehe ich anders, siehe Screenshot. Und auch im Editor-Fenster sehe ich keinen Zeilenumbruch. Bitte verwende
1 | |
um C-Code hier zu veröffentlichen.
Wolfgang Z. schrieb: > Also kein Speicher-Überlauf? Zeig mal dein ganzes Programm. Normalerweise läuft der Speicher alleine durch Funktionsverschachtelungen nicht so schnell über. Heap wirst du auch keinen benutzen, und die 30 Byte für den Puffer sind unkritisch. Was aber schnell blöd werden kann, ist sind Daten, bei denen der '.' erst nach mehr als 30 Zeichen erkannt wird. Deine Empfangsroutine schreibt ja fröhlich immer weiter in den Puffer, ohne Größenbegrenzung. Oliver
Hallo Frank, vielen Dank für den Hinweis. Da ich nur selten Fragen im Forum stelle, war mir das nicht bewusst, sorry!
Hallo Oliver, das mit der Zeichen-Menge habe ich vorher geprüft. Es werden nur Datei-Namen mit .txt zurückgeliefert und für mich sind nur die Namen ohne .txt relevant. Die max. Dateinamen-Länge beträgt 18 Zeichen, somit ist ein Array-Überlauf nicht möglich. Wolfgang
Wolfgang Z. schrieb: > Die max. Dateinamen-Länge beträgt 18 Zeichen, somit ist ein > Array-Überlauf nicht möglich. Famous last words ;) Oliver
Wolfgang Z. schrieb: > Die max. Dateinamen-Länge beträgt 18 Zeichen, somit ist ein > Array-Überlauf nicht möglich. Warum benutzt Du dann einen Buffer mit 30 Zeichen? Aus Angst?
Gast
#6477303
Dachte immer SD Karten haben ein SPI interface ;-)
Gast
#6477310
Wolfgang Z. schrieb: > In RetSD steht dann nur Müll. Warum uint8_t, wenn es sich doch um Text handelt? Also char. Oder? Desweiteren vermisse ich immer noch die nul am Stringende. So gibt es keine Information im Programm wie lang der String ist. Neben anderem Ungemach, wundert mich nicht, dass da Mist ausgegeben wird, wenn kein Programmteil weiß, wie lang/groß irgendwas ist. Wolfgang Z. schrieb: > somit ist ein > Array-Überlauf nicht möglich. Is klar....
Gast
#6477317
Vielleicht versuchst du es mal, den Empfangsinterrupt zu nutzen? Oder hast du den schon irgendwo drin und der schießt dir quer? Der würde vom reinen Code dann ca so aussehen, zeichenzaehler muss natürlich mit 0 initialisiert werden:
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
Der Code der ISR wäre dann
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
Alles bisschen unsauber, aber zum testen sollte es tun.
Patrick schrieb: > ... maximal umständlichen Code ... Was genau ist denn jetzt das Problem im Code des TO, das du durch deinen Code löst? Oliver
Gast
#6477334
Wolfgang Z. schrieb: > Ich habe die Funktion eingesetzt und bekomme als Ergebnis eine 0. Das ist aber ein seltsamer Zufall. Bis du sicher, dass du die richtige Zahl ausgibst? 0 ist jedenfalls zu wenig. Damit kannst du keine einzige Funktion mehr aufrufen, denn Funktionen brauchen Stack.
Ja, war am Anfang so. Habe ich jetzt auf 20 reduziert.
Hallo Uwe, das ist keine normale SD-Karten Ansteuerung. Ich benutze ein Modul der Firma Artekit (Italien) und das hat eine UART-Schnittstelle.
Hallo, das Problem ist, dass das SD-Modul einen Mix aus ASCII und Bytes zurück sendet. Daher der Typ uint8_t, also kein normaler String, somit kann ich das nul-Zeichen auch nicht anfügen.
Hallo an alle, dank der vielen sehr nützlichen Hinweise, macht das Programm jetzt genau das, was es machen sollte. Vielen, vielen Dank für Eure Unterstützung! Gruß Wolfgang
Und was war jetzt das Problem? Oliver
Hallo Oliver, die Lösung war eine Kombi aus verschiedenen Fehlern. Dieser Hinweis von foobar foobar schrieb: > Ich vermute, du hast mehrere RetSD. > > In die .h-Datei gehört nur die Deklaration (mit einem "extern" davor), > in einer .c-Datei dann die Definition so wie oben ohne "extern". Und der Tip von Dirk B. Und einen Fehler den ich selbst eingebaut und zuerst nicht gefunden habe.
Antwort schreiben
Bitte melde dich an, um einen Beitrag zu schreiben.
