SD

所属分类:单片机开发
开发工具:C/C++
文件大小:144KB
下载次数:21
上传日期:2008-06-21 20:30:10
上 传 者cym-930
说明:  sd 卡读写程序 对需要学习与开发的人有用
(sd card reader program to the needs of learning and development were useful)

文件列表:
FATTests\AVR_CF_ADAPTER.brd (63936, 2002-12-18)
FATTests\Avr_CF_Adapter.gif (19417, 2003-04-21)
FATTests\AVR_CF_ADAPTER.sch (73320, 2003-04-20)
FATTests\FATTests\compact.c (7618, 2004-05-12)
FATTests\FATTests\compact.h (2878, 2004-05-09)
FATTests\FATTests\dir.c (14823, 2004-05-20)
FATTests\FATTests\dir.h (1393, 2004-05-09)
FATTests\FATTests\dos.c (10732, 2004-05-09)
FATTests\FATTests\dos.h (2637, 2004-05-09)
FATTests\FATTests\DOSDeleteTest1\dosdelete.c (5058, 2004-05-24)
FATTests\FATTests\DOSDeleteTest1\makefile (1142, 2004-05-21)
FATTests\FATTests\DOSDeleteTest1\mydefs.h (2405, 2004-05-09)
FATTests\FATTests\DOSDeleteTest1\protos.h (665, 2004-03-12)
FATTests\FATTests\DOSDeleteTest1\_make.bat (504, 2004-03-23)
FATTests\FATTests\DOSDeleteTest1\_MAKE.PIF (967, 2004-05-24)
FATTests\FATTests\DOSfreadTest1\dosread1.c (3293, 2004-05-21)
FATTests\FATTests\DOSfreadTest1\makefile (1141, 2004-05-18)
FATTests\FATTests\DOSfreadTest1\mydefs.h (2399, 2004-05-09)
FATTests\FATTests\DOSfreadTest1\protos.h (665, 2004-03-12)
FATTests\FATTests\DOSfreadTest1\_make.bat (500, 2004-03-12)
FATTests\FATTests\DOSfreadTest1\_MAKE.PIF (967, 2004-05-22)
FATTests\FATTests\DOSfreadTest2\dosread2.c (3564, 2004-05-21)
FATTests\FATTests\DOSfreadTest2\makefile (1141, 2004-05-21)
FATTests\FATTests\DOSfreadTest2\mydefs.h (2397, 2004-05-09)
FATTests\FATTests\DOSfreadTest2\protos.h (665, 2004-03-12)
FATTests\FATTests\DOSfreadTest2\_make.bat (500, 2004-03-12)
FATTests\FATTests\DOSfreadTest2\_MAKE.PIF (967, 2004-05-22)
FATTests\FATTests\DOSfwriteTest1\doswrite1.c (3374, 2004-05-21)
FATTests\FATTests\DOSfwriteTest1\makefile (1142, 2004-05-21)
FATTests\FATTests\DOSfwriteTest1\mydefs.h (2399, 2004-05-22)
FATTests\FATTests\DOSfwriteTest1\protos.h (665, 2004-03-12)
FATTests\FATTests\DOSfwriteTest1\_make.bat (504, 2004-03-13)
FATTests\FATTests\DOSfwriteTest1\_MAKE.PIF (967, 2004-05-22)
FATTests\FATTests\DOSfwriteTest2\doswrite2.c (4909, 2004-05-24)
FATTests\FATTests\DOSfwriteTest2\makefile (1142, 2004-05-21)
FATTests\FATTests\DOSfwriteTest2\mydefs.h (2401, 2004-05-24)
FATTests\FATTests\DOSfwriteTest2\protos.h (665, 2004-03-12)
... ...

############################################### # Willkommen bei Holgi's kleinem ATMega-DOS ! # ############################################### 24.05.2004 CompactFlash (CF) werden hier im 8 Bit Microcontroller Modus betrieben. Die Ansteuerung hat nichts mit Festplatten zu tun. Die FAT-Routinen zum lesen/schreiben von Dateien knnte man aber übernehmen. Neu hinzugekommen sind Routinen für die Ansteuerung von MultiMedia- (MMC) und SecureDigital- (SD) Cards im SPI Modus. SD-Cards wurden aber noch nicht getestet ! Alles was ab hier zu CF gesagt wird gilt auch für MMC/SD. Wer wissen mchte wie schnell das ganze arbeitet findet in den Unterverzeichnissen jeweils eine Datei readme.txt mit unverbindlichen Messungen ;) ################### # Zur Geschichte: # ################### Ziel des Projektes war es CompactFlash mit einem Microcontroller zu lesen und zu schreiben weil ein 512kB Flash Eprom wie 29F040 manchmal auch noch zu klein ist. Auerdem sollte eine einfache Mglichkeit her die Daten auch mit dem PC zu lesen oder zu schreiben. Also am besten ein FAT-Filesystem. Kann man mit jedem billigen CF-Reader lesen und schreiben. Beim Microcontroller sollte mglichst kein externes RAM zum Einsatz kommen. Das ist ganz gut gelungen. 1.2kB für ein Dateisystem ohne FAT-Buffer und 1.7kB mit FAT-Buffer passt noch gut in einen ATMega32. Programmspeicherbedarf mit ALLEN Funktionen bisher unter 10kB (5k Worte). Da die Routinen in C geschrieben sind dürfte es nicht all zu schwer sein das ganze auch auf 8051 (dann externes RAM) oder anderen Micro- controllern zum laufen zu bringen. PIC's sind da leider keine gute Wahl weil man wegen des RAM Bankings maximal 256 Byte RAM am Stück bekommt. Das dürfte recht kompliziert werden. Hier eine bersicht welche Funktionen man zur Zeit benutzen kann ohne das man sich erst in FAT-Dateisysteme einarbeiten muss. unsigned char GetDriveInformation(void); unsigned char fopen(char *name, unsigned char flag); unsigned int fread(unsigned char *buf, unsigned int numbytes); unsigned int fwrite(unsigned char *buf, unsigned int numbytes); void fflush(void); void fclose(void); unsigned char chdir(char *name); unsigned char mkdir(char *name); unsigned char remove(char *name); unsigned char FindName(char *name); unsigned char ReadFileRaw(char *name); Namen und Parameter sind so weit wie mglich an die DOS Funktionen angelehnt die man auch vom PC her kennt. Es gibt allerdings Unterschiede und Einschrnkungen. Siehe unten. Zuerst einmal: Was geht nicht ! =============================== Lange Dateinamen werden nicht unterstützt. Sie stren aber nicht und knnen bearbeitet werden wenn man den DOS Namen der Datei kennt. Mehrere Dateien gleichzeitig ffnen geht NICHT. Eine Datei kann nur zum lesen ODER schreiben geffnet werden. Man kann eine Datei nicht zum schreiben ffnen und alte Daten überschreiben. Es wird IMMER hinten drangehngt. Formatieren geht natürlich nicht. Verzeichnisse lschen geht nicht. Noch kein fseek() Befehl vorhanden. Es wird keine Kopie von der FAT angelegt. Scandisk meckert da ! Man kann nur mit der ersten Partition arbeiten. Es gibt keine Laufwerksnamen wie C: Pfadangaben in Dateinamen sind nicht erlaubt. Man kann mit chdir() aber schrittweise in mehrere Unterverzeichnisse wechseln. Was geht ? ========== Das Programm unterstützt FAT12,FAT16 und FAT32 Dateisysteme. Man kann Dateien lesen und neue Dateien erstellen. Daten an vorhandene Dateien dranhngen. Dateien lschen. Man kann neue Verzeichnisse erstellen. Auch in Unterverzeichnissen. Man kann in Verzeichnisse wechseln und alle oben genannten Funktionen darin ausführen. Alle Routinen arbeiten auch mit einer fragmentierten FAT ! RAM Speicherbedarf ================== Ohne FATBuffer ca. 1,2kB RAM Bedarf Mit FATBuffer ca. 1,7kB RAM Bedarf !! Also nur für die greren ATMega ab ATMega32 !!! Ohne FAT-Buffer ist nur für reine Lesesysteme empfehlenswert. Schreiben sollte man damit nicht. Siehe unten. Beim lesen kommt man auch ohne FAT Buffer auf gute Geschwindigkeiten. Schreiben ohne FAT Buffer ========================= Schreiben ohne FAT Buffer ist keine gute Idee. Erstens kommt man nicht richtig auf Geschwindigkeit wenn die FAT fragmentiert ist, zweitens wird die FAT zu oft beschrieben. Das verkürzt die Lebensdauer des CF um einiges. Beispiele CF mit unfragmentierter FAT ganz vollschreiben: 16 MB CF mit FAT12 3900 Cluster Schreiben mit FAT-Buffer 39 FAT Schreibzyklen. Schreiben ohne FAT-Buffer 7815 FAT Schreibzyklen. 32 MB CF mit FAT16 15569 Cluster Schreiben mit FAT-Buffer 121 FAT Schreibzyklen. Schreiben ohne FAT-Buffer 31137 FAT Schreibzyklen. Ein 32MB CF hat z.B. 61 FAT Sektoren. Jeder Sektor wird ohne FAT Buffer also ca. 510 mal beschrieben. Es gibt CF wo jeder Sektor nur 10000 mal beschrieben werden darf ! Das heit aber nicht das der CF nach 20 Versuchen kaputt ist. CF haben eine Sektorreserve für hufig beschriebene Sektoren. Sektoren werden AUTOMATISCH ersetzt wenn sie nicht mehr beschreibbar sind. Der CF ist erst kaputt wenn diese Reserve verbraucht ist. Moderne CF haben >100000 garantierte Schreibzyklen pro Sektor. Mu man mal ins Datenblatt sehen. Für solche CF kann man wenn es nicht auf Geschwindigkeit ankommt auf den FAT Buffer verzichten. Probleme beim schreiben von Daten ================================= Beim schreiben darf man die Schaltung nicht einfach ausschalten bzw. den CF rausziehen bevor nicht fclose() aufgerufen wurde. Die Dateigre stimmt dann nicht oder es gehen Cluster verloren weil sie noch nicht in die FAT eingetragen wurden. Der Grund dafür ist das für Daten und für die FAT immer ein kompletter Sektor im Speicher gehalten wird. Diese Sektorbuffer werden nur geschrieben wenn neue Daten in einem anderen Sektor liegen. Nur so kann man Schreibzugriffe auf den CF minimieren und seine Lebensdauer wirklich ausnutzen. Es gibt ein paar Mglichkeiten das Problem zu umgehen. 100% sicher sind die z.B. bei Stromausfall aber nicht. Win oder Linux gehts da auch nicht anders :) 1. Datei gelegentlich mal mit fclose() schlieen und neu ffnen 2. fflush() in greren Zeitabstnden aufrufen. NICHT im Sekunden- takt. Ein Tag hat 8***00 Sekunden. Eher so alle 10 Minuten. 3. fflush() aufrufen wenn eine vorgegebene Datenmenge erreicht ist. 4. Einen Eingang vorsehen der dazu dient fclose() aufzurufen wenn ein Schalter geschlossen wird. Die sicherste Methode. //################################################################### //################################################################### // Beschreibung der DOS Funktionen //################################################################### //################################################################### Hier die Beschreibungen zu den wichtigsten Funktionen die man benutzen kann. Um die anderen mu man sich nur Gedanken machen wenn man selbst Erweiterungen programmieren mchte. //################################################################### // unsigned char GetDriveInformation(void) //################################################################### Funktion: Diese Funktion ist die wichtigste. Sie ermittelt alle Daten zum CF wie Anzahl Sektoren, Anzahl Cluster und was für ein Filesystem auf dem CF ist (FAT12,FAT16,FAT32), wo sich das RootDirectory befindet und vieles mehr. Ohne diese Informationen knnen weder Daten vom CF gelesen noch darauf geschrieben werden. Diese Funktion MUSS vor allen anderen Funktionen aufgerufen werden ! Parameter: keine Rückgabe: F_OK wenn ein CF gefunden wurde F_ERROR wenn kein CF gefunden wurde. Dann auf keinen Fall weitermachen ! //################################################################### // unsigned char fopen(char *name, unsigned char flag) //################################################################### Funktion: ffnet eine Datei zum lesen ODER schreiben Parameter: "name" ist der Name der zu ffnenden Datei "flag" F_READ Datei zum lesen ffnen "flag" F_WRITE Datei zum schreiben ffnen Rückgabe: F_OK wenn die Datei geffnet werden konnte. F_ERROR wenn die Datei nicht geffnet werden konnte. Wenn F_WRITE benutzt wird und die Datei noch nicht existiert, wird versucht eine neue Datei anzulegen. Wenn die Datei bereits existiert wird an ihr ENDE vorgespult um Daten anzuhngen. Es ist nicht vorgesehen alte Daten zu überschreiben. Das aktuelle Verzeichnis wird automatisch vergrert wenn keine Eintrge mehr frei sind. Das geht bei FAT12 und FAT16 nicht wenn man sich im RootVerzeichnis befindet. Die Anzahl der Eintrge ist fest vom Dateisystem vorgegeben. Wer mehr als 512 Dateien anlegen will MUSS bei FAT12 und FAT16 in einem Unterverzeichnis arbeiten ! //################################################################### // void fclose(void) //################################################################### Funktion: Schliet eine offene Datei Parameter: keine Rückgabe: keine Bei FileFlag F_WRITE wird der Inhalt des Datei-Sektorbuffers geschrieben. Dazu wird fflush() aufgerufen. Falls ein FAT-Write-Buffer verwendet wird, wird dieser auf den CF geschrieben. Auch das passiert in fflush(). Der Verzeichniseintrag der Datei wird mit der zuletzt ermittelten Dateigre aufgefrischt. Wer eine Uhr in seinem System hat knnte mit einer Funktion , z.B. getclock(); , in UpdateFileEntry() auch Uhrzeit und Datum des letzten Schreibzugriffes speichern. //################################################################### // unsigned int fread(unsigned char *buf, unsigned int numbytes) //################################################################### Funktion: Liest eine bestimmte Anzahl Bytes aus einer Datei in einen Puffer Parameter: "buf" Zeiger auf den Puffer wo die Daten rein sollen "numbytes" Anzahl der Bytes die gelesen werden sollen Rückgabe: Anzahl der Bytes die gelesen wurden Beispiel: 11 Bytes lesen unsigned char inbuff[10]; unsigned char by; unsigned int readbytes; if(fopen("mydata.dat",F_READ)==F_OK) { readbytes=fread(inbuff,10); readbytes=fread(&by,1); // Achte auf das & vor by ! fclose(); } Wenn das Dateiende erreicht ist liefert fread() die Anzahl bis zum Dateiende gelesener Bytes oder einfach eine 0. //################################################################### // unsigned int fwrite(unsigned char *buf, unsigned int numbytes) //################################################################### Funktion: Schreibt eine bestimmte Anzahl Bytes aus einem Puffer in eine Datei Parameter: "buf" Zeiger auf den Puffer der die Daten enthlt "numbytes" Anzahl der Bytes die geschrieben werden sollen Rückgabe: Anzahl der Bytes die geschrieben wurden Beispiel: unsigned char outbuff[10]; unsigned char by; unsigned int written; for(by=0; by<10; by++) outbuff[by]=by; if(fopen("mydata.dat",F_WRITE)==F_OK) { written=fwrite("Hello World",11); written=fwrite(outbuff,10); written=fwrite(&by,1); // Achte auf das & vor by ! fclose(); } Wenn fwrite() nicht die Anzahl Bytes zurückliefert die geschrieben werden sollten, dann ist der CF voll ! //################################################################### // void fflush(void) //################################################################### Parameter: keine Rückgabe: keine fflush() ruft man auf wenn alle gesammelten Daten sofort auf den CF geschrieben werden sollen OHNE die Datei zu schlieen. Der Inhalt des Sektorbuffers wird geschrieben. Falls ein FAT-Write-Buffer verwendet wird, wird dieser auf den CF geschrieben. Der Verzeichniseintrag der Datei wird mit der zuletzt ermittelten Dateigre aufgefrischt. Wer eine Uhr in seinem System hat knnte mit einer Funktion , z.B. getclock(); , in UpdateFileEntry() auch Uhrzeit und Datum des letzten Schreibzugriffes speichern. //################################################################### // unsigned char chdir(char *name) //################################################################### Funktion: In ein Unter- oder ein hheres Verzeichnis wechseln Parameter: Der Verzeichnisname z.B. chdir("tmp"); Rückgabe: F_OK wenn das Verzeichnis gefunden wurde, F_ERROR wenn das Verzeichnis nicht gefunden wurde. Man kann immer nur eine Verzeichnistiefe zur Zeit wechseln. Wenn man in "tmp/test" wechseln mchte mu chdir() zweimal aufgerufen werden: chdir("tmp"); chdir("test"); Wenn man eine Verzeichnistiefe zurück mchte ruft man einfach chdir(".."); auf. chdir("/"); wechselt ins RootVerzeichnis. chdir() arbeitet NICHT wenn eine Datei offen ist ! //################################################################### // unsigned char mkdir(char *name) //################################################################### Funktion: Ein neues Verzeichnis erzeugen Parameter: Der Verzeichnisname z.B. mkdir("tmp"); Rückgabe: F_OK wenn das Verzeichnis erstellt werden konnte oder bereits existiert. F_ERROR wenn das Verzeichnis nicht erstellt werden konnte. mkdir() arbeitet NICHT wenn eine Datei offen ist ! //################################################################### // unsigned char remove(char *name) //################################################################### Funktion: Lscht eine Datei Parameter: Der Dateiname z.B. remove("tmp"); Rückgabe: F_OK wenn die Datei gelscht wurde (oder gar nicht existierte ;), F_ERROR wenn die Datei nicht gelscht wurde. remove() arbeitet NICHT wenn eine Datei offen ist ! remove() lscht keine Verzeichnisse. remove() bearbeitet die Eintrge von langen Dateinamen nicht wenn die Datei einen langen Dateinamen hatte ! Nur der Eintrag für den DOS-Namen wird entfernt. Es knnte sein das es dann Probleme beim lesen des CF mit dem PC gibt. remove() ist eine Killer-Routine. Sie scheint zu funktionieren, falls es aber noch Bugs gibt knnten da eine Menge Daten verschwinden ! //################################################################### // unsigned char FindName(char *name) //################################################################### Funktion: Sucht im aktuellen Verzeichnis nach einem Datei- oder Verzeichnisnamen. Parameter: Der Datei/Verzeichnisname z.B. FindName("tmp"); Rückgabe: FULL_MATCH wenn die Datei/das Verzeichnis gefunden wurde. NO_MATCH wenn die Datei/das Verzeichnis nicht gefunden wurde. FindName() wird von fopen(), chdir(), mkdir(), ReadFileRaw() und remove() benutzt. Theoretisch kann man auch mit fopen() herausbekommen ob eine Datei existiert. Sie wird dann aber auch geffnet. FindName() arbeitet NICHT wenn eine Datei offen ist ! Beispiel: Suche nach der Datei "mydata1.dat". Wenn sie existiert dann "mydata2.dat" ffnen. Wenn sie nicht existiert dann "mydata1.dat" erzeugen. if(FindName("mydata1.dat")==FULL_MATCH) { fopen("mydata2.dat",F_WRITE); } else { fopen("mydata1.dat",F_WRITE); } //################################################################### // unsigned char ReadFileRaw(char *name) //################################################################### Funktion: Liest eine Datei im RAW Modus Parameter: Der Dateiname z.B. ReadFileRaw("mydata.dat"); Rückgabe: F_OK wenn die Datei gefunden und gelesen wurde, F_ERROR wenn die Datei nicht gefunden wurde. ReadFileRaw() ist wesentlich schneller als z.B. fread(). Es wird immer ein kompletter Sektor gelesen der dann irgendwie ausgewertet werden kann. fread() ist aber flexibler weil man kleinere Hppchen lesen kann. fopen() darf für ReadFileRaw() nicht aufgerufen werden ! Die Routine zum verarbeiten der Daten mu in readraw.c eingetragen werden ! //################################################################### //################################################################### // Ende Beschreibung der DOS Funktionen //################################################################### //################################################################### !!!!!!!!!!!!!!!!!!!!!!!!!! !! Einsparmglichkeiten !! !!!!!!!!!!!!!!!!!!!!!!!!!! Man kann ein bichen Speicherplatz sparen indem nicht bentigte Programmteile beim compilieren weggelassen werden. So kann man ein reines Lesesystem, ein reines Schreibsystem oder ein Schreib-/Lesesystem erzeugen. Man kann auch ein System erzeugen das nur mit FAT16 arbeitet. Mit oder ohne FAT Buffer. Holgi's kleiner FAT Baukasten sozusagen ;) In den Unterverzeichnissen mit den Testprogrammen liegt jeweils eine Datei namens "mydefs.h". Dort kann man bestimmte Programmteile ausschalten. Beispiel für alle Programmteile erzeugen, einfach keines von den #undef aktivieren: // spare program memory by deciding if we want to read, write or both //#undef DOS_READ //undefine this if you don't want to read files with fread() //#undef DOS_WRITE //undefine this if you don't want to write files with fwrite() //deleting files is also deactivated //#undef DOS_DELETE //undefine this if you don't want to delete files //#undef DOS_READ_RAW //undefine this if you don't want to read files with ReadFileRaw() // spare program memory by deciding if we want to use FAT12, FAT16, FAT32. // comment out FAT types not used. NOT recommended if you don't know the // FAT type of your drive ! //#undef USE_FAT12 //undefine this if you don't want to use FAT12 //#undef USE_FAT16 //undefine this if you don't want to use FAT16 //#undef USE_FAT32 //undefine this if you don't want to use FAT32 //#undef USE_FATBUFFER //undefine this if you don't want to use a FAT Buffer Beispiel für ein reines Schreibsystem das nur mit FAT16 arbeitet und keinen FAT Buffer verwendet, lschen von Dateien mglich: // spar ... ...

近期下载者

相关文件


收藏者