打印
[USB编程]

STM32做一个鼠标键盘复合设备求救(旧帖复开)

[复制链接]
13262|10
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
lh2008xp|  楼主 | 2014-12-16 15:38 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
STM32做一个鼠标键盘复合设备求救@computer00
https://bbs.21ic.com/forum.php?mod=viewthread&tid=631382&fromuid=745651
由于论坛中同样的问题没有最终解决,因此重开帖。
目的:通过修改报告描述符,利用报告ID的方法,实现单接口的HID USB键盘和鼠标复合设备;
方法:借鉴《圈圈教你学USB》;
问题描述:
①已识别为复合设备,并安装驱动成功;
②但是按按键时,鼠标和键盘数据PC无法识别;
③已通过串口读取到需要发送的数据,因此判定按键数据采集过程正常;怀疑USB设备问题;
使用BUS HOUND检测到设备重启6次后挂起!劳烦大家帮忙分析下,集思广益!

const u8 Joystick_ReportDescriptor[JOYSTICK_SIZ_REPORT_DESC] =
  {
/*****************************keyboard ReportDescriptor**************/
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x06, // USAGE (Keyboard)
0xa1, 0x01, // COLLECTION (Application)
0x85, 0x01, //REPORT ID(1)
0x05, 0x07, //     USAGE_PAGE (Keyboard/Keypad)
0x19, 0xe0, //     USAGE_MINIMUM (Keyboard LeftControl)
0x29, 0xe7, //     USAGE_MAXIMUM (Keyboard Right GUI)
0x15, 0x00, //     LOGICAL_MINIMUM (0)
/* 16 */
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)
/* 32 */
0x75, 0x08, //   REPORT_SIZE (8)
0x15, 0x00, //   LOGICAL_MINIMUM(0)
0x25, 0xFF, //   LOGICAL_MAXIMUM (255)
0x05, 0x07, //   USAGE_PAGE(keboard/Keypad)
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, 0x05, //   REPORT_COUNT (5)
0x75, 0x01, //   REPORT_SIZE (1)
  /* 52 */
0x05, 0x08, //   USAGE_PAGE (LEDs)
0x19, 0x01, //   USAGE_MINIMUM (Num Lock)
0x29, 0x05, //   USAGE_MAXIMUM (Kana)
0x91, 0x02, //   OUTPUT (Data,Var,Abs)
0x95, 0x01, //   REPORT_COUNT (1)
0x75, 0x03, //   REPORT_SIZE (3) ÐÞ¸ÄÄÚÈÝ
0x91, 0x03, //   OUTPUT (Cnst,Var,Abs)
0xc0,        // END_COLLECTION
  /* 67 */
/*****************************Mouse ReportDescriptor**************/
0x05,0x01, //USAGE_PAGE(Generic Desktop)
0x09,0x02, //USAGE(MOUSE)
0xa1,0x01, //COLLECTION
0X85,0X02, //REPORT ID(2)
0x09,0x01,         /*Usage(Pointer)*/
0xa1,0x00,          /*Collection(Linked)*/
0x05,0x09,          /*Usage Page(Buttons)*/
0x19,0x01,          /*Usage Minimum(1)*/
        /* 16 */
        0x29,0x03,          /*Usage Maximum(3)*/
        0x15,0x00,          /*Logical Minimum(0)*/
        0x25,0x01,          /*Logical Maximum(1)*/
        0x95,0x03,          /*Report Count(3)*/
        0x75,0x01,          /*Report Size(1)*/
        0x81,0x02,          /*Input(Variable)*/
        0x95,0x01,          /*Report Count(1)*/
        0x75,0x05,          /*Report Size(5)*/
        /* 32 */
        0x81,0x01,          /*Input(Constant,Array)*/
        0x05,0x01,          /*Usage Page(Generic Desktop)*/
        0x09,0x30,          /*Usage(X axis)*/
        0x09,0x31,          /*Usage(Y axis)*/
        0x09,0x38,          /*Usage(Wheel)*/
        0x15,0x81,          /*Logical Minimum(-127)*/
        0x25,0x7F,          /*Logical Maximum(127)*/       
        0x75,0x08,          /*Report Size(8)*/
        /* 48 */
        0x95,0x03,          /*Report Count(3)*/
        0x81,0x06,          /*Input(Variable, Relative)*/
        0xC0,          /*End Collection*/
        0xc0           //End Collection again
        /* 54 */
  }
  ; /* Joystick_ReportDescriptor */
描述符的代码大家应该很熟悉,是书中的源码!
void Joystick_Send(u8 buf0,u8 buf1,u8 buf2,u8 buf3,u8 buf4,u8 buf5,u8 buf6,u8 buf7,u8 buf8)
{
   u8 Keyboard_Buffer[9] = {0, 0, 0, 0,0,0,0,0,0};
   
  /* prepare buffer to send */
  Keyboard_Buffer[0]=buf0;
  Keyboard_Buffer[1]=buf1;
  Keyboard_Buffer[2]=buf2;
  Keyboard_Buffer[3]=buf3;
  Keyboard_Buffer[4]=buf4;
  Keyboard_Buffer[5]=buf5;
  Keyboard_Buffer[6]=buf6;
  Keyboard_Buffer[7]=buf7;
  Keyboard_Buffer[8]=buf8;

  /*copy mouse position info in ENDP1 Tx Packet Memory Area*/
  UserToPMABufferCopy(Keyboard_Buffer, GetEPTxAddr(ENDP1), 8);
  /* enable endpoint for transmission */
  SetEPTxValid(ENDP1);
}
USB数据传输键盘数据程序段如上,由于含ID为因此数据结构为1+8;
主函数中的程序端如下;
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"         
#include "string.h"
#include "usb_lib.h"
#include "hw_config.h"
#include "usb_pwr.h"
#include "I2C.h"
#include "mpu6050.h"
#include "24l01.h"
                
u32 usb_abs(u32 x1,u32 x2)
{
        if(x1>x2)return x1-x2;
        else return x2-x1;
}
  
void usb_port_set(u8 enable)
{         
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);       
        if(enable)_SetCNTR(_GetCNTR()&(~(1<<1)));
        else
        {          
                _SetCNTR(_GetCNTR()|(1<<1));
                GPIOA->CRH&=0XFFF00FFF;
                GPIOA->CRH|=0X00033000;
                PAout(12)=0;                      
        }
}         

int main(void)
{       
                u8 Keyboard_Buffer[8] ={0,0,0,0,0,0,0,0};
          u8 key;
                short X,Y,X1,Y1;
               
                u8 keysta;                  
                delay_init();                     //ÑÓʱº¯Êý³õʼ»¯          
                NVIC_Configuration();          //ÉèÖÃNVICÖжϷÖ×é2:2λÇÀÕ¼ÓÅÏȼ¶£¬2λÏìÓ¦ÓÅÏȼ¶
                uart_init(9600);                 //´®¿Ú³õʼ»¯Îª9600
                printf("´®¿Ú³õʼ»¯Íê±Ï\r\n");
          KEY_Init();                                  //°´¼ü³õʼ»¯
                printf("°´¼ü³õʼ»¯Íê±Ï\r\n");
                usb_port_set(0);         //USBÏȶϿª
                delay_ms(300);
                usb_port_set(1);        //USBÔÙ´ÎÁ¬½Ó
                USB_Interrupts_Config();   
                Set_USBClock();   
                USB_Init();         
                printf("USB¶¼³õʼ»¯Íê±ÏÁË£¬É§Ä꣬¿ªÊ¼½ÓÊÕ°É£¡£¡£¡\r\n");               
        while(1)
        {                
                 key=KEY_Scan(1);//Ö§³ÖÁ¬°´          
                 if(key==WKUP_PRES) Keyboard_Buffer[3]=0x15; //r
                 if(key==KEY1_PRES) Keyboard_Buffer[3]=0x16; //s
                 if(key==KEY0_PRES) Keyboard_Buffer[3]=0x17; //t
//         printf(" %8d%8d\r\n",Keyboard_Buffer[0],Keyboard_Buffer[1]);       
                 Joystick_Send(0x01,Keyboard_Buffer[0],0,Keyboard_Buffer[3],0,0,0,0,0);
     Keyboard_Buffer[3]=0x00;               
        }
}
       
为实现方便性,主函数暂时只考虑发送键盘数据;


相关帖子

来自 2楼
lh2008xp|  楼主 | 2015-2-13 17:36 | 只看该作者
自己的问题自己解决!~目前已基于STM32F103原子开发板实现了键盘和鼠标复合设备,
wk_up键 输入字母r;
KEY1键  鼠标上移;
KEY2键  鼠标下移;
修改主要内容为:
在usb_prop.c程序中SetEPTxCount(ENDP1, 8)修改为在usb_prop.c程序中SetEPTxCount(ENDP1, 8)和SetEPTxCount(ENDP1, 9)
附上工程代码!~

有线复合键鼠V1.1(成功).rar

3.51 MB

使用特权

评论回复
板凳
lh2008xp|  楼主 | 2014-12-17 09:13 | 只看该作者
@computer00
将键盘程序修改成复合设备除了你的书中修改报告描述符,是不是还要修改设备描述符吗?

使用特权

评论回复
地板
diyusb| | 2014-12-18 20:42 | 只看该作者
严格来说,是需要修改配置描述符、接口描述符

使用特权

评论回复
5
lh2008xp|  楼主 | 2014-12-20 15:45 | 只看该作者
diyusb 发表于 2014-12-18 20:42
严格来说,是需要修改配置描述符、接口描述符

主要需要修改这两种描述符中的什么参数?数据长度?

使用特权

评论回复
6
computer00| | 2014-12-22 20:54 | 只看该作者
不需要,只需要修改报告描述符即可实现。
从抓到的信息来看,可能是因为你没有实现set idle这个请求,需要实现一下。
参考书中的例子来应该是OK的。

使用特权

评论回复
7
lh2008xp|  楼主 | 2015-2-9 11:08 | 只看该作者
computer00 发表于 2014-12-22 20:54
不需要,只需要修改报告描述符即可实现。
从抓到的信息来看,可能是因为你没有实现set idle这个请求,需要 ...

[img][/img]
上面的图中含有set idle,怎么看出来没有实现这个请求?还有实现这个请求与上面程序相关?

使用特权

评论回复
8
344534979| | 2016-7-3 23:20 | 只看该作者
楼主太强大了,请问怎么发送鼠标左中右键啊?这个数据的格式在哪里有?

使用特权

评论回复
9
307191841| | 2020-2-26 16:29 | 只看该作者
lh2008xp 发表于 2015-2-13 17:36
自己的问题自己解决!~目前已基于STM32F103原子开发板实现了键盘和鼠标复合设备,
wk_up键 输入字母r;
KEY ...

这个好使,keil版本不同有时候会报错,看下面链接,删掉里面的STM3210X_HD
https://www.cnblogs.com/shirishiqi/p/5484973.html

使用特权

评论回复
10
307191841| | 2020-2-26 16:37 | 只看该作者
lh2008xp 发表于 2015-2-13 17:36
自己的问题自己解决!~目前已基于STM32F103原子开发板实现了键盘和鼠标复合设备,
wk_up键 输入字母r;
KEY ...

这个代码好使,要做全功能键盘的,可以看下附件的HID键码

USB HID键盘----按键代码.pdf

48.92 KB

使用特权

评论回复
11
exxew| | 2024-1-10 15:29 | 只看该作者
踩一脚,留个脚印。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

主题

29

帖子

1

粉丝