[STM32H7] 【STM32H7S78-DK测评】6、SD卡列出目录,读写文件

[复制链接]
 楼主| sujingliang 发表于 2024-9-16 07:02 | 显示全部楼层 |阅读模式
<
本帖最后由 sujingliang 于 2024-9-16 07:10 编辑

目的
通过FatFs (Generic FAT Filesystem module)访问SD卡,读写文件,列出文件目录,通过串口输出结果。
FatFs Module是一种完全免费开源的FAT文件系统模块,专为小型的嵌入式系统而设计。
FatFs Module提供了一系列的文件操作接口,如文件的打开、关闭、读写、移动指针、获取状态等。这些接口函数使得在嵌入式系统中操作文件变得像在PC上一样简单。以下是一些常用的接口函数:

  • f_mount:登记或注销一个工作区域。
  • f_open:打开或创建文件。
  • f_close:关闭一个文件。
  • f_read:从文件中读取数据。
  • f_write:向文件写入数据。
  • f_lseek:移动文件读/写指针。
  • f_stat:获取文件状态。
  • f_mkdir:创建一个目录。
  • f_unlink:删除文件或目录。
  • f_rename:重命名或移动文件/目录。


编译环境:keil5.40


一、硬件方面
0916_1.png
DAT0:数据传输引脚,主要用于单线双向数据传输。在四线数据传输模式中,它也是四根数据线之一,用于高速数据传输。
DAT1、DAT2、DAT3:附加数据传输引脚,在支持四线数据传输的SD卡中,这些引脚与DAT0共同工作,实现高速数据传输。在某些规范中,这些引脚可能会被省略或用作其他目的。

CMD(命令传输引脚):用于主机和SD卡之间的命令传输。主机通过CMD引脚向SD卡发送命令,SD卡则通过CMD引脚或DAT引脚(取决于命令类型)返回响应。
CLK(时钟引脚):提供时钟信号以同步数据传输。CLK引脚控制数据传输的速率和同步性,确保主机和SD卡之间的数据交换能够准确无误地进行
SD卡的DETECT引脚(通常也标记为CD引脚)主要用于检测SD卡是否已正确插入到设备中。这一引脚在SD卡与设备之间的通信中起着至关重要的作用,它允许设备在SD卡插入或拔出时采取相应的操作,如初始化SD卡、读取数据或关闭数据传输等。


二、功能实现
1、为方便调试,利用STM32H7S78-DK的BSP库函数文件stm32h7s78_discovery支持板载LED、UART4:
  1.   BSP_LED_Init(LED_GREEN);
  2.   BSP_LED_Init(LED_RED);
  3.   BSP_LED_Init(LED_ORANGE);
  4.   BSP_LED_Init(LED_BLUE);

  1. /* Initialize COM1 port (115200, 8 bits (7-bit data + 1 stop bit), no parity */
  2.     BspCOMInit.BaudRate   = 115200;
  3.     BspCOMInit.WordLength = COM_WORDLENGTH_8B;
  4.     BspCOMInit.StopBits   = COM_STOPBITS_1;
  5.     BspCOMInit.Parity     = COM_PARITY_NONE;
  6.     BspCOMInit.HwFlowCtl  = COM_HWCONTROL_NONE;
  7.     if (BSP_COM_Init(COM1, &BspCOMInit) != BSP_ERROR_NONE)
  8.     {
  9.       Error_Handler();
  10.     }
2、SD_DETECT引脚初始化
SD_DECTECT需要设置为外部中断引脚
  1.   GPIO_InitStruct.Pin = SD_DETECT_Pin;
  2.   GPIO_InitStruct.Mode = GPIO_MODE_IT_RISING_FALLING;
  3.   GPIO_InitStruct.Pull = GPIO_PULLUP;
  4.   HAL_GPIO_Init(SD_DETECT_GPIO_Port, &GPIO_InitStruct);

  5.   /* EXTI interrupt init*/
  6.   HAL_NVIC_SetPriority(SD_DETECT_EXTI_IRQn, 5, 0);
  7.   HAL_NVIC_EnableIRQ(SD_DETECT_EXTI_IRQn);


3、SD卡的初始化

MX_SDMMC1_SD_Init()
  1. /**
  2.   * [url=home.php?mod=space&uid=247401]@brief[/url] SDMMC1 Initialization Function
  3.   * @param None
  4.   * @retval None
  5.   */
  6. void MX_SDMMC1_SD_Init(void)
  7. {

  8.   /* USER CODE BEGIN SDMMC1_Init 0 */

  9.   /* USER CODE END SDMMC1_Init 0 */

  10.   /* USER CODE BEGIN SDMMC1_Init 1 */

  11.   /* USER CODE END SDMMC1_Init 1 */
  12.   hsd1.Instance = SDMMC1;
  13.   hsd1.Init.ClockEdge = SDMMC_CLOCK_EDGE_FALLING;
  14.   hsd1.Init.ClockPowerSave = SDMMC_CLOCK_POWER_SAVE_DISABLE;
  15.   hsd1.Init.BusWide = SDMMC_BUS_WIDE_4B;
  16.   hsd1.Init.HardwareFlowControl = SDMMC_HARDWARE_FLOW_CONTROL_ENABLE;
  17.   hsd1.Init.ClockDiv = 0x02;

  18.   if(HAL_SD_Init(&hsd1) != HAL_OK)
  19.   {
  20.     Error_Handler();
  21.   }
  22.   /* USER CODE BEGIN SDMMC1_Init 2 */

  23.   /* USER CODE END SDMMC1_Init 2 */

  24. }
4、FatFs 初始化
用到了FREERTOS建立了一个uSDThread_Entry和一个队列
  1. void MX_FATFS_Init(void)
  2. {
  3.   /* USER CODE BEGIN Init */
  4.   /* additional user code for init */
  5.   /*## FatFS: Link the disk I/O driver(s)  ###########################*/
  6.   if (FATFS_LinkDriver(&SD_DMA_Driver, SDPath) == 0)
  7.   {
  8.     /* creation of uSDThread */
  9.     FSAppThreadHandle = osThreadNew(uSDThread_Entry, NULL, &uSDThread_attributes);

  10.     /* Create Storage Message Queue */
  11.     QueueHandle = osMessageQueueNew(1U, sizeof(uint16_t), NULL);
  12.   }
  13.   /* USER CODE END Init */
  14. }
5、uSDThread_Entry
用来处理队列的各种消息,并做对应处理
  1. static void uSDThread_Entry(void *argument)
  2. {
  3.   osStatus_t status;

  4.     if(SD_IsDetected())
  5.     {
  6.       osMessageQueuePut (QueueHandle, &CARD_CONNECTED, 100, 0U);
  7.     }

  8.   /* Infinite Loop */
  9.   for( ;; )
  10.   {
  11.     status = osMessageQueueGet(QueueHandle, &osQueueMsg, NULL, 100);

  12.     if ((status == osOK) && (osQueueMsg== CARD_STATUS_CHANGED))
  13.     {
  14.         if (SD_IsDetected())
  15.         {
  16.           osMessageQueuePut (QueueHandle, &CARD_CONNECTED, 100, 0U);
  17.         }
  18.         else
  19.         {
  20.           osMessageQueuePut (QueueHandle, &CARD_DISCONNECTED, 100, 0U);
  21.         }
  22.      }

  23.      if ((status == osOK) && (osQueueMsg== CARD_CONNECTED))
  24.      {
  25.         //sHAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_SET);
  26.                                 BSP_LED_On(LED_BLUE);
  27.         //FS_FileOperations();
  28.                                 FS_listDirectory();
  29.         statusChanged = 0;
  30.      }

  31.      if ((status == osOK) && (osQueueMsg== CARD_DISCONNECTED))
  32.      {
  33.         HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_SET);
  34.         HAL_GPIO_TogglePin(LED2_GPIO_Port, LED2_Pin);
  35.         osDelay(200);

  36.         f_mount(NULL, (TCHAR const*)"", 0);
  37.         statusChanged = 0;
  38.      }
  39.   }
  40. }
在收到CARD_CONNECTED消息后,会执行FS_listDirectory()

6、SD_DECTECT外部中断处理函数
判断SD_DETECT状态,如果发生改变,向队列中发送CARD_STATUS_CHANGED消息。
  1. void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
  2. {
  3.   if(GPIO_Pin == SD_DETECT_Pin)
  4.   {
  5.      if (statusChanged == 0)
  6.      {
  7.        statusChanged = 1;
  8.        osMessageQueuePut ( QueueHandle, &CARD_STATUS_CHANGED, 100, 0U);
  9.      }
  10.   }
  11. }


7、FS_listDirectory
在这里利用FatFs提供的函数:
f_mount挂载SD。
f_opendir打开"/"目录
f_readdir读取"/"目录
通过循环打印出目录下所有文件名和文件大小

  1. static void FS_listDirectory(void)
  2. {
  3.         FRESULT res;
  4.         DIR dir;
  5.         FILINFO fno;
  6.         uint32_t bytesread;
  7.         
  8.         printf("【1】列出目录中文件内容:\r\n");
  9.   if(f_mount(&SDFatFs, (TCHAR const*)SDPath, 0) == FR_OK)
  10.   {
  11.                 printf("mount SD success\r\n");
  12.                 res = f_opendir(&dir, "/");
  13.                 if (res == FR_OK) {
  14.                                 printf("open directory success\r\n");
  15.                                 printf("list directory / files:\r\n");
  16.         for (;;) {
  17.             res = f_readdir(&dir, &fno);
  18.             if (res != FR_OK || fno.fname[0] == 0) break; // 读取错误或结束标志
  19.             if (fno.fname[0] == '.') continue; // 跳过隐藏文件
  20.             printf("%s  %d\r\n", fno.fname,fno.fsize); // 打印文件名
  21.         }
  22.                         
  23.         f_closedir(&dir);
  24.                 }
  25.                
  26.                 if(f_open(&SDFile, "STM32_1.TXT", FA_READ) == FR_OK)
  27.                 {
  28.                         /* Read data from the text file */
  29.                         res = f_read(&SDFile, ( void *)rtext, sizeof(rtext), (void *)&bytesread);

  30.                         if((bytesread > 0) && (res == FR_OK))
  31.                         {
  32.                                 printf("\r\nSTM32_1.TXT file content:%s\r\n",rtext);
  33.                                 /* Close the open text file */
  34.                                 f_close(&SDFile);
  35.                         }
  36.                 }
  37.         }               
  38. }
8、另外FS_FileOperations函数实现了对文件读写
f_mkfs:建立文件系统,相当于格式化。
  1. static void FS_FileOperations(void)
  2. {
  3.   FRESULT res;                                          /* FatFs function common result code */
  4.   uint32_t byteswritten, bytesread;                     /* File write/read counts */


  5.   /* Register the file system object to the FatFs module */
  6.   if(f_mount(&SDFatFs, (TCHAR const*)SDPath, 0) == FR_OK)
  7.   {
  8.         printf("mount SD success\r\n");
  9.     /* check whether the FS has been already created */
  10.     if (isFsCreated == 0)
  11.     {
  12.                         /*
  13.       if(f_mkfs(SDPath, &OptParm, workBuffer, sizeof(workBuffer)) != FR_OK)
  14.       {
  15.             printf("make file system success\r\n");
  16.         HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);
  17.         return;
  18.       }
  19.       isFsCreated = 1;
  20.                         */
  21.     }
  22.     /* Create and Open a new text file object with write access */
  23.     if(f_open(&SDFile, "STM32_1.TXT", FA_CREATE_ALWAYS | FA_WRITE) == FR_OK)
  24.     {
  25.             printf("open STEM32.TXT success\r\n");
  26.       /* Write data to the text file */
  27.       res = f_write(&SDFile, (const void *)wtext, sizeof(wtext), (void *)&byteswritten);

  28.       if((byteswritten > 0) && (res == FR_OK))
  29.       {
  30.             printf("write finished, close STEM32.TXT success\r\n");
  31.         /* Close the open text file */
  32.         f_close(&SDFile);

  33.         /* Open the text file object with read access */
  34.         if(f_open(&SDFile, "STM32_1.TXT", FA_READ) == FR_OK)
  35.         {
  36.           /* Read data from the text file */
  37.           res = f_read(&SDFile, ( void *)rtext, sizeof(rtext), (void *)&bytesread);

  38.           if((bytesread > 0) && (res == FR_OK))
  39.           {
  40.                   printf("open finished, close STEM32.TXT success\r\n");
  41.             /* Close the open text file */
  42.             f_close(&SDFile);

  43.             /* Compare read data with the expected data */
  44.             if(bytesread == byteswritten)
  45.             {
  46.                     printf("read and written bytes are same\r\n");
  47.               /* Success of the demo: no error occurrence */
  48.               //HAL_GPIO_WritePin(LED1_GPIO_Port, LED1_Pin, GPIO_PIN_RESET);
  49.                                                         BSP_LED_On(LED_RED);
  50.               return;
  51.             }
  52.           }
  53.         }
  54.       }
  55.     }
  56.   }
  57.   /* Error */
  58.   //HAL_GPIO_WritePin(LED2_GPIO_Port, LED2_Pin, GPIO_PIN_RESET);
  59.         BSP_LED_On(LED_BLUE);
  60. }


三、效果
通过串口获得结果:
列出了SD卡上的3个文件,其中SYSTEM~1是系统文件,其他2个是自己建的,并打印出了STM32_1.TXT文件内容。
0916_2.png


将SD卡插入读卡器并连上电脑,我用的带SD卡的收音机,可以看到被识别了U盘,可以看到下面有2个文件。
0916_3.png

呈兴 发表于 2024-9-20 22:54 来自手机 | 显示全部楼层
专为小型的嵌入式系统而设计
Amazingxixixi 发表于 2024-10-31 16:07 | 显示全部楼层
跟进学习一下
您需要登录后才可以回帖 登录 | 注册

本版积分规则

84

主题

146

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部

84

主题

146

帖子

3

粉丝
快速回复 在线客服 返回列表 返回顶部