Hi! Ich bin gerade dabei ata routinen für meinen mp3 player zu schreiben. Nun ist ein sektor ja 512 byte gross, auslesen tue ich jedoch immer nur 32 byte, da ich einen atmega8515(512byte ram) benutze aber kein externes sram verwenden möchte. Also dann werde ich eine Funktion haben, die so aussieht wie etwa: void ReadSector(u32 LBAsect, u16 sectpos) { char buffer[32]; . . . return buffer; } Kann ich denn die ganzen 32 bytes so über return zurück "senden", oder ist return eher für bit / byte werte gedach und ich sollte eher etwas anderes verwenden, wie zum beispiel eine globale variabe(falls das überhaupt geht)? Falls das mit return so gehen würde könnte ich das dan ja etwa so aufrufen: buffer = ReadSector(200, 64); und dann müsste rein theoretisch die 32 bytes dann in dem buffer landen? Mit der Frage seid ihr sicherlich unterfordert-naja sobald ich das Buch finde das mir Rufus empfohlen hat werde ich euch nicht mehr mit so Anfängerfragen nerven..:) mfg Nik
>void ReadSector(u32 LBAsect, u16 sectpos) >{ > char buffer[32]; > return buffer; >} Das ist nicht möglich, da der Speicher auf den buffer[] Zeigt nach dem Verlassen der Funktion 'ReadSector' nicht mehr gültig ist (lokale Variablen existieren auf dem Stack). Am einfachsten sollte es sein, wenn Du buffer[] global anlegst.
oops ich wollte die variabel eigentlich nicht zweimal buffer nennen void ReadSector(u32 LBAsect, u16 sectpos) { char buffer[32]; . . . return buffer; } daten = ReadSector(200, 64); so etwa meinte ich das..dass mit return das ganze zurückgegeben wird und dann nacher in den buffer daten kommt. Aber dadurch verliere ich wohl sowiso nur unnötig ram. Also dann doch wohl besser eine globale variabel. Ich hab schon eine Datei wo ich einige Progmem Strings drinn habe, kann ich dort auch eifach normale strings definieren, oder braucht es eine besondere schreibweise? Ich würde jetzt einfach ausserhalb von einer Funktion unsigned char buffer[32]; schreiben-wäre das so korrekt?
>>void ReadSector(u32 LBAsect, u16 sectpos) >>{ >> char buffer[32]; >> return buffer; >>} > >Das ist nicht möglich, da der Speicher auf den buffer[] Zeigt 'buffer' ist eine loakle Variable, und wird auf dem Stack reserviert, sobald die Funktion aufgerufen wird! Nach dem Verlassen der Funktion wird automatisch alles, was diese Funktion (inkl. Rücksprungadresse des Aufrufes) vom Stack weggeputzt! Du erhälst zwar die Adresse, an der vor wenigen Cycles noch Speicher für 'buffer' reserviert war, aber da kann schon längst etwas völlig anderes stehen... Manipulierst Du jetzt noch schön die Inhalte, die die an dieser Adresse gespeichert wurden, steigt die Wahrscheinlichkeit, daß Dein Programm im Nirvana landet immens...
Das geht in die Hose. void ReadSector(u32 LBAsect, u16 sectpos) { char buffer[32]; . . . return buffer; } - ganz abgesehen davon, daß der Returntyp hier nicht "void", sondern char* heissen müsste. Es geht deshalb in die Hose, weil der zurückgegebene Pointer auf nicht mehr belegten Speicher verweist. "buffer" ist eine automatische Variable, die auf dem Stack angelegt wird und nur innerhalb der Funktion gültig ist. Beim Verlassen der Funktion wird der Stack abgeräumt und der zurückgegebene Pointer weist so ins "leere". Arrays können nicht einfach einander zugewiesen werden: char Array1[20]; char Array2[20]; Array1 = Array2; // das geht nicht Als Rückgabewert einer Funktion können nur Dinge verwendet werden, die auch etwas anderem zugewiesen werden können (RValue). Von den Basisdatentypen (int, char etc.) abgesehen ist das nur noch mit Strukturen möglich. typedef struct { char Text[20]; } ineffizient; ineffizient Variable1; ineffizient Variable2; Variable1 = Variable2; // in ANSI-C (C89) zulässig So wäre eine Möglichkeit die Verwendung einer Struktur anstelle eines Arrays (die Struktur darf wiederum ein Array enthalten) und die Rückgabe dieser Struktur: ineffizient Funktion(int bla) { ineffizient Variable; // irgendwas machen return (Variable); } Das ist eine theoretische Möglichkeit. Wie aber der von mir nicht ohne Grund verwendete Typbezeichner "ineffizient" nahelegt, ist das sehr ineffizient - hier müssen nämlich permanent Daten im Speicher hin- und herkopiert werden. Ältere Compiler haben derartiges auch gar nicht erst zugelassen (in der vor-ANSI-C-Zeit). Wesentlich sinnvoller ist die Verwendung eines Arrays an der Stelle, an der es gebraucht wird und die Übergabe eines Pointers darauf an alle Funktionen, die damit arbeiten sollen. Tja, und den Literaturhinweis haste ja wenigstens schon zur Kenntnis genommen :-)
Äh hallo, es ist IMHO keine gute Idee ATA-Routinen anzulegen, die keinen Status zurückgeben können. Das heißt, wenn ein Fehler auftrat, dann sollte man ihn auch erkennen können (wenn man auch nicht darauf reagieren möchte ;-) ). Daher schlage ich den folgenden Prototypen für eine Funktion vor : uint8_t ui8ATAReadSector(uint32_t ui32LBA, uint16_t* ui16Buffer, uint8_t ui8Position, uint8_t ui8WordCount); Diese FUnktion kann dann aus dem Sektor mit der LBA ui32LBA ab der Position ui8Position (in 16bit - Words) ab ui8WordCount Words (16bit) in den Puffer ui16Buffer lesen. Außerdem kann nach dem Lesen noch der Status des Devices (Harddisk, o.Ä.) ermittelt werden und als Ergebniswert zurückgegeben werden. So lässt sich feststellen, ob die Leseoperation überhaupt erfolgreich war. Dieser Vorschlag kommt nicht von ungefähr. Viel mehr ist es der Prototyp der ATA-Funktion ReadSectors, wie ich sie verwende. Diese Funktion realisiert den "Read Sector(s)"-Command (Command-Code 0x20) in meinen Routinen. Meine bisherigen Bemühungen unterstützen dabei "Read Sector(s)", "Write Sector(s)" sowie Device-Selection und Hardware-Resets bei ATA-Festplatten. Zusammen mit einer schreib-/lesefähigen FAT16/32-Implementation arbeite ich im Moment an einem MP3-Player (so wie jeder ;-) ). Ich kann mit den genannten Routinen bisher über Hyperterminal Dateien von der Festplatte auf den Computer laden, Verzeichnisse und Dateien erstellen, ansehen und durch das Dateisystem browsen. MfG, Daniel.
>Wesentlich sinnvoller ist die Verwendung eines >Arrays an der Stelle, an der es gebraucht wird und >die Übergabe eines Pointers darauf an alle Funktionen, >die damit arbeiten sollen. Also müsste ich eigentlich nicht die Daten, sondern nur den Pointer übergeben? Naja, das mit den Pointern scheint mir immernoch ein wenig fremd, ich werde es dann warscheinlich doch mit einer globalen Variabel versuchen, sofern ich das hinkriege :) >Tja, und den Literaturhinweis haste ja wenigstens >schon zur Kenntnis genommen :-) klar doch :) Ich bin nicht der Typ der einfach in ein Forum kommt, um Fragen zu stellen ohne vorher zu versuchen sie sich selbst zu beantworten. So habe ich schon viel C Sourcecode gelesen(zum Beispiel den von yampp3 & 7). Allerdings gibt es dort Dinge die ich mir nicht ohne weiteres erklären kann, die auch nicht kommentiert sind, weil sie für den Programmierer selbstverständlich waren denke ich... Genau mit solchen Sachen habe ich dann Probleme. Zum Beispiel schon der unterschied von char buffer[20]; zu unsigned char buffer[20]; Vergleichbares findet sich in basic kaum und obwohl ich eigentlich Basic sehr gut beherrsche, muss ich nun in C die Grundlagen wieder lernen :( Ach ja, i kann das Buch einfach nicht finden, nicht einmal beim grössten onlinebuchhändler den ich kenne. Was heisst denn das k&k ausgeschrieben.. ;-) ?
> Ach ja, i kann das Buch einfach nicht finden, nicht einmal beim > grössten onlinebuchhändler den ich kenne. Den Link habe ich Dir in dem anderen Thread schon gegeben. > Was heisst denn das k&k ausgeschrieben.. ;-) ? Das heißt nicht k&k sondern K&R. Es sind die Anfangsbuchstaben der Autoren Brian W. Kernighan und Dennis M. Ritchie. Volkmar
Brian Kernighan & Dennis Ritchie. Bei Lehmanns lieferbar: http://www.lob.de/cgi-bin/work/outputexpert?id=42b01783102b3&frame=yes&flag=new&menupic=yes&mode=viewone&titnr=707552&linkcol=005c21&stich=+kernighan+&katalog=255
Ich möchte nicht mit unnötig vielen Threads nerven, desshalb nochmals hier: Wenn ich einen Integer Wert in 4 bytes umwandeln möchte, geht das dann auch mit einem shift oder funktioniert das nur innerhalb eines bytes mit shift?
Was meinst Du mit "einen Integer Wert in 4 bytes umwandeln"? Könntest Du das anhand eines Beispiels näher erläutern?
naja ich habs nun selbst hereausgefunden-das meinte ich :D : u32 LBA; u08 byte0, byte1, byte2, byte3; byte0 = (u08)(LBA); byte1 = (u08)(LBA >> 8); byte2 = (u08)(LBA >> 16); byte3 = (u08)(LBA >> 24); LBA ist vorgegeben und daraus rechnet es mir dann die bytes aus. Hdd Zugriff funzt schon, da mir Fat zu kompliziert ist für den Anfang, schreibe ich mir warscheinlich ein eigenes Dateisystem.(hab auch schon genaue Pläne wie)
Kennst Du den Begriff 'union'? Damit geht das sehr elegant. Ich vermute mal, das das hier im Forum schon behandelt wurde, eine Suche sollte daher erfolgreich sein. zB hier: http://www.mikrocontroller.net/forum/read-2-13308.html#13331 Volkmar
ja mit union hab ich ein bisschen herum probiert, aber habs dann schliesslich doch nicht hinbekommen, dann lass ich es lieber "unelegant" ;-) Allerdings muss ich dasselbe nun auch noch rückwärts machen, also ich lese 4 bytes ein und muss daraus einen integer machen. Zuerst hab ich an sowas gedacht: FileSize = (minibuf[30]*65536) + (minibuf[29]*256) + minibuf[28]; (das msb lese ich nicht ein, da es sowiso immer null ist) es funktioniert teilweise, aber nicht immer, desshalb frage ich mich obs mit diesen Shift Befehlen nicht irgendwie einfach ginge(und richtig)...?
> ja mit union hab ich ein bisschen herum probiert, aber habs dann > schliesslich doch nicht hinbekommen, dann lass ich es lieber > "unelegant" "unelegant" ist das ganz und gar nicht sondern im Gegenteil portabel. Die union-Lösung ist "unelegant", da compilerabhängig, d.h. von der Byteorder abhängig. Ich nehme daher auch immer die Schiebe-Lösung, auch wenn die vielleicht ein paar Zyklen länger dauert. > es funktioniert teilweise, aber nicht immer Du mußt die Werte es als unsigned long schreiben und minibuf muß vom Typ unsigned char sein, sonst kracht es. FileSize = (minibuf[30]*65536UL) + (minibuf[29]*256U) + minibuf[28]; Peter
Super, so läufts :D Tausend Dank wie müsste ich das denn schreiben wenn ich nun auch noch das msb mit einberechnen würde? FileSize = (minibuf[31]*4294967296UL) + (minibuf[30]*65536UL) + (minibuf[29]*256U) + minibuf[28]; So weit kann ich mir das noch selber denken, aber ist es beim msb dann sowas sie UD für unsigned double?
ich hab gerade noch etwas entdeckt...diese eine Zeile benötigt etwa 500 byte programmspeicher-aber ich werde wohl noch einige male so in der Art etwas umrechnen müssen, habe allerdings nur 8kbyte für das Programm zur Verfügung...Könnte es nicht irgendwie mit einem Shift gehen? Ich stelle mir das etwa so vor, dass dem integer zuerst das msb zugewiesen wird, dann 8 bit shift(welcher richtung weiss ich nicht) dann das nächste byte addiert wird, wieder shift usw... Aber ich kann meine Gedanken nicht wirklich in Code umsetzen.. :(
> diese eine Zeile benötigt etwa 500 byte programmspeicher
ist ja heftig, was für einen Optimierungslevel nimmst Du ?
Versuchs mal so:
FileSize = (minibuf[31]<<24UL) | (minibuf[30]<<16UL) |
(minibuf[29]<<8U) | minibuf[28];
Peter
. FileSize = (minibuf[31]*4294967296UL) + (minibuf[30]*65536UL) + (minibuf[29]*256U) + minibuf[28]; Der erste Faktor ist etwas zu groß. Nicht 2^32, 2^24 solltest Du verwenden, also 16777216 "So weit kann ich mir das noch selber denken, aber ist es beim msb dann sowas sie UD für unsigned double?" Was bitte hat der Datentyp double hier verloren? Du willst doch keine Floatingpoint-Arithmetik veranstalten! uint32_t FileSize; uint8_t Byte1; uint8_t Byte1; uint8_t Byte1; uint8_t Byte1; FileSize = (Byte1 << 24) + (Byte2 << 16) + (Byte3 << 8) + Byte4; Oder FileSize = (Byte1 * 1677216UL) + (Byte2 * 65536UL) + (Byte3 * 256UL) + Byte4; Natürlich kannst Du das auch so umsetzen, wie Du versuchtest zu formulieren: FileSize = Byte1; FileSize <<= 8; FileSize += Byte2; FileSize <<= 8; FileSize += Byte3; FileSize <<= 8; FileSize += Byte4; (Anstelle von 'FileSize <<= 8' könnte auch 'FileSize *= 256' geschrieben werden) Naja, ob das elegant ist oder in einem halben Jahr beim Durchlesen des Quelltextes noch verstanden wird ...
(minibuf[31]<<24UL) 24UL mag im ersten Augenblick unnötig erscheinen, da ja 24 nicht so groß ist. Es hat aber doch seinen Sinn, da C eine Operation in dem größten Format der Operanden ausführt, d.h. es wird damit erzwungen, daß das Zwischenergebnis unsigned long ist. Alternativ geht natürlich auch: ((unsigned long)minibuf[31]<<24) Peter
hey, ich habs nun endlich irgendwie hinbekommen, vielen Dank an euch beide :) Was mich aber verwundert, keine der Varianten FileSize = (Byte1 << 24) + (Byte2 << 16) + (Byte3 << 8) + Byte4; oder FileSize = (minibuf[31]<<24UL) | (minibuf[30]<<16UL) | (minibuf[29]<<8U) | minibuf[28]; hat funktioniert, auch wenn ich die bytes umgedreht habe, also das lsb zuerst, bekam ich zwei der bytes richtig raus, aber zwei waren dann einfach FF... Dann hab ichs mal so versucht; FileSize = minibuf[31]; FileSize <<= 8; FileSize += minibuf[30]; FileSize <<= 8; FileSize +=minibuf[29]; FileSize <<= 8; FileSize += minibuf[28]; Und damit hat es dann funktioniert, wer wiso mit den anderen Varianten nicht... >Naja, ob das elegant ist oder in einem >halben Jahr beim Durchlesen des Quelltextes noch verstanden wird ... Allerdings, aber ich kommentiere solche Stellen gut aus, wenn ich den Code dann vielleicht mal Online stelle-bis jetzt sieht es nämlich schon recht gut aus, ich habe gerade mal 512 bytes ram und 8 kbyte fürs programm. Dabei kann mein Programm bis jetzt das root Directory mit Fat32 auslesen und anzeigen, und auch schon files abspielen(allerdings noch nicht mit fat) So wies aussieht ist das Folgen der Cluster nicht all zu schwer, so denke ich, dass meine Fat Funktionen am Ende warscheinlich etwa 3 kb gross sein werden, denn aktuell, wie oben beschrieben ist der code gerade mal 3.8 kb gross :). Wieviel Ram das ganze in der Fat Funktion jeweils benötigt, weiss ich nicht, aber ich denke, dass ich alleine für fat noch unter 100 byte bin. Nik
Daß FileSize = (minibuf[31]<<24UL) | (minibuf[30]<<16UL) | (minibuf[29]<<8U) | minibuf[28]; nicht funktioniert, ist kein Wunder. Die Elemente von minibuf sind vom Typ uint8_t; wenn man deren Inhalt um mehr als 7 Bits verschiebt, dann bleibt nichts vom Inhalt übrig. (@Peter: Oder wird vom Shift-Operator automatich eine Typerweiterung durchgeführt?) Besser wäre ein Typecast, der zunächst uint8_t auf uint32_t erweitert: (((uint32_t) minibuf[31])<<24UL) etc.
> (((uint32_t) minibuf[31])<<24UL)
Und dann würde doch eine 24 anstelle der 24UL reichen, oder?
Volkmar
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.