日本黄色一级经典视频|伊人久久精品视频|亚洲黄色色周成人视频九九九|av免费网址黄色小短片|黄色Av无码亚洲成年人|亚洲1区2区3区无码|真人黄片免费观看|无码一级小说欧美日免费三级|日韩中文字幕91在线看|精品久久久无码中文字幕边打电话

當前位置:首頁 > 單片機 > 單片機
[導讀]今天要給大家分享的是使用FatFs這個庫來讀寫SD卡上面的文件。工程的初始化函數和FatFs都是通過STM32CubeMX配置生成的,不需要我們手動添加庫。今天分享的內容和我的上一篇帖子SDIO讀取SD卡的扇區(qū)有關,最好掌握了SDI

 

今天要給大家分享的是使用FatFs這個庫來讀寫SD卡上面的文件。工程的初始化函數和FatFs都是通過STM32CubeMX配置生成的,不需要我們手動添加庫。
今天分享的內容和我的上一篇帖子SDIO讀取SD卡的扇區(qū)有關,最好掌握了SDIO讀取SD卡扇區(qū)的基礎之后再來看這一篇帖子。
寫在前面的話
上一次發(fā)表了關于SDIO讀取SD卡的一篇開發(fā)分享的帖子,今天呢就更進一步使用了FatFs文件系統(tǒng)。同樣我們完全使用ST公司提供的STM32CubeMX軟件和HAL庫來進行開發(fā)。如果喜歡我的帖子請多多回復我會努力更新的。
我使用的工具
開發(fā)平臺:正點原子探索者STM32F407開發(fā)板
硬件:使用了NUCLEO-F446RE開發(fā)板的ST-Link作為調試器、SD卡、數據線、開發(fā)板的電源適配器、DELL一體機
軟件:STM32CubeMX、Keil V5、串口助手
學習的知識點
1、使用STM32CubeMX配置SDIO
2、在Keil中初始化SDIO
3、修改HEAP內存塊的大小
4、malloc函數的使用
5、如何使用FatFs提供的一些庫函數
共享的資源
完整的工程文件FatFs.zip
STM32Cube中FatFs的中文幫助文檔
準備工作
參考SDIO讀取SD卡扇區(qū)這篇帖子,這里不再贅述。
目錄
一、在STM32CubeMX中配置好我們的工程
1、配置FatFs
2、配置SDIO
3、配置SYS
4、配置USART
二、在Keil中做初始化
1、調用BSP_SD_Init()函數
2、修改MX_FATFS_Init(void)函數
三、修改啟動文件
1、malloc函數的介紹
2、FatFs對malloc函數的調用
3、改變heap的內存大小
四、使用FatFs
1、定義一些變量
2、使用f_open
3、使用f_read
4、使用f_lseek
5、使用f_write
6、使用f_close
7、再次讀取文件內容
五、上電測試
一、在STM32CubeMX中配置好我們的工程
1、配置FatFs
在STM32CubeMX引腳配置中,找到Configuration->MiddleWares->FatFs,勾選下面的SD Card。
2、配置SDIO
STM32CubeMX引腳配置中Peripherals->SDIO,下拉框里面選擇SD 4 bit Wide bus。
3、配置SYS
STM32CubeMX引腳配置中Peripherals->SYS,下拉框里面選擇SWD and Asynchronous Trace。
4、配置USART
STM32CubeMX引腳配置中Peripherals->USART,下拉框里面選擇Asynchronous。
下面是我的工程配置界面的截圖。
二、在Keil中做初始化
1、調用BSP_SD_Init()函數
在main函數開頭的部分調用了各種初始化函數,這些函數完成了硬件的初始化工作。在我的前一篇帖子 SDIO讀取SD卡扇區(qū) 中,SDIO的初始化也是要添加一點代碼才可以正常的工作。這里也是一樣,不過更加的簡單。我們只需在MX_FATFS_Init();之前調用BSP_SD_Init();函數就可以了,我在下面貼出了這段初始化的代碼。
這里介紹一下BSP_SD_Init()函數。BSP的意思是板級支持包的意思,也就是這個函數是專門針對某一類芯片支持的。這個函數在文件bsp_driver_sd.c文件中,在這個文件里面還有很多的函數,這些函數完成了對讀寫SD卡、查詢SD卡狀態(tài)、初始化SD卡等一系列操作。這些函數原先都是要用戶來編寫,提供給FatFs調用作為驅動支持的。但是這里幫我們都定義好了只需要調用即可,如果你要用FatFs來連接自己的設備的話,那你就需要自己定義這些底層的IO驅動函數了。
關于FatFs底層驅動支持和驅動架構的關系請查看附件UM1721_DM00105259_CN.pdf,這里面有ST官方對這個的詳細說明。
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* Configure the system clock */
SystemClock_Config();
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_SDIO_SD_Init();
MX_USART1_UART_Init();
BSP_SD_Init();
MX_FATFS_Init();
復制代碼
2、修改MX_FATFS_Init(void)函數
除了上面對初始化函數的調用以外,我們還需要一些別的修改。在這里,我希望調用BSP_SD_Init()初始化好了SD卡之后,在調用MX_FATFS_Init()初始化的時候就掛載SD卡。所以我們就在FatFs的初始化函數里面用戶代碼的部分加入了我們的f_mount函數。下面貼出MX_FATFS_Init()函數的代碼,這個函數位于文件Application/User->fatfs.c中。
我還設置了一個簡單的條件語句,如果掛載SD卡成功的話就發(fā)送一個成功的消息。
void MX_FATFS_Init(void)
{
/*## FatFS: Link the SD driver ###########################*/
retSD = FATFS_LinkDriver(&SD_Driver, SD_Path);
/* USER CODE BEGIN Init */
/* additional user code for init */
if(f_mount(&SDCard, SD_Path,0) == 0)
{
HAL_UART_Transmit(&huart1, (uint8_t *)"Success!n", 9, 500);
}
/* USER CODE END Init */
}
復制代碼
OK,到了這里我們對文件的修改就基本上完成了,但是僅僅如此只能讓SD卡正常驅動和掛載,并不能夠打開文件和讀寫操作。接下來的內容就是來解決這個問題的。
三、修改啟動文件
1、malloc函數的介紹
原型
extern void *malloc(unsigned int num_bytes);
頭文件
#include
函數聲明
void *malloc(size_t size);
備注:void* 表示未確定類型的指針,void *可以指向任何類型的數據,更明確的說是指申請內存空間時還不知道用戶是用這段空間來存儲什么類型的數據(比如是char還是int或者其他數據類型)。
功能
分配長度為num_bytes字節(jié)的內存塊
返回值
如果分配成功則返回指向被分配內存的指針(此存儲區(qū)中的初始值不確定),否則返回空指針NULL。當內存不再使用時,應使用free()函數將內存塊釋放。函數返回的指針一定要適當對齊,使其可以用于任何數據對象。
以上是百度百科對malloc函數的一些簡介,在Keil中要使用這個函數需要包含stdlib.h頭文件。同時在Keil的編譯器設置中要選中microlib選項,不過使用STM32CubeMX生成的工程默認都選中了這一選項。這個函數是放在標準庫里面的,所以不能找到這個的定義代碼在哪里,編譯的時候鏈接所屬的庫就可以了。
2、FatFs對malloc函數的調用
為了討論FatFs和malloc函數的關系,我們要先打開MiddleWares/FatFs->syscall.c文件。在這個文件里面,我們可以看到有一些函數是分配內存的函數。滾動頁面到最下面,可以看到最后兩個函數都和分配內存有關。這些函數都調用了malloc函數來動態(tài)分配內存,在ST的手冊中沒有提到這個malloc。但是如果沒有這個系統(tǒng)提供的malloc函數我們就需要自己來定義一個動態(tài)內存分配函數,同時把原來的malloc調用替換為我們提供的函數接口。
這樣我們就知道了FatFs對malloc函數有調用。但是僅僅如此嗎?不是這么簡單。FatFs默認是開啟了對長文件名支持的,這樣就需要很多的內存來存儲文件名這些信息。如果malloc內存初始化的時候內存設置的比較小的話,就不能成功分配內存了不是嗎?這樣一來調用FatFs的f_open函數的時候就會返回17,查詢這個枚舉值的定義就知道是內存分配不足的錯誤。感興趣的話可以不進行下一步修改heap的大小來調用f_open同時把返回值發(fā)送到串口來看一看。
3、改變heap的內存大小
malloc函數的內存是從堆(heap)里面分配的,如果使用了對長文件名的支持我們就需要malloc為FatFs提供內存分配的支持。在使用malloc之前會對malloc的內存池進行初始化,而這個初始化的操作是由我們的庫提供的啟動代碼完成的。
下面貼出匯編語言的啟動代碼的一部分。

Stack_Size EQU 0x00000400
復制代碼
這一段代碼是初始化內存池的匯編語言代碼,在這里我把Heap_Size設置為0x00000800,也就是2KB。默認的數值是512Bytes,這樣的話分配給我們的FatFs使用會不足,分配內存會失敗。只有這樣子修改了之后,后面的f_open這些函數才可以正常使用。
進行了以上的步驟之后,我們就可以輕松愉快地使用FatFs提供的各種函數了。
四、使用FatFs
1、定義一些變量
在我們代碼開始的部分,先定義一些變量供我們使用。這里選擇幾個來解析一下。
第一個FIL file;這個變量是文件的結構體變量,記錄了我們打開的文件的信息。使用f_open等函數的時候都要用到。
第二個Words變量是一個字符串指針,我用這個指針來存儲讀取的字符信息。這里我們就使用了malloc函數來分配內存,我們通過修改啟動代碼提供了更多的堆內存所以這里就可以分配一些給我們使用。
第三個是Path這個字符串,這里保存的是文件所在的路徑。關于文件路徑的寫法,請參考FatFs的官方文檔網站。
FIL file;
復制代碼
2、使用f_open
關于f_open函數的具體用法和詳細說明,參見FatFs官方文檔網站。這里可以看看我在下方貼出的代碼作為參考來使用。
3、使用f_read
關于f_read沒有特別的說明,詳細的用法去看看FatFs官方文檔網站。這里只想說一下第三個和第四個參數。這里的第三個參數是給定的要讀取的字節(jié)數,而第四個參數是最后讀取了的字節(jié)數的存儲指針。這里要說明的是,不一定你要讀取128個字節(jié)就一定會讀取這么多,如果遇到了文件尾符號就會停止讀取。停止讀取的時候就會把讀取的字節(jié)數寫入到第四個參數指定的存儲空間里。所以我們可以通過返回的讀取字節(jié)數來發(fā)送到串口,不需要自己數讀取了多少個字節(jié)。
if(!f_open(&file, Path, FA_READ | FA_OPEN_EXISTING | FA_WRITE))
復制代碼
4、使用f_lseek
我在調用f_write函數之前,調用了一下f_lseek函數來移動文件指針。不過在這里并不需要,你們參考我的完整工程文件就知道。在這之前我已經進行了文件讀取的操作,文件指針已經定位在了文件的最后一個字節(jié)這里。不過我還是調用了一下,因為有時候需要用到這個函數。這個函數的詳細用法請參考FatFs的官方文檔網站。
5、使用f_write
f_write的用法和f_read非常相似,這里就不在贅述。第三個參數和第四個參數的含義也是大同小異。想了解這個函數的詳細說明,請參考FatFs的官方文檔網站。
f_lseek(&file, Number);
復制代碼
6、使用f_close
f_close這個函數的用法就非常的簡單了,這里在寫入操作之后要調用一次這個函數。調用了這個函數之后,寫入的信息才可以保存在SD卡的上面,下一次才可以讀取出來。如果沒有使用這個函數的話,文件就會存儲在緩沖區(qū)中,只有這一次讀取可以成功。到了下一次復位的時候,讀取的還是原先的文件內容。
f_close(&file);
復制代碼
7、再次讀取文件內容
現(xiàn)在我們有寫入了一些信息到了我們的文件里面,再次讀取一下看看寫入成功了嗎。下面的代碼實現(xiàn)了這一功能,大家參考一下。
f_open(&file, Path, FA_READ | FA_OPEN_EXISTING);
復制代碼
五、上電測試
代碼我們都準備好了,只要編譯通過下載到我們的開發(fā)板上就行了。如果你的硬件連接都非常的正確,而且按照前面的步驟來的話就可以開始測試讀取SD卡了。
我在SD卡的根目錄下建立了/File/test.txt
初始的文件內容如下:
This is a test file to confirm the library of FatFs.
Don't support Chinese in this file.
Wish you a good luck!
測試結果
觀察兩次的輸出結果可以看得出來,第二次復位的時候文件的末尾又多了一行文字。這一現(xiàn)象符合我們的程序邏輯。大家可以對比一下這里的結果,自己做一個參考。
寫在后面的話
注意!注意!注意!本人不是什么工程師,只不過是愛好嵌入式開發(fā)的學生一枚,如果你發(fā)現(xiàn)在這個帖子中的錯誤請及時提醒我。如果對本帖的內容有什么疑問請在下方留言,我會經常過來逛論壇的。
這次開發(fā)FatFs讀寫確實走了很多的彎路啊,結果最后發(fā)現(xiàn)不過是堆內存空間不夠,不能分配的錯誤而已。為了發(fā)現(xiàn)這個錯誤我也是找了很多的資料什么的,不過這就是學習的過程吧。我覺得只有這樣才能夠鍛煉我們發(fā)現(xiàn)問題和解決問題的能力。相信在這一次又一次的坎坷和曲折之中我一定會進步越來越大的。大家一起加油!
下一次給大家?guī)淼氖鞘裁茨??我現(xiàn)在貼出一張照片,大家一起猜一猜。
下一次要更新的東西會比較復雜的吧,所以時間可能會隔得比較久,希望期待下一篇帖子的社區(qū)成員多多關注。

 

 

本站聲明: 本文章由作者或相關機構授權發(fā)布,目的在于傳遞更多信息,并不代表本站贊同其觀點,本站亦不保證或承諾內容真實性等。需要轉載請聯(lián)系該專欄作者,如若文章內容侵犯您的權益,請及時聯(lián)系本站刪除。
換一批
延伸閱讀

LED驅動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關鍵字: 驅動電源

在工業(yè)自動化蓬勃發(fā)展的當下,工業(yè)電機作為核心動力設備,其驅動電源的性能直接關系到整個系統(tǒng)的穩(wěn)定性和可靠性。其中,反電動勢抑制與過流保護是驅動電源設計中至關重要的兩個環(huán)節(jié),集成化方案的設計成為提升電機驅動性能的關鍵。

關鍵字: 工業(yè)電機 驅動電源

LED 驅動電源作為 LED 照明系統(tǒng)的 “心臟”,其穩(wěn)定性直接決定了整個照明設備的使用壽命。然而,在實際應用中,LED 驅動電源易損壞的問題卻十分常見,不僅增加了維護成本,還影響了用戶體驗。要解決這一問題,需從設計、生...

關鍵字: 驅動電源 照明系統(tǒng) 散熱

根據LED驅動電源的公式,電感內電流波動大小和電感值成反比,輸出紋波和輸出電容值成反比。所以加大電感值和輸出電容值可以減小紋波。

關鍵字: LED 設計 驅動電源

電動汽車(EV)作為新能源汽車的重要代表,正逐漸成為全球汽車產業(yè)的重要發(fā)展方向。電動汽車的核心技術之一是電機驅動控制系統(tǒng),而絕緣柵雙極型晶體管(IGBT)作為電機驅動系統(tǒng)中的關鍵元件,其性能直接影響到電動汽車的動力性能和...

關鍵字: 電動汽車 新能源 驅動電源

在現(xiàn)代城市建設中,街道及停車場照明作為基礎設施的重要組成部分,其質量和效率直接關系到城市的公共安全、居民生活質量和能源利用效率。隨著科技的進步,高亮度白光發(fā)光二極管(LED)因其獨特的優(yōu)勢逐漸取代傳統(tǒng)光源,成為大功率區(qū)域...

關鍵字: 發(fā)光二極管 驅動電源 LED

LED通用照明設計工程師會遇到許多挑戰(zhàn),如功率密度、功率因數校正(PFC)、空間受限和可靠性等。

關鍵字: LED 驅動電源 功率因數校正

在LED照明技術日益普及的今天,LED驅動電源的電磁干擾(EMI)問題成為了一個不可忽視的挑戰(zhàn)。電磁干擾不僅會影響LED燈具的正常工作,還可能對周圍電子設備造成不利影響,甚至引發(fā)系統(tǒng)故障。因此,采取有效的硬件措施來解決L...

關鍵字: LED照明技術 電磁干擾 驅動電源

開關電源具有效率高的特性,而且開關電源的變壓器體積比串聯(lián)穩(wěn)壓型電源的要小得多,電源電路比較整潔,整機重量也有所下降,所以,現(xiàn)在的LED驅動電源

關鍵字: LED 驅動電源 開關電源

LED驅動電源是把電源供應轉換為特定的電壓電流以驅動LED發(fā)光的電壓轉換器,通常情況下:LED驅動電源的輸入包括高壓工頻交流(即市電)、低壓直流、高壓直流、低壓高頻交流(如電子變壓器的輸出)等。

關鍵字: LED 隧道燈 驅動電源
關閉