关于 KEIL提供的JoystickMouse例程 转化为 USB虚拟键盘

2019-07-21 07:18发布

我只是USB新手,我只是想叙述一下我如何 将JoystickMouse例程 改为 USB虚拟键盘的过程,以及一些仍未解决的疑惑。
我昨天补了1天的USB知识,对USB的枚举,描述符间的关系,控制传输有个大致清晰了解,但是并不深刻。(为此,我决定随后开始从PDIUSB12芯片开始学习起走)

首先,我们先打开JoystickMouse的例程,先下载进单片机看看,以确保单片机和USB之间的通信是正常(即硬件无问题),如果是正常的,驱动程序安装后,鼠标会跑
先看主函数.
int main(void)
{ #ifdef DEBUG
  debug();
#endif   Set_System();   USB_Interrupts_Config();   Set_USBClock();   USB_Init();   while (1)
  {
    Delay(10000);
    if ((JoyState() != 0) & (bDeviceState == CONFIGURED))
    {
      Joystick_Send(JoyState());         //这里便是发送信息至PC机的函数,这个信息可以代表很多设备,主要是看描述符的内容。  
    }
  }
}
要想让Joystick_Send发送控制键盘的信息,我们需要更改描述符.
打开usb_desc.c  usb_desc.h此处是用于编写USB描述符的.c 以及 .h文件
Joystick_DeviceDescriptor 是设备描述符,需要修改一下VID(厂商ID) PID(产品ID)
即更改
0x83,  0x04,  /*idVendor (0x0483)*/
0x10,  0x57,  /*idProduct = 0x5710*/
随意更改下数字即可,我是更改为
0x34, 0x12,/*idVendor (0x1234)*/
0x21, 0x43,/*idProduct = 0x4321*/
其实该处影响并不大,如果ID号不变的话,就会加载之前JoystickMouse的驱动程序(如果成功运行JoystickMouse例程),但是该驱动程序并不满足我们的需求,也就是说和虚拟键盘的描述符之间存在矛盾 .(加载的驱动程序不是我们想要的嘛,肯定就会有问题,换一个ID的话,会重新检测并加载新的驱动程序)


接着改Joystick_ConfigDescriptor,这是配置描述符(注意---配置描述符,接口描述符,HID描述符,端点描述符均包含在其中)
该处参考电脑圈圈的程序,更改为
const u8 Joystick_ConfigDescriptor[JOYSTICK_SIZ_CONFIG_DESC] =
  {
{
 //以下为配置描述符
 0x09, /* bLength: Configuation Descriptor size */
 USB_CONFIGURATION_DESCRIPTOR_TYPE, /* bDescriptorType: Configuration */
 JOYSTICK_SIZ_CONFIG_DESC,
 /* wTotalLength: Bytes returned */
 0x00,
 0x01,         /*bNumInterfaces: 1 interface*/
 0x01,         /*bConfigurationValue: Configuration value*/
 0x00,         /*iConfiguration: Index of string descriptor describing
               the configuration*/
 0xC0,         /*bmAttributes: self powered */
 0x32,         /*MaxPower 100 mA: this current is used for detecting Vbus*/  //以下为接口描述符
 /************** Descriptor of Joystick Mouse interface ****************/
 /* 09 */
 0x09,         /*bLength: Interface Descriptor size*/
 USB_INTERFACE_DESCRIPTOR_TYPE,/*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,         /*bInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
 0,            /*iInterface: Index of string descriptor*/  //以下为HID描述符
 /******************** Descriptor of Joystick Mouse HID ********************/
 /* 18 */
 0x09,         /*bLength: HID Descriptor size*/
 HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
 0x00,         /*bcdHID: HID Class Spec release number*/
 0x01,
 0x00,         /*bCountryCode: Hardware target country*/
 0x01,         /*bNumDescriptors: Number of HID class descriptors to follow*/
 0x22,         /*bDescriptorType*/
 JOYSTICK_SIZ_REPORT_DESC,/*wItemLength: Total length of Report descriptor*/
 0x00,
 
 //以下为输入端点1描述符
 /******************** Descriptor of Joystick Mouse endpoint ********************/
 /* 27 */
 0x07,          /*bLength: Endpoint Descriptor size*/
 USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/
 0x81,          /*bEndpointAddress: Endpoint Address (IN)*/
 0x03,          /*bmAttributes: Interrupt endpoint*/
 0x08,          /*wMaxPacketSize: 8 Byte max */
 0x00,
 0x20,          /*bInterval: Polling Interval (32 ms)*/  //以下为输出端但1描述符
 /* 34 */
 0x07,          /*bLength: Endpoint Descriptor size*/
 USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/
 0x01,          /*bEndpointAddress: Endpoint Address (OUT)*/
 0x03,          /*bmAttributes: Interrupt endpoint*/
 0x08,          /*wMaxPacketSize: 8 Byte max */
 0x00,
 0x20,          /*bInterval: Polling Interval (32 ms)*/
/* 41 */
};
这时候编译试试,会发现
error:   #146too many initializer values的问题,很显然给配置描述符数组设定的大小太小了
打开usb_desc.h
将数组大小改为
#define JOYSTICK_SIZ_CONFIG_DESC                41   //是41个字节嘛~


然后改usb_desc.c里面的Joystick_ReportDescriptor(报告描述符)
我们仍然参考电脑圈圈的程序
const u8 Joystick_ReportDescriptor[JOYSTICK_SIZ_REPORT_DESC] =
{
 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
}; /* Joystick_ReportDescriptor */

好,尝试编译编译。
OK,编译成功,
但是千万不要认为就这样结束了!!!!!!!!!!
Joystick_ReportDescriptor[JOYSTICK_SIZ_REPORT_DESC]的数组大小还没改呢!
这个必须得改,不改的话,PC机识别不了人体输入设备。
我曾在这里花了很久的时间。。。。。。。这个大小必须改为实际大小
数数行数 1行2个,最后1行1个。
1共61个字节。
返回usb_desc.h中,
#define JOYSTICK_SIZ_REPORT_DESC                61
OK。

描述符就改完了。
现在描述符是用于处理键盘的了。

我们试试编译下载程序,打开设备管理器看看,发现是这样的

 

不用着急,还有些东西也需要改。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
42条回答
lsj9383
1楼-- · 2019-07-22 11:41
回复【7楼】皮皮鲁:
---------------------------------
USB我也有很多不懂,我打算从PDIUSBD12学习起走。模块都买了,不过还没到,呵呵,最近考试月了,也事情多了。
简万樟
2楼-- · 2019-07-22 14:02
辛苦楼主了,小弟也在搞这个,学习了!!!
balcoyang
3楼-- · 2019-07-22 17:38
 精彩回答 2  元偷偷看……
colordrv
4楼-- · 2019-07-22 18:56
回复【楼主位】lsj9383:
---------------------------------
Lz,关于那个Get_SerialNum()函数,我感觉应该这样的。
首先,这个函数是通过读取STM32内部的96bit Unique ID,然后转成Unicode 码写到Joystick_StringSerial[]这个序列号字符串数组的,而这个数组会被作为字符串描述符返回给Pc作为设备序列号。而主机将联合VID,PID和这个设备序列号用来识别不同设备。由于lz已经插过STM32的USBJoystick了,所以这个设备序列号也就应该被PC登记了,所以可能造成冲突无法识别了。所以不注释该函数的话,改改Joystick_StringSerial[]的内容应该也可以成功识别吧,求验证。
void Get_SerialNum(void)
{
  uint32_t Device_Serial0, Device_Serial1, Device_Serial2;

  Device_Serial0 = *(uint32_t*)ID1;
  Device_Serial1 = *(uint32_t*)ID2;
  Device_Serial2 = *(uint32_t*)ID3;
  
  Device_Serial0 += Device_Serial2;

  if (Device_Serial0 != 0) // ??????0,?±????????????
  {
    IntToUnicode (Device_Serial0, &Joystick_StringSerial[2] , 8); // 18-2=16byte=2*8 8*4=32bit
    IntToUnicode (Device_Serial1, &Joystick_StringSerial[18], 4); // 4*2=8byte 4*4=16bit
  }
}
ifus
5楼-- · 2019-07-22 22:27
最近在看USB,写得很好
tsacy
6楼-- · 2019-07-23 02:37
不错。我顶!!!!!!

一周热门 更多>