【正点原子探索者STM32F407开发板例程连载+教学】第58章 USB U盘(Host)实验

2019-07-20 06:18发布

第五十八章 USB U(Host)实验

       [mw_shl_code=c,true]1.硬件平台:正点原子探索者STM32F407开发板 2.软件平台:MDK5.1 3.固件库版本:V1.4.0[/mw_shl_code]
前面两章,我们介绍了STM32F407USB SLAVE应用,本章我们介绍STM32F407USB HOST应用,即通过USB HOST功能,实现读写U/读卡器等大容量USB存储设备。本章分为如下几个部分: 58.1 U盘简介 58.2 硬件设计 58.3 软件设计 58.4 下载验证  

58.1 U盘简介

U盘,全称USB闪存盘,英文名“USB flash disk”。它是一种使用USB接口的无需物理驱动器的微型高容量移动存储产品,通过USB接口与主机连接,实现即插即用,是最常用的移动存储设备之一。 STM32F4USB OTG FS支持U盘,并且ST官方提供了USB HOST大容量存储设备(MSC)例程,ST官方例程路径:光盘à8STM32参考资料àSTM32 USB 学习资料àSTM32_USB-Host-Device_Lib_V2.1.0àProjectàUSB_Host_ExamplesàMSC。本章代码,我们就要移植该例程到探索者STM32F4开发板上,以通过STM32F4USB HOST接口,读写U盘或SD卡读卡器等设备。  

58.2 硬件设计

本章实验功能简介:开机后,检测字库,然后初始化USB HOST,并不断轮询。当检测并识别U盘后,在LCD上面显示U盘总容量和剩余容量,此时便可以通过USMART调用FATFS相关函数,来测试U盘数据的读写了,方法同FATFS实验一模一样。当U盘没插入的时候,DS0闪烁,提示程序运行,当U盘插入后,DS1闪烁,提示可以通过USMART测试了。 所要用到的硬件资源如下: 1)  指示灯DS0 DS1 2)  串口 3)  TFTLCD模块 4)  SD卡(非必须) 5)  SPI FLASH 6)  USB HOST接口 前面5部分,在之前的实例中都介绍过了,我们在此就不介绍了。接下来看看我们电脑USBSTM32USB HOST连接口。 ALIENTEK探索者STM32F4开发板的USB HOST接口采用的是侧式USB-A座,它和USB SLAVE5PIN MiniUSB接头是共用USB_DMUSB_DP信号的,所以USB HOSTUSB SLAVE不能同时使用。 USB HOSTSTM32F4的连接原理图,如图58.2.1所示:
                      58.2.1 USB HOST接口与STM32F4的连接原理图 从上图可以看出,USB_HOSTUSB_SLAVE共用USB_DM/DP信号,通过P11连接到STM32F4。所以我们需要通过跳线帽将PA11PA12分别连接到D-D+,如图58.2.2所示:  58.2.2 硬件连接示意图58.2.1中,我们还有一个USB_PWR的控制信号,用于控制给USB设备供电,该信号连接在PA15上面,和JTAG JTDI信号共用,所以我们建议大家使用SWD模式调试,这样PA15就解放了,可以用于USB_PWR的控制。 使用USB HOST驱动外部USB设备的时候,必须要先控制USB_PWR输出1,给外部设备供电,之后才可以识别到外部设备!

58.3 软件设计

本章,我们在:实验41 图片显示实验 的基础上修改,代码移植自ST官方例程:STM32_USB-Host-Device_Lib_V2.1.0ProjectUSB_Host_ExamplesMSC,我打开该例程即可知道USB相关的代码有哪些,如图58.3.1所示:  58.3.1 ST官方例程USB相关代码        有了这个官方例程做指引,我们就知道具体需要哪些文件,从而实现本章例程。 从上图可以看出,这里并没有像第五十六章图56.3.1那样,区分不同分组,而是都放到USB_Host组下,看起来有点小乱,我们移植的时候,还是以56章的方式,分不同分组添加代码,方便阅读和管理。 这里面usbh_msc_fatfs.c,是为了支持fatfs而写的一些底层接口函数,我们例程就直接放到diskio.c里面了,方便统一管理。 本例程的具体移植步骤,我们这里就不一一介绍了,最终移植好之后的工程截图,如图58.3.2所示:  58.3.2 添加USB驱动等相关代码        移植时,我们重点要修改的就是USB_APP文件夹下面的代码。其他代码(USB_OTGUSB_HOST文件夹下的代码)一般不用修改。 usb_bsp.c的代码,和上一章的一样,可以用上一章的代码直接替换即可正常使用。 usbh_usr.c提供用户应用层接口函数,相比前两章例程,USB HOST通信的回调函数更多一些,这里重点介绍3个函数,代码如下: extern u8 USH_User_App(void);         //用户测试主程序 //USB HOST MSC类用户应用程序 int USBH_USR_MSC_Application(void) {        u8 res=0;       switch(AppState)       {            case USH_USR_FS_INIT://初始化文件系统                      printf("开始执行用户程序!!! ");                      AppState=USH_USR_FS_TEST;                  break;            case USH_USR_FS_TEST:   //执行USB OTG 测试主程序                      res=USH_User_App(); //用户主程序                  res=0;                      if(res)AppState=USH_USR_FS_INIT;                  break;            default:break;       }        return res; } //用户定义函数,实现fatfs diskio的接口函数 extern USBH_HOST              USB_Host;  //U //buf:读数据缓存区 //sector:扇区地址 //cnt:扇区个数       //返回值:错误状态;0,正常;其他,错误代码;        u8 USBH_UDISK_Read(u8* buf,u32 sector,u32 cnt) {        u8 res=1;        if(HCD_IsDeviceConnected(&USB_OTG_Core)&&AppState==USH_USR_FS_TEST) //连接还存在,且是APP测试状态        {                              do               {                      res=USBH_MSC_Read10(&USB_OTG_Core,buf,sector,512*cnt);                      USBH_MSC_HandleBOTXfer(&USB_OTG_Core ,&USB_Host);                                       if(!HCD_IsDeviceConnected(&USB_OTG_Core))                      {                             res=1;//读写错误                             break;                      };                 }while(res==USBH_MSC_BUSY);        }else res=1;                    if(res==USBH_MSC_OK)res=0;          return res; } //U //buf:写数据缓存区 //sector:扇区地址 //cnt:扇区个数       //返回值:错误状态;0,正常;其他,错误代码;        u8 USBH_UDISK_Write(u8* buf,u32 sector,u32 cnt) {        u8 res=1;        if(HCD_IsDeviceConnected(&USB_OTG_Core)&&AppState==USH_USR_FS_TEST) //连接还存在,且是APP测试状态        {                              do               {                      res=USBH_MSC_Write10(&USB_OTG_Core,buf,sector,512*cnt);                      USBH_MSC_HandleBOTXfer(&USB_OTG_Core ,&USB_Host);                                       if(!HCD_IsDeviceConnected(&USB_OTG_Core))                      {                             res=1;//读写错误                             break;                      };                 }while(res==USBH_MSC_BUSY);        }else res=1;                    if(res==USBH_MSC_OK)res=0;          return res; } 其中,USBH_USR_MSC_Application函数通过状态机的方式,处理相关事务,执行到这个函数,说明U盘已经被成功识别了,此时用户可以执行一些自己想要做的事情,比如读取U盘文件什么的,这里我们直接进入到USH_User_App函数,执行各种处理,后续会介绍该函数。 USBH_UDISK_ReadUSBH_UDISK_Write这两个函数,用于U盘读写,从指定扇区地址读写指定个数的扇区数据,这两个函数,再配合fatfs,即可实现对U盘的文件读写访问。 其他代码,我们就不详细讲解了,请大家参考光盘本例程源码,最后修改main.c里面代码如下: USBH_HOST  USB_Host; USB_OTG_CORE_HANDLE  USB_OTG_Core; //用户测试主程序 //返回值:0,正常 //       1,有问题 u8 USH_User_App(void) {        u32 total,free;u8 res=0;        Show_Str(30,140,200,16,"设备连接成功!.",16,0);           f_mount(fs[2],"2:",1);   //重新挂载U        res=exf_getfree("2:",&total,&free);        if(res==0)        {               POINT_COLOR=BLUE;//设置字体为蓝 {MOD}                  LCD_ShowString(30,160,200,16,16,"FATFS OK!");                LCD_ShowString(30,180,200,16,16,"U Disk Total Size:     MB");                     LCD_ShowString(30,200,200,16,16,"U Disk  Free Size:     MB");                        LCD_ShowNum(174,180,total>>10,5,16); //显示U盘总容量 MB               LCD_ShowNum(174,200,free>>10,5,16);          }        while(HCD_IsDeviceConnected(&USB_OTG_Core))//设备连接成功,死循环        {                   LED1=!LED1;               delay_ms(200);        }       f_mount(0,"2:",1);        //卸载U        POINT_COLOR=RED;//设置字体为红 {MOD}             Show_Str(30,140,200,16,"设备连接中...",16,0);        LCD_Fill(30,160,239,220,WHITE);        return res; } int main(void) {               u8 t;        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2        delay_init(168);  //初始化延时函数        uart_init(115200);         //初始化串口波特率为115200        LED_Init();                  //初始化与LED连接的硬件接口        KEY_Init();                  //按键       LCD_Init();                  //初始化LCD        W25QXX_Init();           //SPI FLASH初始化        usmart_dev.init(84);      //初始化USMART        my_mem_init(SRAMIN);//初始化内部内存池         exfuns_init();                //fatfs相关变量申请内存        piclib_init();                 //初始化画图       f_mount(fs[0],"0:",1);   //挂载SD        f_mount(fs[1],"1:",1);   //挂载外部SPI FLASH          POINT_COLOR=RED;            while(font_init())         //检查字库        {                       LCD_ShowString(60,50,200,16,16,"Font Error!"); delay_ms(200);                                        LCD_Fill(60,50,240,66,WHITE); delay_ms(200);//清除显示                                        }        Show_Str(30,50,200,16,"探索者STM32F407开发板",16,0);                                            Show_Str(30,70,200,16,"USB U盘实验",16,0);                                                 Show_Str(30,90,200,16,"2014722",16,0);                       Show_Str(30,110,200,16,"正点原子@ALIENTEK",16,0);        Show_Str(30,140,200,16,"设备连接中...",16,0);                                        //初始化USB主机       USBH_Init(&USB_OTG_Core,USB_OTG_FS_CORE_ID,&USB_Host,&USBH_MSC_cb ,&USR_Callbacks);         while(1)        {               USBH_Process(&USB_OTG_Core, &USB_Host);               delay_ms(1);               t++;               if(t==200){ LED0=!LED0; t=0;} } } 相比USB SLAVE例程,我们这里多了一个USB_HOST的结构体定义:USB_Host,用于存储主机相关状态。所以,使用USB主机的时候,需要两个结构体:USB_OTG_CORE_HANDLEUSB_HOST 然后,USB初始化,使用的是USBH_Init,用于USB主机初始化,包括对USB硬件和USB驱动库的初始化。如果是:USB SLAVE通信,在只需要调用USBD_Init函数即可,不过USB HOST则还需要调用另外一个函数USBH_Process,该函数用于实现USB主机通信的核心状态机处理,该函数必须在主函数里面,被循环调用,而且调用频率得比较快才行(越快越好),以便及时处理各种事务。注意,USBH_Process函数仅在U盘识别阶段,需要频繁反复调用,但是当U盘被识别后,剩下的操作(U盘读写),都可以由USB中断处理。 以上代码,main函数十分简单,就不多做介绍了,这里主要看看USH_User_App函数,该函数前面有提到,是在USBH_USR_MSC_Application函数里面被调用,用于实现U盘插入后,用户想要实现的功能,一旦进入到该函数,即表示U盘已经成功识别了,所以,函数里面提示设备连接成功,挂载U盘(U盘盘符为20代表SD卡,1代表SPI FLASH)并读取U盘总容量和剩余容量,显示在LCD上面,然后,进入死循环,只要USB连接一直存在,则一直死循环,同时控制LED1闪烁,提示U盘已经准备好了。U盘拔出来后,卸载U盘,然后再次提示设备连接中,会到main函数死循环,等待U盘再次连上。 最后,我们需要将FATFS相关测试函数(mf_open/ mf_close等函数),加入USMART管理,这里同第四十四章(FATFS实验)一模一样,可以参考第四十四章的方法操作。 软件设计部分,就给大家介绍到这里。

58.4 下载验证

在代码编译成功之后,我们下载到探索者STM32F4开发板上,然后在USB_HOST端子插入U/读卡器(带卡),注意:此时USB SLAVE口不要插USB线到电脑,否则会干扰!!U盘成功识别后,便可以看到LCD显示U盘容量等信息,如图58.4.1所示:  58.4.1 U盘识别成功 此时,我们便可以通过USMART来测试U盘读写了,如图58.4.2和图58.4.3所示:  58.4.2 测试读取U盘读取    58.4.3 测试U盘写入        58.4.2通过发送:mf_scan_files("2:"),扫描U盘根目录所有文件,然后通过ai_load_picfile ("2:/测试用图片.jpg",0,0,480,800,1),解码图片,并显示在LCD上面。说明读U盘是没问题的。        58.4.3通过发送:mf_open("2:test u disk.txt",7),在U盘根目录创建test u disk.txt这个文件,然后发送:mf_write("This is a test",14),写入This is a test到这个文件里面,然后发送:mf_close(),关闭文件,完成一次文件创建。最后,发送:mf_scan_files("2:"),扫描U盘根目录文件,发现比图58.4.2所示多出了一个test u disk.txt的文件,说明U盘写入成功。        这样,就完成了本实验的设计目的:实现U盘的读写操作。最后,大家还可以调用其他函数,实现相关功能测试,这里就不给大家一一演示了,测试方法同:FATFS实验(第四十四章)。
  实验详细手册和源码下载地址:http://www.openedv.com/posts/list/41586.htm  正点原子探索者STM32F407开发板购买地址http://item.taobao.com/item.htm?id=41855882779
  
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。