OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3301|回复: 0

《STM32F407 探索者开发指南》第六十六章 USB U盘(Host)实验

[复制链接]

1117

主题

1128

帖子

2

精华

超级版主

Rank: 8Rank: 8

积分
4667
金钱
4667
注册时间
2019-5-8
在线时间
1224 小时
发表于 2023-9-28 17:42:13 | 显示全部楼层 |阅读模式
本帖最后由 正点原子运营 于 2023-9-28 17:42 编辑

第六十六章 USB U盘(Host)实验
1)实验平台:正点原子探索者STM32F407开发板

2) 章节摘自【正点原子】STM32F407开发指南 V1.1

3)购买链接:https://detail.tmall.com/item.htm?id=609294673401

4)全套实验源码+手册+视频下载地址:http://www.openedv.com/docs/boards/stm32/zdyz_stm32f407_explorerV3.html

5)正点原子官方B站:https://space.bilibili.com/394620890

6)STM32技术交流QQ群:151941872

155537c2odj87vz1z9vj6l.jpg

155537nfqovl2gg9faaol9.png

本章我们先介绍FATFS这个软件工具,利用它在STM32上实现类似电脑上的文件管理功能,通过USB HOST功能,实现读写U盘/读卡器等大容量USB存储设备。
本章分为如下几个小节:
66.1 FATFS简介
66.2 U盘简介
66.3 硬件设计
66.4 程序设计
66.5 下载验证

66.1 U盘简介
U盘,全称USB闪存盘,英文名“USB flash disk”。它是一种使用USB接口的无需物理驱动器的微型高容量移动存储产品,通过USB接口与主机连接,实现即插即用,是最常用的移动存储设备之一。
STM32F407的USB OTG HS支持U盘,并且ST官方提供了USB HOST大容量存储设备(MSC)例程,ST官方例程路径:光盘à8,STM32参考资料 à 1,STM32CubeF4固件包 à STM32Cube_FW_F4_V1.26.0à Projects à STM324xG_EVALà Applications à USB_Host à
MSC_Standalone。本实验,我们就要移植该例程到开发板上,以通过STM32F407的USB HOST接口,读写U盘或SD卡读卡器等设备。

66.3 硬件设计
1. 例程功能
本实验代码,开机后,检测字库,然后初始化USB HOST,并不断轮询。当检测并识别U盘后,在LCD上面显示U盘总容量和剩余容量,此时便可以通过USMART调用FATFS相关函数,来测试U盘数据的读写了,方法同FATFS实验一模一样。LED1指示USB连接状态:USB连接,LED1常亮,USB未连接,LED1灭。
LED0闪烁,提示程序运行。

2. 硬件资源
1)LED灯
    LED0 – PF9
    LED1 – PF10
2)串口1(PA9/PA10连接在板载USB转串口芯片CH340上面)
3)正点原子2.8/3.5/4.3/7寸TFTLCD模块(仅限MCU屏,16位8080并口驱动)
4)norflash(本例程使用的是W25Q128,连接在SPI1)
5)外部SRAM芯片,通过FSMC驱动
6)Micro SD卡,通过SDIO驱动
7)USB_HOST接口(D-/D+连接在PA11/PA12上)

3. 原理图
本开发板的USB HOST接口采用的是贴片USB母座,它和USB SLAVE的Type-C接头是共用USB_DM和USB_DP信号的,所以USB HOST和USB SLAVE功能不能同时使用。USB HOST和STM32的连接原理图,如下图所示:                                 
image001.png
图66.3.1 USB母座与STM32的连接电路图

从上图可以看出,USB HOST通过USB_PWR控制电源供电,USB_D+和USB_D-通过跳线帽连接到STM32F407,所以硬件上不需要我们做什么操作,可直接使用。

需要注意的是:这个USB母座(USB_HOST)和Type-C接口是共用D+和D-的,所以他们不能同时使用。这个在使用的时候,要特别注意!本实验测试时,数据线要用USB_ UART接口连接到电脑。

66.4 程序设计
66.4.1 程序流程图
QQ截图20230928174129.png
图66.4.1.1 USB U盘(Host)实验程序流程图

66.4.2 程序解析
这里我们只讲解核心代码,详细的源码请大家参考光盘本实验对应源码。

本实验,我们在:实验41 图片显示实验上修改,代码移植自ST官方例程:STM32Cube_FW_F4_V1.26.0\Projects\STM324xG_EVAL\Applications\USB_Host\MSC_Standalone。有了这个官方例程做指引,我们就知道具体需要哪些文件,从而实现本实验。
本实验的具体移植步骤,我们这里就不一一介绍了,最终移植好之后的工程分组截图,如图66.4.2.1所示:     
image005.png
图66.4.2.1 USB U盘(Host)实验工程分组

上图工程分组中的Middlewares/USB_CORE和Middlewares/USB_CLASS分组下的.c文件,直接拷贝ST官方USB HOST库,我们重点要修改的是USB_APP文件夹下面的代码和FATFS文件夹下面的代码,详细的源码请参考光盘本实验对应的源码。

1. USB驱动代码
usbh_conf.c提供了USB主机库的回调及MSP初始化函数,当USB状态机处理完不同事务的时候,会调用这些回调函数,我们通过这些回调函数,就可以知道USB当前状态,比如:是否连接上了?是否断开了?等,根据这些状态,用户应用程序可以执行不同操作,完成特定功能。该.c文件我们重点介绍3个函数,和USB_PWR电源控制GPIO,首先是初始化PCD MSP函数,其定义如下:
  1. #define USB_PWR(x)  do{ x ? \
  2.                             HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15,GPIO_PIN_SET) : \
  3.                             HAL_GPIO_WritePin(GPIOA, GPIO_PIN_15,GPIO_PIN_RESET); \
  4.                         }while(0)
  5. /**
  6. *@brief        初始化PCD MSP
  7. *@param        hpcd : PCD结构体指针
  8. *@retval       无
  9. */
  10. voidHAL_HCD_MspInit(HCD_HandleTypeDef*hcdHandle)
  11. {
  12.    GPIO_InitTypeDef gpio_init_struct= { 0 };
  13.     if (hcdHandle->Instance == USB_OTG_FS)
  14.     {
  15.        __HAL_RCC_GPIOA_CLK_ENABLE();    /* 使能GPIOA时钟 */
  16.        gpio_init_struct.Pin = GPIO_PIN_15;
  17.        gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP;          /* 推挽输出模式 */
  18.        gpio_init_struct.Pull = GPIO_NOPULL;                   /* 浮空 */
  19.        gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; /* 高速模式 */
  20.        HAL_GPIO_Init(GPIOA, &gpio_init_struct);              /* 初始化PWR引脚 */
  21.        gpio_init_struct.Pin = GPIO_PIN_11 | GPIO_PIN_12;
  22.        gpio_init_struct.Mode = GPIO_MODE_AF_PP;              /* 复用 */
  23.        gpio_init_struct.Pull = GPIO_NOPULL;                   /* 浮空 */
  24.        gpio_init_struct.Speed = GPIO_SPEED_FREQ_VERY_HIGH; /* 高速 */
  25.        gpio_init_struct.Alternate = GPIO_AF10_OTG_FS;      /* 复用为OTG1_FS */
  26.        HAL_GPIO_Init(GPIOA, &gpio_init_struct);      /* 初始化PA11和PA12引脚 */
  27.        USB_PWR(0);
  28.        USBH_Delay(100);
  29.        USB_PWR(1);
  30.        __HAL_RCC_USB_OTG_FS_CLK_ENABLE();    /* 使能OTG FS时钟 */
  31.        HAL_NVIC_SetPriority(OTG_FS_IRQn, 1, 0);
  32.        HAL_NVIC_EnableIRQ(OTG_FS_IRQn);
  33.     }
  34. }
复制代码
HAL_HCD_MspInit函数,用于使能USB时钟,选择内核时钟源,初始化IO口,开启USB供电,设置中断等。该函数在HAL_HCD_Init函数里面被调用。

接下来介绍的是USB OTG 中断服务函数,其定义如下:
  1. /**
  2. *@brief        USB OTG 中断服务函数
  3. *  @note       处理所有USB中断
  4. *@param        无
  5. *@retval       无
  6. */
  7. voidOTG_FS_IRQHandler(void)
  8. {
  9.     HAL_HCD_IRQHandler(&g_hhcd_USB_OTG_FS);
  10. }
复制代码
OTG_FS_IRQHandler函数,是USB的中断服务函数,通过调用HAL_HCD_IRQHandler函数,实现对USB各种事务的处理。

最后介绍的是USBH底层初始化函数,其定义如下:
  1. /**
  2. *@brief        USBH 底层初始化函数
  3. *@param        phost            :USBH句柄指针
  4. *@retval       USB状态
  5. *  @arg        USBH_OK(0)      , 正常;
  6. *  @arg        USBH_BUSY(1)    , 忙;
  7. *  @arg        其他              , 失败;
  8. */
  9. USBH_StatusTypeDef USBH_LL_Init(USBH_HandleTypeDef *phost)
  10. {
  11.     /* Init USB_IP */
  12.     if (phost->id == HOST_FS)
  13.     {
  14.        /* Link the driver to the stack. */
  15.        g_hhcd_USB_OTG_FS.Instance = USB_OTG_FS;    /* 使用USB_OTG */
  16.        g_hhcd_USB_OTG_FS.Init.Host_channels = 8;   /* 主机通道数为11个 */
  17.        g_hhcd_USB_OTG_FS.Init.speed = HCD_SPEED_FULL;  /* USB全速 12M */
  18.        g_hhcd_USB_OTG_FS.Init.dma_enable = DISABLE;    /* 使用DMA */
  19.        g_hhcd_USB_OTG_FS.Init.phy_itface = HCD_PHY_EMBEDDED;   /* 使能内部PHY */
  20.        g_hhcd_USB_OTG_FS.Init.Sof_enable = DISABLE;             /* 禁止SOF中断 */
  21.        g_hhcd_USB_OTG_FS.Init.vbus_sensing_enable = 0;     /* 不使能VBUS检测 */
  22.        g_hhcd_USB_OTG_FS.Init.lpm_enable = 0;                /* 不使能连接电源管理 */
  23.        g_hhcd_USB_OTG_FS.Init.low_power_enable = 0;         /* 不使能低功耗模式 */
  24.        g_hhcd_USB_OTG_FS.pData = phost; /*g_hhcd_USB_OTG_FS的pData指向phost */
  25.        /* phost的pData指向g_hhcd_USB_OTG_FS*/
  26.        phost->pData = &g_hhcd_USB_OTG_FS;
  27.        if (HAL_HCD_Init(&g_hhcd_USB_OTG_FS) != HAL_OK)      /* 初始化LL驱动 */
  28.         {
  29.            printf("USBInit ERROR \r\n");
  30.        }
  31.        else
  32.        {
  33.            printf("USBInit OK \r\n");
  34.        }
  35.        USBH_LL_SetTimer(phost, HAL_HCD_GetCurrentFrame(&g_hhcd_USB_OTG_FS));
  36.     }
  37.     return USBH_OK;
  38. }
复制代码
USBH_LL_Init函数,用于初始化USB底层设置,因为我们定义的是:USE_USB_FS,因此会设置USB OTG使用USB_OTG_FS,然后完成各种设置,比如,使用内部PHY,使用全速模式,不使能VBUS检测等,详见以上代码。该函数在USBH_Init函数里面被调用。

usbh_diskio.c提供U盘和FATFS文件系统之间的输入/输出接口函数,这里总共有5个函数,首先介绍的是初始化USBH函数,其定义如下:
  1. /**
  2. *@brief        初始化 USBH
  3. *@param        无
  4. *@retval       无
  5. */
  6. DSTATUS USBH_initialize(void)
  7. {
  8.     return RES_OK;
  9. }
复制代码
USBH_initialize函数,用于初始化U盘,我们不需要做任何事情,直接返回OK即可。

下面介绍的是获取U盘状态函数,其定义如下:
  1. /**
  2. *@brief        获取U盘状态
  3. *@param        无
  4. *@retval       无
  5. */
  6. DSTATUS USBH_status(void)
  7. {
  8.    DRESULT res = RES_ERROR;
  9.    MSC_HandleTypeDef *MSC_Handle = hUSBHost.pActiveClass->pData;
  10.     if (USBH_MSC_UnitIsReady(&g_hUSBHost, MSC_Handle->current_lun))
  11.     {
  12.        printf("U盘状态查询成功\r\n");
  13.        res = RES_OK;
  14.     }
  15.     else
  16.     {
  17.        printf("U盘状态查询失败\r\n");
  18.        res = RES_ERROR;
  19.     }
  20.     return res;
  21. }
复制代码
USBH_status函数,用于获取U盘状态,本实验暂时用不到。

下面介绍的是U盘读扇区操作函数,其定义如下:
  1. /**
  2. *@brief        U盘读扇区操作
  3. *@param        buff    : 数据缓冲首地址
  4. *@param        sector  : 扇区地址
  5. *@param        count   : 需要读取的扇区数
  6. *@retval       执行结果(详见DRESULT定义)
  7. */
  8. DRESULT USBH_read(BYTE *buff, DWORD sector, UINT count)
  9. {
  10.    DRESULT res = RES_ERROR;
  11.    MSC_LUNTypeDef info;
  12.    MSC_HandleTypeDef *MSC_Handle=hUSBHost.pActiveClass->pData;
  13.    
  14.     if (USBH_MSC_Read(&hUSBHost, MSC_Handle->current_lun, sector, buff, count)
  15.    == USBH_OK)
  16.     {
  17.        res = RES_OK;
  18.     }
  19.     else
  20.     {
  21.        printf("U盘读取失败\r\n");
  22.        USBH_MSC_GetLUNInfo(&hUSBHost, MSC_Handle->current_lun, &info);
  23.        switch (info.sense.asc)
  24.        {
  25.            caseSCSI_ASC_LOGICAL_UNIT_NOT_READY:
  26.            caseSCSI_ASC_MEDIUM_NOT_PRESENT:
  27.            caseSCSI_ASC_NOT_READY_TO_READY_CHANGE:
  28.                 USBH_ErrLog("USB Disk isnot ready!");
  29.                 res = RES_NOTRDY;
  30.                break;
  31.            default:
  32.                 res = RES_ERROR;
  33.                 break;
  34.        }
  35.     }
  36.     return res;
  37. }
复制代码
USBH_read函数,用于从U盘指定位置,读取指定长度的数据。

下面介绍的是U盘写扇区操作函数,其定义如下:
  1. /**
  2. *@brief        U盘写扇区操作
  3. *@param        buff    : 数据缓冲首地址
  4. *@param        sector  : 扇区地址
  5. *@param        count   : 需要写入的扇区数
  6. *@retval       执行结果(详见DRESULT定义)
  7. */
  8. DRESULT USBH_write(const BYTE *buff, DWORD sector, UINT count)
  9. {
  10.    DRESULT res = RES_ERROR;
  11.    MSC_LUNTypeDef info;
  12.    MSC_HandleTypeDef *MSC_Handle=hUSBHost.pActiveClass->pData;
  13.     if (USBH_MSC_Write(&hUSBHost, MSC_Handle->current_lun, sector,
  14.                                                          (BYTE *)buff, count) == USBH_OK)
  15.     {
  16.        res=RES_OK;
  17.     }
  18.     else
  19.     {
  20.        printf("U盘写入失败\r\n");
  21.        USBH_MSC_GetLUNInfo(&hUSBHost, MSC_Handle->current_lun, &info);
  22.        switch (info.sense.asc)
  23.        {
  24.            caseSCSI_ASC_WRITE_PROTECTED:
  25.                 USBH_ErrLog("USB Disk isWrite protected!");
  26.                 res = RES_WRPRT;
  27.                 break;
  28.            caseSCSI_ASC_LOGICAL_UNIT_NOT_READY:
  29.            caseSCSI_ASC_MEDIUM_NOT_PRESENT:
  30.            caseSCSI_ASC_NOT_READY_TO_READY_CHANGE:
  31.                 USBH_ErrLog("USB Disk isnot ready!");
  32.                 res = RES_NOTRDY;
  33.                 break;
  34.            default:
  35.                 res = RES_ERROR;
  36.                 break;
  37.        }
  38.     }
  39.     return res;
  40. }
复制代码
USBH_write函数,用于往U盘指定位置,写入指定长度的数据。

最后介绍的是U盘IO控制操作函数,其定义如下:
  1. /**
  2. *@brief        U盘IO控制操作
  3. *@param        cmd     : 控制命令
  4. *@param        buff    : 控制数据
  5. *@retval       执行结果(详见DRESULT定义)
  6. */
  7. DRESULT USBH_ioctl(BYTE cmd,void *buff)
  8. {
  9.    DRESULT res = RES_ERROR;
  10.    MSC_LUNTypeDef info;
  11.    MSC_HandleTypeDef *MSC_Handle = hUSBHost.pActiveClass->pData;
  12.     switch(cmd)
  13.     {
  14.        case CTRL_SYNC:
  15.            res = RES_OK;
  16.            break;
  17.        caseGET_SECTOR_COUNT :  /* 获取扇区数量 */
  18.            if(USBH_MSC_GetLUNInfo(&hUSBHost, MSC_Handle->current_lun,  &info)
  19.                                          == USBH_OK)
  20.            {
  21.                 *(DWORD*)buff = info.capacity.block_nbr;
  22.                 res = RES_OK;
  23.                 printf("扇区数量:%d\r\n", info.capacity.block_nbr);
  24.            }
  25.            else
  26.            {
  27.                 res = RES_ERROR;
  28.            }
  29.            break;
  30.        caseGET_SECTOR_SIZE :   /* 获取扇区大小 */
  31.            if(USBH_MSC_GetLUNInfo(&hUSBHost,MSC_Handle->current_lun, &info)
  32. == USBH_OK)
  33.            {
  34.                 *(DWORD*)buff = info.capacity.block_size;
  35.                 res = RES_OK;
  36.                 printf("扇区大小:%d\r\n", info.capacity.block_size);
  37.            }
  38.            else
  39.            {
  40.                 res = RES_ERROR;
  41.            }
  42.            break;
  43.        caseGET_BLOCK_SIZE :    /* 获取一个扇区里面擦除块的大小 */
  44.            if(USBH_MSC_GetLUNInfo(&hUSBHost, MSC_Handle->current_lun, &info)
  45. == USBH_OK)
  46.            {
  47.                 *(DWORD*)buff = info.capacity.block_size / USB_DEFAULT_BLOCK_SIZE;
  48.                 printf("每个扇区擦除块:%d\r\n",
  49.                                   info.capacity.block_size / USB_DEFAULT_BLOCK_SIZE);
  50.                 res = RES_OK;
  51.            }
  52.            else
  53.            {
  54.                 res = RES_ERROR;
  55.            }
  56.            break;
  57.        default:
  58.            res = RES_PARERR;
  59.            break;
  60.     }
  61.     return res;
  62. }
复制代码
USBH_ioctl函数,可以用于获取U盘扇区数量、扇区大小和块大小等信息。

我们将这5个函数在diskio.c里面和FATFS完成对接,同时需要设置FATFS支持3个磁盘(SD卡、SPI FLASH和U盘),需要在ffconf.h文件里面将FF_VOLUMES的宏定义值改成3,以支持FATFS操作U盘。

2 main.c代码
下面是main.c的程序,具体如下:
  1. USBH_HandleTypeDef g_hUSBHost;    /* USB Host处理结构体 */
  2. static voidUSBH_UserProcess(USBH_HandleTypeDef *phost, uint8_t id)
  3. {
  4.     uint32_t total, free;
  5.     uint8_t res = 0;
  6.    printf("id:%d\r\n", id);
  7.     switch (id)
  8.     {
  9.        caseHOST_USER_SELECT_CONFIGURATION:
  10.            break;
  11.        caseHOST_USER_DISCONNECTION:
  12.            f_mount(0, "2:", 1);          /* 卸载U盘 */
  13.            text_show_string(30, 140, 200, 16, "设备连接中...", 16, 0, RED);
  14.            LED1(1);
  15.            lcd_fill(30, 160, 239, 220, WHITE);
  16.            break;
  17.        caseHOST_USER_CLASS_ACTIVE:
  18.            text_show_string(30, 140, 200, 16, "设备连接成功!", 16, 0, RED);
  19.            f_mount(fs[2], "2:", 1);      /* 重新挂载U盘 */
  20.            LED1(0);
  21.            res =exfuns_get_free("2:", &total, &free);
  22.            if (res == 0)
  23.            {
  24.                 lcd_show_string(30, 160, 200, 16, 16, "FATFS OK!", BLUE);
  25.                 lcd_show_string(30, 180, 200, 16, 16, "U Disk Total Size:     MB",
  26.                                    BLUE);
  27.                 lcd_show_string(30, 200, 200, 16, 16, "U Disk  FreeSize:     MB",
  28.                                    BLUE);
  29.                 /* 显示U盘总容量 MB */
  30.                 lcd_show_num(174, 180, total >> 10, 5, 16, BLUE);
  31.                 lcd_show_num(174, 200, free >> 10, 5, 16, BLUE);
  32.            }
  33.            else
  34.            {
  35.                 printf("U盘存储空间获取失败\r\n");
  36.            }
  37.            break;
  38.        caseHOST_USER_CONNECTION:
  39.            break;
  40.        default:
  41.            break;
  42.     }
  43. }
  44. int main(void)
  45. {
  46.     uint8_t t = 0;
  47.    HAL_Init();                             /* 初始化HAL库 */
  48.    sys_stm32_clock_init(336, 8, 2, 7); /* 设置时钟, 168Mhz */
  49.    delay_init(168);                       /* 延时初始化 */
  50.    usart_init(115200);                   /* 串口初始化为115200 */
  51.    usmart_dev.init(84);                  /* USMART初始化 */
  52.    led_init();                             /* 初始化LED */
  53.    lcd_init();                             /* 初始化LCD */
  54.    key_init();                             /* 初始化按键 */
  55.    sram_init();                            /* 初始化外部SRAM */
  56.    my_mem_init(SRAMIN);                  /* 初始化内部SRAM内存池 */
  57.    my_mem_init(SRAMEX);                  /* 初始化外部SRAM内存池 */
  58.    my_mem_init(SRAMCCM);                 /* 初始化CCM内存池 */
  59.    norflash_init();                       /* 外部Flash初始化 */
  60.    exfuns_init();                         /* 为fatfs相关变量申请内存 */
  61.    f_mount(fs[0], "0:", 1);              /* 挂载SD卡 */
  62.    f_mount(fs[1], "1:", 1);              /* 挂载FLASH */
  63.    piclib_init();                         /* 初始化画图 */
  64.     while (fonts_init())                  /* 检查字库 */
  65.     {
  66.        lcd_show_string(30, 50, 200, 16, 16, "FontError!", RED);
  67.        delay_ms(200);
  68.        lcd_fill(30, 50, 240, 66, WHITE);   /* 清除显示 */
  69.        delay_ms(200);
  70.     }
  71.    
  72.    text_show_string(30, 50, 200, 16, "STM32", 16, 0, RED);
  73.    text_show_string(30, 70, 200, 16, "USB U盘 实验", 16, 0, RED);
  74.    text_show_string(30, 90, 200, 16, "ATOM@ALIENTEK", 16, 0, RED);
  75.    text_show_string(30, 120, 200, 16, "设备连接中...", 16, 0, RED);
  76.    USBH_Init(&g_hUSBHost,USBH_UserProcess, HOST_FS);
  77.    USBH_RegisterClass(&g_hUSBHost, USBH_MSC_CLASS);
  78.    USBH_Start(&g_hUSBHost);
  79.     while (1)
  80.     {
  81.        USBH_Process(&g_hUSBHost);
  82.        delay_ms(10);
  83.        t++;
  84.        if (t == 50)
  85.        {
  86.            t = 0;
  87.            LED0_TOGGLE();
  88.        }
  89.     }
  90. }
复制代码
其中,USBH_HandleTypeDef是一个用于USB主机类通信处理的结构体类型,它包含了USB主机通信的各种变量、结构体参数、传输状态和管道信息等。凡是USB主机类通信,都必须要用定义一个这样的结构体,这里定义成:g_hUSBHost。

同USB Device类通信类似,USB Host的初始化过程如下:
1,  调用USBH_Init函数,初始化USB主机内核;
2,  调用USBH_RegisterClass函数,链接MSC主机类驱动程序到主机内核;
3,  调用USBH_Start函数,启动USB通信;

经过以上三步处理,USB主机就启动了,所有USB事务,都是通过USB中断触发,并由USB驱动库自动处理。USB中断服务函数在usbh_conf.c里面:
  1. /**
  2. *@brief        USB OTG 中断服务函数
  3. *  @note       处理所有USB中断
  4. *@param        无
  5. *@retval       无
  6. */
  7. voidOTG_FS_IRQHandler(void)
  8. {
  9.     HAL_HCD_IRQHandler(&g_hhcd_USB_OTG_FS);
  10. }
复制代码
该函数调用HAL_HCD_IRQHandler函数来处理各种USB中断请求。

整个main函数代码比较简单,不过我们在main函数里面,必须不停的调用:USBH_Process函数,该函数用于实现USB主机通信的核心状态机处理,该函数必须在主函数里面被循环调用,而且调用频率得比较快才行(越快越好),以便及时处理各种事务。

USBH_UserProcess函数是USB主机用户处理回调函数,参数id表示USB主机当前的一些状态,总共有6种状态:
  1. #define HOST_USER_SELECT_CONFIGURATION     0x01U   /* USB进入配置状态 */
  2. #define HOST_USER_CLASS_ACTIVE               0x02U   /* USB初始化配置完成 */
  3. #define HOST_USER_CLASS_SELECTED             0x03U   /* USB选择了一个类 */
  4. #define HOST_USER_CONNECTION                 0x04U   /* USB连接成功 */
  5. #define HOST_USER_DISCONNECTION              0x05U   /* USB连接断开 */
  6. #define HOST_USER_UNRECOVERED_ERROR         0x06U  /* USB发生了不可恢复错误 */
复制代码
本例程我们只用了:HOST_USER_DISCONNECTION和HOST_USER_CLASS_ACTIVE两个状态。程序运行后,如果没有U盘插入,则不会执行到USBH_UserProcess函数,当插入U盘,并成功识别之后,USBH_UserProcess函数会进入:HOST_USER_CLASS_ACTIVE状态,我们就可以挂载U盘,并显示容量等信息,表示U盘识别完成。此时,如果我们把U盘拔出,则会进入:HOST_USER_DISCONNECTION状态,表示U盘拔出,我们取消U盘的挂载,并显示设备连接中...(表示当前正在连接设备)。

最后,我们需要将FATFS相关测试函数(mf_open/ mf_close等函数),加入USMART管理,这里和FATFS实验一模一样,可以参考该实验的方法操作。

66.5 下载验证
将程序下载到开发板后,然后在USB_HOST端子插入U盘/读卡器(带卡),注意:此时USB SLAVE口不要插USB线到电脑,否则会干扰!
等U盘成功识别后,便可以看到LCD显示U盘容量等信息,如图66.5.1所示:     
image007.png
图66.5.1U盘识别成功

此时,我们便可以通过USMART来测试U盘读写了,如图66.5.2和图66.5.3所示:   
image009.png
图66.5.2 测试读取U盘读取

image011.png
图66.5.3 测试U盘写入

图66.5.2分别是通过发送:mf_scan_files("2:")和mf_scan_files("2:/PICTURE"),扫描U盘根目录所有文件和PICTURE目录下的所有文件,然后通过piclib_ai_load_picfile("2:/PICTURE/示例图片.jpg",0,0,480,800,1),解码图片,并显示在LCD上面。说明读U盘是没问题的。

图66.5.3通过发送:mf_open("2:test u disk.txt",7),在U盘根目录创建test u disk.txt这个文件,然后发送:mf_write("这是一个测试,写入文件",22),写入“这是一个测试,写入文件”到这个文件里面,然后发送:mf_close(),关闭文件,完成一次文件创建。最后,发送:mf_scan_files("2:"),扫描U盘根目录文件,发现比图66.5.3所示多出了一个test u disk.txt的文件,说明U盘写入成功。

这样,就完成了本实验的设计目的:实现U盘的读写操作。最后,大家还可以调用其他函数,实现相关功能测试,这里就不给大家一一演示了。
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2024-11-23 07:40

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

快速回复 返回顶部 返回列表