基于stm32cubemx对fatfs文件系统进行移植

发布者:悠闲之旅最新更新时间:2016-12-03 来源: eefocus关键字:stm32  cubemx  fatfs文件系统  移植 手机看文章 扫描二维码
随时随地手机看文章

今天要给大家分享的是使用FatFs这个库来读写SD卡上面的文件。工程的初始化函数和FatFs都是通过STM32CubeMX配置生成的,不需要我们手动添加库。 
今天分享的内容和我的上一篇帖子 SDIO读取SD卡的扇区 有关,最好掌握了SDIO读取SD卡扇区的基础之后再来看这一篇帖子。
写在前面的话
上一次发表了关于SDIO读取SD卡的一篇开发分享的帖子,今天呢就更进一步使用了FatFs文件系统。同样我们完全使用ST公司提供的STM32CubeMX软件和HAL库来进行开发。如果喜欢我的帖子请多多回复我会努力更新的。
我使用的工具
开发平台:正点原子探索者STM32F407开发板 
硬件:使用了NUCLEO-F446RE开发板的ST-Link作为调试器、SD卡、数据线、开发板的电源适配器、DELL一体机 
软件:STM32CubeMX、Keil V5、串口助手
学习的知识点
1、使用STM32CubeMX配置SDIO 
2、在Keil中初始化SDIO 
3、修改HEAP内存块的大小 
4、malloc函数的使用 
5、如何使用FatFs提供的一些库函数
共享的资源
完整的工程文件 FatFs.zip
STM32Cube中FatFs的中文帮助文档 
准备工作
参考 SDIO读取SD卡扇区 这篇帖子,这里不再赘述。
目录
一、在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卡扇区 中,SDIO的初始化也是要添加一点代码才可以正常的工作。这里也是一样,不过更加的简单。我们只需在MX_FATFS_Init();之前调用BSP_SD_Init();函数就可以了,我在下面贴出了这段初始化的代码。 
这里介绍一下BSP_SD_Init()函数。BSP的意思是板级支持包的意思,也就是这个函数是专门针对某一类芯片支持的。这个函数在文件bsp_driver_sd.c文件中,在这个文件里面还有很多的函数,这些函数完成了对读写SD卡、查询SD卡状态、初始化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卡成功的话就发送一个成功的消息。 
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字节的内存块 
返回值 
如果分配成功则返回指向被分配内存的指针(此存储区中的初始值不确定),否则返回空指针NULL。当内存不再使用时,应使用free()函数将内存块释放。函数返回的指针一定要适当对齐,使其可以用于任何数据对象。 
以上是百度百科对malloc函数的一些简介,在Keil中要使用这个函数需要包含stdlib.h头文件。同时在Keil的编译器设置中要选中microlib选项,不过使用STM32CubeMX生成的工程默认都选中了这一选项。这个函数是放在标准库里面的,所以不能找到这个的定义代码在哪里,编译的时候链接所属的库就可以了。
2、FatFs对malloc函数的调用
为了讨论FatFs和malloc函数的关系,我们要先打开MiddleWares/FatFs->syscall.c文件。在这个文件里面,我们可以看到有一些函数是分配内存的函数。滚动页面到最下面,可以看到最后两个函数都和分配内存有关。这些函数都调用了malloc函数来动态分配内存,在ST的手册中没有提到这个malloc。但是如果没有这个系统提供的malloc函数我们就需要自己来定义一个动态内存分配函数,同时把原来的malloc调用替换为我们提供的函数接口。 
这样我们就知道了FatFs对malloc函数有调用。但是仅仅如此吗?不是这么简单。FatFs默认是开启了对长文件名支持的,这样就需要很多的内存来存储文件名这些信息。如果malloc内存初始化的时候内存设置的比较小的话,就不能成功分配内存了不是吗?这样一来调用FatFs的f_open函数的时候就会返回17,查询这个枚举值的定义就知道是内存分配不足的错误。感兴趣的话可以不进行下一步修改heap的大小来调用f_open同时把返回值发送到串口来看一看。
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官方文档 网站。这里只想说一下第三个和第四个参数。这里的第三个参数是给定的要读取的字节数,而第四个参数是最后读取了的字节数的存储指针。这里要说明的是,不一定你要读取128个字节就一定会读取这么多,如果遇到了文件尾符号就会停止读取。停止读取的时候就会把读取的字节数写入到第四个参数指定的存储空间里。所以我们可以通过返回的读取字节数来发送到串口,不需要自己数读取了多少个字节。
if(!f_open(&file, Path, FA_READ | FA_OPEN_EXISTING | FA_WRITE)) 
复制代码
4、使用f_lseek
我在调用f_write函数之前,调用了一下f_lseek函数来移动文件指针。不过在这里并不需要,你们参考我的完整工程文件就知道。在这之前我已经进行了文件读取的操作,文件指针已经定位在了文件的最后一个字节这里。不过我还是调用了一下,因为有时候需要用到这个函数。这个函数的详细用法请参考FatFs的官方文档 网站
5、使用f_write
f_write的用法和f_read非常相似,这里就不在赘述。第三个参数和第四个参数的含义也是大同小异。想了解这个函数的详细说明,请参考FatFs的官方文档 网站
f_lseek(&file, Number); 
复制代码
6、使用f_close
f_close这个函数的用法就非常的简单了,这里在写入操作之后要调用一次这个函数。调用了这个函数之后,写入的信息才可以保存在SD卡的上面,下一次才可以读取出来。如果没有使用这个函数的话,文件就会存储在缓冲区中,只有这一次读取可以成功。到了下一次复位的时候,读取的还是原先的文件内容。
f_close(&file); 
复制代码
7、再次读取文件内容
现在我们有写入了一些信息到了我们的文件里面,再次读取一下看看写入成功了吗。下面的代码实现了这一功能,大家参考一下。
f_open(&file, Path, FA_READ | FA_OPEN_EXISTING); 
复制代码
五、上电测试
代码我们都准备好了,只要编译通过下载到我们的开发板上就行了。如果你的硬件连接都非常的正确,而且按照前面的步骤来的话就可以开始测试读取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! 
测试结果 
观察两次的输出结果可以看得出来,第二次复位的时候文件的末尾又多了一行文字。这一现象符合我们的程序逻辑。大家可以对比一下这里的结果,自己做一个参考。 
写在后面的话
注意!注意!注意!本人不是什么工程师,只不过是爱好嵌入式开发的学生一枚,如果你发现在这个帖子中的错误请及时提醒我。如果对本帖的内容有什么疑问请在下方留言,我会经常过来逛论坛的。 
这次开发FatFs读写确实走了很多的弯路啊,结果最后发现不过是堆内存空间不够,不能分配的错误而已。为了发现这个错误我也是找了很多的资料什么的,不过这就是学习的过程吧。我觉得只有这样才能够锻炼我们发现问题和解决问题的能力。相信在这一次又一次的坎坷和曲折之中我一定会进步越来越大的。大家一起加油! 
下一次给大家带来的是什么呢?我现在贴出一张照片,大家一起猜一猜。 
下一次要更新的东西会比较复杂的吧,所以时间可能会隔得比较久,希望期待下一篇帖子的社区成员多多关注。

关键字:stm32  cubemx  fatfs文件系统  移植 引用地址:基于stm32cubemx对fatfs文件系统进行移植

上一篇:s3c2410_gpio_setpin()与s3c2410_gpio_cfgpin()函数定义
下一篇:灵活使用ARM汇编的WEAK关键字

推荐阅读最新更新时间:2024-03-16 15:22

STM32 I/O口不能正常输出高低电平问题的解决方案
I/O口不能正常输出一般都是端口被复用了造成的,除了检查程序中是否有把端口复用的程序外,还应注意:有些端口在单片机上电时默认就是复用的,如与JTAG相关的PA13,PA14,PA15,PB3,PB4引脚,禁用JTAG或SWD可以释放其中的一些引脚,见表格: 具体做法: RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO ,ENABLE);//重映射需要先使能AFIO时钟 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE);//只关闭JTAG而保留SWD
[单片机]
使用STM32寄存器点亮LED灯
事先声明哦,我也是最近才开始学32的,不过我会尽可能详细的讲解这些小知识点 我们口中常说的LED灯其实是指LED发光二极管,关于这一点涉及到的知识点,我已经在51单片机教程中提及(同点亮LED灯),故而不再详述。 刚开始接触STM32的时候,觉得他的操作明显区别于51,比如我们点亮一个LED灯,直接控制相应的IO口即可;但32不一样,我们需要先设置时钟控制寄存器 RCC_APB2ENR|=1 4; //一共32位 然后设置它的工作方式,输出速度。 GPIOC_CRL&=~(0x0f (4*i)); //控制第i+1个led GPIOC_CRL|=(3 (4*i)); //3可以表示为0011,然后在它的前面补零,凑
[单片机]
使用<font color='red'>STM32</font>寄存器点亮LED灯
STM32单片机按键消抖和FPGA按键消抖大全
写在前面: STM32单片机按键消抖和FPGA按键消抖大全 按键去抖:由上图可以看出理想波形与实际波形之间是有区别的,实际波形在按下和释放的瞬间都有抖动的现象,抖动时间的长短和按键的机械特性有关,一般为5~10ms。通常我们手动按键然后释放,这个动作中稳定闭合的时间超过了20ms。因此单片机在检测键盘是否按下时都要加上去抖动操作,有专用的去抖动电路,也有专门的去抖动芯片,但通常我们采用软件延时的方法就可以解决抖动问题。 1. 单片机中按键消抖程序 1.1 单片机中,比如STM32中,一般的方法(最简单的方法) 软件消抖程序: if(GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_14
[单片机]
<font color='red'>STM32</font>单片机按键消抖和FPGA按键消抖大全
STM32 HAL HSE_VALUE
stm32f4xx.h默认25M外部晶振(HSE): 而我们正常情况是接8M晶振,所以要做修改,否则将会出现串口乱码等奇怪问题 #if !defined (HSE_VALUE) // #define HSE_VALUE (25000000U) /*! Value of the External oscillator in Hz */ #define HSE_VALUE (8000000U) /*! Value of the External oscillator in Hz */ #endif /* HSE_VALUE */
[单片机]
全新Netduino 3登陆Mouser 新增Wi-Fi连接功能 助力快速建立原型
贸泽电子(Mouser Electronics) 开始分销Netduino 3电子平台,能够使商业硬件解决方案和个人电子项目快速上市,同时提供了最大的设计灵活性并降低了风险。最新版本的开源Netduino平台不但具有让先前版本广受欢迎的最佳功能,还增加了Wi-Fi连接功能。 Mouser分销的 Netduino 3为针对Microsoft .NET Micro Framework而设计的开源电子平台,结合了高级编码的便利性与STM32 F4系列微控制器的原始功能集。Netduino 3基板型采用搭载168MHz ARM Cortex-M4处理器的32位STM32F427VG 微控制器(内置可实现读写同步的1MB双区
[嵌入式]
CRC校验 、STM32中CRC计算单元、 CRC应用
从这一段时间后台反馈的问题可以看得出来,好些朋友对CRC没有什么概念,今天就在这里讲述一下关于CRC校验、STM32中CRC计算单元相关内容。 1关于CRC校验 CRC:Cyclic Redundancy Check,即循环冗余校验码。 CRC是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定。 循环冗余检查(CRC)是一种数据传输检错功能,对数据进行多项式计算,并将得到的结果附在帧的后面,接收设备也执行类似的算法,以保证数据传输的正确性和完整性。 ---来自百度百科 学电子、计算机相关专业的同学都应该学习过CRC的基础原理。其原理说难不难,可以说就是一个公式。同时,说简单也不简单,这个公
[单片机]
CRC校验 、<font color='red'>STM32</font>中CRC计算单元、 CRC应用
STM32单片机--PWM输出
采用定时器2的通道2,使PA1输出频率1K,占空比40的PWM波形,用PA8随意延时取反led灯,指示程序运行 上午花了半天时间熟悉了stm32的PWM模块。中午利用午饭时间把PWM功能调试成功。当然,很简单的东西,也许很多前辈估计都不屑一顾的东西。 今天最大的感叹就是网络资源实在是个巨大的宝库,真的很庆幸,在这个复杂的社会环境里,在一个到处充斥着私心、私利的时代,各个网站,各个论坛上的众多网友都时刻保持着开源的氛围。学习一定要和他人交流,而网络提供了这么一个极好的平台。 废话少说,言归正传。 实现功能:采用定时器2的通道2,使PA1输出频率1K,占空比40的PWM波形,用PA8随意延时取反led灯,指示程序运行。
[单片机]
<font color='red'>STM32</font>单片机--PWM输出
STM32 USB NAND Flash模拟U盘无法格式化问题的解决
前几天,一直在寻找NAND Flash模拟U盘程序无法格式化的问题。在中秋月圆之夜,还苦逼地在实验室调代码,也许是杭州大圆月的原因,今晚感觉整人特别亢奋,效率也特别高,灵感也多。终于,在不懈的努力下,找到代码中的害群之马,把无法格式的问题解决掉了。下面就来说说。 这几天一直在想问题出在哪里,不知道自己的代码跟官方的例程对照了多少次,把不一样的地方全都改了一遍,最终未果。今晚思路特别清晰,于是在想到格式化实际上就是向存储器写数据而已,而设计到写数据部分的代码就只在mass_mal.c、memory.c以及存储器的驱动文件。于是反复检查这几个文件,终于发现一点端倪了,问题出在memroy.c这个文件里。 memory.c这个文
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved