第五十八章 USB U盘(Host)实验
[mw_shl_code=c,true]1.硬件平台:正点原子探索者STM32F407开发板
2.软件平台:MDK5.1
3.固件库版本:V1.4.0[/mw_shl_code]
前面两章,我们介绍了
STM32F407的
USB SLAVE应用,本章我们介绍
STM32F407的
USB HOST应用,即通过
USB HOST功能,实现读写
U盘
/读卡器等大容量
USB存储设备。本章分为如下几个部分:
58.1 U盘简介
58.2 硬件设计
58.3 软件设计
58.4 下载验证
58.1 U盘简介
U盘,全称
USB闪存盘,英文名“
USB flash disk”。它是一种使用
USB接口的无需物理驱动器的微型高容量移动存储产品,通过
USB接口与主机连接,实现即插即用,是最常用的移动存储设备之一。
STM32F4的
USB OTG FS支持
U盘,并且
ST官方提供了
USB HOST大容量存储设备(
MSC)例程,
ST官方例程路径:光盘à
8,
STM32参考资料à
STM32 USB 学习资料à
STM32_USB-Host-Device_Lib_V2.1.0à
Projectà
USB_Host_Examplesà
MSC。本章代码,我们就要移植该例程到探索者
STM32F4开发板上,以通过
STM32F4的
USB 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部分,在之前的实例中都介绍过了,我们在此就不介绍了。接下来看看我们电脑
USB与
STM32的
USB HOST连接口。
ALIENTEK探索者
STM32F4开发板的
USB HOST接口采用的是侧式
USB-A座,它和
USB SLAVE的
5PIN MiniUSB接头是共用
USB_DM和
USB_DP信号的,所以
USB HOST和
USB SLAVE不能同时使用。
USB HOST同
STM32F4的连接原理图,如图
58.2.1所示:
图
58.2.1 USB HOST接口与
STM32F4的连接原理图
从上图可以看出,
USB_HOST和
USB_SLAVE共用
USB_DM/DP信号,通过
P11连接到
STM32F4。所以我们需要通过跳线帽将
PA11和
PA12分别连接到
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_OTG和
USB_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_Read和
USBH_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,"2014年
7月
22日
",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_HANDLE和
USB_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盘盘符为
2,
0代表
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
一周热门 更多>