电子大神的日记本,供应链专家的功夫茶盘,在这里记录、分享与共鸣。

登录以开始

USB键盘的实现

** ** 

 

 

一、移植过程分析

 

1、移植前的准备工作

现在我们实现一个系统,很少是从0开始,都是在已有的系统上借鉴和修改,这是软件可重用性的表现。

(1)我的USB键盘的目标

摇杆的“上、右、下、左”分别代表“a b c d”,OK键表示“左GUI键”,PB2表示“左CTRL键”。

我的实现完全是在“JoyStickMouse”例程的基础上进行修改。

(2)需要修改的地方

首先是描述符:要多使用一个端点、因此接口描述符要修改,增加一个端点描述符,报告描述符也要修改成键盘数据集合。

 

其次是要增加中断输出端点处理。分析数据,并控制LED灯(把它当成大小写指示灯。

 

2、移植前的准备工作

开始进行移植。

(1)增加命令ukey。

鼠标是用的命令umouse,这里改成ukey,由于这两个现在还不能同时实现,所以命令数不用增加,直接在原来的基础上修改。这里甚至连命令处理函数的名称我都不修改了。

 

(2)修改usb_desc.c

将设备描述符里的产品序列号由02 00 改为 02 01。

将HID接口描述符所用的端点数目 由1个 改为 2个。

 

增加了一个端点描述符:

    0x07,          /*bLength: Endpoint Descriptor size*/

    USB_ENDPOINT_DESCRIPTOR_TYPE, /*bDescriptorType:*/

    0x01,          /*使用1号的输出端点*/

    0x03,          /*中断端点*/

    0x04,          /*wMaxPacketSize: 4 Byte max */

    0x00,

    0x20,

加了这个端点描述符后,要改变配置集合描述符的长度。加上7就行了,这个在头文件中用“define”重新定义就行了。

 

最重要的修改报告描述符:

上一篇博文这个工作已经做好了。改过之后的描述符变为61=0x3D个字节,所以要修改报告描述符的长度,这个也是在头文件中修改。

 

修改字符串描述符,产品名称改为“ntsc2004的小键盘”。产品序列号改变为“stm2004”。

改变之后,先单独编译一下,没有发生错误。

 

(3)增加一个usb_endp.c

这个函数专门用于处理中断输出端点数据的接收和处理。

中断端点1输出处理是调用:

void (*pEpInt_OUT[7])(void) =

  {

    EP1_OUT_Callback,

    EP2_OUT_Callback,

    EP3_OUT_Callback,

    EP4_OUT_Callback,

    EP5_OUT_Callback,

    EP6_OUT_Callback,

    EP7_OUT_Callback,

  };

第一个函数进行处理的,所以我们在这个文件里就实现这个函数。

 

先包含必须的头文件。

在usb_conf.h中,先把以下语句注释掉。

//#define  EP1_OUT_Callback   NOP_Process。因为我们接下来要实现它。

先不具体实现功能,只加了以下代码:

void EP1_OUT_Callback(void){

#if usb_debug

      Uart_PutString("端点1中断输出\r\n" );

#endif

}

 

既然用到了端点1的中断输出,则必须先进行初始化,包括端点类型的设置(中断类型)、端点描述符表的初始化(给它设置接收缓冲区的地址和大小)。这个是在用户提供的初始化代码中完成的。

初始化代码在Device_Properti->Reset()函数中。

  SetEPType(ENDP1, EP_INTERRUPT);

  SetEPTxAddr(ENDP1, ENDP1_TXADDR); //设置发送缓冲区。

  SetEPRxAddr(ENDP1, ENDP1_RXADDR); //设置接收缓冲区,接收报告一个字节。

  SetEPTxCount(ENDP1, 2);  //发送的最大数组2个。

  SetEPRxCount(ENDP1,64); //接收的最大数值64个。

  SetEPRxStatus(ENDP1, EP_RX_NAK);

  SetEPTxStatus(ENDP1, EP_TX_NAK); //设置端点状态,现在为不响应。

 

那么端点什么时候变得有效呢?

(4)修改usbmouse.c

我这里就不改变文件名称了。

(5)改变Joystick_Send(KeyAct)的行为。

void Joystick_Send(u8 Keys)

{

  u8 Mouse_Buffer[2] = {0, 0};

  switch (Keys)

  {

    case 'a':

      Mouse_Buffer[1]=0x59;  //对应小键盘上的“ 1”。

      break;

    case 'b':

      Mouse_Buffer[1]=0x5A;  // “2”

      break;

    case 'c':

      Mouse_Buffer[1]=0x5B;

      break;

    case 'd':

      Mouse_Buffer[1]=0x5C;;

      break;

    case 1:

       Mouse_Buffer[0] |= 0x01;  //左Ctrl键。

      break;

    case 4:

      Mouse_Buffer[0] |= 0x08;  //左GUI键

      break;

    default:

      return;

  }

 

  UserToPMABufferCopy(Mouse_Buffer, GetEPTxAddr(ENDP1), 2);

  SetEPTxValid(ENDP1);

  Mouse_Buffer[0] = 0;

  Mouse_Buffer[1] = 0;

}

 

(6)编写usb_endp.c

在端点1输出中断中如下处理:

void EP1_OUT_Callback(void){

    u8 OutBuf;

#if usb_debug

      Uart_PutString("端点1数据:" );

#endif

      PMAToUserBufferCopy(&OutBuf, GetEPRxAddr(ENDP1), 1);  //读取一个字节的数据到用户缓冲区 OutBuf。

#if usb_debug

      Uart_PutHex(OutBuf);

      Uart_PutString("\r\n" );

#endif

      if ( OutBuf & 0x01 )

             GPIO_WriteBit(GPIOB,GPIO_Pin_5,Bit_SET);

    else

        GPIO_WriteBit(GPIOB,GPIO_Pin_5,Bit_RESET);

    SetEPRxValid(ENDP1);

}

 

 

3、下载测试。

整个工程编译下载,很快就成功了。在设备管理器发现了该设备如下所示:


博主
nthq2004
nthq2004's Blog
欢迎来到我的博客!
点击跳转