完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
1)实验平台:alientek 阿波罗 STM32F767 开发板
2)摘自《STM32F7 开发指南(HAL 库版)》关注官方微信号公众号,获取更多资料:正点原子 第六十四章 USB U 盘(Host)实验 前面两章,我们介绍了 STM32F767 的 USB SLAVE 应用,本章我们介绍 STM32F767 的 USB HOST 应用,即通过 USB HOST 功能,实现读写 U 盘/读卡器等大容量 USB 存储设备。本章分为如下几个部分: 64.1 U 盘简介 64.2 硬件设计 64.3 软件设计 64.4 下载验证 64.1 U 盘简介 U 盘,全称 USB 闪存盘,英文名“USB flash disk”。它是一种使用 USB 接口的无需物理驱 动器的微型高容量移动存储产品,通过 USB 接口与主机连接,实现即插即用,是最常用的移动 存储设备之一。 STM32F767 的 USB OTG FS 支持 U 盘,并且 ST 官方提供了 USB HOST 大容量存储设备 (MSC)例程,ST 官方例程路径:光盘8,STM32 参考资料STM32 USB 学习资料 STM32_USB-Host-Device_Lib_V2.2.0ProjectUSB_Host_ExamplesMSC。本章代码,我 们就要移植该例程到阿波罗 STM32 开发板上,以通过 STM32F767 的 USB HOST 接口,读写 U 盘或 SD 卡读卡器等设备。 64.2 硬件设计 本章实验功能简介:开机后,检测字库,然后初始化 USB HOST,并不断轮询。当检测并 识别 U 盘后,在 LCD 上面显示 U 盘总容量和剩余容量,此时便可以通过 USMART 调用 FATFS 相关函数,来测试 U 盘数据的读写了,方法同 FATFS 实验一模一样。当 U 盘没插入的时候, DS0 闪烁,提示程序运行,当 U 盘插入后,DS1 闪烁,提示可以通过 USMART 测试了。 所要用到的硬件资源如下: 1) 指示灯 DS0 、DS1。 2) 串口 3) LCD 模块 4) SPI FLASH 5) USB HOST 接口 前面 4 部分,在之前的实例中都介绍过了,我们在此就不介绍了。接下来看看我们电脑 USB 与 STM32 的 USB HOST 连接口。 ALIENTEK 阿波罗 STM32 开发板的 USB HOST 接口采用的是侧式 USB-A 座,它和 USB SLAVE 的 5PIN MiniUSB 接头是共用 USB_DM 和 USB_DP 信号的,所以 USB HOST 和 USB SLAVE 不能同时使用。USB HOST 同 STM32 的连接原理图,如图 64.2.1 所示: 图 64.2.1 USB HOST 接口与 STM32F767 的连接原理图 从上图可以看出,USB_HOST 和 USB_SLAVE 共用 USB_DM/DP 信号,通过 P10 连接到 STM32F767。所以我们需要通过跳线帽将 PA11 和 PA12 分别连接到 D-和 D+,如图 64.2.2 所示: 图 64.2.2 硬件连接示意图 图 64.2.1 中,我们还有一个 USB_PWR 的控制信号,用于控制给 USB 设备供电,该信号 连接在 PCF8574T 的 P3 口上面,通过 PCF874T 进行间接控制。PCF8574T 的使用说明见第三十 一章 IO 扩展实验。 使用 USB HOST 驱动外部 USB 设备的时候,必须要先控制 USB_PWR 输出 1,给外部设 备供电,之后才可以识别到外部设备! 64.3 软件设计 本章,我们在:实验 44 图片显示实验 的基础上修改,代码移植自 ST 官方例程: STM32_USB-Host-Device_Lib_V2.2.0ProjectUSB_Host_ExamplesMSC,我打开该例程(用 IAR 打开)即可知道 USB 相关的代码有哪些,如图 64.3.1 所示: 图 64.3.1 ST 官方例程 USB 相关代码 有了这个官方例程做指引,我们就知道具体需要哪些文件,从而实现本章例程。 这里面 u***h_msc_fatfs.c,是为了支持 fatfs 而写的一些底层接口函数,我们例程就直接放到 diskio.c 里面了,方便统一管理。 本例程的具体移植步骤,我们这里就不一一介绍了,最终移植好之后的工程截图,如图 64.3.2 所示: 图 64.3.2 添加 USB 驱动等相关代码 注意:为了支持 STM32F7,USB OTG 库部分代码要做修改,详见 61.3 节的介绍(USB HOST 实验只需要修改 u***_core.c 这一个文件就可以支持 STM32F7 了)。 移植时,我们重点要修改的就是 USB_APP 文件夹下面的代码。其他代码(USB_OTG 和 USB_HOST 文件夹下的代码)一般不用修改。 u***_bsp.c 的代码,和上一章的一样,可以用上一章的代码直接替换即可正常使用。 u***h_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("开始执行用户程序!!!rn"); AppState=USH_USR_FS_TEST; break; case USH_USR_FS_TEST: //执行 USB OTG 测试主程序 res=USH_User_App(); //用户主程序 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) { u8 led1sta=1; u8 res=0; u32 total,free; Show_Str(30,140,200,16,"设备连接成功!.",16,0); f_mount(fs[3],"3:",1); //重新挂载 U 盘 res=exf_getfree("3:",&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(led1sta^=1); delay_ms(200); } LED1(1); //关闭 LED1 f_mount(0,"3:",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; Cache_Enable(); //打开 L1-Cache HAL_Init(); //初始化 HAL 库 Stm32_Clock_Init(432,25,2,9); //设置时钟,216Mhz delay_init(216); //延时初始化 uart_init(115200); //串口初始化 LED_Init(); //初始化 LED KEY_Init(); //初始化按键 SDRAM_Init(); //初始化 SDRAM LCD_Init(); //初始化 LCD W25QXX_Init(); //初始化 W25Q256 PCF8574_Init(); //初始化 PCF8574 my_mem_init(SRAMIN); //初始化内部内存池 my_mem_init(SRAMEX); //初始化外部内存池 my_mem_init(SRAMDTCM); //初始化 DTCM 内存池 exfuns_init(); //为 fatfs 相关变量申请内存 f_mount(fs[0],"0:",1); //挂载 SD 卡 f_mount(fs[1],"1:",1); //挂载 SPI FLASH. f_mount(fs[2],"2:",1); //挂载 NAND 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,"阿波罗 STM32F4/F7 开发板",16,0); Show_Str(30,70,200,16,"USB U 盘实验",16,0); Show_Str(30,90,200,16,"2016 年 8 月 11 日",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_cb); while(1) { USBH_Process(&USB_OTG_Core, &USB_Host); delay_ms(1); t++; if(t==200) { LED0_Toggle; 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 盘盘符为 3,0:SD 卡,1:SPI FLASH,2:NAND FLASH)并 读取 U 盘总容量和剩余容量,显示在 LCD 上面,然后,进入死循环,只要 USB 连接一直存在, 则一直死循环,同时控制 LED1 闪烁,提示 U 盘已经准备好了。 当 U 盘拔出来后,卸载 U 盘,然后再次提示设备连接中,会到 main 函数死循环,等待 U 盘再次连上。 最后,我们需要将 FATFS 相关测试函数(mf_open/ mf_close 等函数),加入 USMART 管理, 这里同第四十七章(FATFS 实验)一模一样,可以参考第四十七章的方法操作。 软件设计部分,就给大家介绍到这里。 64.4 下载验证 在代码编译成功之后,我们下载到阿波罗 STM32 开发板上,然后在 USB_HOST 端子插入 U 盘/读卡器(带卡),注意:此时 USB SLAVE 口不要插 USB 线到电脑,否则会干扰!! 等 U 盘成功识别后,便可以看到 LCD 显示 U 盘容量等信息,如图 64.4.1 所示: 图 64.4.1 U 盘识别成功 此时,我们便可以通过 USMART 来测试 U 盘读写了,如图 64.4.2 和图 64.4.3 所示: 图 64.4.2 测试读取 U 盘读取 图 64.4.3 测试 U 盘写入 图 64.4.2 通过发送:mf_scan_files("3:"),扫描 U 盘根目录所有文件,然后通过 ai_load_picfile ("3:/示例图片.jpg",0,0,480,800,1),解码图片,并显示在 LCD 上面。说明读 U 盘是没问题的。 图 64.4.3 通过发送:mf_open("3:test u disk.txt",7),在 U 盘根目录创建 test u disk.txt 这个文 件,然后发送:mf_write("这是一个测试,写入文件",22),写入“这是一个测试,写入文件”到 这个文件里面,然后发送:mf_close(),关闭文件,完成一次文件创建。最后,发送: mf_scan_files("3:"),扫描 U 盘根目录文件,发现比图 64.4.2 所示多出了一个 test u disk.txt 的文 件,说明 U 盘写入成功。 这样,就完成了本实验的设计目的:实现 U 盘的读写操作。最后,大家还可以调用其他函 数,实现相关功能测试,这里就不给大家一一演示了,测试方法同:FATFS 实验(第四十七章)。 |
|
相关推荐
|
|
2234 浏览 1 评论
AD7686芯片不传输数据给STM32,但是手按住就会有数据。
2053 浏览 3 评论
4664 浏览 0 评论
如何解决MPU-9250与STM32通讯时,出现HAL_ERROR = 0x01U
2197 浏览 1 评论
hal库中i2c卡死在HAL_I2C_Master_Transmit
2734 浏览 1 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-26 20:45 , Processed in 0.559672 second(s), Total 34, Slave 27 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号