本帖最后由 无为之益 于 2019-9-20 16:49 编辑
小白第一次开发USB,现在初步能用STM32读写U盘。本人经常请教大家,现在也为论坛贡献点力量。
该方法简单易移植,初次接触USB开发的朋友可参考。
开发平台:Keil uVision5
使用的库及原始资料:
1、STM32官方程序:stm32_f105-07_f2_f4_usb-host-device_lib_V2.2.1
用 USB host MSC模式
2、文件系统:FatFs用的是官方R0.13C版。
移植方法如下:
先上一个项目截图(.c文件只需要如下图所示的几个文件):
.h文件需要如下:
就只要提取这些文件,其它的都不需要!
一般地,USB_Host文件夹里的程序不需要改动,FatFs文件夹里的程序也不需要改动。
先修改usb_bsp.c里的void USB_OTG_BSP_Init(USB_OTG_CORE_HANDLE * pdev)函数,使自己的硬件USB接口和程序对应。
再配置USB全局中断void USB_OTG_BSP_EnableInterrupt(USB_OTG_CORE_HANDLE * pdev)
最后主要只修改了usbh_usr.c文件里的内容。(我的项目只需要接一个U盘就可以)。——好像也没什么需要修改的。
开发过程中遇到过的 2个难题:
1、调试初始化函数void USBH_Init(USB_OTG_CORE_HANDLE *pdev,USB_OTG_CORE_ID_TypeDef coreID,USBH_HOST *phost, USBH_Class_cb_TypeDef *class_cb, USBH_Usr_cb_TypeDef *usr_cb),
到其中的HCD_Init(pdev , coreID);就运行不下去了,不知道哪里出了问题…后来打印跟踪调试发现:忘了开例程的TIMER2中断,打开后就OK了。即别忘了写上这个函数(我现在忘了它当时在哪个文件里了。我就是完全采用STM32官方的延时方法)
void TIM2_IRQHandler(void) { USB_OTG_BSP_TimerIRQ(); } 到此就全部Ok!可以读写U盘了!不过我这暂时只能识别2G的U盘,8G和16G 的U盘识别不了,因为时间关系,暂时没有去查找原因(我们项目2G暂时够用)。有知道的朋友请告诉我一声,免得我花时间去查找,谢谢!
2、因为我的项目还需要知道U盘的剩余容量,而官方例程中只有读取总容量,没有读取剩余容量的方法。于是我借鉴原子的例子(主要替换、修改int USBH_USR_MSC_Application(void) 函数)。 但是原子的例子挂载U盘在main的初始化程序里,而我的main函数如下(没有挂载U盘) int main(void) { peripherals_init(); xDelay(); xDelay(); //等待LCM屏自身初始化完毕 init_variable(); USBH_Init(&USB_OTG_Core, USB_OTG_FS_CORE_ID,&USB_Host, &USBH_MSC_cb, &USR_cb); for(;;) { USBH_Process(&USB_OTG_Core, &USB_Host); xDelay(); } } 所以在调用函数FRESULT f_getfree (const TCHAR* path,DWORD* nclst,FATFS** fatfs)时总是出错。返回值要么是0x0b,要么是0x0c。我一直以为是自己的PATH写错了(当时也确实不知道它该是什么)。在网上查了很多资料,觉得自己就一个U盘,应该是默认的0通道。但是把原子例子里的res=exf_getfree(“2:”,&Utotal,&Ufree); 改成res=exf_getfree(“0:”,&Utotal,&Ufree); 后还是不对。 最后发现要先挂载U盘,终于成功。 我修改了原子的程序如下:(只借鉴了他这3个函数并作了修改,其它的全是用的官方程序) int USBH_USR_MSC_Application(void) { u8 res=0; switch(USBH_USR_ApplicationState) { case USH_USR_FS_INIT: //初始化文件系统 if(f_mount(&fatfs, "", 0) != FR_OK) //挂载U盘----初始化时必须要有这一步,否正后面无法挂载成功 {//efs initialisation fails printf("> Cannot initialize File System.\r\n"); return (-1); } printf("> File System initialized.\r\n"); printf("> Disk capacity : %lu Bytes\r\n", USBH_MSC_Param.MSCapacity *USBH_MSC_Param.MSPageLength); printf("开始执行用户程序!!!\r\n"); USBH_USR_ApplicationState=USH_USR_FS_RW; break; case USH_USR_FS_RW: //执行USB OTG 读写操作程序 res=USBH_user_App(); //用户主程序 break; default: break; } return res; }
u8 USBH_user_App(void) { u32 Utotal,Ufree; u8 res=0; printf("设备连接成功!.\r\n"); res=exf_getfree("0:",&Utotal,&Ufree); if(res==0) { printf("FATFS OK!\r\n"); //printf("U盘总容量(16进制): %04X MB\r\n",Utotal>>10); //显示U盘总容量 MB----打印16进制 //printf("U盘剩余容量(16进制):%04X MB\r\n",Ufree>>10); //U盘剩余容量 MB printf("U盘总容量(10进制): %04d MB\r\n",Utotal>>10); //显示U盘总容量 MB----打印10进制 printf("U盘剩余容量(10进制):%04d MB\r\n",Ufree>>10); //U盘剩余容量 MB } while(HCD_IsDeviceConnected(&USB_OTG_Core))//设备连接成功 { Toggle_USBLed(); delay(200); } printf("设备连接中...\r\n"); return res; }
u8 exf_getfree(u8 *drv,u32 *total,u32 *free) {//f_getfree函数获取驱动器上空闲簇的数目 FATFS *fs1; u8 res; DWORD fre_clust=0, fre_sect=0, tot_sect=0; //得到磁盘信息及空闲簇数量 f_mount(&fatfs,"0:",1); // 重新挂载U盘 res = f_getfree((const TCHAR*)drv, &fre_clust, &fs1); if(res==0) { tot_sect=(fs1->n_fatent-2)*fs1->csize; //得到总扇区数 fre_sect=fre_clust*fs1->csize; //得到空闲扇区数 #if FF_MAX_SS!=512 //扇区大小不是512字节,则转换为512字节 tot_sect*=(fs1->ssize)/512; fre_sect*=(fs1->ssize)/512; #endif *total=tot_sect>>1; //单位为KB *free=fre_sect>>1; //单位为KB } return res; } 至此,全部OK!(没有优化)
|