Obsługa FAT w mikrokontrolerach STM32 – obsługa kart
Podstawowe operacje na plikach i katalogach
Gdy mikrokontroler umie się już porozumiewać z kartą SD i system plików jest należycie obsługiwany, to kolejnym krokiem są już właściwe operacje na plikach i katalogach, jakie wymaga projektowana aplikacja. Wszystkie funkcje, jakie oferuje moduł FatFs zostały omówione na jego stronie internetowej http://elm-chan.org/fsw/ff/00index_e.html , a ich spis umieszczono w tab. 2. Tutaj zajmiemy się przykładami aplikacji wykonywujących niezbędne zadania na plikach i katalogach.
Tab. 2. Funkcje udostępnione przez moduł FatFs
Funkcja | Opis |
f_mount | „montuje” (rejestruje) dysk logiczny w systemie |
f_open | otwieranie lub/i tworzenie pliku |
f_close | zamykanie pliku |
f_read | czytanie zawartości pliku |
f_write | zapisywanie pliku |
f_lseek | przesuwa wskaźnik zapisu/odczytu pliku |
f_truncate | skraca długość pliku |
f_sync | działanie podobne do f_close, z tym, że plik pozostaje otwarty, więc dalej można na nim wykonywać operacje |
f_opendir | otwiera katalog |
f_readdir | czyta zawartość katalogu |
f_getfree | pozwala odczytać liczbę wolnych klastrów |
f_stat | odczytuje informacje o pliku/katalogu |
f_mkdir | tworzy katalog |
f_unlink | usuwa katalog lub plik |
f_chmod | zmienia atrybuty pliku lub katalogu |
f_utime | zmienia datę i czas dla określonego pliku lub katalogu |
f_rename | zmiana nazwy lub przeniesienie pliku/katalogu |
f_mkfs | tworzy system plików na nośniku |
f_forward | czyta dane z nosnika i bezpośrednio przekazuje dalej |
Przykładowy program, którego zadaniem jest wykonywanie podstawowych operacji na plikach i katalogach pokazano na list. 5. Przedstawiony kod najpierw montuje dysk logiczny za pomocą funkcji f_mount() , dzięki czemu moduł FatFs będzie mógł wykonywać operacje dyskowe. W argumentach przesyłamy numer dysku (tutaj 0) oraz, przez referencję, główną zmienną systemu plików typu FATFS .
List. 5. Przykładowy program wykonujący podstawowe operacje na plikach i katalogach
int main(void) { FRESULT fresult; FIL plik; WORD zapisanych_bajtow; RCC_Conf(); GPIO_Conf(); SysTick_Conf(); fresult = f_mount(0, &g_sFatFs); // Tworzenie pliku fresult = f_open (&plik,"plik.txt", FA_CREATE_ALWAYS); fresult = f_close (&plik); // Tworzenie katalogu fresult = f_mkdir("katalog1"); // Zapis pliku fresult = f_open (&plik,"plik.txt", FA_WRITE); fresult = f_write(&plik, "zawartosc pliku", 15, &zapisanych_bajtow); fresult = f_close (&plik); // Usuniecie pliku fresult = f_unlink("plik.txt"); while(1); }
Po zamontowaniu dysku można już dowolnie zarządzać zawartością karty pamięci. W omawianym programie w pierwszej kolejności następuje utworzenie nowego pliku tekstowego w katalogu głównym karty. Wykorzystano do tego celu funkcję f_open() , która z pozoru (nazwy) nie ma z czynnościami tworzenia plików wiele wspólnego. Mimo tego, że nazwa funkcji na to nie wskazuje, to służy ona również do tworzenia nowych plików.
Jako pierwszy argument przekazujemy (prze referencję) adres do uchwytu pliku. Warto na to zwrócić uwagę, ponieważ, jak się przy okazji omawiania pozostałych funkcji okaże, jeśli operacje są wykonywane na pliku, to zawsze przekazujemy jego uchwyt w ten sposób. Drugim argumentem jest łańcuch znaków, który będzie stanowił nazwę pliku, w przedstawionym przykładzie będzie to plik tekstowy o plik.txt . Jako trzeci argument przesyłamy żądanie akcji, jaka ma być wykonana. Dla funkcji f_open() wszystkie możliwe wartości ostatniego argumentu pokazano w tab. 3. Na omawianym list. 5 widać, że program tworzy nowy plik, niezależnie, czy wcześniej istniał na karcie pamięci plik o nazwie plik.txt czy nie.
Tab. 3. Możliwe wartości ostatniego argumentu funkcji f_open()
Sposób otwarcia | Opis |
FA_READ | plik otwierany do odczytu |
FA_WRITE | plik otwierany do zapisu |
FA_OPEN_EXISTING | otwarcie pliku, jeśli plik nie istnieje, to zostanie zgłoszony błąd |
FA_OPEN_ALWAYS | otwarcie pliku, jeśli nie istnieje, to zostanie stworzony nowy plik |
FA_CREATE_NEW | utworzenie nowego pliku, jeżeli plik istnieje, to zostanie zgłoszony błąd |
FA_CREATE_ALWAYS | utworzenie nowego pliku, jeżeli już istnieje, to nadpisanie na stary plik |
Każda funkcja z modułu FatFs zwraca wartość typu FRESULT. Generalnie, jeśli zwracana wartość wynosi 0, to wszystko przebiegło prawidłowo, w przeciwnym wypadku wystąpiły błędy.
Oprócz tworzenia plików warto również dysponować mechanizmem pozwalającym na tworzenie katalogów. W module FatFs takiego mechanizmu dostarcza funkcja f_mkdir() . W argumencie do funkcji przekazujemy nazwę katalogu. Jeśli katalog nie ma być utworzony w jakimś innym katalogu to wystarczy jego nazwa, a jeśli chcemy utworzyć folder jako podkatalog, to należy podać całą jego ścieżkę. Ostatni przypadek przedstawia poniższa linia kodu:
fresult = f_mkdir("katalog1/katalog2");
Jeśli można tworzyć pliki i katalogi, to wypadałoby również móc je usuwać. Zapewnia to wywołanie funkcji f_unlink() , w argumencie należy podajać nazwę pliku lub katalogu przeznaczonego do usunięcia. Zapis do pliku, po jego wcześniejszym otwarciu do zapisu, wykonuje się przez wywołanie funkcji f_write() . Oprócz uchwytu do pliku przekazujemy tablice z bajtami przeznaczonymi do zapisu oraz liczbę zapisywanych bajtów. Ostatnim argumentem jest przekazanie przez referencję zmiennej typu DWORD , do której zostanie wpisana faktyczna ilość zapisanych do pliku bajtów.
Administrowanie zawartością karty pamięci może niekiedy wymagać skracania długości pliku, czyli innymi słowy zmniejszenia jego rozmiarów. Można tego dokonać dzięki funkcji f_truncate() ( truncate – skracać), której wywołanie może wyglądać podobnie poniżej zamieszczonej linii kodu:
fresult = f_truncate(&plik);
Jak widać, jedynym wymaganym do przekazania argumentem jest adres do uchwytu pliku, czyli zmiennej (struktury) zawierającej wszystkie informacje na temat pliku, niezbędne do jego poprawnego egzystowania w systemie plików. Funkcja f_truncate() do skracania długości pliku wykorzystuje aktualny wskaźnik zapisu/odczytu. Mechanizm zmniejszania rozmiarów pliku przedstawiono na rys. 5. Mechanizm skracania długości pliku może znaleźć zastosowanie na przykład w systemach akwizycji dużej ilości danych, gdzie niekiedy zachodzi potrzeba odrzucenia części zebranych informacji.
Rys. 5. Mechanizm zmniejszania rozmiarów pliku
Przeglądanie zawartości karty pamięci, informacje o plikach i katalogach
Informacje na temat plików w module FatFs można uzyskać poprzez wywołanie funkcji f_stat() , wystarczy w programie umieścić następującą linię kodu:
fresult = f_stat("plik.txt", &plikInfo);
Jako pierwszy argument należy podać łańcuch znaków zawierający nazwę pliku, ściślej wskaźnik na początek tablicy z nazwą pliku.
Informacje zostają zapisane do struktury typu FILINFO , której budowa pokazano na list. 6, a jej adres jest przekazywany jako drugi argument w wywołaniu funkcji f_stat() . Dane na temat pliku, jakie otrzymujemy to: rozmiar, data ostatniej modyfikacji, czas modyfikacji, atrybuty pliku, nazwa w tablicy 13-elementowej (format 8 + 3).
List. 6. Budowa struktury FILINFO
/* File status structure */ typedef struct _FILINFO { DWORD fsize; /* Size */ WORD fdate; /* Date */ WORD ftime; /* Time */ char fname[13]; /* Name (8.3 format) */ } FILINFO;
Przeglądu zawartości całego katalogu można dokonać z wykorzystaniem funkcji f_readdir() . Przykładowy program, który zbiera informację na temat tego, co znajduję się w folderze katalog1 został przedstawiony na list. 7.
List. 7. Program testowy gromadzący informacje na temat zawartości folderu katalog1
fresult = f_opendir(&Dir, "katalog1"); if(fresult != FR_OK) return(fresult); for(;;) { fresult = f_readdir(&Dir, &plikInfo); if(fresult != FR_OK) return(fresult); if(!plikInfo.fname[0]) break; // p jest wkaznikiem na tablice elemetnow typu FILINFO *p++ = plikInfo; }
Po otwarciu katalogu za pomocą funkcji f_opendir() w nieskończonej pętli następuje odczytywanie informacji o kolejnych plikach i folderach przez skopiowanie struktury wyżej omówionego typu ( FILINFO ). Kolejne wywołania funkcji f_readdir() powodują samoczynne czytanie informacji o następujących po sobie elementach katalogu. Jeśli pole nazwy elementu będzie puste, to oznacza wtedy, że nie ma już w danym folderze elementów i wykonywanie pętli zostaje przerwane.