赞
踩
USB ,是英文 Universal Serial BUS(通用串行总线)的缩写,而其中文简称为“通串线,是一个外部总线标准,用于规范电脑与外部设备的连接和通讯。是应用在 PC 领域的接口技术。USB 接口支持设备的即插即用和热插拔功能。
标准 USB 共四根线组成,除 VCC/GND 外,另外为 D+和 D-,这两根数据线采用的是差分电压的方式进行数据传输的。在 USB 主机上,D-和 D+都是接了 15K 的电阻到地的,所以在没有设备接入的时候,D+、D-均是低电平。而在 USB 设备中,如果是高速设备,则会在 D+上接一个 1.5K 的电阻到 VCC,而如果是低速设备,则会在 D-上接一个 1.5K 的电阻到 VCC。这样当设备接入主机的时候,主机就可以判断是否有设备接入,并能判断设备是高速设备还是低速设备。
STM32F407 系列芯片自带有 USB OTG FS(全速)和 USB OTG HS(高速),其中 HS 需要外扩高速 PHY 芯片实现。STM32F407 的 USB OTG FS 是一款双角色设备 (DRD) 控制器,同时支持从机功能和主机功能,完全符合 USB 2.0 规范的 On-The-Go 补充标准。此外,该控制器也可配置为“仅主机”模式或“仅从机” 模式,完全符合 USB 2.0 规范。在主机模式下,OTG FS 支持全速(FS,12 Mb/s)和低速(LS,1.5 Mb/s)收发器,而从机模式下则仅支持全速(FS,12 Mb/s)收发器。OTG FS 同时支持 HNP 和 SRP。对于USB OTG FS功能模块,STM32F4通过AHB总线访问(AHB频率必须大14.2Mhz),其中 48Mhz 的 USB 时钟,是来自时钟树图里面的 PLL48CK(和 SDIO 共用)。STM32F407 USB OTG FS 框图如图所示:
STM32F407 的 USB OTG FS 主要特性可分为三类:通用特性、主机模式特性和从机模式特性:
ST 提供的 USB OTG 库,该库包含了 STM32F4 USB 主机(Host)和从机(Device)驱动库,并提供了 10 个例程供我们参考,下载链接如下:https://download.csdn.net/download/weixin_44567668/87853740
USB技术的发展,使得PC和周边设备能够通过简单的方式、适度的制造成本,将各种数据传输速度的设备连接在一起。我们提到的应用,都是通过USB连接到PC,并在PC的控制下进行数据交换。但这种方便的交换方式,一旦离开了PC,各设备间无法利用USB口进行操作,因为没有一个设备能够像PC一样充当主机。
OTG是On-The-Go的缩写,是近年发展起来的技术。2001年12月18日由USB标准化组织公布,主要应用于不同的设备或移动设备间的联接,进行数据交换。OTG技术允许在没有主机(Host)的情况下,实现设备间的数据传送。例如数码相机直接连接到打印机上,通过OTG技术,连接两台设备间的USB口,将拍出的相片立即打印出来;也可以将数码照相机中的数据,通过OTG发送到USB接口的移动硬盘上,野外操作就没有必要携带价格昂贵的存储卡,或者背一个便携电脑。
本实验通过获取SD卡或者外部SPI FLASH当作存储容量,来实现类似U盘功能,从而连接电脑时,可以当作U盘从而实现从设备Slave功能
代码移植自 ST 官方例程:STM32_USB-Host-Device_Lib_V2.1.0\Project\USB_Device_Examples\MSC
在工程上添加相关文件
移植时我们重点要修改的就是 USB_APP 文件夹下面的代码。其他代码(USB_OTG 和USB_DEVICE 文件夹下的代码)一般不用修改。
usb_bsp.c 提供了几个 USB 库需要用到的底层初始化函数,包括:IO 设置、中断设置、VBUS配置以及延时函数等,需要我们自己实现。USB Device(Slave)和 USB Host 共用这个.c 文件。
#include "usb_bsp.h" #include "sys.h" #include "delay.h" #include "usart.h" //USB主机电源控制口 #define USB_HOST_PWRCTRL PAout(15) //PA15 //USB OTG 底层IO初始化 //pdev:USB OTG内核结构体指针 void USB_OTG_BSP_Init(USB_OTG_CORE_HANDLE *pdev) { GPIO_InitTypeDef GPIO_InitStructure; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA时钟 RCC_AHB2PeriphClockCmd(RCC_AHB2Periph_OTG_FS, ENABLE);//使能USB OTG时钟 钟 //GPIOA11,A12设置 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11 | GPIO_Pin_12;//PA11/12复用功能输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能 GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//100MHz GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;//PA15推挽输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//输出功能 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化 USB_HOST_PWRCTRL=1; //开启USB HOST电源供电 GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_OTG_FS);//PA11,AF10(USB) GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_OTG_FS);//PA12,AF10(USB) } //USB OTG 中断设置,开启USB FS中断 //pdev:USB OTG内核结构体指针 void USB_OTG_BSP_EnableInterrupt(USB_OTG_CORE_HANDLE *pdev) { NVIC_InitTypeDef NVIC_InitStructure; NVIC_InitStructure.NVIC_IRQChannel = OTG_FS_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x00;//抢占优先级0 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x03;//子优先级3 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能通道 NVIC_Init(&NVIC_InitStructure);//配置 } //USB OTG 中断设置,开启USB FS中断 //pdev:USB OTG内核结构体指针 void USB_OTG_BSP_DisableInterrupt(void) { } //USB OTG 端口供电设置(本例程未用到) //pdev:USB OTG内核结构体指针 //state:0,断电;1,上电 void USB_OTG_BSP_DriveVBUS(USB_OTG_CORE_HANDLE *pdev, uint8_t state) { } //USB_OTG 端口供电IO配置(本例程未用到) //pdev:USB OTG内核结构体指针 void USB_OTG_BSP_ConfigVBUS(USB_OTG_CORE_HANDLE *pdev) { } //USB_OTG us级延时函数 //本例程采用SYSTEM文件夹的delay.c里面的delay_us函数实现 //官方例程采用的是定时器2来实现的. //usec:要延时的us数. void USB_OTG_BSP_uDelay (const uint32_t usec) { delay_us(usec); } //USB_OTG ms级延时函数 //本例程采用SYSTEM文件夹的delay.c里面的delay_ms函数实现 //官方例程采用的是定时器2来实现的. //msec:要延时的ms数. void USB_OTG_BSP_mDelay (const uint32_t msec) { delay_ms(msec); }
usbd_desc.c 提供了 USB 设备类的描述符,直接决定了 USB 设备的类型、断点、接口、字符串、制造商等重要信息。这个里面的内容,我们一般不用修改,直接用官方的即可。注意,这里:usbd_desc.c 里面的:usbd 即 device 类,同样:usbh 即 host 类,所以通过文件名我们可以很容易区分该文件是用在 device 还是 host,而只有 usb 字样的那就是 device 和 host 可以共用的。
usbd_usr.c 提供用户应用层接口函数,即 USB 设备类的一些回调函数,当 USB 状态机处理完不同事务的时候,会调用这些回调函数,我们通过这些回调函数,就可以知道 USB 当前状态,比如:是否枚举成功了?是否连接上了?是否断开了?等,根据这些状态,用户应用程序可以执行不同操作,完成特定功能。
#include "usbd_usr.h" #include "usb_dcd_int.h" #include <stdio.h> #include <usart.h> //表示USB连接状态 //0,没有连接; //1,已经连接; vu8 bDeviceState=0; //默认没有连接 extern USB_OTG_CORE_HANDLE USB_OTG_dev; //USB OTG 中断服务函数 //处理所有USB中断 void OTG_FS_IRQHandler(void) { USBD_OTG_ISR_Handler(&USB_OTG_dev); } //指向DEVICE_PROP结构体 //USB Device 用户回调函数. USBD_Usr_cb_TypeDef USR_cb = { USBD_USR_Init, USBD_USR_DeviceReset, USBD_USR_DeviceConfigured, USBD_USR_DeviceSuspended, USBD_USR_DeviceResumed, USBD_USR_DeviceConnected, USBD_USR_DeviceDisconnected, }; //USB Device 用户自定义初始化函数 void USBD_USR_Init(void) { //printf("USBD_USR_Init\r\n"); } //USB Device 复位 //speed:USB速度,0,高速;1,全速;其他,错误. void USBD_USR_DeviceReset (uint8_t speed) { switch (speed) { case USB_OTG_SPEED_HIGH: printf("USB Device Library v1.1.0 [HS]\r\n"); break; case USB_OTG_SPEED_FULL: printf("USB Device Library v1.1.0 [FS]\r\n"); break; default: printf("USB Device Library v1.1.0 [??]\r\n"); break; } } //USB Device 配置成功 void USBD_USR_DeviceConfigured (void) { printf("MSC Interface started.\r\n"); } //USB Device挂起 void USBD_USR_DeviceSuspended(void) { printf("Device In suspend mode.\r\n"); } //USB Device恢复 void USBD_USR_DeviceResumed(void) { printf("Device Resumed\r\n"); } //USB Device连接成功 void USBD_USR_DeviceConnected (void) { bDeviceState=1; printf("USB Device Connected.\r\n"); } //USB Device未连接 void USBD_USR_DeviceDisconnected (void) { bDeviceState=0; printf("USB Device Disconnected.\r\n"); }
usbd_storage_msd.c 提供一些磁盘操作函数,包括支持的磁盘个数,以及每个磁盘的初始化和读写等函数。本章我们设置了 2 个磁盘:SD 卡和 SPI FLASH。
#include "usbd_msc_mem.h" #include "usb_conf.h" #include "w25qxx.h" #include "sdio_sdcard.h" //最大支持的设备数,2个 #define STORAGE_LUN_NBR 2 自己定义的一个标记USB状态的寄存器/// //bit0:表示电脑正在向SD卡写入数据 //bit1:表示电脑正从SD卡读出数据 //bit2:SD卡写数据错误标志位 //bit3:SD卡读数据错误标志位 //bit4:1,表示电脑有轮询操作(表明连接还保持着) vu8 USB_STATUS_REG=0; //USB Mass storage 标准查询数据(每个lun占36字节) const int8_t STORAGE_Inquirydata[] = { /* LUN 0 */ 0x00, 0x80, 0x02, 0x02, (USBD_STD_INQUIRY_LENGTH - 4), 0x00, 0x00, 0x00, /* Vendor Identification */ 'A', 'L', 'I', 'E', 'N', 'T', 'E', 'K', ' ',//9字节 /* Product Identification */ 'S', 'P', 'I', ' ', 'F', 'l', 'a', 's', 'h',//15字节 ' ','D', 'i', 's', 'k', ' ', /* Product Revision Level */ '1', '.', '0', ' ', //4字节 /* LUN 1 */ 0x00, 0x80, 0x02, 0x02, (USBD_STD_INQUIRY_LENGTH - 4), 0x00, 0x00, 0x00, /* Vendor Identification */ 'A', 'L', 'I', 'E', 'N', 'T', 'E', 'K',' ', //9字节 /* Product Identification */ 'S', 'D', ' ', 'F', 'l', 'a', 's', 'h', ' ',//15字节 'D', 'i', 's', 'k', ' ', ' ', /* Product Revision Level */ '1', '.', '0' ,' ', //4字节 }; int8_t STORAGE_Init (uint8_t lun); int8_t STORAGE_GetCapacity (uint8_t lun,uint32_t *block_num,uint32_t *block_size); int8_t STORAGE_IsReady (uint8_t lun); int8_t STORAGE_IsWriteProtected (uint8_t lun); int8_t STORAGE_Read (uint8_t lun,uint8_t *buf,uint32_t blk_addr,uint16_t blk_len); int8_t STORAGE_Write (uint8_t lun,uint8_t *buf,uint32_t blk_addr,uint16_t blk_len); int8_t STORAGE_GetMaxLun (void); //USB Device 用户回调函数接口 USBD_STORAGE_cb_TypeDef USBD_MICRO_SDIO_fops = { STORAGE_Init, STORAGE_GetCapacity, STORAGE_IsReady, STORAGE_IsWriteProtected, STORAGE_Read, STORAGE_Write, STORAGE_GetMaxLun, (int8_t *)STORAGE_Inquirydata, }; USBD_STORAGE_cb_TypeDef *USBD_STORAGE_fops=&USBD_MICRO_SDIO_fops;//指向USBD_MICRO_SDIO_fops结构体. //初始化存储设备 //lun:逻辑单元编号,0,SD卡;1,SPI FLASH //返回值:0,成功; // 其他,错误代码 int8_t STORAGE_Init (uint8_t lun) { SD_Init(); W25QXX_Init(); return 0; } //获取存储设备的容量和块大小 //lun:逻辑单元编号,0,SD卡;1,SPI FLASH //block_num:块数量(扇区数) //block_size:块大小(扇区大小) //返回值:0,成功; // 其他,错误代码 int8_t STORAGE_GetCapacity (uint8_t lun, uint32_t *block_num, uint32_t *block_size) { if(lun==1) { *block_size=512; *block_num=SDCardInfo.CardCapacity/512; }else { *block_size=512; *block_num=1024*1024*12/512; //SPI FLASH的前面12M字节,文件系统用 } return 0; } //查看存储设备是否就绪 //lun:逻辑单元编号,0,SD卡;1,SPI FLASH //返回值:0,就绪; // 其他,未就绪 int8_t STORAGE_IsReady (uint8_t lun) { USB_STATUS_REG|=0X10;//标记轮询 return 0; } //查看存储设备是否写保护 //lun:逻辑单元编号,0,SD卡;1,SPI FLASH //返回值:0,没有写保护; // 其他,写保护(只读) int8_t STORAGE_IsWriteProtected (uint8_t lun) { return 0; } //从存储设备读取数据 //lun:逻辑单元编号,0,SD卡;1,SPI FLASH //buf:数据存储区首地址指针 //blk_addr:要读取的地址(扇区地址) //blk_len:要读取的块数(扇区数) //返回值:0,成功; // 其他,错误代码 int8_t STORAGE_Read (uint8_t lun,uint8_t *buf,uint32_t blk_addr,uint16_t blk_len) { int8_t res=0; USB_STATUS_REG|=0X02;//标记正在读数据 if(lun==1) { res=SD_ReadDisk(buf,blk_addr,blk_len); if(res)USB_STATUS_REG|=0X08;//SD卡读错误! }else { W25QXX_Read(buf,blk_addr*512,blk_len*512); } return res; } //向存储设备写数据 //lun:逻辑单元编号,0,SD卡;1,SPI FLASH //buf:数据存储区首地址指针 //blk_addr:要写入的地址(扇区地址) //blk_len:要写入的块数(扇区数) //返回值:0,成功; // 其他,错误代码 int8_t STORAGE_Write (uint8_t lun,uint8_t *buf,uint32_t blk_addr,uint16_t blk_len) { int8_t res=0; USB_STATUS_REG|=0X01;//标记正在写数据 if(lun==1) { res=SD_WriteDisk (buf,blk_addr,blk_len); if(res)USB_STATUS_REG|=0X04;//SD卡写错误! }else { W25QXX_Write(buf,blk_addr*512,blk_len*512); } return res; } //获取支持的最大逻辑单元个数 //返回值:支持的逻辑单元个数-1 int8_t STORAGE_GetMaxLun (void) { return (STORAGE_LUN_NBR - 1); }
只需要在主函数初始化里添加USB初始化。
USB_OTG_CORE_HANDLE USB_OTG_dev;
//主函数里添加
USBD_Init(&USB_OTG_dev,USB_OTG_FS_CORE_ID,&USR_desc,&USBD_MSC_cb,&USR_cb);
其中,USB_OTG_CORE_HANDLE 是一个全局结构体类型,用于存储 USB 通信中 USB 内核需要使用的的各种变量、状态和缓存等。
执行完该函数以后,USB 就启动了,所有 USB 事务,都是通过 USB 中断触发,并由 USB 驱动库自动处理。USB 中断服务函数在usbd_usr.c 里面:
//USB OTG 中断服务函数 处理所有 USB 中断
void OTG_FS_IRQHandler(void)
{
USBD_OTG_ISR_Handler(&USB_OTG_dev);
}
U 盘,全称 USB 闪存盘,英文名“USB flash disk”。它是一种使用 USB 接口的无需物理驱动器的微型高容量移动存储产品,通过 USB 接口与主机连接,实现即插即用,是最常用的移动存储设备之一。本实验就是将单片机当作Host,以通过 STM32F4 的 USB HOST 接口,读写 U盘或 SD 卡读卡器等设备。
代码移植自 ST 官方例程:STM32_USB-Host-Device_Lib_V2.1.0\Project\USB_Host_Examples\MSC
在上个实验的基础上,只需要修改APP文件夹里的文件即可。将STM32_USB-Host-Device_Lib_V2.1.0\Project\USB_Host_Examples\MSC\src文件夹里的usb_bsp.c、usbh_usr.c拷贝进来,再将STM32_USB-Host-Device_Lib_V2.1.0\Project\USB_Host_Examples\MSC\inc里的usb_conf.h、usbh_conf.h、usbh_usr.h总共3个文件拷贝进来,结果如下:
usb_bsp.c 的代码,和上一章的一样,可以用上一章的代码直接替换即可正常使用。usbh_usr.c 提供用户应用层接口函数,相比上章例程,USB HOST 通信的回调函数更多一些
#include "usbh_usr.h" #include "led.h" #include "ff.h" #include "usart.h" static u8 AppState; extern USB_OTG_CORE_HANDLE USB_OTG_Core; //USB OTG 中断服务函数 //处理所有USB中断 void OTG_FS_IRQHandler(void) { USBH_OTG_ISR_Handler(&USB_OTG_Core); } //USB HOST 用户回调函数. USBH_Usr_cb_TypeDef USR_Callbacks= { USBH_USR_Init, USBH_USR_DeInit, USBH_USR_DeviceAttached, USBH_USR_ResetDevice, USBH_USR_DeviceDisconnected, USBH_USR_OverCurrentDetected, USBH_USR_DeviceSpeedDetected, USBH_USR_Device_DescAvailable, USBH_USR_DeviceAddressAssigned, USBH_USR_Configuration_DescAvailable, USBH_USR_Manufacturer_String, USBH_USR_Product_String, USBH_USR_SerialNum_String, USBH_USR_EnumerationDone, USBH_USR_UserInput, USBH_USR_MSC_Application, USBH_USR_DeviceNotSupported, USBH_USR_UnrecoveredError }; / //以下为各回调函数实现. //USB HOST 初始化 void USBH_USR_Init(void) { printf("USB OTG HS MSC Host\r\n"); printf("> USB Host library started.\r\n"); printf(" USB Host Library v2.1.0\r\n\r\n"); } //检测到U盘插入 void USBH_USR_DeviceAttached(void)//U盘插入 { LED1=1; printf("检测到USB设备插入!\r\n"); } //检测到U盘拔出 void USBH_USR_DeviceDisconnected (void)//U盘移除 { LED1=0; printf("USB设备拔出!\r\n"); } //复位从机 void USBH_USR_ResetDevice(void) { printf("复位设备...\r\n"); } //检测到从机速度 //DeviceSpeed:从机速度(0,1,2 / 其他) void USBH_USR_DeviceSpeedDetected(uint8_t DeviceSpeed) { if(DeviceSpeed==HPRT0_PRTSPD_HIGH_SPEED) { printf("高速(HS)USB设备!\r\n"); } else if(DeviceSpeed==HPRT0_PRTSPD_FULL_SPEED) { printf("全速(FS)USB设备!\r\n"); } else if(DeviceSpeed==HPRT0_PRTSPD_LOW_SPEED) { printf("低速(LS)USB设备!\r\n"); } else { printf("设备错误!\r\n"); } } //检测到从机的描述符 //DeviceDesc:设备描述符指针 void USBH_USR_Device_DescAvailable(void *DeviceDesc) { USBH_DevDesc_TypeDef *hs; hs=DeviceDesc; printf("VID: %04Xh\r\n" , (uint32_t)(*hs).idVendor); printf("PID: %04Xh\r\n" , (uint32_t)(*hs).idProduct); } //从机地址分配成功 void USBH_USR_DeviceAddressAssigned(void) { printf("从机地址分配成功!\r\n"); } //配置描述符获有效 void USBH_USR_Configuration_DescAvailable(USBH_CfgDesc_TypeDef * cfgDesc, USBH_InterfaceDesc_TypeDef *itfDesc, USBH_EpDesc_TypeDef *epDesc) { USBH_InterfaceDesc_TypeDef *id; id = itfDesc; if((*id).bInterfaceClass==0x08) { printf("可移动存储器设备!\r\n"); }else if((*id).bInterfaceClass==0x03) { printf("HID 设备!\r\n"); } } //获取到设备Manufacturer String void USBH_USR_Manufacturer_String(void *ManufacturerString) { printf("Manufacturer: %s\r\n",(char *)ManufacturerString); } //获取到设备Product String void USBH_USR_Product_String(void *ProductString) { printf("Product: %s\r\n",(char *)ProductString); } //获取到设备SerialNum String void USBH_USR_SerialNum_String(void *SerialNumString) { printf("Serial Number: %s\r\n",(char *)SerialNumString); } //设备USB枚举完成 void USBH_USR_EnumerationDone(void) { printf("设备枚举完成!\r\n\r\n"); } //无法识别的USB设备 void USBH_USR_DeviceNotSupported(void) { printf("无法识别的USB设备!\r\n\r\n"); } //等待用户输入按键,执行下一步操作 USBH_USR_Status USBH_USR_UserInput(void) { printf("跳过用户确认步骤!\r\n"); return USBH_USR_RESP_OK; } //USB接口电流过载 void USBH_USR_OverCurrentDetected (void) { printf("端口电流过大!!!\r\n"); } 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; } //用户要求重新初始化设备 void USBH_USR_DeInit(void) { AppState=USH_USR_FS_INIT; } //无法恢复的错误!! void USBH_USR_UnrecoveredError (void) { printf("无法恢复的错误!!!\r\n\r\n"); } //用户定义函数,实现fatfs diskio的接口函数 extern USBH_HOST USB_Host; //获取U盘状态 //返回值:0,U盘未就绪 // 1,就绪 u8 USBH_UDISK_Status(void) { return HCD_IsDeviceConnected(&USB_OTG_Core);//返回U盘状态 } //读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 盘的文件读写访问。
#include "usbh_usr.h" USBH_HOST USB_Host; USB_OTG_CORE_HANDLE USB_OTG_Core; //用户测试主程序 //返回值:0,正常 // 1,有问题 u8 USH_User_App(void) { u32 total,free; u8 res=0; printf("设备连接成功!."); res=exf_getfree("2:",&total,&free); //2为U盘 if(res==0) { printf("U Disk Total Size:%d MB\r\n",total); //显示U盘总容量 MB printf("U Disk Free Size:%d MB\r\n",free); //显示U盘剩余容量 MB } while(HCD_IsDeviceConnected(&USB_OTG_Core))//设备连接成功 { LED1=!LED1; delay_ms(200); } printf("设备连接中..."); return res; } int main(void) { u8 t; /************* 一系列初始化 */ f_mount(fs[2],"2:",1); //挂载U盘 //初始化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; } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。