入门级详细usb移植教程致正在为usb烦恼的朋友.docx
- 文档编号:9247465
- 上传时间:2023-05-17
- 格式:DOCX
- 页数:10
- 大小:23.07KB
入门级详细usb移植教程致正在为usb烦恼的朋友.docx
《入门级详细usb移植教程致正在为usb烦恼的朋友.docx》由会员分享,可在线阅读,更多相关《入门级详细usb移植教程致正在为usb烦恼的朋友.docx(10页珍藏版)》请在冰点文库上搜索。
入门级详细usb移植教程致正在为usb烦恼的朋友
入门级详细USB移植教程——致正在为USB烦恼的朋友
同上一篇MPU6050一样,我还是写一篇关于USB的帖子,在圈圈等玩USB的大神面前,我掌握的USB知识实在是九牛一毛,所以这篇帖子加上了入门级的修饰语。
写这篇帖子主要是为了那些想快速开发USB的人,至于想深入了解USB协议,可以先学完我这个再去看看别的高级教程可能会好点,虽然我强调自己掌握的USB知识不多,但是对于一般的应用已经足够,我这里主要是学会怎么去用USB做自己的东西,而且我觉得刚学完一个东西就来教下别人实在是一个一举两得的做法,因为我更清楚学习时的心理和一些小问题,而且我也可以进一步总结。
我有个观点不知道其他大神中不中听,好像圈圈大神就搞了USB几年达到了精通的水平,可能一些几个月达到了很懂的水平,但是这个过程实在是很漫长,对于很多人也没有必要对USB进行彻底的研究,只要会用就好,就像你可能不懂车的高级原理,但是你会开车就好了,^_^。
其他大神不同意的话,写个高级的USB教程让我们学习下吧。
这里其实也是个人学习笔记。
记得一个月前,我想做无线鼠标,开始在网上查找资料,从那个时候开始学习USB,找了圈圈的书将前面足足看了3、4遍,还只是瞎子摸象,不过瞎子摸象很正常啦,学什么东西一开始哪里可能能够弄清全局。
看了3、4编,实在是很煎熬,一直没有什么进展,没有搞出点成果。
就开始上网找资料,让瞎子摸象来得更彻底一点。
如果学过I2C的话,可能对USB理解会更透彻点,两者在某些方面还是有共通之处的,某种意义上来说,STM32的USB跟硬件I2C有点像,89C52的USB介于软件I2C和硬件I2C之间,89C52有了USB芯片的协助后,很多时序不用自己模拟,但是编程使用芯片搞USB这过程就跟软件I2C一样的蛋疼。
首先STM32是有USB的两个数据端口的,首先看上面的这张图,是野火ISO板子USB原理图部分,一个VCC,一个GND连接到USB设备,充电的时候就是这两个起作用,供电的作用。
D+和D-就是差分数据线,ID我们一般没有用到,是用来设备和主机之间的识别用到,有时候两台机器可以做设备和主机就靠这根线来区别。
主要是三极管这部分,由电路图可以知道PD3口要给低电平上拉电阻才能接到D+,应该这里在D-还要有一个三极管和上拉电路,不然这里默认了所接的设备一定是全速设备和高速设备,不是低速设备,不知道接低速设备有没有事。
USB运行的前提是要上拉电阻接通才行喔,这里不直接接上拉的原因就是可以自己控制,你可以再程序中控制这里来断开USB连接然后再接上去,选择较多,当然也有直接接上去的。
除了STM32,89c52和STC12等单片机也可以搞USB,圈圈就是用89C52来搞的,但是89C52是没有像STM32那样子内置USB外设的,那么就需要加多1块USB芯片,还有相应的外围电路,但是STM32就不用,好方便的说。
”主机在检测到设备接入后,会执行设备识别,这个过程比较麻烦,它的枚举过程包含了设备的一些相关信息与通信方式。
“这个过程我觉得如果不是要真正研究USB的话,也没有必要看,看了搞不好神经错乱。
加上ST官方库的USB例程后,STM32搞USB难度降低了几个等级。
ST官方有个JoyStickMouse的例程,就是通过摇杆来控制鼠标。
我们接下来是用按键来控制鼠标。
官方的源文件地址:
工程地址:
STM32F102/103的USB模块和USB库函数:
的USB程序开发笔记(看不懂,不过好像很牛逼):
USB源代码分析(很详细的)提供了设备、端点、接口、字符串、群组、制造商描述符(本来想在这里讲解下描述符的,但是描述符在这里的作用不大明显,到USB键盘那块的时候再讲解吧)问题八:
在标准的USB请求命令中,经常会看到Descriptor,这是什么来的呢?
回答八:
Descriptor即描述符,是一个完整的数据结构,可以通过C语言等编程实现,并存储在USB设备中,用于描述一个USB设备的所有属性,USB主机是通过一系列命令来要求设备发送这些信息的。
它的作用就是通过如问答节中的命令***作来给主机传递信息,从而让主机知道设备具有什么功能、属于哪一类设备、要占用多少带宽、使用哪类传输方式及数据量的大小,只有主机确定了这些信息之后,设备才能真正开始工作,所以描述符也是十分重要的部分,要好好掌握。
标准的描述符有5种,USB为这些描述符定义了编号:
1——设备描述符2——配置描述符3——字符描述符4——接口描述符5——端点描述符上面的描述符之间有一定的关系,一个设备只有一个设备描述符,而一个设备描述符可以包含多个配置描述符,而一个配置描述符可以包含多个接口描述符,一个接口使用了几个端点,就有几个端点描述符。
这间描述符是用一定的字段构成的,详细说明见上面文档的10页。
简单理解里面就是USB设备的一些描述,像档案。
usb_prop.c:
提供了Device_Property(性能),Device_Table&USER_STANDARD_REQUEST(请求)结构描述,这3个东西定义于usb_core.c,摇杆鼠标的一些处理过程hw_config.c:
提供了实际硬件需要的操作函数,Joystick_Send()通过函数UserToPMABufferCopy和SetEPTxValid将坐标值发给了USB端口。
STM32f10x_it.c:
里面有中断处理函数,千万别忽略里面的内容。
usb_core.c:
USB总线数据处理的核心文件,标准协议。
usb_init.c,usb_int.c:
用于端点数据输入输入中断处理usb_mem.c:
用于缓冲区操作usb_regs.c:
用于寄存器操作2.接下来要在main里面配置USB详细步骤如下:
1.官方例函数Set_System();用途:
配置好系统时钟等,按键IO口,以及上面我们提到的接通上拉电阻的那个管脚,USB管脚等等,这个函数根据作用分为以下几个部分:
系统时钟配置部分(可以省略)开启上拉时钟管脚的时钟,然后配置该管脚,这个管脚(USB_DISCONNECT_PIN)应该找到它定义的地方,将它改为你板子上面对应的管脚,可以用Ctrl+F找,我们找到它所在的地方如下图,因为这里涉及条件编译,所以你需要找到你对应编译部分的全部改掉。
我需要将它改成PD3.如果你的板子上面没有对应的管脚,只有类似下面的一个跳帽,就需要接上跳帽,接上去之后不要管这部分了,跟你都已经没有关系了。
/*EnabletheUSBdisconnectGPIOclock*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIO_DISCONNECT,ENABLE);/*USB_DISCONNECTusedasUSBpull-up*/GPIO_InitStructure.GPIO_Pin=USB_DISCONNECT_PIN;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD;GPIO_Init(USB_DISCONNECT,&GPIO_InitStructure);复制代码配置USB管脚,不知道为什么没有设置USB还是可以工作。
/*SetPA11,12asIN-USB_DM,DP*/RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA,ENABLE);GPIO_InitStructure.GPIO_Pin=GPIO_Pin_11|GPIO_Pin_12;GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF;GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_NOPULL;GPIO_Init(GPIOA,&GPIO_InitStructure);/*SETPA11,12forUSB:
USB_DM,DP*/GPIO_PinAFConfig(GPIOA,GPIO_PinSource11,GPIO_AF_14);GPIO_PinAFConfig(GPIOA,GPIO_PinSource12,GPIO_AF_14);复制代码配置按键等端口,官方的库是配置摇杆的4个管脚。
/*EnableJoystickGPIOsclock*/RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOF,ENABLE);RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB,ENABLE);RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOE,ENABLE);/*ConfiguretheJoyStickIOsasinputfloating*/GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_4|GPIO_Pin_9|GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN;GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_DOWN;/*PullDownismandatoryforJoystickpins*/GPIO_Init(GPIOF,&GPIO_InitStructure);/*ConfiguretheJoyStickIOsasinputfloating*/GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2|GPIO_Pin_5;GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN;GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_DOWN;/*PullDownismandatoryforJoystickpins*/GPIO_Init(GPIOB,&GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;GPIO_Init(GPIOF,&GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7;GPIO_Init(GPIOE,&GPIO_InitStructure);复制代码配置USB中断向量,USB传输数据过程需要中断,这个是重中之重,你可以不设置上面其他的东西,但是这个必须设置,别人就会出现,后面自己设置这个,可能多次出现这个,很大原因是中断设置的问题。
EXTI_ClearITPendingBit(EXTI_Line18);EXTI_InitStructure.EXTI_Line=EXTI_Line18;EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;EXTI_InitStructure.EXTI_LineCmd=ENABLE;EXTI_Init(&EXTI_InitStructure);复制代码上面几个步骤直接简化USB中断向量的设置,所以我在我的程序屏蔽了这个官方函数,直接自己写个,然后放在配置的最前面。
EXTI_InitTypeDefEXTI_InitStructure;voidUSB_IT_Config(void){EXTI_ClearITPendingBit(EXTI_Line18);EXTI_InitStructure.EXTI_Line=EXTI_Line18;EXTI_InitStructure.EXTI_Trigger=EXTI_Trigger_Rising;EXTI_InitStructure.EXTI_LineCmd=ENABLE;EXTI_Init(&EXTI_InitStructure);}复制代码2.官方例函数USB_Interrupts_Config();作用:
初始化USB中断,更准确的解释是:
开启USB唤醒中断和USB低优先级数据处理中断3.官方例函数Set_USBClock()作用:
开启USB时钟,更准确的解释是:
配置USB时钟,也就是从72M的主频得到48M的USB时钟(1.5分频)4.官方例函数USB_Init();作用:
USB硬件初始化,更准确的解释是:
用于初始化USB,最主要的就是调用了Joystick_init函数,开启了USB部分的电源等这里面有个很重要的东西要说下voidUSB_Init(void){pInformation=&Device_Info;pInformation->ControlState=2;pProperty=&Device_Property;pUser_Standard_Requests=&User_Standard_Requests;/*Initializedevicesonebyone*/pProperty->Init();}复制代码&Device_Property是跟pProperty一样的类型的结构体指针,结构体类型定义如下,不看也可以typedefstruct_DEVICE_PROP{void(*Init)(void);/*Initializethedevice*/void(*Reset)(void);/*Resetroutineofthisdevice*//*Devicedependentprocessafterthestatusstage*/void(*Process_Status_IN)(void);void(*Process_Status_OUT)(void);/*Procedureofprocessonsetupstageofaclassspecifiedrequestwithdatastage*//*AllclassspecifiedrequestswithdatastageareprocessedinClass_Data_SetupClass_Data_Setup()responsestocheckallspecialrequestsandfillsENDPOINT_INFOaccordingtotherequestIfINtokensareexpected,thenwLength&wOffsetwillbefilledwiththetotaltransferringbytesandthestartingpositionIfOUTtokensareexpected,thenrLength&rOffsetwillbefilledwiththetotalexpectedbytesandthestartingpositioninthebufferIftherequestisvalid,Class_Data_SetupreturnsSUCCESS,elseUNSUPPORTCAUTION:
SinceGET_CONFIGURATION&GET_INTERFACEarehighlyrelatedtotheindividualclasses,theywillbecheckedandprocessedhere.*/RESULT(*Class_Data_Setup)(uint8_tRequestNo);/*Procedureofprocessonsetupstageofaclassspecifiedrequestwithoutdatastage*//*AllclassspecifiedrequestswithoutdatastageareprocessedinClass_NoData_SetupClass_NoData_SetupresponsestocheckallspecialrequestsandperformtherequestCAUTION:
SinceSET_CONFIGURATION&SET_INTERFACEarehighlyrelatedtotheindividualclasses,theywillbecheckedandprocessedhere.*/RESULT(*Class_NoData_Setup)(uint8_tRequestNo);/*Class_Get_Interface_SettingThisfunctionisusedbythefileusb_core.ctotestiftheselectedInterfaceandAlternateSetting(uint8_tInterface,uint8_tAlternateSetting)aresupportedbytheapplication.Thisfunctioniswritingbyuser.Itshouldreturn"SUCCESS"iftheInterfaceandAlternateSettingaresupportedbytheapplicationor"UNSUPPORT"iftheyarenotsupported.*/RESULT(*Class_Get_Interface_Setting)(uint8_tInterface,uint8_tAlternateSetting);uint8_t*(*GetDeviceDescriptor)(uint16_tLength);uint8_t*(*GetConfigDescriptor)(uint16_tLength);uint8_t*(*GetStringDescriptor)(uint16_tLength);/*Thisfieldisnotusedincurrentlibraryversion.Itiskeptonlyforcompatibilitywithpreviousversions*/void*RxEP_buffer;uint8_tMaxPacketSize;}DEVICE_PROP;复制代码Device_Property这个结构体里面有多个我们已经定义好的函数,如下:
DEVICE_PROPDevice_Property={Joystick_init,Joystick_Reset,Joystick_Status_In,Joystick_Status_Out,Joystick_Data_Setup,Joystick_NoData_Setup,Joystick_Get_Interface_Setting,Joystick_GetDeviceDescriptor,Joystick_GetConfigDescriptor,Joystick_GetStringDescriptor,0,0x40/*MAXPACKETSIZE*/};复制代码在语句pProperty=&Device_Property;和pProperty->Init();之后,就运行了这个函数Joystick_init,里面有再看PowerOn,里面又有USB_Cable_Config(ENABLE);好不容易找到我们想要的函数。
这个就是断开和连接上拉电阻的函数,前面我们只是打开时钟和配置这个管脚而已,同样的他对应的管脚是USB_DISCONNECT和USB_DISCONNECT_PIN,前面如果将这两个改了,就不要改了。
/********************************************************************************FunctionName:
USB_Cable_Config.*Description:
SoftwareConnection/DisconnectionofUSBCable.*Input:
NewState:
newstate.*Output:
None.*Return:
None*******************************************************************************/voidUSB_Cable_Config(Functional
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 入门 详细 usb 移植 教程 正在 烦恼 朋友