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

来源:互联网 发布:淘宝详细图片尺寸 编辑:程序博客网 时间:2024/05/16 23:54

1 前言

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

2 创建工程

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

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

2.1 硬件介绍

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

USB电路

图1 USB电路

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

按键相关电路

图2 按键相关电路

2.2 创建CubeMx工程

STM3240G-EVAL评估板使用的是STM32F407IGH6,因此创建对应的CubeMx工程,在pingout页面中使能USB_OTG_FS外设,并设置为Host_Only:

USB_OTG_FS设置为主机模式

图3 USB_OTG_FS设置为主机模式

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

 pinout分布

图4 pinout分布

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

时钟树设置

图5 时钟树设置

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

按键检测外部中断

图6 按键检测外部中断

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

中断优先级配置

图7 中断优先级配置

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

USB MSC类和FAT文件系统

图8 USB MSC类和FAT文件系统

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

文件系统参数配置

图9 文件系统参数配置

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

堆栈大小设置

图10 堆栈大小设置

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

2.3 代码修改

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

  • 完成系统初始化
  • 使能VBUS
  • 当检测到插入U盘时挂载文件系统
  • 当检测到U盘拔出时,卸载文件系统
    于是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盘拔出时则卸载文件系统。

接下来看按键中断处理,这里,我们在按键中断中分别做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");    }}

文件扫面测试,写问津测试,读文件测试:

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;}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);}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的。

3 结论

  1. 按键的中断EXIT15的优先级一定不能过于USB的中断优先级,否则代码运行到操作文件的时候回卡死!

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

示例代码:http://download.csdn.net/detail/flydream0/9717879

1 0
原创粉丝点击