前面的基础知识讲的也差不多了,直接上教程: 1. 利用stm32cubemx创建1个stm32f407的工程,工程需要配置的有:RCC 、SYS、USB_OTG_FS,USB_DEVICE,PID,VID…如果需要详细的步骤就看第一节的教程,这里给大家推荐一个usb的调试工具叫device-monitoring-studio我看网上大部分人都在用bus-hound两者相比,我认为前者的用于usb调试更加方便,不过这种就是仁者见仁智者见智了。 2.我用的编译器IAR,我看网上有许多人都在用Keil,两者的步骤也差不多,打开工程. 3. 我在程序中main.c增加了1个按键和1个LED,用来模拟键盘按键和键盘灯 /* USER CODE BEGIN 4 */ static void UserGpioInit(void) { /* KEY PE2,PE3,PE4*/ /* LED PF9,PF10*/ /* GPIO Ports Clock Enable */ GPIO_InitTypeDef GPIO_InitStruct; /* GPIO Ports Clock Enable */ __HAL_RCC_GPIOF_CLK_ENABLE(); __HAL_RCC_GPIOE_CLK_ENABLE(); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOF,GPIO_PIN_9|GPIO_PIN_10, GPIO_PIN_RESET); /*Configure GPIO pins : PF9 PF10 */ GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOF, &GPIO_InitStruct); /*Configure GPIO pin Output Level */ HAL_GPIO_WritePin(GPIOE,GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4, GPIO_PIN_RESET); /*Configure GPIO pins : PF9 PF10 */ GPIO_InitStruct.Pin =GPIO_PIN_2|GPIO_PIN_3|GPIO_PIN_4; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(GPIOE, &GPIO_InitStruct); } uint32_t ReturnKeyData(void) { uint32_t i; if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_2)==GPIO_PIN_RESET){ for(i=0;i<0xff;i++); if(HAL_GPIO_ReadPin(GPIOE,GPIO_PIN_2)==GPIO_PIN_RESET){ return 1; } } else if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3)==GPIO_PIN_RESET){ for(i=0;i<0xff;i++); if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_3)==GPIO_PIN_RESET){ return 2; } } else if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4)==GPIO_PIN_RESET){ for(i=0;i<0xff;i++); if(HAL_GPIO_ReadPin(GPIOE, GPIO_PIN_4)==GPIO_PIN_RESET){ return 3; } } return 0; } 4.因为生成的例程是鼠标例程,并且例程中只使用了一个端点(因为鼠标只需要向上发送数据),但键盘需要向上位机发送数据(in端点0x81),并且同时也接收上位机的数据(out端点0x01),并且鼠标和键盘的数据格式也不同,我们还需要发送键盘的数据格式。 下面我们整理一下需要修改的地方: 1)首先让上位机认识咱们的设备是键盘 2)增加1个端点,完成接收上位机下发下来的数据 3)讲下位机发送的数据格式改成符合键盘的格式。 完成以上操作之后,我们就可以将我们的开发板变成一个USB键盘. 5.我们的例程由于是usb-hid设备,而键盘设备也是hid设备,所以如果让上位机把我们的设备认识键盘的话,只需要改一下接口描述符就可以了: /************** Descriptor of JoystickMouse interface ****************/ /*09 */ 0x09, /*bLength: InterfaceDescriptor size*/ USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/ 0x00, /*bInterfaceNumber:Number of Interface*/ 0x00, /*bAlternateSetting:Alternate setting*/ 0x02, /*bNumEndpoints*/ 0x03, /*bInterfaceClass:HID*/ 0x01, /*bInterfaceSubClass: 1=BOOT, 0=no boot*/ 0x02, /*nInterfaceProtocol :0=none, 1=keyboard, 2=mouse*/ 0, /*iInterface: Indexof string descriptor*/
将nInterfaceProtocol改成2就可以了 6.增加端点 需要修改增加配置描述符 ① 将端点接口描述符中的端点改成2 ② 增加配置描述符数组最后增加一个端点描述符 /******************** Descriptor of Keyboard outputendpoint ********************/ /* 34 */ 0x07, /*bLength: Endpoint Descriptor size*/ USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/ HID_EPOUT_ADDR, /*bEndpointAddress: Endpoint Address(IN)*/ 0x03, /*bmAttributes: Interrupt endpoint*/ HID_EPOUT_SIZE, /*wMaxPacketSize: 4 Byte max*/ 0x00, HID_FS_BINTERVAL, /*bInterval: Polli ng Interval (10ms)*/ /*41*/ ③ 修改HID描述符中的报告描述符长度索引 /******************** Descriptor ofJoystick Keyboard HID ********************/ /*18 */ 0x09, /*bLength: HIDDescriptor size*/ HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/ 0x11, /*bcdHID: HID ClassSpec release number*/ 0x01, 0x00, /*bCountryCode:Hardware target country*/ 0x01, /*bNumDescriptors:Number of HID class descriptors to follow*/ 0x22, /*bDescriptorType*/ HID_KEYBOARD_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/ 0x00, ④ 修改整个配置描述符的大小,这个是在hid.h中定义的 0x09, /* bLength: ConfigurationDescriptor size */ USB_DESC_TYPE_CONFIGURATION, /*bDescriptorType: Configuration */ USB_HID_CONFIG_DESC_SIZ, /* wTotalLength: Bytes returned */ 0x00, 0x01, /*bNumInterfaces: 1interface*/ 0x01, /*bConfigurationValue: Configuration value*/ 0x00, /*iConfiguration:Index of string descriptor describing the configuration*/ 0xE0, /*bmAttributes: buspowered and Support Remote Wake-up */ 0x32, /*MaxPower 100 mA: this current isused for detecting Vbus*/ 修改后的配置描述符为: /** * \GET_DESCRIPTOR 请求 * \描述符类型及编号 * | 描述符类型 | 编号 * |:-------------------------|:---------- * | 设备描述符(DEVICE) | 1 * | 配置描述符(CONFIGURATION)| 2 * | 字符串描述符(STRING) | 3 * | 接口描述符(INTERFACE) | 4 * | 端点描述符(ENDPOINT) | 5 */ /* USB HID device ConfigurationDescriptor */ __ALIGN_BEGIN static uint8_tUSBD_HID_CfgDesc[USB_HID_CONFIG_DESC_SIZ] __ALIGN_END = { 0x09, /* bLength: Configuration Descriptor size */ USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */ USB_HID_CONFIG_DESC_SIZ, /* wTotalLength: Bytes returned */ 0x00, 0x01, /*bNumInterfaces: 1interface*/ 0x01, /*bConfigurationValue: Configuration value*/ 0x00, /*iConfiguration:Index of string descriptor describing the configuration*/ 0xE0, /*bmAttributes: buspowered and Support Remote Wake-up */ 0x32, /*MaxPower 100 mA:this current is used for detecting Vbus*/ /************** Descriptor of Joystick Keyboard interface****************/ /* 09 */ 0x09, /*bLength: InterfaceDescriptor size*/ USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/ 0x00, /*bInterfaceNumber:Number of Interface*/ 0x00, /*bAlternateSetting:Alternate setting*/ 0x02, /*bNumEndpoints*/ 0x03, /*bInterfaceClass:HID*/ 0x01, /*bInterfaceSubClass: 1=BOOT, 0=no boot*/ 0x01, /*nInterfaceProtocol: 0=none, 1=keyboard, 2=mouse*/ 0, /*iInterface: Indexof string descriptor*/ /******************** Descriptor of Joystick Keyboard HID********************/ /* 18 */ 0x09, /*bLength: HIDDescriptor size*/ HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/ 0x11, /*bcdHID: HID ClassSpec release number*/ 0x01, 0x00, /*bCountryCode:Hardware target country*/ 0x01, /*bNumDescriptors:Number of HID class descriptors to follow*/ 0x22, /*bDescriptorType*/ HID_KEYBOARDMOUSE_REPORT_DESC_SIZE,//HID_KEYBOARD_REPORT_DESC_SIZE,//HID_MOUSE_REPORT_DESC_SIZE,/*wItemLength:Total length of Report descriptor*/ 0x00, /******************** Descriptor of Keyboardinput endpoint ********************/ /* 27 */ 0x07, /*bLength: EndpointDescriptor size*/ USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/ HID_EPIN_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/ 0x03, /*bmAttributes:Interrupt endpoint*/ HID_EPIN_SIZE, /*wMaxPacketSize: 4 Byte max */ 0x00, HID_FS_BINTERVAL, /*bInterval: Polli ng Interval (10 ms)*/ /******************** Descriptor ofKeyboard output endpoint********************/ /* 34 */ 0x07, /*bLength: EndpointDescriptor size*/ USB_DESC_TYPE_ENDPOINT, /*bDescriptorType:*/ HID_EPOUT_ADDR, /*bEndpointAddress: Endpoint Address (IN)*/ 0x03, /*bmAttributes:Interrupt endpoint*/ HID_EPOUT_SIZE, /*wMaxPacketSize: 4 Byte max */ 0x00, HID_FS_BINTERVAL, /*bInterval: Polli ng Interval (10 ms)*/ /*41*/ } ; 修改完成配置描述符之后,我们还需要修改报告描述符,将报告描述符改成键盘。 __ALIGN_BEGIN static uint8_tHID_KEYBOARD_ReportDesc[HID_KEYBOARD_REPORT_DESC_SIZE] __ALIGN_END = { 0x05,0x01, 0x09,0x06, 0xa1,0x01, 0x05,0x07, 0x19,0xe0, 0x29,0xe7, 0x15,0x00, 0x25,0x01, 0x95,0x08, 0x75,0x01, 0x81,0x02, 0x95,0x01, 0x75,0x08, 0x81,0x03, 0x95,0x06, 0x75,0x08, 0x15,0x00, 0x25,0xff, 0x05,0x07, 0x19,0x00, 0x29,0x65, 0x81,0x00, 0x25,0x01, 0x95,0x05, 0x75,0x01, 0x05,0x08, 0x19,0x01, 0x29,0x05, 0x91,0x02, 0x95,0x01, 0x75,0x03, 0x91,0x03, 0xc0 }; 修改完成之后,还需要将报告描述符和配置描述符关联上,我们需要修改 static uint8_t USBD_HID_Setup (USBD_HandleTypeDef *pdev, USBD_SetupReqTypedef *req)函数中的
case USB_REQ_GET_DESCRIPTOR:选项: 关联上之后,还需要初始化新添加的这个out端点 先宏定义一个这个端点的地址和大小 #define HID_EPOUT_ADDR 0x01 #define HID_EPOUT_SIZE 0x10 然后在static uint8_t USBD_HID_Init(USBD_HandleTypeDef *pdev, uint8_t cfgidx)函数中增加 /* Open EP OUT */ USBD_LL_OpenEP(pdev, HID_EPOUT_ADDR, USBD_EP_TYPE_INTR, HID_EPOUT_SIZE);
初始化完成后,我们还需要重新定义一个OUT函数 我增加了USBD_HID_DataOut函数 至此,我们的设备就成为了一个usb键盘设备了。 修改uint8_t USBD_HID_SendReport (USBD_HandleTypeDef *pdev, uint8_t *report, uint16_t len) 函数用于向上位机发送数据 uint8_t USBD_HID_SendReport (USBD_HandleTypeDef *pdev, uint8_t*report, uint16_t len) { USBD_HID_HandleTypeDef *hhid =(USBD_HID_HandleTypeDef*)pdev->pClassData; if (pdev->dev_state == USBD_STATE_CONFIGURED ) { if(hhid->state == HID_IDLE) { hhid->state = HID_BUSY; USBD_LL_Transmit (pdev, HID_EPIN_ADDR, report, len); } } return USBD_OK; } 在主函数中调用: txbuffer[2] = 0x4; USBD_HID_SendReport (&hUsbDeviceFS,txbuffer,8); 调用上面两句代码之后,pc机上就会收到一连a,那么为什么0x4代码a那?这都是报告描述符的功劳,想了解的就去看报告描述符吧。 如果想让设备停止发送的话,只需要将4改成0 就可以了。
注:当我们在键盘上按下“capsLock”“numlock”等能够开启键盘灯的按键时,我们的usb接收数组usbrxbuffer都能接收到相应的数值,我们只要根据数值点亮对应的LED,就实现了键盘灯的操作了这个就不贴代码了,看了教程的人就自己操作吧。
|