• 关于stm32的USB学习笔记之usbcore.c


    #include <stm32f10x_lib.h>
    #include "usbreg.h"
    #include "usbcore.h"
    #include "usbuser.h"
    #include "usbcfg.h"
    #include "usb.h"
    #include "usb_hw.h"
    #include "usbdesc.h"
    #include "hid.h"
    #include "hiduser.h"
    
    
    #define	_DEBUG_
    #include "debug.h"
    
    #pragma diag_suppress 111,1441
    
    //用来指示USB设备的状态
    WORD	USB_DeviceStatus;
    //用来存储设备的地址
    BYTE	USB_DeviceAddress;
    //用来存储USB当前使用的设备的配置
    BYTE	USB_Configuration;
    //此配置使用端点
    DWORD USB_EndPointMask;
    //用于标志此端点是否已经被停止0~15依次代表15个端点
    DWORD USB_EndPointHalt;
    //此配置使用的接口数
    BYTE  USB_NumInterfaces;
    //每个接口可用的当前接口可替换值
    BYTE  USB_AltSetting[USB_IF_NUM];
    
    
    /*用于临时存储控制传输时的数据包*/
    USB_SETUP_PACKET SetupPacket;
    
    /*用于向主机发送数据的EP0的数据结构*/
    USB_EP_DATA EP0Data;
    /*EP0Buf用于向USB发送数据时用的缓冲区*/
    BYTE	EP0Buf[USB_MAX_PACKET0];
    
    /*功能:复位USB的一些数据标志
     *参数:无
     *返回值:无
     */
    void	USB_ResetCore(void)
    {
    	//默认为总线供电,因为我们的USB现在不都是插在电脑上才能工作的么&^_^
    	USB_DeviceStatus 	=	USB_POWER;	
    	//在枚举之初地址当然是0
    	USB_DeviceAddress	=	0;
    	//配置描述符的标识从1开始,这里也先置为0
    	USB_Configuration	=	0;
    	//目前使用的是端点0
    	USB_EndPointMask	= 	0x00010001;
    	//没有停止的端点
    	USB_EndPointHalt	=	0x00000000;
    }
    
    /*功能:建立阶段,读取建立数据包
     *参数:无
     *返回值:无
     */
    void USB_SetupStage(void)
    {
    	 USB_ReadEP(0x00,(BYTE*)&SetupPacket);
    }
    /*功能:建立阶段,In握手包
     *参数:无
     *返回值:无
     */
    void USB_StatusInStage(void)
    {
    	 USB_WriteEP(0x80,NULL,0);
    }
    /*功能:建立阶段,Out握手包
     *参数:无
     *返回值:无
     */
    void USB_StatusOutStage(void)
    {
    	 USB_ReadEP(0x00,EP0Buf);
    }
    /*功能:数据In阶段
     *参数:无
     *返回值:无
     */
    void USB_DataInStage(void)
    {
    	DWORD	cnt;
    	//先计算引次要发送多少数据
    	if(EP0Data.Count > USB_MAX_PACKET0)
    		cnt	= USB_MAX_PACKET0;
    	else
    		cnt	= EP0Data.Count;
    	//这里写端点却主机读,则将Dir位置1
       	cnt	= USB_WriteEP(0x80,EP0Data.pData,cnt);
    	EP0Data.pData	+=	cnt;
    	EP0Data.Count	-=	cnt;
    }
    /*功能:数据Out阶段
     *参数:无
     *返回值:无
     */
    void USB_DataOutStage(void)
    {
    	 DWORD	cnt;
    
    	 cnt	=	USB_ReadEP(0x00,EP0Data.pData);
    	 EP0Data.pData+=cnt;
    	 EP0Data.Count-=cnt;
    }
    /*功能:获取USB设备的状态
     *参数:无 
     *返回值:TRUE	--->成功
     *		 FALSE	--->错误
     */
    __inline BOOL	USB_GetStatus(void)
    {
    	DWORD	n,m;
    	
    	switch(SetupPacket.bmRequestType.BM.Recipient)
    	{
    		//接收端是设备
    		case REQUEST_TO_DEVICE:
    			//返回设备状态给他
    			EP0Data.pData = (BYTE *)&USB_DeviceStatus;
    			//将状态信息发送给主机
    			USB_DataInStage();
    			break;
    		//接收端是接口
    		case REQUEST_TO_INTERFACE:
    			/*配置描述符的标识从1开始,并且请求的接口号不能大于接口的数目,因为接口数目从0开始
    			 *因为我们接口描述符中的接口号是一个字节所以这里wIndex中的数据中人低字节有效
    			 */
    			if((USB_Configuration !=0)&&(SetupPacket.wIndex.WB.L < USB_NumInterfaces))
    			{	
    				//清0两个字节,因为根据USB协议此处必须返回0
    				*((__packed WORD *)EP0Buf) = 0;	
    				EP0Data.pData = EP0Buf;
    				//发送给主机
    				USB_DataInStage();
    			}
    			//此接口出现了错误
    			else
    				return	FALSE;
    			break;
    		case REQUEST_TO_ENDPOINT:
    			//端点号高1位0方向,低4位为端点号
    			n	= SetupPacket.wIndex.WB.L & 0x8f;
    			//m的高16位代表in端点的标志,低16位代表out端点的标志
    			m	= (n&0x80)?(1<<16 )<< (n&0x0f) :(1<<n);
    			//如果配置标识不为0,或配置标识为0,但是是端点0时,才算正常
    			if((USB_Configuration !=0)||((n&0x0f)==0)&&(USB_EndPointMask & m))
    			{
    				//查看此端点是否已经停用
    				*((__packed WORD *)EP0Buf) = (USB_EndPointHalt &m )?1:0;
    				EP0Data.pData = EP0Buf;
    				//将数据发送给主机
    				USB_DataInStage();
    			}
    			//说明配置描述符出了问题
    			else
    				return	FALSE;
    			break;
    		default:
    			return	FALSE;
    	}	
      	return TRUE;
    }
    /*功能:设置/清除USB设备的特征
     *参数:sc
     			0----->清除
    			1----->设置
     *返回值:TRUE	--->成功
     *		 FALSE	--->错误
     */
    __inline BOOL USB_SetClrFeature(DWORD	sc)
    {
    	DWORD	n,m;
    	switch(SetupPacket.bmRequestType.BM.Recipient)
    	{
    		//接收端是设备,则清除或设置设备的特性
    		case REQUEST_TO_DEVICE:
    			if(SetupPacket.wValue.W == USB_FEATURE_REMOTE_WAKEUP)
    			{
    				if(sc)
    				{
    					printf("设置设备远程唤醒特性\r\n");
    					//设置USB状态为使能远程唤醒
    					USB_DeviceStatus |= USB_GETSTATUS_REMOTE_WAKEUP;
    					/*stm32硬件本身就支持远程唤醒,这里就不用设置了
    					 *当然,软件支不支持在于对中断屏蔽位的设置
    					 */
    				}	
    				else
    				{
    					printf("清除设备远程唤醒特性\r\n");
    					USB_DeviceStatus &= ~USB_GETSTATUS_REMOTE_WAKEUP;
    					/*stm32硬件本身就支持远程唤醒,这里就不用设置了
    					 *当然,软件支不支持在于对中断屏蔽位的设置
    					 */
    				}
    			}
    			//不支持的请求
    			else
    			{
    				printf("不支持的请求\r\n");
    				return FALSE;
    			}
    			break;
    		//接收端是接口
    		case REQUEST_TO_INTERFACE:
    			//接口不支持清除特性
    			printf("清楚设置接口特征不被USB2.0支持\r\n");
    			return 	FALSE;
    		//接收端是端点
    		case REQUEST_TO_ENDPOINT:
    			//取得端点号
    			n = SetupPacket.wIndex.WB.L & 0x8F;
    //			printf("请求的端点是:");
    //			printhex(n);
    //			printf("USB_Configuration:");
    //			printhex(USB_Configuration);
    //			printf("USB_EndPointMask");
    //			printhex(USB_EndPointMask);
    //			printf("\r\n");
    			//将端点转化成与EndPointMask一样的格式
    			m =	(n & 0x80)?((1<<16) << (n&0x0f)) : (1<<n);
    		    /*根据USB协议来说,
    			 *地址状态下只有端点0才能使用,
    			 *配置状态下可用
    			 *不知道他这句是不是bug
    			 *原文件引用:
    			 *This request is valid when the device is in the Address state;
    			 *references to interfaces or to endpoints other than endpoint zero 
    			 *shall cause the device to respond with a Request Error
    			 */
    			 /*	此处认为只用配置状态下的非0端点才能清楚特征 ,至于地址状态下没有处理
    			  *
    			  */
    			if((USB_Configuration !=0) && ((n&0x0f)!=0) && (USB_EndPointMask & m))
    			{
    				//设置/清楚 某个端点stall状态
    				if(SetupPacket.wValue.W == USB_FEATURE_ENDPOINT_STALL)
    				{
    					//设置
    					if(sc)
    					{
    						printf("设置端点远程唤醒特性\r\n");
    						//设置请求的端点为stall
    						USB_SetStallEP(n);
    						//更新USB的状态位
    						USB_EndPointHalt |= m;	
    					}
    					//清楚
    					else
    					{
    						printf("清楚端点远程唤醒特性\r\n");
    						USB_ClrStallEP(n);
    						USB_EndPointHalt &= ~m;
    					}
    
    				}
    				//未定义的请求
    				else
    				{
    					printf("不正确的端点请求\r\n");
    					return FALSE;
    				}
    			}
    			//不正确的请求时机
    			else
    			{
    				printf("不正确的请求时机\r\n");
    				return	FALSE;
    			}
    			break;
    		//未定义的接收端类型
    		default:
    				printf("未定义的接收端类型\r\n");
    				printf("接收端为:");
    				printhex(SetupPacket.bmRequestType.BM.Recipient);
    				printf("\r\n");
    				return	FALSE;
    			
    	}
    	return TRUE;
    }
    /*功能:用于向主机发送描述符
     *参数:无 
     *返回值:TRUE	--->成功
     *		 FALSE	--->发生了错误
     */
    __inline BOOL	USB_GetDescriptor()
    {
    	BYTE 	* pD;
    	DWORD	len,n;
    
    	switch (SetupPacket.bmRequestType.BM.Recipient)
    	{
    		//发给设备的请求
    		 case REQUEST_TO_DEVICE:
    		 	switch(SetupPacket.wValue.WB.H)
    			{
    				//获取设备描述符
    				case USB_DEVICE_DESCRIPTOR_TYPE:
    				  	printf("获取设备描述符\r\n");
    					EP0Data.pData = (BYTE *)USB_DeviceDescriptor;
    					len	= USB_DEVICE_DESC_SIZE;
    					break;
    				//获取配置描述符
    				case USB_CONFIGURATION_DESCRIPTOR_TYPE:
    				  	printf("获取USB配置描述符\r\n");
    					pD = (BYTE *)USB_ConfigDescriptor;
    				/* 引用USB协议:The range of values used for a
    				 * descriptor index is from 0 to one less than 
    				 * the number of descriptors of that type implemented by the device
    				 * 配置描述符中的标识是从1开始计的,但是,请求中的值是标识值为配置描述符
    				 */
    				 /*由于可能有几个配置描述符所以可能需要描述一下指针*/
    					for(n=0;n!= SetupPacket.wValue.WB.L;n++)
    					{
    						if(((USB_CONFIGURATION_DESCRIPTOR *)pD)-> bLength != 0)
    						{
    							pD+=((USB_CONFIGURATION_DESCRIPTOR *)pD)->wTotalLength;
    						}
    					}
    					//如果请求的描述符为空则返回stall
    					if(((USB_CONFIGURATION_DESCRIPTOR *)pD)->bLength == 0)
    						return	FALSE;
    					//设置要传送的指针
    					EP0Data.pData = pD;
    					//虽然配置描述符中多了一个字节,但是wTotalLength中没有算上,所以这里不用管,直接用就行了
    					len = ((USB_CONFIGURATION_DESCRIPTOR*)pD)->wTotalLength;
    				  	break;
    				//字符串描述符
    				case USB_STRING_DESCRIPTOR_TYPE:
    				  	printf("获取字符串描述符\r\n");
    					EP0Data.pData = (BYTE *)USB_StringDescriptor + SetupPacket.wValue.WB.L;
    					len = ((USB_STRING_DESCRIPTOR *)EP0Data.pData)->bLength;
    					break;
    				default:
    					return	FALSE;
    			}
    			break;
    		//请求接收端接口
    //		case REQUEST_TO_INTERFACE:
    //			printf("请求接收端接口\r\n");
    //			switch(SetupPacket.wValue.WB.H)
    //			{
    //				//Hid 描述符
    //				case HID_HID_DESCRIPTOR_TYPE:  
    //					printf("请求HID描\r\n");
    //					break;
    //				case HID_REPORT_DESCRIPTOR_TYPE:
    //					printf("请求报告描述符\r\n");
    //					//这里只有一个报告描述符,报告描述符的索引是从0开始计,跟数组是一样的,如是不是0则返回Stall
    //					if(SetupPacket.wIndex.WB.L != 0)
    //						return FALSE;
    //					EP0Data.pData = (BYTE *)HID_ReportDescriptor;
    //					printf("报告描述符请求的字节:");
    //					printhex(EP0Data.Count);
    //					printf("报告描述符本来的长度:");
    //					printhex(HID_ReportDescSize);
    //					printf("\r\n");
    //					len = HID_ReportDescSize;
    //					break;
    //				default:
    //					printf("未识别的请求!!!###,类型是:");
    //					printhex(SetupPacket.wValue.WB.H);
    //					printf("\r\n");
    //					break;
    //			}
    //			break;
    		default:
    			return	FALSE;
     	}
    
    	printf("获取描述符成功\r\n");
    	//将数据发送给主机
    	if(EP0Data.Count > len)
    		EP0Data.Count = len;
    	USB_DataInStage();
    	return 	TRUE;
    }
    /*功能:设置配置请求
     *参数:无
     *返回值:TRUE 	--- >成功
     *		 FALSE	--- >失败
     */
    __inline BOOL USB_SetConfiguration(void)
    {
    	USB_COMMON_DESCRIPTOR * pD;
    	DWORD	alt,n,m;
    	printf("设置配置\r\n");
    	//配置值不能为0
    	if(SetupPacket.wValue.WB.L)
    	{
    		pD=(USB_COMMON_DESCRIPTOR *)USB_ConfigDescriptor;
    		//循环到配置描述符中的最后一个端点描述符
    		while(pD->bLength)
    		{
    			 switch(pD->bDescriptorType)
    			 {
    			 	//此时是配置描述符
    			 	case USB_CONFIGURATION_DESCRIPTOR_TYPE:	
    					//如果此配置描述符是主机要设置的配置描述符
    					if(((USB_CONFIGURATION_DESCRIPTOR * )pD)->bConfigurationValue == SetupPacket.wValue.WB.L)
    					{
    						//保存起此时,设备所用的配置值
    						USB_Configuration = SetupPacket.wValue.WB.L;
    						//保存起此时,设备所用的配置的接口数目
    						USB_NumInterfaces = ((USB_CONFIGURATION_DESCRIPTOR*)pD)->bNumInterfaces;
    						//清0每个接口可替换设置值
    						for(n=0;n<USB_IF_NUM;n++)
    						{
    							USB_AltSetting[n]=0;	
    						}	
    						//我们将所有的以前可能使用的端点禁用,如果需要,在端点描述符中再使能就行了
    						//这样如果更改了配置就保证了,不会使用到以前配置使用,而本次配置没有使用的端点
    						//可能是为了防止干扰,猜的^-^!
    						for(n=1;n<16;n++)
    						{
    							if(USB_EndPointMask & (1<<n))
    								USB_DisableEP(n);
    							if(USB_EndPointMask & ((1<<16)<<n))
    								USB_DisableEP(n|0x80);
    						}
    						//还没有枚举到端点因此这里只使用的是端点0
    						USB_EndPointMask = 0x00010001;
    						//刚配置,当然没有停止的端点啊,全新的&_^
    						USB_EndPointHalt = 0x00000000;
    						/*在复位时,我们默认是总线供电,现在开始正式运行以前要因为主机会根据我们的配
    						 *置描述符进行调整,一旦配置描述符返回后,配置描述符就生效了,所以这里必须来依据实际
    						 *来重新设置
    						 */
    						if(((USB_CONFIGURATION_DESCRIPTOR *)pD)->bmAttributes & USB_CONFIG_SELF_POWERED)
    							USB_DeviceStatus |= USB_GETSTATUS_SELF_POWERED;
    						else
    							USB_DeviceStatus &= ~USB_GETSTATUS_SELF_POWERED;
    					}
    					//否则略过,下一个配置描述符
    					else
    					{
    						(BYTE *)pD += ((USB_CONFIGURATION_DESCRIPTOR *)pD)->wTotalLength;
    						continue;		
    					}
    					break;
    				//下面是接口描述符
    				case USB_INTERFACE_DESCRIPTOR_TYPE:
    					alt = ((USB_INTERFACE_DESCRIPTOR *)pD)->bAlternateSetting;
    					break;
    				case USB_ENDPOINT_DESCRIPTOR_TYPE:
    					//我们仅仅需要处理多个子接口中的第一个就行了,(如果有子接口的话,没有的话刚好也是0)
    					if(alt == 0)
    					{
    						//得到此端点
    						n = ((USB_ENDPOINT_DESCRIPTOR *)pD)->bEndpointAddress & 0x8f;
    						//将端点号转化成bit以存储在USB_EndPointMask中去代表我们使用了此端点
    						m = (n&0x80)?((1<<16)<<(n&0x0f)):(1<<n);
    						USB_EndPointMask |= m;
    						//配置端点
    						USB_ConfigEP((USB_ENDPOINT_DESCRIPTOR  *)pD);
    						//使能端点
    						USB_EnableEP(n);
    					    //复位端点,使端点处于确定的端点
    						USB_ResetEP(n);
    					}
    					break;
    			 }
    		(BYTE *)pD += pD->bLength;
    		}	
    	}
    	//如果请求的配置为0,则我们将所有的配置恢复到地址状态时的配置
    	else
    	{
    		USB_Configuration = 0;
    		for(n=1;n<16;n++)
    		{
    			//如果上一个配置使用了此端点,则disable it
    			if(USB_EndPointMask & (1<<n)) //OUT端点
    				 USB_DisableEP(n);
    			if(USB_EndPointMask & (1<<16)<<n)  //IN端点
    				 USB_DisableEP(n | 0x80);
    		}	
    		//清除使用的全部端点,(当然0端点还是除外的)
    		USB_EndPointMask = 0x00010001;
    		USB_EndPointHalt = 0x00000000;
    	}
    	//我们根据USB_Configuration的值来查看我们到底时否找到了所需要的值
    	if(USB_Configuration == SetupPacket.wValue.WB.L)
    	{	
    		printf("设置配置成功\r\n");
    		return	TRUE;
    	}
    	else
    	{
    		printf("设置配置失败\r\n");
    		return	FALSE;
    	}
    }
    
    /*功能:用于处理端点0的输入和输出请求函数
     *参数: USB_EVT_SETUP 枚举时上位机发送的数据包
     *      USB_EVT_OUT	  普通传输时,上位机发送的数据包
     *		USB_EVT_IN	  普通传输时,上位机请求发送数据
     *返回值:无
     */
    void USB_EndPoint0 (DWORD event)
    {
    //	printf("进入端点0处理函数\r\n");
    	switch (event)
    	{
    		//控制传输
    		case USB_EVT_SETUP:
    		//	printf("进入建立阶段\r\n");
    			//首先读取主机发来的请求
    			USB_SetupStage();
    		   	//设置EP0的数据结构
    			EP0Data.Count = SetupPacket.wLength;
    			//识别是何请求
    //			printf("请求是");
    //			printhex(SetupPacket.bRequest);
    //			printf("    被请求对象:");
    //			printhex(SetupPacket.bmRequestType.B);
    //			printf("\r\n");
    			//bRequestType.bit5~bit6代表请求类型
    			switch(SetupPacket.bmRequestType.BM.Type)
    			{
    				//标准请求
    				case REQUEST_STANDARD:
    					switch(SetupPacket.bRequest)
    					{
    					//获取USB状态
    					case USB_REQUEST_GET_STATUS:
    						 //如果状态失败则停止0x81端点
    					 	if(!USB_GetStatus())
    						{
    							printf("获取状态失败\r\n");
    							goto	stall_i;
    						}
    						break;
    					case USB_REQUEST_CLEAR_FEATURE:
    						//如果清除特征失败则停止0x81端点
    						if(!USB_SetClrFeature(0))
    						{
    							printf("清楚特征失败\r\n");
    							goto stall_i;	
    						}
    						//成功了握一下手OK
    						USB_StatusInStage();	
    						break;
    					case USB_REQUEST_SET_FEATURE:
    						//如果状态失败则停止0x81端点
    						if(!USB_SetClrFeature(1))
    						{
    							printf("设置特征失败\r\n");
    							goto stall_i;	
    						}	
    						//成功了握一下手OK
    						USB_StatusInStage();
    						break;
    					case USB_REQUEST_SET_ADDRESS:
    						switch(SetupPacket.bmRequestType.BM.Recipient)
    						{
    							//只支持向设备设置地址
    							/*USB协议指出必须在改地址前完成检测并对此信息包进行响应
    							 *即USB的设置地址阶段必须在主机接收到0长度数据包后才能进行
    							 *当主机接收到状态阶段的0数据包时将会产生接收中断
    							 *所以放到了USB_EVT_IN处*/
    							case REQUEST_TO_DEVICE:
    								printf("设置地址\r\n");
    								USB_DeviceAddress = 0x80 | SetupPacket.wValue.WB.L;
    								USB_StatusInStage();
    						   		break;
    							default:
    								printf("未识别的接收端,接收端是");
    								printhex(SetupPacket.bmRequestType.BM.Recipient);
    								printf("\r\n");
    								goto	stall_i;
    						}
    						break;
    					//获取设置描述符
    					case USB_REQUEST_GET_DESCRIPTOR:
    						if(!USB_GetDescriptor())
    							goto	stall_i;
    						break;
    					//设置配置请求
    					case USB_REQUEST_SET_CONFIGURATION:
    						switch(SetupPacket.bmRequestType.BM.Recipient)
    						{
    							//对设备
    						 	case REQUEST_TO_DEVICE:
    								if(!USB_SetConfiguration())
    								{
    									//如果失败则对主机返回stall
    									goto stall_i;
    								}
    								//完成了请求,握个手OK
    								USB_StatusInStage();
    								break;
    							//不支持对其他类型请求
    							default:
    								goto stall_i;
    						}
    						break;
    					case USB_REQUEST_GET_INTERFACE:
    						printf("请求接口\r\n");
    						break;
    					default:
    						printf("未识别的请求,请求代码是");
    						printhex(SetupPacket.bRequest);
    						printf("\r\n");
    						break;
    					}
    				break;
    				//类请求
    				case REQUEST_CLASS:
    					printf("类请求\r\n");
    					switch (SetupPacket.bmRequestType.BM.Recipient)
    					{
    						//对接口请求
    						case REQUEST_TO_INTERFACE:
    							if(SetupPacket.wIndex.WB.L == USB_HID_IF_NUM)
    							{
    								switch(SetupPacket.bRequest)
    								{
    									case HID_REQUEST_GET_REPORT:
    										printf("获取报告描述符\r\n");
    										break;
    									case HID_REQUEST_SET_REPORT:
    										printf("设置报告描述符\r\n");
    										break;
    									case HID_REQUEST_GET_IDLE:
    										printf("获取空闲率\r\n");
    										break;
    									case HID_REQUEST_SET_IDLE:
    										printf("设置空闲\r\n");
    										break;
    								    case HID_REQUEST_GET_PROTOCOL:
    										printf("查询报告协议是否在活动\r\n");
    										break;				
    									case HID_REQUEST_SET_PROTOCOL:
    										printf("SetReprot\r\n");
    										break;	
    									default:
    										printf("不支持的HID请求\r\n");
    										break;
    						   		}
    							}
    							break;
    					}
    					break;
    				//产商请求
    				case REQUEST_VENDOR:
    				//未定义请求
    				default:
    		stall_i:
    					USB_SetStallEP(0x80);
    					break;
    			}
    			break;
    		//接收成功
    		case USB_EVT_OUT:
    			printf("USB_EVT_OUT\r\n");
    			if(SetupPacket.bmRequestType.BM.Dir ==0)
    			{
    				printf(" 请求是:");
    				printhex(SetupPacket.bRequest);
    				printf("\r\n");
    			}
    			//返回握手
    			else
    			{
    				USB_StatusOutStage();
    			}
    			break;
    		//发送成功
    		case USB_EVT_IN:
    		//	printf("USB_EVT_IN\r\n");
    			if(SetupPacket.bmRequestType.BM.Dir == 1)
    				USB_DataInStage();
    			/*USB协议指出必须在改地址前完成检测并对此信息包进行响应
    			 *即USB的设置地址阶段必须在主机接收到0长度数据包后才能进行
    			 *当主机接收到状态阶段的0数据包时将会产生接收中断
    			 *所以放到了USB_EVT_IN处*/
    			 //原keil库没有加if判断,怀疑为bug,这里判断是否是由于设置地址的状态阶段成功而触发的中断
    			 else// if(SetupPacket.bRequest == USB_REQUEST_SET_ADDRESS)
    			 {
    				if(USB_DeviceAddress & 0x80)
    				{
    					USB_DeviceAddress &= 0x7f;
    					USB_SetAddress(USB_DeviceAddress);
    				}		 	
    			 }
    			break;
    	}
    
    }
    

  • 相关阅读:
    数据查询语句
    数据操作语句
    数据定义语句
    linux的常用命令
    NIO/IO/AIO阻塞/非阻塞/同步/异步
    XCode使用自带SVN,SVN命令
    正则表达式大全——持续更新中。。。
    sql语句优化
    sql一些语句性能及开销优化
    高质量图片无损压缩算法
  • 原文地址:https://www.cnblogs.com/findstr/p/2803691.html
Copyright © 2020-2023  润新知