打印
[应用相关]

如何制作一个读取U盘文件系统的工程(转)

[复制链接]
667|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
1 前言

本文介绍基于CubeMx如何创建一个读取U盘的工程,并通过FAT32文件系统创建和读取文件。


使用特权

评论回复
沙发
八层楼|  楼主 | 2019-6-17 11:55 | 只看该作者
2 创建工程

读取U盘的程序在实际项目中经常会用到,这里我们基于STM3240G-EVAL评估板来示例如何创建一个读取U盘的程序。

在这个示例中,我们将通过一个按键来触发文件的读写。


使用特权

评论回复
板凳
八层楼|  楼主 | 2019-6-17 11:55 | 只看该作者
2.1 硬件介绍

在正式创建工程之前,我们首先非常必要了解STM3240G-EVAL评估板相关的电路设计。
STM3240G-EVAL使用25M外部HSE,USB相关电路如下:


如上图所示,MCU通过PH5管脚来控制外部U盘的VBUS,低电平为使能。

使用特权

评论回复
地板
八层楼|  楼主 | 2019-6-17 11:56 | 只看该作者

按键相关电路如下:


使用特权

评论回复
5
八层楼|  楼主 | 2019-6-17 11:56 | 只看该作者
2.2 创建CubeMx工程
STM3240G-EVAL评估板使用的是STM32F407IGH6,因此创建对应的CubeMx工程,在pingout页面中使能USB_OTG_FS外设,并设置为Host_Only:

并见PH5设置为GPIO_Output模式,用作使能VBUS。同时将PH15设置为外部中断,检测下降沿。



使用特权

评论回复
6
八层楼|  楼主 | 2019-6-17 11:57 | 只看该作者

时钟树方面外部25M HSE,主频设置为168M,USB时钟48M,如下所示:


使用特权

评论回复
7
八层楼|  楼主 | 2019-6-17 11:57 | 只看该作者

在配置方面,HAL层GPIO基本没有什么特殊,记得外部中断使用检测下降沿,这个是使用在按键中:


使用特权

评论回复
8
八层楼|  楼主 | 2019-6-17 11:57 | 只看该作者

在NVIC中,一定要将USB的中断优先级高于按键中断,否则U盘不能正常读取。这里USB中断优先级设置为1,而外部中断15设置为5,如下图所示:


使用特权

评论回复
9
八层楼|  楼主 | 2019-6-17 11:57 | 只看该作者

同时为USB选上MSC类,且勾上使用USB disk FAT文件系统:


使用特权

评论回复
10
八层楼|  楼主 | 2019-6-17 11:58 | 只看该作者

中间件配置方面,其实可以使用默认,不过我们还是修改部分参数。
在文件系统配置方面:


使用特权

评论回复
11
八层楼|  楼主 | 2019-6-17 11:58 | 只看该作者

我们只是简单地将其配置成支持中文,并支持长文件名。
最后,将栈和堆的空间大小都设置为2K:




OK,接下来就可以生成工程了。


使用特权

评论回复
12
八层楼|  楼主 | 2019-6-17 11:58 | 只看该作者
2.3 代码修改

在生成的代码中,首先我们对main函数进行修改,在main函数中我们需要做的工作主要有以下几件:

  • 完成系统初始化
  • 使能VBUS
  • 当检测到插入U盘时挂载文件系统
  • 当检测到U盘拔出时,卸载文件系统

使用特权

评论回复
13
八层楼|  楼主 | 2019-6-17 11:59 | 只看该作者
于是main函数如下所示:
int main(void)
{

  /* USER CODE BEGIN 1 */
static ApplicationTypeDef pre_state = APPLICATION_IDLE;
   FATFS fs;
  /* USER CODE END 1 */

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

  /* 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_FATFS_Init();
  MX_USB_HOST_Init();

  /* USER CODE BEGIN 2 */
HAL_GPIO_WritePin(GPIOH, GPIO_PIN_5, GPIO_PIN_RESET);//enable usb VBUS
  /* USER CODE END 2 */

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

  /* USER CODE BEGIN 3 */
    if (pre_state != Appli_state)
    {
        switch(Appli_state)
        {
            case APPLICATION_DISCONNECT: //USB flash disk remove
                /* Register the file system object to the FatFs module */
                if(f_mount(NULL, "", 0) != FR_OK)
                {
                    USBH_UsrLog("ERROR : Cannot exit FatFs! \n");
                }
                break;
            case APPLICATION_READY:   //USB flash disk plugin
                /* Open or create a log file and ready to append */
                if(f_mount(&fs, "", 0) != FR_OK)
                {
                    break;
                }
                break;
            default:
                break;
            }
        }
        pre_state = Appli_state;
  }
  /* USER CODE END 3 */

}


如上代码,程序通过拉低PH5管脚来使能VBUS。使用使用一个静态的局部变量pre_state来记录之前的U盘拔插状态,用以跟踪U盘的连接状态,当U盘插入时,立即挂载文件系统。当检测到U盘拔出时则卸载文件系统。

使用特权

评论回复
14
八层楼|  楼主 | 2019-6-17 11:59 | 只看该作者
接下来看按键中断处理,这里,我们在按键中断中分别做3次测试,写文件测试,和文件扫描测试 :

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    static uint8_t step =0;
    if(USBH_MSC_IsReady(&hUsbHostFS))
    {
        switch(step ++)
        {
        case 0:
            writefile_test(); //写文件测试
            break;
        case 1:
            readfile_test();    //读文件测试
            break;
        case 2:
            Explore_Disk("0:/", 1); //文件扫描测试
            break;
        default:
            break;
        }
        if(step >2)
        {
            step =0;
        }
    }
    else
    {
        USBH_UsrLog("USB Device is not ready.\n");
    }
}


使用特权

评论回复
15
八层楼|  楼主 | 2019-6-17 11:59 | 只看该作者
文件扫面测试,写问津测试,读文件测试:

FRESULT Explore_Disk(char *path, uint8_t recu_level)
{
  FRESULT res = FR_OK;
  FILINFO fno;
  DIR dir;
  char *fn;
  char tmp[14];
  uint8_t line_idx = 0;

#if _USE_LFN
  static char lfn[_MAX_LFN + 1];   /* Buffer to store the LFN */
  fno.lfname = lfn;
  fno.lfsize = sizeof lfn;
#endif

  res = f_opendir(&dir, path);
  if(res == FR_OK)
  {
    while(USBH_MSC_IsReady(&hUsbHostFS))
    {
      res = f_readdir(&dir, &fno);
      if(res != FR_OK || fno.fname[0] == 0)
      {
        break;
      }
      if(fno.fname[0] == '.')
      {
        continue;
      }

#if _USE_LFN
      fn = *fno.lfname ? fno.lfname : fno.fname;
#else
      fn = fno.fname;
#endif
      strcpy(tmp, fn);

      line_idx++;
      if(line_idx > 9)
      {
        line_idx = 0;
      }

      if(recu_level == 1)
      {
        USBH_UsrLog("   |__");
      }
      else if(recu_level == 2)
      {
        USBH_UsrLog("   |   |__");
      }
      if((fno.fattrib & AM_MASK) == AM_DIR)
      {
        strcat(tmp, "\n");
        USBH_UsrLog((void *)tmp);
        Explore_Disk(fn, 2);
      }
      else
      {
        strcat(tmp, "\n");
        USBH_UsrLog((void *)tmp);
      }

      if(((fno.fattrib & AM_MASK) == AM_DIR)&&(recu_level == 2))
      {
        Explore_Disk(fn, 2);
      }
    }
    f_closedir(&dir);
  }
  return res;
}


使用特权

评论回复
16
八层楼|  楼主 | 2019-6-17 12:00 | 只看该作者
void writefile_test(void)
{
    FIL fil;
    FRESULT fr;

    /* Opens an existing file. If not exist, creates a new file. */
    fr = f_open(&fil, "0:/mytest.txt", FA_READ | FA_WRITE | FA_CREATE_ALWAYS);
    if (fr != FR_OK)
    {
        return;
    }
    f_printf(&fil, "%s\n", "[USB]write txt OK!0123456789");

    /* Close the file */
    f_close(&fil);
}


使用特权

评论回复
17
八层楼|  楼主 | 2019-6-17 12:00 | 只看该作者
void readfile_test(void)
{
    FIL fil;
    FRESULT fr;
    uint8_t buff[20];
    UINT off = 0;

    /* Opens an existing file. If not exist, creates a new file. */
    fr = f_open(&fil, "0:/mytest.txt", FA_READ);
    if (fr != FR_OK)
    {
        return;
    }

    f_read(&fil, buff, 16, &off);
    buff[16] = 0;

    /* Close the file */
    f_close(&fil);
}
最后将U盘去下来插入到windows查看,可以正常考到测试文件mytest.txt文件,这证明结果是OK的。



使用特权

评论回复
18
八层楼|  楼主 | 2019-6-17 12:00 | 只看该作者
3 结论
  • 按键的中断EXIT15的优先级一定不能过于USB的中断优先级,否则代码运行到操作文件的时候回卡死!

  • 通过CubeMx工具将一个比较复杂的读取文件系统工程大大简化的。



使用特权

评论回复
19
无为之益| | 2019-9-18 11:11 | 只看该作者
请教楼主,怎么读取U盘的剩余容量?

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

83

主题

3887

帖子

2

粉丝