stm32f103 usb 修改成自定义复合设备教程

单片机型号   STM32F103C8T6

软件  KEIL5

将现有的 HID设备  改成  有HID设备和 鼠标(或者键盘)的复合设备

HID设备  使用端点1和端点2 

键盘 (或者鼠标)使用端点3


使用最小系统板   亲测 可以实现 HID设备 接收34字节每次

键盘可以使用

鼠标也可以使用



修改 usb_desc.c 文件 如下


设备描述符不用动  基本没有什么用

const u8 Joystick_DeviceDescriptor[JOYSTICK_SIZ_DEVICE_DESC] =
{
		
	0x12, 
		
    0x01, 
		
    0x00,
    0x02,
		
    0x00, 
    0x00, 
    0x00,
		
    0x40,//64
		
    0x47,//Vid
    0x20,
		
    0x01,//Pid
    0x03,
		
    0x00,
    0x02,
		
    1, 
    2, 
    3,
    0x01
		
}
;


重要的是 配置描述符

const u8 Joystick_ConfigDescriptor[JOYSTICK_SIZ_CONFIG_DESC] =
{

	  
 0x09,		//bLength字段
 USB_CONFIGURATION_DESCRIPTOR_TYPE,		
 JOYSTICK_SIZ_CONFIG_DESC,//长度
 0x00,
 0x02,	//接口数目	总共两个接口    接口和端点是不用的
 0x01,	//???????????????????????
 0x00,	//	
 0x80,	//	
 0x32,	//	


		//接口描述符---------------------------------
    0x09, 
    0x04,//
    0x00,//接口编号
    0x00,//
    0x01,//端点数量
    0x03,//该接口所使用的类   键盘属于HID
    0x00,//子类
    0x00,//键盘是1   鼠标是2  0是自定义设备
    0, 
		
		
		
		
		//HID描述符------------------------------------
    0x09,
    0x21,//HID是21
		
    0x10,//HID 1.0协议  是0x0100
    0x01,
		
    0x00,//国家代码
		
    0x01,//-----------------下一级描述符的数目?????????????????
    0x22,//-----------------下一级的描述符的类型是报告描述符  报告描述符编号0x22
		
    sizeof(KeyboardReportDescriptor)&0xFF,				 //下级描述符的长度。下级描述符为键盘报告描述符。
		(sizeof(KeyboardReportDescriptor)>>8)&0xFF,
			
		
		//端点描述符-------------------------------------
    0x07,
    0x05,//端点描述符编号

    0x82, //地址    D7 1:输入   0:输出     D3-D0  是地址            

    0x03, //中断端点编号
		
    34%256,  //最大包长度  2字节
    34/256,
		
    0x01,//端点查询时间
		
		
		//端点描述--------------------------------------
    0x07,
    0x05,//端点描述符编号

    0x01, //地址    D7 1:输入   0:输出     D3-D0  是地址    

		0x03,	//中断端点编号
		
    34%256,//最大包长度  2字节
    34/256,
		
    0x01,	//端点查询时间
		
		
		
		 //第二个接口描述符-------键盘用的
 0x09,	
 0x04,	
 0x01,	//接口编号  是1 
 0x00,	//
 0x01,	//1个端点
 0x03,	//
 0x01,	//
 0x01,	//1是键盘 2是鼠标
 0x00,	//
 
 
  //HID描述符
 0x09,	//
 0x21,	//
 0x10,	//
 0x01,
 0x21,	//
 0x01,	//
 0x22,	//
 sizeof(MouseReportDescriptor)&0xFF,
 (sizeof(MouseReportDescriptor)>>8)&0xFF,
 
 //输入端点描述符
 0x07,	//
 0x05,	//
 0x83,	//端点3输入
 0x03,	//中断方式
 0x08,	//数据长度
 0x00,
 0x0A 	//
};

HID报告描述符如下

//HID描述符 
const u8 KeyboardReportDescriptor[KP_ReportDescriptor_Size]=
{
	
	

0x05, 0x8c,
0x09, 0x01,
0xa1, 0x01,



0x09,0x03, 
0x15,0x00, 
0x26,0x00, 0xFF, 
0x75,0x08, 
0x95,34, 
0x81,0x02, 

	
0x09,0x04, 
0x15,0x00,
0x26,0x00,0xFF, 
0x75,0x08,
0x95,34,
0x91,0x02,

0xc0
};


键盘报告描述符如下

//USB鼠标报告描述符的定义
const u8 MouseReportDescriptor[Mouse_ReportDescriptor_Size]=
{
	
	0x05, 0x01, // USAGE_PAGE (Generic Desktop)
	0x09, 0x06, // USAGE (Keyboard)
	0xa1, 0x01, // COLLECTION (Application)
	0x05, 0x07, // USAGE_PAGE (Keyboard/Keypad)
	0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
	0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
	0x15, 0x00, // LOGICAL_MINIMUM (0)
	0x25, 0x01, // LOGICAL_MAXIMUM (1)
	0x95, 0x08, // REPORT_COUNT (8)
	0x75, 0x01, // REPORT_SIZE (1)	   
	0x81, 0x02, // INPUT (Data,Var,Abs)
	0x95, 0x01, // REPORT_COUNT (1)
	0x75, 0x08, // REPORT_SIZE (8)
	0x81, 0x03, // INPUT (Cnst,Var,Abs)
	0x95, 0x06, // REPORT_COUNT (6)
	0x75, 0x08, // REPORT_SIZE (8)
	0x25, 0xFF, // LOGICAL_MAXIMUM (255)
	0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
	0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
	0x81, 0x00, // INPUT (Data,Ary,Abs)
	0x25, 0x01, // LOGICAL_MAXIMUM (1)
	0x95, 0x02, // REPORT_COUNT (2)
	0x75, 0x01, // REPORT_SIZE (1)
	0x05, 0x08, // USAGE_PAGE (LEDs)
	0x19, 0x01, // USAGE_MINIMUM (Num Lock)
	0x29, 0x02, // USAGE_MAXIMUM (Caps Lock)
	0x91, 0x02, // OUTPUT (Data,Var,Abs)
	0x95, 0x01, // REPORT_COUNT (1)
	0x75, 0x06, // REPORT_SIZE (6)
	0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
	0xc0        // END_COLLECTION
};




usb_prop.c  文件中  需要修改的地方如下

void Joystick_Reset(void)
{
     pInformation->Current_Configuration = 0;															//设置当前的配置为0,表示没有配置过
     pInformation->Current_Interface = 0;  															//默认的接口
  

     pInformation->Current_Feature = Joystick_ConfigDescriptor[7];				//当前的属性,bmAttributes:设备的一些特性,0xc0表示自供电,不支持远程唤醒
  
     SetBTABLE(BTABLE_ADDRESS);


     SetEPType(ENDP0, EP_CONTROL);																		//设置端点1为控制端点
     SetEPTxStatus(ENDP0, EP_TX_STALL);																//设置端点0发送延时
     SetEPRxAddr(ENDP0, ENDP0_RXADDR);																//设置端点0的接收缓冲区地址
     SetEPTxAddr(ENDP0, ENDP0_TXADDR);																//设置端点0的发送缓冲区地址
     Clear_Status_Out(ENDP0);																					//清除端点0的状态
     SetEPRxCount(ENDP0, Device_Property.MaxPacketSize);							//设置端点0的接收的计数
     SetEPRxValid(ENDP0);																							//使能接收状态
	
	

  //端点1
     SetEPType(ENDP1, EP_INTERRUPT);//端点1 输出 PC向stm32发送数据 		//设置端点1为中断控制端点
     SetEPRxAddr(ENDP1, ENDP1_RXADDR);																//设置端点1的接收缓冲地址
     SetEPRxCount(ENDP1, 34);																					//设置端点1的接收计数
     SetEPRxStatus(ENDP1, EP_RX_VALID);																//设置端点1接收有效
     //SetEPTxStatus(ENDP1, EP_TX_DIS);



  //端点2
     SetEPType(ENDP2, EP_INTERRUPT);//端点2 输入 Stm32向pc发送数据		//设置端点2为中断控制端点
     SetEPTxAddr(ENDP2, ENDP2_TXADDR);																//设置端点2的接收缓冲地址
     SetEPTxCount(ENDP2, 34);																					//设置端点2的发送计数
    // SetEPTxStatus(ENDP2, EP_TX_DIS);
     SetEPTxStatus(ENDP2, EP_TX_NAK);																	//设置端点2为接收不响应
		 
	
 //端点3---------为键盘增加的
     SetEPType(ENDP3, EP_INTERRUPT);//端点2 输入 Stm32向pc发送数据		//设置端点2为中断控制端点
     SetEPTxAddr(ENDP3, ENDP3_TXADDR);																//设置端点2的接收缓冲地址
     SetEPTxCount(ENDP3, 8);																					//设置端点2的发送计数
    // SetEPTxStatus(ENDP2, EP_TX_DIS);
     SetEPTxStatus(ENDP3, EP_TX_NAK);																	//设置端点2为接收不响应
	 
		 
		 
		 


     bDeviceState = ATTACHED;																					//设置设备状态为 ATTACHED状态
  

     SetDeviceAddress(0);																							//设置设备为默认地址
}


usb_conf.h  修改如下


#define EP_NUM     (4)-----------改成4个EP   EP0用于控制  EP1电脑下发  EP2单片机上传  EP3键盘或者鼠标上传

/*-------------------------------------------------------------*/
/* --------------   Buffer Description Table  -----------------*/
/*-------------------------------------------------------------*/
/* buffer table base address */
/* buffer table base address */
#define BTABLE_ADDRESS      (0x00)

/* EP0  */
/* rx/tx buffer base address */
#define ENDP0_RXADDR        (0x40)//(0x18)
#define ENDP0_TXADDR        (0x80)//(0x58)

/* EP1  */
/* tx buffer base address */
//地址为32位对其,位4的倍数,不能超过 bMaxPacketSize

#define ENDP1_RXADDR        (0xc0)//(0x98)
#define ENDP1_TXADDR        (0x100)//(0xD8)
//EP2
//#define ENDP2_RXADDR        (0x118)
#define ENDP2_TXADDR        (0x140)//(0x118)

//EP3
#define ENDP3_TXADDR        (0x180)//(0x158)


usb_endp.c 文件中  添加EP1接收函数

void EP1_OUT_Callback(void)
{
	u8 DataLen; 
	u8 DataBuffer[64]; 
	 
	USB_ReceiveFlg = TRUE;
	DataLen = GetEPRxCount(ENDP1);
	PMAToUserBufferCopy(DataBuffer, ENDP1_RXADDR, DataLen); 
	SetEPRxValid(ENDP1); 
}


main函数中添加   发送数据函数



EP2上传数据的函数    发送一个

	UserToPMABufferCopy(Transi_Buffer, ENDP2_TXADDR, 34);	//发送的数组	端点地址   发送字节数
SetEPTxValid(ENDP2);//发送 
  

 
  

键盘上传的函数  发送一个键值0x04  按键a    然后再发送8个字节0    就是按下a后再松开

			Transi_Buffer[0] = 0x00;
			Transi_Buffer[1] = 0x00;
			Transi_Buffer[2] = 0x04;
			Transi_Buffer[3] = 0x00;
			Transi_Buffer[4] = 0x00;
			Transi_Buffer[5] = 0x00;
			Transi_Buffer[6] = 0x00;
			Transi_Buffer[7] = 0x00;
			 
			UserToPMABufferCopy(Transi_Buffer, GetEPTxAddr(ENDP3), 8);
			SetEPTxCount(ENDP3, 8);
			SetEPTxValid(ENDP3);
			
			Delay(1000000);
			
			
			Transi_Buffer[0] = 0x00;
			Transi_Buffer[1] = 0x00;
			Transi_Buffer[2] = 0x00;
			Transi_Buffer[3] = 0x00;
			Transi_Buffer[4] = 0x00;
			Transi_Buffer[5] = 0x00;
			Transi_Buffer[6] = 0x00;
			Transi_Buffer[7] = 0x00;
			 
			UserToPMABufferCopy(Transi_Buffer, GetEPTxAddr(ENDP3), 8);
			SetEPTxCount(ENDP3, 8);
			SetEPTxValid(ENDP3);




承接USB开发   QQ727341554   TEL13810175694








你可能感兴趣的:(STM32USB)