[APM32F407]单片机中使用文件系统FATFS(SDIO接口SD卡)

引:
        最小的文件系统,可以是控制U盘的时候,实现,也可以是控制SD卡的时候实现,甚至是一颗FLASH芯片也可以做最小的文件系统FATFS。这篇文章,说一下如何使用SDIO接口形式对SD卡进行操作​:
        主芯片:APM32F​4系列单片机。
        ​接口形式:SDIO
        开发环境​:KEIL
        ​FATFS版本:R0.11a
 


一、FATFS下载
        可以直接在官网进行下载。​这部分是开源的。​官网地址如下:
http://elm-chan.org/
​       


        进入官网之后,选择softwares
 


        在softwares中选择FatFs Module​,进入之后,拉到网页的最下端,看见版本号,进行下载,现在的版本号已经更新到R0.15:      
 


二、将FATFS添加到工程中
       将以下几个文件添加到项目中:

复制

diskio.c

ff.c

cc936.c

bsp_sdio.sd.c


 


       前面的几个文件可以不修改,主要查看bsp_sdio_sd.c文件的管脚是否使用正确,​打开C文件,查看一下。

复制

voidSD_LowLevel_DeInit(void)

{

    GPIO_InitTypeDef  GPIO_InitStructure;    /*!< Disable SDIO Clock */  

    SDIO_ClockCmd(DISABLE);    /*!< Set Power State to OFF */  

    SDIO_SetPowerState(SDIO_PowerState_OFF);​  /*!< DeInitializes the SDIO peripheral */  

    SDIO_DeInit();    /* Disable the SDIO APB2 Clock */  

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDIO, DISABLE);​  

    GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_MCO);  

    GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_MCO);  

    GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_MCO);  

    GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_MCO);  

    GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_MCO);  

    GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_MCO);​  /* Configure PC.08, PC.09, PC.10, PC.11 pins: D0, D1, D2, D3 pins */  

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;  

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;  

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;  

    GPIO_Init(GPIOC, &GPIO_InitStructure);​  /* Configure PD.02 CMD line */  

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;  

    GPIO_Init(GPIOD, &GPIO_InitStructure);​  /* Configure PC.12 pin: CLK pin */  

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;  

    GPIO_Init(GPIOC, &GPIO_InitStructure);

}

​

voidSD_LowLevel_Init(void)

{  

    GPIO_InitTypeDef  GPIO_InitStructure;​  /* GPIOC and GPIOD Periph clock enable */  

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOC | RCC_AHB1Periph_GPIOD, ENABLE);​  

    GPIO_PinAFConfig(GPIOC, GPIO_PinSource8, GPIO_AF_SDIO);  

    GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_SDIO);  

    GPIO_PinAFConfig(GPIOC, GPIO_PinSource10, GPIO_AF_SDIO);  

    GPIO_PinAFConfig(GPIOC, GPIO_PinSource11, GPIO_AF_SDIO);  

    GPIO_PinAFConfig(GPIOC, GPIO_PinSource12, GPIO_AF_SDIO);  

    GPIO_PinAFConfig(GPIOD, GPIO_PinSource2, GPIO_AF_SDIO);​  /* Configure PC.08, PC.09, PC.10, PC.11 pins: D0, D1, D2, D3 pins */  

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_11;  

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;  

    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;  

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;  

    GPIO_Init(GPIOC, &GPIO_InitStructure);​  /* Configure PD.02 CMD line */  

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;  

    GPIO_Init(GPIOD, &GPIO_InitStructure);​  /* Configure PC.12 pin: CLK pin */  

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;  

    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;  

    GPIO_Init(GPIOC, &GPIO_InitStructure);​  /* Enable the SDIO APB2 Clock */  

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_SDIO, ENABLE);​  /* Enable the DMA2 Clock */  

    RCC_AHB1PeriphClockCmd(SD_SDIO_DMA_CLK, ENABLE);

}


        以下是SD卡初始化函数:

复制

SD_Error SD_Init(void)

{  

    __IO SD_Error errorstatus = SD_OK;    /**************配置SDIO中断 DMA中断**********************/  

    NVIC_InitTypeDef NVIC_InitStructure;    // Configure the NVIC Preemption Priority Bits   

    NVIC_PriorityGroupConfig (NVIC_PriorityGroup_1);  

    NVIC_InitStructure.NVIC_IRQChannel = SDIO_IRQn;  

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;  

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;  

    NVIC_Init (&NVIC_InitStructure);  

    NVIC_InitStructure.NVIC_IRQChannel = SD_SDIO_DMA_IRQn;  

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;  

    NVIC_Init (&NVIC_InitStructure);  /**********************************************************/    /* SDIO Peripheral Low Level Init */  

    SD_LowLevel_Init();​  

    SDIO_DeInit();​  

    errorstatus = SD_PowerON();​  

    if (errorstatus != SD_OK)  

    {    /*!< CMD Response TimeOut (wait for CMDSENT flag) */    

        return(errorstatus);  

    }​  

    errorstatus = SD_InitializeCards();​  

    if (errorstatus != SD_OK)  

    {    /*!< CMD Response TimeOut (wait for CMDSENT flag) */    

        return(errorstatus);  

    }​  /*!< Configure the SDIO peripheral */  /*!< SDIO_CK = SDIOCLK / (SDIO_TRANSFER_CLK_DIV + 2) */  /*!< on STM32F4xx devices, SDIOCLK is fixed to 48MHz */  

    SDIO_InitStructure.SDIO_ClockDiv = SDIO_TRANSFER_CLK_DIV;  

    SDIO_InitStructure.SDIO_ClockEdge = SDIO_ClockEdge_Rising;  

    SDIO_InitStructure.SDIO_ClockBypass = SDIO_ClockBypass_Disable;  

    SDIO_InitStructure.SDIO_ClockPowerSave = SDIO_ClockPowerSave_Disable;  

    SDIO_InitStructure.SDIO_BusWide = SDIO_BusWide_1b;  

    SDIO_InitStructure.SDIO_HardwareFlowControl = SDIO_HardwareFlowControl_Disable;  

    SDIO_Init(&SDIO_InitStructure);​  /*----------------- Read CSD/CID MSD registers ------------------*/  

    errorstatus = SD_GetCardInfo(&SDCardInfo);​  

    if (errorstatus == SD_OK)  

    {    /*----------------- Select Card --------------------------------*/    

        errorstatus = SD_SelectDeselect((uint32_t)

         (SDCardInfo.RCA << 16));  

    }​  

    if (errorstatus == SD_OK)  

    {    

        errorstatus = SD_EnableWideBusOperation(SDIO_BusWide_4b);  

    }  ​  

    return(errorstatus);

}


三、应用接口函数
        在刚刚下载的网站中可以看见应用的接口函数,这部分重点说明一下:
打开文件函数f_open函数,这个函数既可以作为打开文件的函数,也可以作为建立文件的函数,里面含有打开文件的模式“只读”,“读、写”,“创建、写”等等,根据自己的需要进行打开或者建立文件。如果查看SD卡中没有相应的文件,会直接建立该文件名的文件。
关闭文件,关闭文件和打开文件相对应的,可以形象的知道在win操作中,打开一个文件的话,如果不关闭文件是无法保存编辑的过程。所以在操作文件的时候,必然最后要进行关闭文件,不然无法进行文件的编辑操作。
读取文件,打开文件之后,进行读取,需要设定读取的指针还有读取数据到哪个缓冲区中,需要建立一个缓冲区,然后将读取的数据赋值到缓冲区中,方便后续的调用操作。
写入文件,写入文件的时候,需要使用到另外一个函数f_lseek函数,这个函数之前的时候没有用好,在后续的例子程序中有说明。
F_mount函数,这个函数的作用是建立工作区,在FAT系统中进行工作区的建立,后续的代码中有这方面的说明。
F_mkfs函数,这个函数的作用是检查SD卡的系统是否是FAT系统,如果不是fat系统,那么会在SD卡中建立一个FAT系统,在这里可以选用FAT32进行格式化操作。
 


        当然,也可以在ff.h中进行查看​接口函数的说明。
 


四、实际操作
       在c文件开始部分增加以下​引用,文件系统对象的定义,文件对象的定义,文件操作结果的定义,文件成功读写的数量,需要定义四个变量,我们在跟踪调试的时候,主要查看res_sd变量是否为ok是很重要的。

复制

#include "ff.h"

FATFS fs;             /* FatFs文件系统对象 */

FIL fnew;             /* 文件对象 */

FRESULT res_sd;       /* 文件操作结果 */

UINT fnum;            /* 文件成功读写数量 */


        查看SD卡中是否存在文件系统,如果不存在,我们进行格式化​SD操作。这里就用到了上文提到的两个函数,建立空间和FAT系统函数。

复制

//SD卡文件初始化,查看卡中有多少文件

voidSD_file_test(void)

{   

    char path[16]={""};   

    res_sd = f_mount(&fs,"0:",1);   

    if(res_sd == FR_NO_FILESYSTEM)   

    {        

        res_sd=f_mkfs("0:",0,0);        

        if(res_sd == FR_OK)        

        {            

            res_sd = f_mount(NULL,"0:",1);            

            res_sd = f_mount(&fs,"0:",1);        

        }   

    }   

    scan_files(path);   

    f_mount(NULL,"0:",1);

}


        建立一个0:00.csv的文件,当然这里面也可以建立一个txt文件,或者是建立dat文件,无论建立哪种形式的文件,将SD卡取出放到读卡器中,接入电脑,都可以用文本文件的形式进行打开,查看在文件中写入的内容,这个文件的格式也是采用8+3的格式进行建立的。标准的格式。

复制

//建立0.00的CSV文件

voidSD_WFile_Init(void)

{   

    unsignedchar numberTmp;   

    TCHAR filenameTmp[13]="0:00.csv";   

    res_sd = f_mount(&fs,"0:",1);   

    if(res_sd == FR_NO_FILESYSTEM)   

    {        

        res_sd=f_mkfs("0:",0,0);        

        if(res_sd == FR_OK)        

        {            

            res_sd = f_mount(NULL,"0:",1);            

            res_sd = f_mount(&fs,"0:",1);        

        }   

    }   

    numberTmp = filenumber;   

    if((numberTmp==0)||(numberTmp==50))   

    {        

        filenameTmp[3] = '1';   

    }   

    else

    {        

        if(numberTmp>9)        

        {            

            filenameTmp[2] = (numberTmp +1)/10+ 0x30;            

            filenameTmp[3] = (numberTmp +1)%10+ 0x30;        

        }        

        else

        {            

            filenameTmp[3] = numberTmp + 1 + 0x30;        

        }   

    }   

    f_open(&fnew, filenameTmp,FA_CREATE_ALWAYS | FA_WRITE );

}


        将buffer中的数据写入到0:00.csv中,这部分使用的函数,就是先进行指针的判断,查看文件中包含多少字节,用到的函数就是前面提到的f_lseek函数,先把文件尾部的指针确定之后,再将buf中的数据写入到文件中,如果没有f_lseek函数,那么指针还是从0开始的,也就是从文件的开始进行写入,会覆盖之前写入的内容。这部分需要注意下。

复制

//文件写入

voidSD_WFile_Write(void)

{   

     res_sd=f_lseek(&fnew,fnew.fsize);   

     res_sd=f_write(&fnew,buffer,sizeof(buffer),&fnum);

}


        写完文件之后,记得关闭文件,关闭文件的同时,将工作区也一并进行关闭才是可以的。关闭文件之后,将SD卡通过读卡器接入电脑,才可以查看文件中的内容,不然会发现是一个空文件。

复制

//文件关闭

voidSD_WFile_Close(void)

{   

    f_close(&fnew);   

    f_mount(NULL,"0:",1);

}


结:
        以上就是单片机对文件系统的操作,只要是单片机带有SDIO接口的话,都可以直接应用这样的方式进行文件的建立和​操作。如果大家感兴趣的话,后续可以做一些SPI接口的SD卡的文件系统,同时,也可以在flash中进行文件系统的移植工作。

d257e7bccc8af1a6c8153eb8edd79235 (28.28 KB )

d257e7bccc8af1a6c8153eb8edd79235

736cd77f6974305b13842ed02eb19ccf (52.7 KB )

736cd77f6974305b13842ed02eb19ccf

238ad0625d3a03edcb00b4d1e2d27c89 (24.19 KB )

238ad0625d3a03edcb00b4d1e2d27c89

e4bd8783d11aca14da19b3f594f039e2 (25.1 KB )

e4bd8783d11aca14da19b3f594f039e2

7383acaf6147c6849e4c1515bcb90b95 (237.83 KB )

7383acaf6147c6849e4c1515bcb90b95

236ecf39914abbfd03c0946477192e8d (702.39 KB )

236ecf39914abbfd03c0946477192e8d

0917b0f57e4aff591c99fa8e288a4168


---------------------
作者:单片小菜
链接:https://bbs.21ic.com/icview-3319070-1-1.html
来源:21ic.com
此文章已获得原创/原创奖标签,著作权归21ic所有,任何人未经允许禁止转载。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值