OpenEdv-开源电子网

 找回密码
 立即注册
正点原子全套STM32/Linux/FPGA开发资料,上千讲STM32视频教程免费下载...
查看: 3869|回复: 11

STM32L4R5板子模拟带鼠标功能的USB键盘(方法二)的问题

[复制链接]

74

主题

182

帖子

0

精华

高级会员

Rank: 4

积分
588
金钱
588
注册时间
2014-10-15
在线时间
137 小时
发表于 2023-6-18 22:19:08 | 显示全部楼层 |阅读模式
1金钱
我参考网上的STM32例程和电脑圈圈的书,想实现带鼠标功能的USB键盘(方法二)。
现在模拟的鼠标和键盘都出来了。
0.jpg
可是按键不反应。
我的按键代码如下:
  1. if(HAL_GPIO_ReadPin(GPIOC,KEY_Pin)==1)    //键盘
  2.                 {
  3.                        
  4.                                 sendbuffer[0]=1;
  5.                                 if((KeyPress&1)==0)
  6.                                 {
  7.                                         HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, GPIO_PIN_SET);

  8.                                         sendbuffer[3]=0x04;
  9.                                 }
  10.                                 if((KeyPress&2)==0)
  11.                                         sendbuffer[3]=0x05;
  12.                                 if((KeyPress&4)==0)
  13.                                         sendbuffer[3]=0x06;
  14.                                 if((KeyPress&8)==0)
  15.                                         sendbuffer[3]=0x07;
  16.                                
  17.                                 USBD_HID_SendReport(&hUsbDeviceFS,sendbuffer,9);//发送报文
  18.                                 memset(sendbuffer,0,9);
  19.                                 KeyDown=0;
  20.                                 KeyUp=0;
  21.                        
  22.                 }
  23.                 else
  24.                 {
  25.                         sendbuffer1[0]=1;
  26.                         if((KeyPress&1)==0)
  27.                         {
  28.                                 HAL_GPIO_WritePin(LD1_GPIO_Port, LD1_Pin, GPIO_PIN_SET);
  29.                                 sendbuffer1[2]=-10;
  30.                         }
  31.                         if((KeyPress&2)==0)
  32.                                 sendbuffer1[2]=10;
  33.                         if((KeyPress&4)==0)
  34.                                 sendbuffer1[3]=-10;
  35.                         if((KeyPress&8)==0)
  36.                                 sendbuffer1[3]=10;
  37.                        
  38.                         USBD_HID_SendReport(&hUsbDeviceFS,sendbuffer1,5);//发送报文
  39.                         memset(sendbuffer1,0,5);
  40.                         KeyDown=0;
  41.                         KeyUp=0;
  42.                 }
复制代码
板子上的键按下代表键盘功能,松开代表鼠标功能。又从另外一块板子上接了四个键。
我现在有一个疑问,圈圈的书上说,前面的例子发送报告是通过端点1,现在发送键盘报告是通过端点1,发送鼠标报告通过端点2.
那在程序里如何体现呢?
请高手指教,谢谢!

正点原子逻辑分析仪DL16劲爆上市
回复

使用道具 举报

3

主题

821

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3359
金钱
3359
注册时间
2011-11-10
在线时间
207 小时
发表于 2023-6-19 09:44:45 | 显示全部楼层
HID的报告描述符仔细看看。
回复

使用道具 举报

74

主题

182

帖子

0

精华

高级会员

Rank: 4

积分
588
金钱
588
注册时间
2014-10-15
在线时间
137 小时
 楼主| 发表于 2023-6-19 11:52:02 | 显示全部楼层
c2007s 发表于 2023-6-19 09:44
HID的报告描述符仔细看看。

谢谢!我看了。可是圈圈的书上的写法和STM32不一样。我贴一下圈圈的写法:
  1. if(ConfigValue!=0) //如果已经设置为非0的配置,则可以返回报告数据
  2.   {
  3.    //为显示KEY1选择功能,当KEY1按住时,将LED8点亮,表示键盘功能状态
  4.    if(KeyPress & KEY1)
  5.    {
  6.     OnLed8();
  7.     //如果端点1输入没有处于忙状态,则可以发送数据
  8.     if(!Ep1InIsBusy)
  9.     {
  10.      KeyCanChange=0;  //禁止按键扫描
  11.      if(KeyUp||KeyDown) //如果有按键事件发生
  12.      {
  13.       SendKeyboardReport();  //则返回报告
  14.      }
  15.      KeyCanChange=1;  //允许按键扫描
  16.     }
  17.    }
  18.    else
  19.    {
  20.     OffLed8();
  21.     //如果端点2输入没有处于忙状态,则可以发送数据
  22.     if(!Ep2InIsBusy)
  23.     {
  24.      KeyCanChange=0;  //禁止按键扫描
  25.      if(KeyUp||KeyDown) //如果有按键事件发生
  26.      {
  27.       SendMouseReport();  //则返回报告
  28.      }
  29.      KeyCanChange=1;  //允许按键扫描
  30.     }   
  31.    }
  32.   }
复制代码
  1. /********************************************************************
  2. 函数功能:根据按键情况返回键盘报告的函数。
  3. 入口参数:无。
  4. 返    回:无。
  5. 备    注:无。
  6. ********************************************************************/
  7. void SendKeyboardReport(void)
  8. {
  9. //需要返回的9字节报告的缓冲(一字节报告ID加键盘8字节报告)

  10. uint8 Buf[9]={0,0,0,0,0,0,0,0,0};

  11. //由于需要返回多个按键,所以需要增加一个变量来保存当前的位置。
  12. //由于报告ID占用第一字节,所以普通按键从第四字节开始存放。
  13. uint8 i=3;

  14. //我们用KEY1键来选择剩余的7个键是键盘功能还是鼠标功能。
  15. //当KEY1按住时,剩余7个键为键盘功能,这7个键的功能跟键盘
  16. //实例的一样。

  17. //根据不同的按键设置输入报告
  18. Buf[0]=0x01;  //第一字节为报告ID,报告ID为1。
  19. if(KeyPress & KEY2) //如果KEY2按住
  20. {
  21.   Buf[1]|=0x02;  //KEY2为左Shift键。
  22. }
  23. if(KeyPress & KEY3) //如果KEY3按住
  24. {
  25.   Buf[1]|=0x04;  //KEY3为左Alt键
  26. }
  27. if(KeyPress & KEY4) //如果KEY4按住
  28. {
  29.   Buf[i]=0x59;  //KEY4为数字小键盘1键。
  30.   i++;  //切换到下个位置。
  31. }
  32. if(KeyPress & KEY5)  //如果KEY5按住
  33. {
  34.   Buf[i]=0x5A;  //KEY5数字小键盘2键。
  35.   i++;  //切换到下个位置。
  36. }
  37. if(KeyPress & KEY6)  //如果KEY6按住
  38. {
  39.   Buf[i]=0x5B;  //KEY6为数字小键盘3键。
  40.   i++;  //切换到下个位置。
  41. }
  42. if(KeyPress & KEY7)  //如果KEY7按住
  43. {
  44.   Buf[i]=0x39;  //KEY7为大/小写切换键。
  45.   i++;  //切换到下个位置。
  46. }
  47. if(KeyPress & KEY8)  //如果KEY8按住
  48. {
  49.   Buf[i]=0x53;  //KEY8为数字小键盘功能切换键。
  50. }
  51. //报告准备好了,通过端点1返回,长度为9字节。
  52. D12WriteEndpointBuffer(3,9,Buf);
  53. Ep1InIsBusy=1;  //设置端点1输入忙标志。
  54. //记得清除KeyUp和KeyDown
  55. KeyUp=0;
  56. KeyDown=0;
  57. }
  58. ////////////////////////End of function//////////////////////////////

  59. /********************************************************************
  60. 函数功能:根据按键情况返回鼠标报告的函数。
  61. 入口参数:无。
  62. 返    回:无。
  63. 备    注:无。
  64. ********************************************************************/
  65. void SendMouseReport(void)
  66. {
  67. //需要返回的5字节报告的缓冲(一字节报告ID加键盘4字节报告)

  68. uint8 Buf[5]={0,0,0,0,0};

  69. //当KEY1松开时,剩余7个键为鼠标功能,功能分别为:
  70. //KEY2:光标左移,KEY3:光标右移,KEY4:光标上移,KEY5:光标下移。
  71. //KEY6:鼠标左键,KEY7:鼠标中键,KEY8:鼠标右键。

  72. //根据不同的按键设置输入报告。注意此处,报告ID要跟报告描述符中的一致。
  73. Buf[0]=0x01;  //第一字节为报告ID,报告ID为1。
  74. if(KeyDown & KEY2) //如果KEY2按下
  75. {
  76.   Buf[2]=-10;  //KEY2为鼠标左移,按一次移动10个单位。
  77. }
  78. if(KeyDown & KEY3) //如果KEY3按下
  79. {
  80.   Buf[2]=10;  //KEY3为鼠标右移,按一次移动10个单位。
  81. }
  82. if(KeyDown & KEY4) //如果KEY4按下
  83. {
  84.   Buf[3]=-10;  //KEY4为鼠标上移,按一次移动10个单位。
  85. }
  86. if(KeyDown & KEY5)  //如果KEY5按下
  87. {
  88.   Buf[3]=10;  //KEY5为鼠标下移,按一次移动10个单位。
  89. }
  90. if(KeyPress & KEY6)  //如果KEY6按住
  91. {
  92.   Buf[1]|=0x01;  //KEY6为鼠标左键。
  93. }
  94. if(KeyPress & KEY7)  //如果KEY7按住
  95. {
  96.   Buf[1]|=0x04;  //KEY7为鼠标中键。
  97. }
  98. if(KeyPress & KEY8)  //如果KEY8按住
  99. {
  100.   Buf[1]|=0x02;  //KEY8为鼠标右键。
  101. }
  102. //注意此处,要通过端点2返回。
  103. //报告准备好了,通过端点2返回,长度为5字节。
  104. D12WriteEndpointBuffer(5,5,Buf);
  105. Ep2InIsBusy=1;  //设置端点2输入忙标志。
  106. //记得清除KeyUp和KeyDown
  107. KeyUp=0;
  108. KeyDown=0;
  109. }
复制代码
发送键盘的函数是D12WriteEndpointBuffer(3,9,Buf);
发送鼠标的函数是D12WriteEndpointBuffer(5,5,Buf);
可是STM32程序
发送报告是这样写的
USBD_HID_SendReport(&hUsbDeviceFS,sendbuffer,9);//发送报文
hUsbDeviceFS是这样定义的,USBD_HandleTypeDef hUsbDeviceFS;
我找遍了整个工程也没见怎么给它赋值。
况且带鼠标功能的USB键盘(方法一)我已经做成功了。
这个问题看描述符能解决吗?而且是鼠标和键盘都不反应,
我实在是想不到该怎么解决了。你能不能给我提个醒啊?谢谢
回复

使用道具 举报

74

主题

182

帖子

0

精华

高级会员

Rank: 4

积分
588
金钱
588
注册时间
2014-10-15
在线时间
137 小时
 楼主| 发表于 2023-6-19 22:36:06 | 显示全部楼层

我用bus hound抓包,一上电,好像有错误。
2.jpg
按键什么数据也发不出来。
回复

使用道具 举报

3

主题

821

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3359
金钱
3359
注册时间
2011-11-10
在线时间
207 小时
发表于 2023-6-20 08:15:35 | 显示全部楼层
报告描述符是告知主设备收到数据后用怎么解析它。你的鼠标和键盘都是通用设备,会自动解析。前提是报告描述符必须正确无误。1. PC获取的报告描述符是否完整,如果不完整检查HID描述符里填充的报告描述符字节数。2. 报告描述符里规定的数据类型和范围和你函数填充的数据是否一致。 3. 发送端点地址是否和你的报告描述符匹配。可用用USBhound软件监控一下数据。
回复

使用道具 举报

74

主题

182

帖子

0

精华

高级会员

Rank: 4

积分
588
金钱
588
注册时间
2014-10-15
在线时间
137 小时
 楼主| 发表于 2023-6-20 11:31:41 | 显示全部楼层
现在键盘好了,鼠标还是不行。
我用BUS HOUND抓包
发现鼠标数据发出来了,可是有一行提示出错 3.jpg
回复

使用道具 举报

74

主题

182

帖子

0

精华

高级会员

Rank: 4

积分
588
金钱
588
注册时间
2014-10-15
在线时间
137 小时
 楼主| 发表于 2023-6-20 12:20:42 | 显示全部楼层
如何通过端点2发送数据呢?谢谢
回复

使用道具 举报

74

主题

182

帖子

0

精华

高级会员

Rank: 4

积分
588
金钱
588
注册时间
2014-10-15
在线时间
137 小时
 楼主| 发表于 2023-6-20 17:43:42 | 显示全部楼层
c2007s 发表于 2023-6-20 08:15
报告描述符是告知主设备收到数据后用怎么解析它。你的鼠标和键盘都是通用设备,会自动解析。前提是报告描述 ...

谢谢!我感觉最可能的问题就是发送端点地址不对。
键盘是用端点一,没问题。鼠标是用端点二,我感觉这儿有问题,可又不知道怎么改。
回复

使用道具 举报

0

主题

24

帖子

0

精华

初级会员

Rank: 2

积分
54
金钱
54
注册时间
2022-4-21
在线时间
19 小时
发表于 2023-6-21 06:50:59 | 显示全部楼层
你可以试下端点1发送鼠标是否正确,
然后再用端点2发送,
你还得重新构建电脑端的驱动,才能实现键盘鼠标合一。
回复

使用道具 举报

3

主题

821

帖子

0

精华

论坛元老

Rank: 8Rank: 8

积分
3359
金钱
3359
注册时间
2011-11-10
在线时间
207 小时
发表于 2023-6-21 08:23:42 | 显示全部楼层
仔细跟踪检查一下D12WriteEndpointBuffer(5,5,Buf);函数
回复

使用道具 举报

74

主题

182

帖子

0

精华

高级会员

Rank: 4

积分
588
金钱
588
注册时间
2014-10-15
在线时间
137 小时
 楼主| 发表于 2023-6-25 23:15:50 | 显示全部楼层
13760162819 发表于 2023-6-21 06:50
你可以试下端点1发送鼠标是否正确,
然后再用端点2发送,
你还得重新构建电脑端的驱动,才能实现键盘鼠标 ...

两个好像都是用端点1发送的。我根本不知道怎么用端点二发送。
  1. USBD_HID_SendReport(&hUsbDeviceFS,sendbuffer,9);//发送报文
复制代码
  1. USBD_HandleTypeDef hUsbDeviceFS;
复制代码
  1. uint8_t USBD_HID_SendReport(USBD_HandleTypeDef *pdev, uint8_t *report, uint16_t len)
  2. {
  3.         USBD_SetupReqTypedef *req;
  4.   USBD_HID_HandleTypeDef *hhid = (USBD_HID_HandleTypeDef *)pdev->pClassData;

  5.   if (hhid == NULL)
  6.   {
  7.     return (uint8_t)USBD_FAIL;
  8.   }

  9.   if (pdev->dev_state == USBD_STATE_CONFIGURED)
  10.   {
  11.     if (hhid->state == HID_IDLE)
  12.     {
  13.       hhid->state = HID_BUSY;
  14.                        
  15.                         (void)USBD_LL_Transmit(pdev, HID_EPIN_ADDR, report, len);
  16.                        
  17.     }
  18.   }

  19.   return (uint8_t)USBD_OK;
  20. }
复制代码
  1. #define HID_EPIN_ADDR                              0x81U
  2. #define HID_EPIN_SIZE                              0x04U
复制代码
我自己定义端点二,
  1. #define HID_EPIN2_ADDR                              0x82U
  2. #define HID_EPIN2_SIZE                              0x04U
复制代码
根本不好使,好像还要打开端点,激活端点等。我搞了好久,端点二不起作用。
回复

使用道具 举报

74

主题

182

帖子

0

精华

高级会员

Rank: 4

积分
588
金钱
588
注册时间
2014-10-15
在线时间
137 小时
 楼主| 发表于 2023-6-25 23:19:17 | 显示全部楼层
c2007s 发表于 2023-6-21 08:23
仔细跟踪检查一下D12WriteEndpointBuffer(5,5,Buf);函数

/********************************************************************
函数功能:将数据写入端点缓冲区函数。
入口参数:Endp:端点号;Len:需要发送的长度;Buf:保存数据的缓冲区。
返    回:Len的值。
备    注:无。
********************************************************************/
uint8 D12WriteEndpointBuffer(uint8 Endp,uint8 Len,uint8 * Buf)
{
uint8 i;
D12SelectEndpoint(Endp); //选择端点
D12WriteCommand(D12_WRITE_BUFFER); //写Write Buffer命令
D12WriteByte(0); //该字节必须写0
D12WriteByte(Len);  //写需要发送数据的长度

#ifdef DEBUG1 //如果定义了DEBUG1,则需要显示调试信息
Prints("写端点");
PrintLongInt(Endp/2); //端点号。由于D12特殊的端点组织形式,
                       //这里的0和1分别表示端点0的输出和输入;
                       //而2、3分别表示端点1的输出和输入;
                       //3、4分别表示端点2的输出和输入。
                       //因此要除以2才显示对应的端点。
Prints("缓冲区");
PrintLongInt(Len);    //写入的字节数
Prints("字节。\r\n");
#endif
D12SetPortOut(); //将数据口设置为输出状态(注意这里为空宏,移植时可能有用)
for(i=0;i<Len;i++)
{
  //这里不直接调用写一字节的函数,而直接在这里模拟时序,可以节省时间
  D12ClrWr(); //WR置低  
  D12SetData(*(Buf+i)); //将数据放到数据线上
  D12SetWr();  //WR置高,完成一字节写
#ifdef DEBUG1
  PrintHex(*(Buf+i));  //如果需要显示调试信息,则显示发送的数据
  if(((i+1)%16)==0)Prints("\r\n"); //每16字节换行一次
#endif
  }
#ifdef DEBUG1
if((Len%16)!=0)Prints("\r\n"); //换行
#endif
D12SetPortIn(); //数据口切换到输入状态
D12ValidateBuffer(); //使端点数据有效
return Len; //返回Len
}
这个跟32差的太远。

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则



关闭

原子哥极力推荐上一条 /2 下一条

正点原子公众号

QQ|手机版|OpenEdv-开源电子网 ( 粤ICP备12000418号-1 )

GMT+8, 2025-4-18 06:56

Powered by OpenEdv-开源电子网

© 2001-2030 OpenEdv-开源电子网

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