STM32CubeMX+SPI+FATFS实现SD卡文件系统移植与数据记录

发布时间:2026/6/28 19:40:27

STM32CubeMX+SPI+FATFS实现SD卡文件系统移植与数据记录 1. 环境准备与硬件连接在开始SD卡文件系统移植之前我们需要准备好开发环境和硬件设备。我用的是正点原子mini开发板核心芯片是STM32F103RCT6搭配一张8GB的microSD卡。这里有个小建议最好使用容量不超过32GB的SD卡因为大容量卡可能需要额外处理。硬件连接非常简单SD卡通过SPI接口与STM32通信。具体接线如下SD卡MOSI接PA7SD卡MISO接PA6SD卡SCK接PA5SD卡CS接PA3开发软件方面我使用的是STM32CubeMX 6.6.1和Keil MDK 5.29。如果你用其他版本配置过程可能略有不同。建议先检查下你的开发环境是否完整特别是STM32CubeMX的FATFS中间件是否已经安装。2. STM32CubeMX工程配置打开STM32CubeMX新建工程选择你的STM32型号。我这里以STM32F103RCT6为例。2.1 基础外设配置首先配置时钟树我习惯使用外部8MHz晶振通过PLL倍频到72MHz主频。然后依次配置SYSDebug选择Serial WireRCCHSE选择Crystal/Ceramic ResonatorUSART1用于调试输出波特率1152002.2 SPI接口配置找到SPI1进行配置ModeFull-Duplex MasterHardware NSSDisablePrescaler选择8分频9MHzClock PolarityLowClock Phase1 EdgeData Size8bitFirst BitMSB2.3 FATFS中间件配置在Middleware选项卡中找到FATFS勾选Use FATFSDrive选择SD CardUse the disk I/O driver勾选File System选择FAT32Enable long file names建议选择LFN with static LFN working buffer这里有个关键点如果你的SD卡是FAT32格式但系统识别不到可能需要调整MAX_SS参数。我遇到过这个问题把默认的512改为4096就解决了。3. 底层驱动适配3.1 SPI底层驱动实现在生成的代码中我们需要完善SPI的读写函数。打开spi.c文件添加以下代码// SPI速度设置函数 void SPI1_SetSpeed(u8 prescaler) { assert_param(IS_SPI_BAUDRATE_PRESCALER(prescaler)); __HAL_SPI_DISABLE(hspi1); hspi1.Instance-CR1 0xFFC7; hspi1.Instance-CR1 | prescaler; __HAL_SPI_ENABLE(hspi1); } // SPI读写一个字节 u8 SPI1_ReadWriteByte(u8 TxData) { u8 Rxdata; HAL_SPI_TransmitReceive(hspi1, TxData, Rxdata, 1, 1000); return Rxdata; }3.2 SD卡驱动实现新建mmc_sd.c和mmc_sd.h文件实现SD卡底层驱动。关键函数包括// SD卡初始化 u8 SD_Init(void) { u8 r1; u16 retry; u8 buf[4]; SD_SPI_Init(); SD_SPI_SpeedLow(); for(u8 i0;i10;i) SD_SPI_ReadWriteByte(0XFF); retry20; do { r1SD_SendCmd(CMD0,0,0x95); }while((r1!0X01) retry--); // ... 省略后续初始化代码 }这里有个坑要注意SD卡初始化时需要先低速通信初始化完成后再切换到高速。我刚开始没注意这点导致初始化总是失败。4. FATFS接口适配4.1 user_diskio.c实现这是连接FATFS和SD卡驱动的关键文件。我们需要实现以下几个函数// 初始化函数 DSTATUS USER_initialize(BYTE pdrv) { if(SD_Init() 0) return RES_OK; else return RES_ERROR; } // 读扇区函数 DRESULT USER_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count) { u8 res SD_ReadDisk(buff, sector, count); if(res 0) return RES_OK; else return RES_ERROR; } // 写扇区函数 DRESULT USER_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count) { u8 res SD_WriteDisk((u8*)buff, sector, count); if(res 0) return RES_OK; else return RES_ERROR; }4.2 文件系统测试在main.c中添加测试代码void FatfsTest(void) { FRESULT fr; FIL fil; UINT bw; char buf[100]; // 挂载文件系统 fr f_mount(USERFatFS, USERPath, 1); if(fr ! FR_OK) { printf(Mount error: %d\r\n, fr); return; } // 创建并写入文件 fr f_open(fil, test.txt, FA_CREATE_ALWAYS | FA_WRITE); if(fr FR_OK) { f_write(fil, Hello FATFS!\r\n, 14, bw); f_close(fil); } // 读取文件内容 fr f_open(fil, test.txt, FA_READ); if(fr FR_OK) { f_read(fil, buf, sizeof(buf), bw); printf(File content: %s\r\n, buf); f_close(fil); } // 卸载文件系统 f_mount(NULL, USERPath, 0); }5. 常见问题排查在实际项目中我遇到过几个典型问题SD卡无法识别检查硬件连接特别是CS引脚。确保SPI时钟在初始化阶段不超过400kHz。文件写入失败可能是文件系统格式问题。建议在电脑上格式化SD卡为FAT32格式分配单元大小选择4096字节。长时间运行后数据丢失记得在每次文件操作后调用f_sync()函数确保数据写入物理存储。内存不足在CubeMX配置中增大堆栈大小我一般设置Heap Size为0x1000Stack Size为0x800。中文文件名乱码需要在ffconf.h中设置_CODE_PAGE为936并启用LFN支持。这个方案我已经在多个环境监测项目中实际应用包括温湿度记录仪和空气质量监测设备。实测可以稳定记录数据每5秒写入一次连续工作30天无异常。关键是要做好错误处理比如在写入失败时尝试重新初始化SD卡。

相关新闻