DIY编程器网

 找回密码
 注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 1420|回复: 0
打印 上一主题 下一主题

[接口电路] STM32的USB键盘及鼠标例程

[复制链接]
跳转到指定楼层
楼主
发表于 2012-1-16 14:47:05 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
STM32的USB键盘及鼠标例程通过网络可以搜到很,但是在同一个设备中集成键盘及鼠标的例程却比较少见(我通过GOOGLE只搜到圈圈的基于51+D12的版本)。以下为我参考圈圈的例程做出来的集成键盘及鼠标的STM32的程序。
  程序上除了usb_desc.c及usb_endp.c外,其它部份同单一的键盘鼠标一样。下面着重说一下usb_desc.c及usb_endp.c的不同之处。
  单一键盘鼠标跟集成键盘鼠标这区别主要是报告描述符不同。单一键盘鼠标的报告描述符因只有一组报告输入/输出,故没有报告ID,而集成的有两组报告(键盘及鼠标),所以每一组报告都有一个报告ID加以区别。
  另外就是在usb_endp.c中对端点的数据发送不知道是不是我的原因,待发送数据长度有问题,原因还未找到,只能在后面增加一条设置发送数据长度的语句。(如果不加的话,PC端只会收到8位数据,尽管我程序里设置了9位数据)
  完整的usb_desc.c文件如下:
  #include "STM32Lib\USBLib\usb_lib.h"
  #include "usb_desc.h"
  // KM_DeviceDescriptor
  const u8 HID_DeviceDescriptor[HID_SIZE_DEVICE_DESC]=
  {
  0X12, // bLength
  USB_DEVICE_DESCRIPTOR_TYPE, // bDescriptorType
  0x00, // bcdUSB
  0x02,
  0x00, // bDeviceClass
  0X00, // bDeviceSubClass
  0x00, // bDeviceProtocol
  0x40, // bMaxPacketSize40
  0x34, // idVendor (0x0483)
  0x12,
  0x78, // idProduct = 0x5710
  0x56,
  0x00, // bcdDevice rel.20.00
  0x02,
  1, // index of string descriptor describing manufacturer
  2, // index of string descriptor describing product
  3, // index of string descriptor describing the device serial number
  0x01 // bNumConfigurations
  };
  // USB Configuration Descriptor
  const u8 HID_ConfigDescriptor[HID_SIZE_CONFIG_DESC]=
  {
  0X09, // bLength
  USB_CONFIGURATION_DESCRIPTOR_TYPE, // bDescriptorType
  HID_SIZE_CONFIG_DESC, // wTotalLength
  0x00,
  0x01, // bNumInterfaces 接口数目
  0x01, // bConfigurationValue set_configuration命令所需要的参数值
  0x00, // iConfiguration
  0xE0, // bmAttributes
  0x32, // MaxPower 100mA
  //***************接口1配置***************
  0x09,
  USB_INTERFACE_DESCRIPTOR_TYPE,
  0x00, // 接口编号
  0x00,
  0x02, // 端点数
  0x03,
  0x01, // 1 = boot 0 = no boot
  0x01, // 0 = none 1 = keyboard 2 = mouse
  0, //接口描述符索引值
  //***************HID 描述符****************
  0x09,
  HID_DESCRIPTOR_TYPE,
  0x10,
  0x01,
  0x00,
  0x01,
  0x22,
  HID_SIZE_REPORT_DESC,
  0x00,
  //***************端点1输入描述***************
  0x07,
  USB_ENDPOINT_DESCRIPTOR_TYPE,
  0x81,
  0x03,
  0x0A,
  0x00,
  0x20,

                          
                       
                          
                                //***************端点1输出描述***************
?
  0x07,
  USB_ENDPOINT_DESCRIPTOR_TYPE,
  0x01,
  0x03,
  0x0A,
  0x00,
  0x20,
  };
  // MOUSE ConfigDescriptor
  const u8 HID_ReportDescriptor[HID_SIZE_REPORT_DESC]=
  {
  /************************USB键盘部分报告描述符**********************/
  /*******************************************************************/
  //这是一个全局(bType为1)条目,将用途页选择为普通桌面Generic Desktop Page(0x01)
  //后面跟一字节数据(bSize为1),后面的字节数就不注释了,
  //自己根据bSize来判断。
  0x05, 0x01, // USAGE_PAGE (Generic Desktop)
  //这是一个局部(bType为2)条目,说明接下来的集合用途用于键盘
  0x09, 0x06, // USAGE (Keyboard)
  //这是一个主条目(bType为0)条目,开集合,后面跟的数据0x01表示
  //该集合是一个应用集合。它的性质在前面由用途页和用途定义为
  //普通桌面用的键盘。
  0xa1, 0x01, // COLLECTION (Application)
  //报告ID,这里定义键盘报告的ID为1(报告ID 0是保留的)
  0x85, 0x01, //Report ID (1)
  //这是一个全局条目,选择用途页为键盘(Keyboard/Keypad(0x07))
  0x05, 0x07, // USAGE_PAGE (Keyboard/Keypad)
  //这是一个局部条目,说明用途的最小值为0xe0。实际上是键盘左Ctrl键。
  //具体的用途值可在HID用途表中查看。
  0x19, 0xe0, // USAGE_MINIMUM (Keyboard LeftControl)
  //这是一个局部条目,说明用途的最大值为0xe7。实际上是键盘右GUI键。
  0x29, 0xe7, // USAGE_MAXIMUM (Keyboard Right GUI)
  //这是一个全局条目,说明返回的数据的逻辑值(就是我们返回的数据域的值)
  //最小为0。因为我们这里用Bit来表示一个数据域,因此最小为0,最大为1。
  0x15, 0x00, // LOGICAL_MINIMUM (0)
  //这是一个全局条目,说明逻辑值最大为1。
  0x25, 0x01, // LOGICAL_MAXIMUM (1)
  //这是一个全局条目,说明数据域的数量为八个。
  0x95, 0x08, // REPORT_COUNT (8)
  //这是一个全局条目,说明每个数据域的长度为1个bit。
  0x75, 0x01, // REPORT_SIZE (1)
  //这是一个主条目,说明有8个长度为1bit的数据域(数量和长度
  //由前面的两个全局条目所定义)用来做为输入,
  //属性为:Data,Var,Abs。Data表示这些数据可以变动,Var表示
  //这些数据域是独立的,每个域表示一个意思。Abs表示绝对值。
  //这样定义的结果就是,当某个域的值为1时,就表示对应的键按下。
  //bit0就对应着用途最小值0xe0,bit7对应着用途最大值0xe7。
  0x81, 0x02, // INPUT (Data,Var,Abs)
  //这是一个全局条目,说明数据域数量为1个
  0x95, 0x01, // REPORT_COUNT (1)
  //这是一个全局条目,说明每个数据域的长度为8bit。
  0x75, 0x08, // REPORT_SIZE (8)
  //这是一个主条目,输入用,由前面两个全局条目可知,长度为8bit,
  //数量为1个。它的属性为常量(即返回的数据一直是0)。
  //该字节是保留字节(保留给OEM使用)。
  0x81, 0x03, // INPUT (Cnst,Var,Abs)
  //这是一个全局条目。定义位域数量为6个。
  0x95, 0x06, // REPORT_COUNT (6)
  //这是一个全局条目。定义每个位域长度为8bit。
  //其实这里这个条目不要也是可以的,因为在前面已经有一个定义
  //长度为8bit的全局条目了。
  0x75, 0x08, // REPORT_SIZE (8)
  //这是一个全局条目,定义逻辑最小值为0。
  //同上,这里这个全局条目也是可以不要的,因为前面已经有一个
  //定义逻辑最小值为0的全局条目了。
  0x15, 0x00, // LOGICAL_MINIMUM (0)
  //这是一个全局条目,定义逻辑最大值为255。
  0x25, 0xFF, // LOGICAL_MAXIMUM (255)
  //这是一个全局条目,选择用途页为键盘。
  //前面已经选择过用途页为键盘了,所以该条目不要也可以。
  0x05, 0x07, // USAGE_PAGE (Keyboard/Keypad)
  //这是一个局部条目,定义用途最小值为0(0表示没有键按下)
  0x19, 0x00, // USAGE_MINIMUM (Reserved (no event indicated))
  //这是一个局部条目,定义用途最大值为0x65
  0x29, 0x65, // USAGE_MAXIMUM (Keyboard Application)
  //这是一个主条目。它说明这六个8bit的数据域是输入用的,
  //属性为:Data,Ary,Abs。Data说明数据是可以变的,Ary说明
  //这些数据域是一个数组,即每个8bit都可以表示某个键值,
  //如果按下的键太多(例如超过这里定义的长度或者键盘本身无法
  //扫描出按键情况时),则这些数据返回全1(二进制),表示按键无效。
  //Abs表示这些值是绝对值。
  0x81, 0x00, // INPUT (Data,Ary,Abs)
  //以下为输出报告的描述
  //逻辑最小值前面已经有定义为0了,这里可以省略。
  //这是一个全局条目,说明逻辑值最大为1。
  0x25, 0x01, // LOGICAL_MAXIMUM (1)
  //这是一个全局条目,说明数据域数量为5个。
  0x95, 0x05, // REPORT_COUNT (5)
  //这是一个全局条目,说明数据域的长度为1bit。
  0x75, 0x01, // REPORT_SIZE (1)
  //这是一个全局条目,说明使用的用途页为指示灯(LED)
  0x05, 0x08, // USAGE_PAGE (LEDs)
  //这是一个局部条目,说明用途最小值为数字键盘灯。
  0x19, 0x01, // USAGE_MINIMUM (Num Lock)
  //这是一个局部条目,说明用途最大值为Kana灯。
  0x29, 0x05, // USAGE_MAXIMUM (Kana)
  //这是一个主条目。定义输出数据,即前面定义的5个LED。
  0x91, 0x02, // OUTPUT (Data,Var,Abs)
  //这是一个全局条目。定义位域数量为1个。
  0x95, 0x01, // REPORT_COUNT (1)
  //这是一个全局条目。定义位域长度为3bit。
  0x75, 0x03, // REPORT_SIZE (3)
  //这是一个主条目,定义输出常量,前面用了5bit,所以这里需要
  //3个bit来凑成一字节。
  0x91, 0x03, // OUTPUT (Cnst,Var,Abs)
  //下面这个主条目用来关闭前面的集合。bSize为0,所以后面没数据。
  0xc0, // END_COLLECTION
  //以下注释不包括第一字节报告ID。
  //通过上面的报告描述符的定义,我们知道返回的输入报告具有8字节。
  //第一字节的8个bit用来表示特殊键是否按下(例如Shift、Alt等键)。
  //第二字节为保留值,值为常量0。第三到第八字节是一个普通键键值的
  //数组,当没有键按下时,全部6个字节值都为0。当只有一个普通键按下时,
  //这六个字节中的第一字节值即为该按键的键值(具体的键值请看HID的
  //用途表文档),当有多个普通键同时按下时,则同时返回这些键的键值。
  //如果按下的键太多,则这六个字节都为0xFF(不能返回0x00,这样会让
  //操作系统认为所有键都已经释放)。至于键值在数组中的先后顺序是
  //无所谓的,操作系统会负责检查是否有新键按下。我们应该在中断端点1
  //中按照上面的格式返回实际的键盘数据。另外,报告中还定义了一个字节
  //的输出报告,是用来控制LED情况的。只使用了低7位,高1位是保留值0。
  //当某位的值为1时,则表示对应的LED要点亮。操作系统会负责同步各个
  //键盘之间的LED,例如你有两块键盘,一块的数字键盘灯亮时,另一块
  //也会跟着亮。键盘本身不需要判断各种LED应该何时亮,它只是等待主机
  //发送报告给它,然后根据报告值来点亮相应的LED。我们在端点1输出中断
  //中读出这1字节的输出报告,然后对它取反(因为学习板上的LED是低电平时
  //亮),直接发送到LED上。这样main函数中按键点亮LED的代码就不需要了。
                          
                       
                          
                                /************************USB鼠标部分报告描述符**********************/
?
  /*******************************************************************/
  //这是一个全局(bType为1)条目,选择用途页为普通桌面Generic Desktop Page(0x01)
  0x05, 0x01, // USAGE_PAGE (Generic Desktop)
  //这是一个局部(bType为2)条目,说明接下来的应用集合用途用于鼠标
  0x09, 0x02, // USAGE (Mouse)
  //这是一个主条目(bType为0)条目,开集合,后面跟的数据0x01表示
  //该集合是一个应用集合。它的性质在前面由用途页和用途定义为
  //普通桌面用的鼠标。
  0xa1, 0x01, // COLLECTION (Application)
  //报告ID,这里定义鼠标报告的ID为2
  0x85, 0x02, //Report ID (2)
  //这是一个局部条目。说明用途为指针集合
  0x09, 0x01, // USAGE (Pointer)
  //这是一个主条目,开集合,后面跟的数据0x00表示该集合是一个
  //物理集合,用途由前面的局部条目定义为指针集合。
  0xa1, 0x00, // COLLECTION (Physical)
  //这是一个全局条目,选择用途页为按键(Button Page(0x09))
  0x05, 0x09, // USAGE_PAGE (Button)
  //这是一个局部条目,说明用途的最小值为1。实际上是鼠标左键。
  0x19, 0x01, // USAGE_MINIMUM (Button 1)
  //这是一个局部条目,说明用途的最大值为3。实际上是鼠标中键。
  0x29, 0x03, // USAGE_MAXIMUM (Button 3)
  //这是一个全局条目,说明返回的数据的逻辑值(就是我们返回的数据域的值啦)
  //最小为0。因为我们这里用Bit来表示一个数据域,因此最小为0,最大为1。
  0x15, 0x00, // LOGICAL_MINIMUM (0)
  //这是一个全局条目,说明逻辑值最大为1。
  0x25, 0x01, // LOGICAL_MAXIMUM (1)
  //这是一个全局条目,说明数据域的数量为三个。
  0x95, 0x03, // REPORT_COUNT (3)
  //这是一个全局条目,说明每个数据域的长度为1个bit。
  0x75, 0x01, // REPORT_SIZE (1)
  //这是一个主条目,说明有3个长度为1bit的数据域(数量和长度
  //由前面的两个全局条目所定义)用来做为输入,
  //属性为:Data,Var,Abs。Data表示这些数据可以变动,Var表示
  //这些数据域是独立的,每个域表示一个意思。Abs表示绝对值。
  //这样定义的结果就是,第一个数据域bit0表示按键1(左键)是否按下,
  //第二个数据域bit1表示按键2(右键)是否按下,第三个数据域bit2表示
  //按键3(中键)是否按下。
  0x81, 0x02, // INPUT (Data,Var,Abs)
  //这是一个全局条目,说明数据域数量为1个
  0x95, 0x01, // REPORT_COUNT (1)
  //这是一个全局条目,说明每个数据域的长度为5bit。
  0x75, 0x05, // REPORT_SIZE (5)
  //这是一个主条目,输入用,由前面两个全局条目可知,长度为5bit,
  //数量为1个。它的属性为常量(即返回的数据一直是0)。
  //这个只是为了凑齐一个字节(前面用了3个bit)而填充的一些数据
  //而已,所以它是没有实际用途的。
  0x81, 0x03, // INPUT (Cnst,Var,Abs)
  //这是一个全局条目,选择用途页为普通桌面Generic Desktop Page(0x01)
  0x05, 0x01, // USAGE_PAGE (Generic Desktop)
  //这是一个局部条目,说明用途为X轴
  0x09, 0x30, // USAGE (X)
  //这是一个局部条目,说明用途为Y轴
  0x09, 0x31, // USAGE (Y)
  //这是一个局部条目,说明用途为滚轮
  0x09, 0x38, // USAGE (Wheel)
  //下面两个为全局条目,说明返回的逻辑最小和最大值。
  //因为鼠标指针移动时,通常是用相对值来表示的,
  //相对值的意思就是,当指针移动时,只发送移动量。
  //往右移动时,X值为正;往下移动时,Y值为正。
  //对于滚轮,当滚轮往上滚时,值为正。
  0x15, 0x81, // LOGICAL_MINIMUM (-127)
  0x25, 0x7f, // LOGICAL_MAXIMUM (127)
  //这是一个全局条目,说明数据域的长度为8bit。
  0x75, 0x08, // REPORT_SIZE (8)
  //这是一个全局条目,说明数据域的个数为3个。
  0x95, 0x03, // REPORT_COUNT (3)
  //这是一个主条目。它说明这三个8bit的数据域是输入用的,
  //属性为:Data,Var,Rel。Data说明数据是可以变的,Var说明
  //这些数据域是独立的,即第一个8bit表示X轴,第二个8bit表示
  //Y轴,第三个8bit表示滚轮。Rel表示这些值是相对值。
  0x81, 0x06, // INPUT (Data,Var,Rel)
  //下面这两个主条目用来关闭前面的集合用。
  //我们开了两个集合,所以要关两次。bSize为0,所以后面没数据。
  0xc0, // END_COLLECTION
  0xc0 // END_COLLECTION
  //以下注释不包括第一字节报告ID。
  //通过上面的报告描述符的定义,我们知道返回的输入报告具有4字节。
  //第一字节的低3位用来表示按键是否按下的,高5位为常数0,无用。
  //第二字节表示X轴改的变量,第三字节表示Y轴的改变量,第四字节表示
  //滚轮的改变量。我们在中断端点1中应该要按照上面的格式返回实际的
  //鼠标数据。
  };
  // USB String Descriptors
  const u8 HID_StringLangID[HID_SIZE_STRING_LANGID]=
  {
  HID_SIZE_STRING_LANGID,
  USB_STRING_DESCRIPTOR_TYPE,
  0x09,
  0x04
  };
  const u8 HID_StringVendor[HID_SIZE_STRING_VENDOR]=
  {
  HID_SIZE_STRING_VENDOR,
  USB_STRING_DESCRIPTOR_TYPE,
  'S', 0, 'T', 0, 'M', 0, 'i', 0, 'c', 0, 'r', 0, 'o', 0, 'e', 0,
  'l', 0, 'e', 0, 'c', 0, 't', 0, 'r', 0, 'o', 0, 'n', 0, 'i', 0,
  'c', 0, 's', 0
  };
  const u8 HID_StringProduct[HID_SIZE_STRING_PRODUCT] =
  {
  HID_SIZE_STRING_PRODUCT, /* bLength */
  USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */
  0x34, 0x6c, //水
  0x62, 0x97, //面
  0x4b, 0x4e, //之
  0x0b, 0x4e, //下
  0x84, 0x76, //的
  0x55, 0x00, //U
  0x53, 0x00, //S
  0x42, 0x00, //B
  0x4b, 0x6d, //测
  0xd5, 0x8b, //试
  };
  u8 HID_StringSerial[HID_SIZE_STRING_SERIAL] =
  {
  HID_SIZE_STRING_SERIAL, /* bLength */
  USB_STRING_DESCRIPTOR_TYPE, /* bDescriptorType */
  0x73, 0x00, //s
  0x6e, 0x00, //n
  0x69, 0x00, //i
  0x63, 0x00, //c
  0x5f, 0x00, //_
  0x6b, 0x00, //k
  0x84, 0x76, //的
  0x55, 0x00, //U
  0x53, 0x00, //S
  0x42, 0x00, //B
  0x2e, 0x95, //键
  0xd8, 0x76, //盘
  };
                          
                       
                          
                               
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友 微信微信
收藏收藏1 分享分享 支持支持 反对反对
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|文字版|手机版|DIY编程器网 ( 桂ICP备14005565号-1 )

GMT+8, 2025-9-22 14:13 , 耗时 0.091831 秒, 19 个查询请求 , Gzip 开启.

各位嘉宾言论仅代表个人观点,非属DIY编程器网立场。

桂公网安备 45031202000115号

DIY编程器群(超员):41210778 DIY编程器

DIY编程器群1(满员):3044634 DIY编程器1

diy编程器群2:551025008 diy编程器群2

QQ:28000622;Email:libyoufer@sina.com

本站由桂林市临桂区技兴电子商务经营部独家赞助。旨在技术交流,请自觉遵守国家法律法规,一旦发现将做封号删号处理。

快速回复 返回顶部 返回列表