OpenEdv-开源电子网

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

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

[复制链接]

230

主题

1950

帖子

10

精华

论坛元老

Rank: 8Rank: 8

积分
4562
金钱
4562
注册时间
2010-12-14
在线时间
32 小时
发表于 2014-12-9 14:28:45 | 显示全部楼层 |阅读模式

第五十八章 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.0\Project\USB_Host_Examples\MSC,我打开该例程即可知道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("开始执行用户程序!!!\r\n");

                     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;//设置字体为蓝色   

              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;//设置字体为红色     

       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

  

第五十八章 USB U盘(Host)实验-STM32F4开发指南-正点原子探索者STM32开发板.pdf

727.54 KB, 下载次数: 2549

实验53 USB U盘(Host)实验.zip

1.45 MB, 下载次数: 4067

我是开源电子网?网站管理员,对网站有任何问题,请与我联系!QQ:389063473Email:389063473@qq.com
正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

23

主题

292

帖子

0

精华

高级会员

Rank: 4

积分
501
金钱
501
注册时间
2013-9-17
在线时间
17 小时
发表于 2015-4-1 18:37:20 | 显示全部楼层
闷鱼闷闷不乐吃焖鱼
回复 支持 反对

使用道具 举报

86

主题

983

帖子

0

精华

论坛大神

Rank: 7Rank: 7Rank: 7

积分
1848
金钱
1848
注册时间
2013-4-15
在线时间
163 小时
发表于 2015-7-22 15:45:11 | 显示全部楼层
牛逼           mark一下    用到的时候学习一下
合肥-文盲
回复 支持 反对

使用道具 举报

0

主题

4

帖子

0

精华

新手入门

积分
8
金钱
8
注册时间
2016-2-19
在线时间
1 小时
发表于 2016-2-22 15:10:28 | 显示全部楼层
原子兄,我用的是探索者开发板,但U盘识别不了,用的是开发板光盘内的源程序
回复 支持 反对

使用道具 举报

0

主题

4

帖子

0

精华

新手入门

积分
8
金钱
8
注册时间
2016-2-19
在线时间
1 小时
发表于 2016-2-23 17:53:10 | 显示全部楼层
自己顶下
回复 支持 反对

使用道具 举报

2

主题

9

帖子

0

精华

初级会员

Rank: 2

积分
75
金钱
75
注册时间
2016-4-4
在线时间
13 小时
发表于 2016-7-9 11:35:51 | 显示全部楼层
问一下这个怎么又明了换行和回车吗?怎么操作都不好回车和换行···
回复 支持 反对

使用道具 举报

1

主题

19

帖子

0

精华

初级会员

Rank: 2

积分
51
金钱
51
注册时间
2011-4-4
在线时间
2 小时
发表于 2016-11-14 12:42:17 | 显示全部楼层
学习一下。
回复 支持 反对

使用道具 举报

4

主题

35

帖子

0

精华

初级会员

Rank: 2

积分
95
金钱
95
注册时间
2015-9-16
在线时间
15 小时
发表于 2016-12-16 23:49:18 | 显示全部楼层
原子哥,你好,我想问下,这个程序支持USB3.0的U盘吗?
回复 支持 反对

使用道具 举报

0

主题

11

帖子

0

精华

初级会员

Rank: 2

积分
129
金钱
129
注册时间
2017-4-11
在线时间
31 小时
发表于 2017-4-20 15:36:19 | 显示全部楼层
感谢此教程
回复 支持 反对

使用道具 举报

5

主题

96

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
235
金钱
235
注册时间
2010-12-16
在线时间
28 小时
发表于 2017-7-13 11:10:08 | 显示全部楼层
有HID教程吗?
这个项目用的比较多。。。。
回复 支持 反对

使用道具 举报

12

主题

77

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
352
金钱
352
注册时间
2014-1-22
在线时间
43 小时
发表于 2017-8-24 09:36:00 | 显示全部楼层
有没有其他设备的 比如 触摸的程序呀?
任何一件事情,只要心甘情愿,总是能够变得简单。
回复 支持 反对

使用道具 举报

4

主题

37

帖子

0

精华

中级会员

Rank: 3Rank: 3

积分
288
金钱
288
注册时间
2012-9-13
在线时间
65 小时
发表于 2017-12-16 09:19:40 | 显示全部楼层
在原子的探索者开发板上实现了HID和MSC两套驱动,都能成功运行。
现在有个想法,把HID和MSC合到一起,既能处理HID又可以处理MSC,我就把usbh_core.c的 USBH_Process函数中,
case HOST_USR_INPUT 的代码改成了这样:

  case HOST_USR_INPUT:   
    /*The function should return user response true to move to class state */
    if ( phost->usr_cb->UserInput() == USBH_USR_RESP_OK)
    {
      switch(phost->device_prop.Itf_Desc[0].bInterfaceClass)
      {
      case USB_HID:
                  phost->class_cb = &USBH_HID_cb;
                break;
          case USB_MSC:
                  phost->class_cb = &USBH_MSC_cb;
                break;
          default:break;
      }
      if((phost->class_cb->Init(pdev, phost)) == USBH_OK)
      {
        phost->gState  = HOST_CLASS_REQUEST;     
      }     
    }   
    break;

现在也可以算是移植成功了,HID和MSC都能识别。

但我有一点点强迫症,这样子改就是改了USB库文件,我想有没有办法不改这里,而是在 usbh_usr.c 中的某个函数里做回调函数的重绑定?

开始我想在UserInput里面,但是这个函数没有参数,获取不到host信息。
不知道各位有没有其他办法?
回复 支持 反对

使用道具 举报

10

主题

55

帖子

0

精华

初级会员

Rank: 2

积分
62
金钱
62
注册时间
2017-5-3
在线时间
44 小时
发表于 2018-9-6 11:41:02 | 显示全部楼层
mark!!!
回复 支持 反对

使用道具 举报

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

本版积分规则



关闭

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

正点原子公众号

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

GMT+8, 2025-6-8 00:44

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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