STM32F4读写SD卡:从读写扇区到FATFS文件系统

使用STM32读写SD卡在低功耗存储中的应用是比较常见的,但是网上大多数资料都是基于标准库或者基于寄存器的开发。随着嵌入式设备越来越复杂,使用HAL库能够大大降低开发者的学习成本,从而提高开发效率。近年来,ST官方主推以STM32CubeMx为核心代码初始化工具,给开发者节省了配置硬件要花费的精力。

尽管上一篇博客填了ST留下来的坑,但是依然使用的是按扇区写入数据,通用性不是很好。因此本文探索使用FATFS这个模块来实现文件系统。

硬件准备

1、STM32F407VET6开发板,带SD卡槽

2、1G逻辑分析仪

软件准备

STM32CubeMX (本项目使用6.12.1版本)

IAR 9.50.2(本项目主要使用IAR,相比于Keil编译速度更快,生成的文件体积更小,若需要Keil版本的代码,可通过STM32CubeMX生成对应版本)

操作步骤

使用STM32CubeMx生成代码

1、配置RCC

2、配置调试器

3、配置SDIO,注意这里要配置DMA和SDIO全局中断,其它默认

4、添加一个串口用于调试

5、配置时钟树

6、这里配置FATFS

7、最后生成代码

修改代码

1、注意这里生成的代码是有问题的,需要给成1B,在前面一篇文章讲过

2、重定向printf函数输出到串口,用于调试

c 复制代码
#include <stdio.h>
int fputc(int ch, FILE *f) {
    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
    return ch;
}

3、主函数如下

c 复制代码
int main(void)
{

  /* USER CODE BEGIN 1 */
    
  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */
    
  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */
    
  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_DMA_Init();
  MX_SDIO_SD_Init();
  MX_USART1_UART_Init();
  MX_FATFS_Init();
  /* USER CODE BEGIN 2 */
  setvbuf(stdout, NULL, _IONBF, 0);

    /* 挂载文件系统 */
    FRESULT res;
    const TCHAR* SDPath = "0:";  // SD 卡路径
    res = f_mount(&SDFatFS, SDPath, 1);
    if (res != FR_OK)
    {
        printf("f_mount error: %d\n", res);
        if (res == FR_NO_FILESYSTEM)
        {
            printf("No filesystem, trying to format...\n");
            // 格式化 SD 卡
            res = f_mkfs(SDPath, FM_EXFAT, 0, work, sizeof(work));
            if (res == FR_OK)
            {
                printf("Format success, trying to mount again...\n");
                res = f_mount(&SDFatFS, SDPath, 1);
                if (res == FR_OK)
                {
                    printf("Mount success after format\n");
                }
                else
                {
                    printf("Mount failed after format, error: %d\n", res);
                    while(1);
                }
            }
            else
            {
                printf("Format failed, error: %d\n", res);
                while(1);
            }
        }
        else
        {
            while(1);
        }
    }
    else
    {
        printf("Mount success\n");
    }
    
    /* 打开文件进行写入 */
    res = f_open(&MyFile, "0:/data.txt", FA_READ | FA_WRITE | FA_CREATE_ALWAYS);
    if (res == FR_OK)
    {
        UINT byteswritten;
        
        /* 将 data 数组重复写入文件 100 次 */
        for (int i = 0; i < 1000; i++)
        {
            /* 写入数据 */
            res = f_write(&MyFile, data, strlen(data), &byteswritten);
            if ((res == FR_OK) && (byteswritten == strlen(data)))
            {
                printf("Data written successfully (%d/100)\n", i + 1);
            }
            else
            {
                printf("Failed to write data at iteration %d, error: %d\n", i + 1, res);
                break;  // 发生错误,退出循环
            }
        }
        
        /* 关闭文件 */
        f_close(&MyFile);
    }
    else
    {
        printf("Failed to open file for writing, error: %d\n", res);
    }
    
    /* 读取文件内容 */
    res = f_open(&MyFile, "0:/data.txt", FA_READ);
    if (res == FR_OK)
    {
        char buffer[64];
        UINT bytesread;
        
        printf("File content:\n");
        do
        {
            res = f_read(&MyFile, buffer, sizeof(buffer)-1, &bytesread);
            if (res == FR_OK)
            {
                buffer[bytesread] = '\0';
                printf("%s", buffer);
            }
            else
            {
                printf("Failed to read file, error: %d\n", res);
                break;
            }
        } while (bytesread > 0);
        
        /* 关闭文件 */
        f_close(&MyFile);
    }
    else
    {
        printf("Failed to open file for reading, error: %d\n", res);
    }
    
    
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
    while (1)
    {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
    }
  /* USER CODE END 3 */
}

4、结果如下

总结

可见,使用FATFS可以轻松实现数据的写入、读取,方便管理,大大降低了开发难度。后续结合以太网还可以实现FTP直接读取文件,或者直接将SD卡拔出来使用读卡器在PC上读取数据。

以上这些优点都是直接读取扇区无法做到的。

代码

https://github.com/dwgan/STM32F407_SDIO

在sdio_fatfs这个分支

相关推荐
星空真迷人6 小时前
嵌入式鸿蒙并非精简版,核心究竟是什么?
stm32·单片机·嵌入式硬件·物联网·华为·harmonyos·iot
hongmai6668886 小时前
GK7205V300芯片深度解析:H.265低功耗视觉主控,助力安防监控高效选型
arm开发·嵌入式硬件·物联网·智能家居·h.265·risc-v
微硬创新6 小时前
耐达讯自动化:16路4-20mA模拟信号,该怎样平稳接入PROFINET控制系统?
人工智能·物联网·网络协议·自动化·信息与通信
云边云科技_云网融合7 小时前
金融医疗混合云组网如何满足数据安全与合规要求?
大数据·人工智能·物联网
mengpp_1234568 小时前
物联网云平台可以离线使用吗?摒弃云端依赖,工业现场离线自动化解决方案
运维·物联网·自动化·华为云
武汉唯众智创9 小时前
高职物联网应用技术专业实训室怎么建?嵌入式开发实训室建设方案详解
物联网·物联网实训室·物联网嵌入式实训室·物联网实训室解决方案
星恒讯工业路由器10 小时前
2G/3G网络退网趋势解读:对工业物联网设备的影响与应对策略
物联网·信息与通信·工业物联网·工业通信·5g redcap·2g3g退网·4g/5g升级
科莱特SAP10 小时前
精准匹配双向赋能:科莱特数智人才猎场重塑数字化人才服务模式
大数据·人工智能·物联网·人力资源·科莱特·科莱特人才服务
延凡科技20 小时前
工业锅炉智慧云管控平台解决方案|物联网远程监测、智能预警与能耗优化
物联网·远程控制·工业物联网·设备运维·智慧锅炉
数字新视界1 天前
IT资产管理系统推动智能化运维与资源更优化管理
物联网·机房管理·蓄电池·动力与环境监控系统·机房动力环境监控