找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 6382|回复: 0
打印 上一主题 下一主题
收起左侧

CH549模拟USB键鼠复合设备源码

[复制链接]
跳转到指定楼层
楼主
制作出来的实物图如下:


单片机源程序如下:
  1. /********************************** (C) COPYRIGHT *******************************
  2. * File Name          : CompositeKM.C
  3. * Author             : WCH
  4. * Version            : V1.0
  5. * Description        : CH549模拟USB键鼠复合设备,支持类命令,支持唤醒
  6.                        演示键盘鼠标简单操作。其他键值,参考 HID USAGE TABLE协议文档
  7.                        串口0接收字符:
  8.                        ‘L’:鼠标左键
  9.                        ‘R’: 鼠标右键
  10.                        ‘A’: 键盘‘A’键
  11.                        ‘Q’: 键盘‘Caps’键
  12.                     任意字符:主机睡眠状态下,设备远程唤醒主机(注意设备一般需自供电,因为主机休眠可能USB口也会掉电)
  13. *******************************************************************************/
  14. #include ".\Public\CH549.H"
  15. #include ".\Public\DEBUG.H"
  16. //#define Fullspeed
  17. #ifdef  Fullspeed
  18. #define THIS_ENDP0_SIZE         64
  19. #else
  20. #define THIS_ENDP0_SIZE         8                                              //低速USB,中断传输、控制传输最大包长度为8
  21. #endif
  22. #define EP1_IN_SIZE             8                                              //键盘端点数据包大小
  23. #define EP2_IN_SIZE             4                                              //鼠标端点数据包大小
  24. UINT8X  Ep0Buffer[ THIS_ENDP0_SIZE+2 ] _at_ 0x0000;                            //端点0 OUT&IN缓冲区,必须是偶地址
  25. UINT8X  Ep1Buffer[ EP1_IN_SIZE+2 ]     _at_ THIS_ENDP0_SIZE+2;                 //端点1 IN缓冲区,必须是偶地址
  26. UINT8X  Ep2Buffer[ EP2_IN_SIZE+2 ]     _at_ THIS_ENDP0_SIZE+EP1_IN_SIZE+4;     //端点2 IN缓冲区,必须是偶地址
  27. UINT8   SetupReq,Ready,UsbConfig;
  28. UINT16  SetupLen;
  29. PUINT8  pDescr;                                                                //USB配置标志
  30. USB_SETUP_REQ   SetupReqBuf;                                                   //暂存Setup包
  31. #define UsbSetupBuf     ((PUSB_SETUP_REQ)Ep0Buffer)
  32. #pragma  NOAREGS
  33. /*设备描述符*/
  34. UINT8C DevDesc[] = { 0x12,0x01,0x10,0x01,0x00,0x00,0x00,THIS_ENDP0_SIZE,
  35.                      0x86,0x1a,0xe1,0xe6,0x00,0x01,0x01,0x02,
  36.                      0x00,0x01
  37.                    };
  38. /*字符串描述符*/
  39. UINT8C  MyLangDescr[] = { 0x04, 0x03, 0x09, 0x04 };                                    // 语言描述符
  40. UINT8C  MyManuInfo[] = { 0x0E, 0x03, 'w', 0, 'c', 0, 'h', 0, '.', 0, 'c', 0, 'n', 0 }; // 厂家信息
  41. UINT8C  MyProdInfo[] = { 0x0C, 0x03, 'C', 0, 'H', 0, '5', 0, '4', 0, '9', 0 };         // 产品信息
  42. /*HID类报表描述符*/
  43. UINT8C KeyRepDesc[] =
  44. {
  45.     0x05,0x01,0x09,0x06,0xA1,0x01,0x05,0x07,
  46.     0x19,0xe0,0x29,0xe7,0x15,0x00,0x25,0x01,
  47.     0x75,0x01,0x95,0x08,0x81,0x02,0x95,0x01,
  48.     0x75,0x08,0x81,0x01,0x95,0x03,0x75,0x01,
  49.     0x05,0x08,0x19,0x01,0x29,0x03,0x91,0x02,
  50.     0x95,0x05,0x75,0x01,0x91,0x01,0x95,0x06,
  51.     0x75,0x08,0x26,0xff,0x00,0x05,0x07,0x19,
  52.     0x00,0x29,0x91,0x81,0x00,0xC0
  53. };
  54. UINT8C MouseRepDesc[] =
  55. {
  56.     0x05,0x01,0x09,0x02,0xA1,0x01,0x09,0x01,
  57.     0xA1,0x00,0x05,0x09,0x19,0x01,0x29,0x03,
  58.     0x15,0x00,0x25,0x01,0x75,0x01,0x95,0x03,
  59.     0x81,0x02,0x75,0x05,0x95,0x01,0x81,0x01,
  60.     0x05,0x01,0x09,0x30,0x09,0x31,0x09,0x38,
  61.     0x15,0x81,0x25,0x7f,0x75,0x08,0x95,0x03,
  62.     0x81,0x06,0xC0,0xC0
  63. };
  64. /*配置描述符*/
  65. UINT8C CfgDesc[] =
  66. {
  67.     0x09,0x02,0x3b,0x00,0x02,0x01,0x00,0xA0,0x32,                    //配置描述符

  68.     0x09,0x04,0x00,0x00,0x01,0x03,0x01,0x01,0x00,                    //接口描述符,键盘
  69.     0x09,0x21,0x11,0x01,0x00,0x01,0x22,sizeof(KeyRepDesc)&0xFF,sizeof(KeyRepDesc)>>8,//HID类描述符
  70.     0x07,0x05,0x81,0x03,EP1_IN_SIZE,0x00,0x0a,                       //端点描述符

  71.     0x09,0x04,0x01,0x00,0x01,0x03,0x01,0x02,0x00,                    //接口描述符,鼠标
  72.     0x09,0x21,0x10,0x01,0x00,0x01,0x22,sizeof(MouseRepDesc)&0xFF,sizeof(MouseRepDesc)>>8,//HID类描述符
  73.     0x07,0x05,0x82,0x03,EP2_IN_SIZE,0x00,0x0a                        //端点描述符
  74. };
  75. /*键盘数据*/
  76. UINT8 HIDKey[EP1_IN_SIZE];
  77. /*鼠标数据*/
  78. UINT8 HIDMouse[EP2_IN_SIZE];
  79. UINT8 Endp1Busy = 0;                                                 //传输完成控制标志位
  80. UINT8 Endp2Busy = 0;
  81. UINT8 WakeUpEnFlag = 0;                                              //远程唤醒使能标志
  82. /*******************************************************************************
  83. * Function Name  : CH554USBDevWakeup()
  84. * Description    : CH554设备模式唤醒主机,发送K信号
  85. * Input          : None
  86. * Output         : None
  87. * Return         : None
  88. *******************************************************************************/
  89. void CH554USBDevWakeup( )
  90. {
  91. #ifdef Fullspeed
  92.     UDEV_CTRL |= bUD_LOW_SPEED;
  93.     mDelaymS(2);
  94.     UDEV_CTRL &= ~bUD_LOW_SPEED;
  95. #else
  96.     UDEV_CTRL &= ~bUD_LOW_SPEED;
  97.     mDelaymS(2);
  98.     UDEV_CTRL |= bUD_LOW_SPEED;
  99. #endif
  100. }
  101. /*******************************************************************************
  102. * Function Name  : USBDeviceInit()
  103. * Description    : USB设备模式配置,设备模式启动,收发端点配置,中断开启
  104. * Input          : None
  105. * Output         : None
  106. * Return         : None
  107. *******************************************************************************/
  108. void USBDeviceInit()
  109. {
  110.     IE_USB = 0;
  111.     USB_CTRL = 0x00;                                                           // 先设定USB设备模式
  112.     UDEV_CTRL = bUD_PD_DIS;                                                    // 禁止DP/DM下拉电阻
  113. #ifndef Fullspeed
  114.     UDEV_CTRL |= bUD_LOW_SPEED;                                                //选择低速1.5M模式
  115.     USB_CTRL |= bUC_LOW_SPEED;
  116. #else
  117.     UDEV_CTRL &= ~bUD_LOW_SPEED;                                               //选择全速12M模式,默认方式
  118.     USB_CTRL &= ~bUC_LOW_SPEED;
  119. #endif
  120.     UEP1_T_LEN = 0;                                                            //预使用发送长度一定要清空
  121.     UEP2_T_LEN = 0;                                                            //预使用发送长度一定要清空
  122.     UEP2_DMA = Ep2Buffer;                                                      //端点2数据传输地址
  123.     UEP2_3_MOD = UEP2_3_MOD & ~bUEP2_BUF_MOD | bUEP2_TX_EN;                    //端点2发送使能 64字节缓冲区
  124.     UEP2_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK;                                 //端点2自动翻转同步标志位,IN事务返回NAK
  125.     UEP0_DMA = Ep0Buffer;                                                      //端点0数据传输地址
  126.     UEP4_1_MOD &= ~(bUEP4_RX_EN | bUEP4_TX_EN);                                //端点0单64字节收发缓冲区
  127.     UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;                                 //OUT事务返回ACK,IN事务返回NAK
  128.     UEP1_DMA = Ep1Buffer;                                                      //端点1数据传输地址
  129.     UEP4_1_MOD = UEP4_1_MOD & ~bUEP1_BUF_MOD | bUEP1_TX_EN;                    //端点1发送使能 64字节缓冲区
  130.     UEP1_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK;                                 //端点1自动翻转同步标志位,IN事务返回NAK
  131.     USB_DEV_AD = 0x00;
  132.     USB_CTRL |= bUC_DEV_PU_EN | bUC_INT_BUSY | bUC_DMA_EN;                     // 启动USB设备及DMA,在中断期间中断标志未清除前自动返回NAK
  133.     UDEV_CTRL |= bUD_PORT_EN;                                                  // 允许USB端口
  134.     USB_INT_FG = 0xFF;                                                         // 清中断标志
  135.     USB_INT_EN = bUIE_SUSPEND | bUIE_TRANSFER | bUIE_BUS_RST;
  136.     IE_USB = 1;
  137. }
  138. /*******************************************************************************
  139. * Function Name  : Enp1IntIn
  140. * Description    : USB设备模式端点1的中断上传
  141. * Input          : None
  142. * Output         : None
  143. * Return         : None
  144. *******************************************************************************/
  145. void Enp1IntIn( UINT8 *buf,UINT8 len )
  146. {
  147.     memcpy( Ep1Buffer, buf, len );                                            //加载上传数据
  148.     UEP1_T_LEN = len;                                                         //上传数据长度
  149.     UEP1_CTRL = UEP1_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK;                 //有数据时上传数据并应答ACK
  150. }
  151. /*******************************************************************************
  152. * Function Name  : Enp2IntIn()
  153. * Description    : USB设备模式端点2的中断上传
  154. * Input          : None
  155. * Output         : None
  156. * Return         : None
  157. *******************************************************************************/
  158. void Enp2IntIn( UINT8 *buf,UINT8 len )
  159. {
  160.     memcpy( Ep2Buffer, buf, len);                                              //加载上传数据
  161.     UEP2_T_LEN = len;                                                          //上传数据长度
  162.     UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_ACK;                  //有数据时上传数据并应答ACK
  163. }
  164. /*******************************************************************************
  165. * Function Name  : DeviceInterrupt()
  166. * Description    : CH559USB中断处理函数
  167. *******************************************************************************/
  168. void    DeviceInterrupt( void ) interrupt INT_NO_USB using 1                    //USB中断服务程序,使用寄存器组1
  169. {
  170.     UINT16 len = 0;
  171.     if(UIF_TRANSFER)                                                            //USB传输完成标志
  172.     {
  173.         switch (USB_INT_ST & (MASK_UIS_TOKEN | MASK_UIS_ENDP))
  174.         {
  175.         case UIS_TOKEN_IN | 2:                                                  //endpoint 2# 中断端点上传
  176.             UEP2_T_LEN = 0;                                                     //预使用发送长度一定要清空
  177. //            UEP1_CTRL ^= bUEP_T_TOG;                                          //如果不设置自动翻转则需要手动翻转
  178.             Endp2Busy = 0;
  179.             UEP2_CTRL = UEP2_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK;           //默认应答NAK
  180.             break;
  181.         case UIS_TOKEN_IN | 1:                                                  //endpoint 1# 中断端点上传
  182.             UEP1_T_LEN = 0;                                                     //预使用发送长度一定要清空
  183. //            UEP2_CTRL ^= bUEP_T_TOG;                                          //如果不设置自动翻转则需要手动翻转
  184.             Endp1Busy = 0;
  185.             UEP1_CTRL = UEP1_CTRL & ~ MASK_UEP_T_RES | UEP_T_RES_NAK;           //默认应答NAK
  186.             break;
  187.         case UIS_TOKEN_SETUP | 0:                                               //SETUP事务
  188.             UEP0_CTRL = UEP0_CTRL & (~MASK_UEP_T_RES )| UEP_T_RES_NAK;          //预置NAK,防止stall之后不及时清除响应方式
  189.             len = USB_RX_LEN;
  190.             if(len == (sizeof(USB_SETUP_REQ)))
  191.             {
  192.                 SetupLen = ((UINT16)UsbSetupBuf->wLengthH<<8) + UsbSetupBuf->wLengthL;
  193.                 len = 0;                                                        // 默认为成功并且上传0长度
  194.                 SetupReq = UsbSetupBuf->bRequest;
  195.                 if ( ( UsbSetupBuf->bRequestType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )/* HID类命令 */
  196.                 {
  197.                     switch( SetupReq )
  198.                     {
  199.                     case 0x01://GetReport
  200.                         break;
  201.                     case 0x02://GetIdle
  202.                         break;
  203.                     case 0x03://GetProtocol
  204.                         break;
  205.                     case 0x09://SetReport
  206.                         break;
  207.                     case 0x0A://SetIdle
  208.                         break;
  209.                     case 0x0B://SetProtocol
  210.                         break;
  211.                     default:
  212.                         len = 0xFFFF;                                  /*命令不支持*/
  213.                         break;
  214.                     }
  215.                 }
  216.                 else
  217.                 {
  218.                     //标准请求
  219.                     switch(SetupReq)                                        //请求码
  220.                     {
  221.                     case USB_GET_DESCRIPTOR:
  222.                         switch(UsbSetupBuf->wValueH)
  223.                         {
  224.                         case 1:                                             //设备描述符
  225.                             pDescr = DevDesc;                               //把设备描述符送到要发送的缓冲区
  226.                             len = sizeof(DevDesc);
  227.                             break;
  228.                         case 2:                                             //配置描述符
  229.                             pDescr = CfgDesc;                               //把设备描述符送到要发送的缓冲区
  230.                             len = sizeof(CfgDesc);
  231.                             break;
  232.                         case 3:
  233.                             switch( UsbSetupBuf->wValueL )
  234.                             {
  235.                             case 1:
  236.                                 pDescr = (PUINT8)( &MyManuInfo[0] );
  237.                                 len = sizeof( MyManuInfo );
  238.                                 break;
  239.                             case 2:
  240.                                 pDescr = (PUINT8)( &MyProdInfo[0] );
  241.                                 len = sizeof( MyProdInfo );
  242.                                 break;
  243.                             case 0:
  244.                                 pDescr = (PUINT8)( &MyLangDescr[0] );
  245.                                 len = sizeof( MyLangDescr );
  246.                                 break;
  247.                             default:
  248.                                 len = 0xFFFF;                           // 不支持的字符串描述符
  249.                                 break;
  250.                             }
  251.                             break;
  252.                         case 0x22:                                          //报表描述符
  253.                             if(UsbSetupBuf->wIndexL == 0)                   //接口0报表描述符
  254.                             {
  255.                                 pDescr = KeyRepDesc;                        //数据准备上传
  256.                                 len = sizeof(KeyRepDesc);
  257.                             }
  258.                             else if(UsbSetupBuf->wIndexL == 1)              //接口1报表描述符
  259.                             {
  260.                                 pDescr = MouseRepDesc;                      //数据准备上传
  261.                                 len = sizeof(MouseRepDesc);
  262.                             }
  263.                             else
  264.                             {
  265.                                 len = 0xFFFF;                                 //本程序只有2个接口,这句话正常不可能执行
  266.                             }
  267.                             break;
  268.                         default:
  269.                             len = 0xFFFF;                                     //不支持的命令或者出错
  270.                             break;
  271.                         }
  272.                         if ( SetupLen > len )
  273.                         {
  274.                             SetupLen = len;    //限制总长度
  275.                         }
  276.                         len = SetupLen >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE : SetupLen; //本次传输长度
  277.                         memcpy(Ep0Buffer,pDescr,len);                        //加载上传数据
  278.                         SetupLen -= len;
  279.                         pDescr += len;
  280.                         break;
  281.                     case USB_SET_ADDRESS:
  282.                         SetupLen = UsbSetupBuf->wValueL;                     //暂存USB设备地址
  283.                         break;
  284.                     case USB_GET_CONFIGURATION:
  285.                         Ep0Buffer[0] = UsbConfig;
  286.                         if ( SetupLen >= 1 )
  287.                         {
  288.                             len = 1;
  289.                         }
  290.                         break;
  291.                     case USB_SET_CONFIGURATION:
  292.                         UsbConfig = UsbSetupBuf->wValueL;
  293.                         if(UsbConfig)
  294.                         {
  295. #ifdef DE_PRINTF
  296.                             printf("SET CONFIG.\n");
  297. #endif
  298.                             Ready = 1;                                                   //set config命令一般代表usb枚举完成的标志
  299.                         }
  300.                         break;
  301.                     case 0x0A:
  302.                         break;
  303.                     case USB_CLEAR_FEATURE:                                              //Clear Feature
  304.                         if ( ( UsbSetupBuf->bRequestType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )// 端点
  305.                         {
  306.                             switch( UsbSetupBuf->wIndexL )
  307.                             {
  308.                             case 0x82:
  309.                                 UEP2_CTRL = UEP2_CTRL & ~ ( bUEP_T_TOG | MASK_UEP_T_RES ) | UEP_T_RES_NAK;
  310.                                 break;
  311.                             case 0x81:
  312.                                 UEP1_CTRL = UEP1_CTRL & ~ ( bUEP_T_TOG | MASK_UEP_T_RES ) | UEP_T_RES_NAK;
  313.                                 break;
  314.                             case 0x01:
  315.                                 UEP1_CTRL = UEP1_CTRL & ~ ( bUEP_R_TOG | MASK_UEP_R_RES ) | UEP_R_RES_ACK;
  316.                                 break;
  317.                             default:
  318.                                 len = 0xFFFF;                                            // 不支持的端点
  319.                                 break;
  320.                             }
  321.                         }
  322.                         if ( ( UsbSetupBuf->bRequestType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_DEVICE )// 设备
  323.                         {
  324.                             WakeUpEnFlag = 0;
  325.                             printf("Wake up\n");
  326.                             break;
  327.                         }
  328.                         else
  329.                         {
  330.                             len = 0xFFFF;                                                // 不是端点不支持
  331.                         }
  332.                         break;
  333.                     case USB_SET_FEATURE:                                               /* Set Feature */
  334.                         if( ( UsbSetupBuf->bRequestType & 0x1F ) == 0x00 )              /* 设置设备 */
  335.                         {
  336.                             if( ( ( ( UINT16 )UsbSetupBuf->wValueH << 8 ) | UsbSetupBuf->wValueL ) == 0x01 )
  337.                             {
  338.                                 if( CfgDesc[ 7 ] & 0x20 )
  339.                                 {
  340.                                     WakeUpEnFlag = 1;                                   /* 设置唤醒使能标志 */
  341.                                     printf("Enable Remote Wakeup.\n");
  342.                                 }
  343.                                 else
  344.                                 {
  345.                                     len = 0xFFFF;                                        /* 操作失败 */
  346.                                 }
  347.                             }
  348.                             else
  349.                             {
  350.                                 len = 0xFFFF;                                            /* 操作失败 */
  351.                             }
  352.                         }
  353.                         else if( ( UsbSetupBuf->bRequestType & 0x1F ) == 0x02 )        /* 设置端点 */
  354.                         {
  355.                             if( ( ( ( UINT16 )UsbSetupBuf->wValueH << 8 ) | UsbSetupBuf->wValueL ) == 0x00 )
  356.                             {
  357.                                 switch( ( ( UINT16 )UsbSetupBuf->wIndexH << 8 ) | UsbSetupBuf->wIndexL )
  358.                                 {
  359.                                 case 0x82:
  360.                                     UEP2_CTRL = UEP2_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* 设置端点2 IN STALL */
  361.                                     break;
  362.                                 case 0x02:
  363.                                     UEP2_CTRL = UEP2_CTRL & (~bUEP_R_TOG) | UEP_R_RES_STALL;/* 设置端点2 OUT Stall */
  364.                                     break;
  365.                                 case 0x81:
  366.                                     UEP1_CTRL = UEP1_CTRL & (~bUEP_T_TOG) | UEP_T_RES_STALL;/* 设置端点1 IN STALL */
  367.                                     break;
  368.                                 default:
  369.                                     len = 0xFFFF;                               //操作失败
  370.                                     break;
  371.                                 }
  372.                             }
  373.                             else
  374.                             {
  375.                                 len = 0xFFFF;                                   //操作失败
  376.                             }
  377.                         }
  378.                         else
  379.                         {
  380.                             len = 0xFFFF;                                      //操作失败
  381.                         }
  382.                         break;
  383.                     case USB_GET_STATUS:
  384.                         Ep0Buffer[0] = 0x00;
  385.                         Ep0Buffer[1] = 0x00;
  386.                         if ( SetupLen >= 2 )
  387.                         {
  388.                             len = 2;
  389.                         }
  390.                         else
  391.                         {
  392.                             len = SetupLen;
  393.                         }
  394.                         break;
  395.                     default:
  396.                         len = 0xFFFF;                                           //操作失败
  397.                         break;
  398.                     }
  399.                 }
  400.             }
  401.             else
  402.             {
  403.                 len = 0xFFFF;                                                   //包长度错误
  404.             }
  405.             if(len == 0xFFFF)
  406.             {
  407.                 SetupReq = 0xFF;
  408.                 UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL;//STALL
  409.             }
  410.             else if(len)                                                //上传数据或者状态阶段返回0长度包
  411.             {
  412.                 UEP0_T_LEN = len;
  413.                 UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;//默认数据包是DATA1,返回应答ACK
  414.             }
  415.             else
  416.             {
  417.                 UEP0_T_LEN = 0;  //虽然尚未到状态阶段,但是提前预置上传0长度数据包以防主机提前进入状态阶段
  418.                 UEP0_CTRL = bUEP_R_TOG | bUEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;//默认数据包是DATA1,返回应答ACK
  419.             }
  420.             break;
  421.         case UIS_TOKEN_IN | 0:                                               //endpoint0 IN
  422.             switch(SetupReq)
  423.             {
  424.             case USB_GET_DESCRIPTOR:
  425.                 len = SetupLen >= THIS_ENDP0_SIZE ? THIS_ENDP0_SIZE : SetupLen;    //本次传输长度
  426.                 memcpy( Ep0Buffer, pDescr, len );                            //加载上传数据
  427.                 SetupLen -= len;
  428.                 pDescr += len;
  429.                 UEP0_T_LEN = len;
  430.                 UEP0_CTRL ^= bUEP_T_TOG;                                     //同步标志位翻转
  431.                 break;
  432.             case USB_SET_ADDRESS:
  433.                 USB_DEV_AD = USB_DEV_AD & bUDA_GP_BIT | SetupLen;
  434.                 UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
  435.                 break;
  436.             default:
  437.                 UEP0_T_LEN = 0;                                              //状态阶段完成中断或者是强制上传0长度数据包结束控制传输
  438.                 UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
  439.                 break;
  440.             }
  441.             break;
  442.         case UIS_TOKEN_OUT | 0:  // endpoint0 OUT
  443.             len = USB_RX_LEN;
  444.             if(SetupReq == 0x09)
  445.             {
  446.                 if(Ep0Buffer[0])
  447.                 {
  448.                     printf("Light on Num Lock LED!\n");
  449.                 }
  450.                 else if(Ep0Buffer[0] == 0)
  451.                 {
  452.                     printf("Light off Num Lock LED!\n");
  453.                 }
  454.             }
  455.             UEP0_CTRL ^= bUEP_R_TOG;                                      //同步标志位翻转
  456.             break;
  457.         default:
  458.             break;
  459.         }
  460.         UIF_TRANSFER = 0;                                                 //写0清空中断
  461.     }
  462.     else if(UIF_BUS_RST)                                                  //设备模式USB总线复位中断
  463.     {
  464.         UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
  465.         UEP1_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK;
  466.         UEP2_CTRL = bUEP_AUTO_TOG | UEP_T_RES_NAK;
  467.         USB_DEV_AD = 0x00;
  468.         UIF_SUSPEND = 0;
  469.         UIF_TRANSFER = 0;
  470.         Ready = 0;
  471.         UIF_BUS_RST = 0;                                                 //清中断标志
  472.     }
  473.     else if (UIF_SUSPEND)                                                           //USB总线挂起/唤醒完成
  474.     {
  475.         UIF_SUSPEND = 0;
  476.         if ( USB_MIS_ST & bUMS_SUSPEND )                                            //挂起
  477.         {
  478. #ifdef DE_PRINTF
  479.             printf( "z" );                                                          //睡眠状态
  480. #endif
  481. //             while ( XBUS_AUX & bUART0_TX )
  482. //             {
  483. //                 ;    //等待发送完成
  484. //             }
  485. //             SAFE_MOD = 0x55;
  486. //             SAFE_MOD = 0xAA;
  487. //             WAKE_CTRL = bWAK_BY_USB | bWAK_RXD0_LO;                              //USB或者RXD0有信号时可被唤醒
  488. //             PCON |= PD;                                                          //睡眠
  489. //             SAFE_MOD = 0x55;
  490. //             SAFE_MOD = 0xAA;
  491. //             WAKE_CTRL = 0x00;
  492.         }
  493.         else                                                                        // 唤醒
  494.         {
  495. #ifdef DE_PRINTF
  496.             printf( "w" );
  497. #endif
  498.         }
  499.     }
  500.     else {                                                                          //意外的中断,不可能发生的情况
  501.         USB_INT_FG = 0xFF;                                                          //清中断标志
  502. #ifdef DE_PRINTF
  503.         printf("UnknownInt  \n");
  504. #endif
  505.     }
  506. }
  507. void HIDValueHandle()
  508. {
  509.     UINT8 i;
  510.     i = getkey( );
  511.     printf( "%c", (UINT8)i );
  512.     if( WakeUpEnFlag )                                                   //主机已休眠
  513.     {
  514.         CH554USBDevWakeup();                                             //唤醒主机
  515.     }
  516.     else
  517.     {
  518.         switch(i)
  519.         {
  520. //鼠标数据上传示例
  521.         case 'L':                                                        //左键
  522.             HIDMouse[0] = 0x01;
  523.             while( Endp2Busy )
  524.             {
  525.                 ;    //如果忙(上一包数据没有传上去),则等待。
  526.             }
  527.             Endp2Busy = 1;                                               //设置为忙状态
  528.             Enp2IntIn(HIDMouse,sizeof(HIDMouse));
  529.             HIDMouse[0] = 0;                                             //抬起
  530.             while( Endp2Busy )
  531.             {
  532.                 ;    //如果忙(上一包数据没有传上去),则等待。
  533.             }
  534.             Endp2Busy = 1;                                               //设置为忙状态
  535.             Enp2IntIn(HIDMouse,sizeof(HIDMouse));
  536.             break;
  537.         case 'R':                                                        //右键
  538.             HIDMouse[0] = 0x02;
  539.             while( Endp2Busy )
  540.             {
  541.                 ;    //如果忙(上一包数据没有传上去),则等待。
  542.             }
  543.             Endp2Busy = 1;                                               //设置为忙状态
  544.             Enp2IntIn(HIDMouse,sizeof(HIDMouse));
  545.             HIDMouse[0] = 0;                                             //抬起
  546.             while( Endp2Busy )
  547.             {
  548.                 ;    //如果忙(上一包数据没有传上去),则等待。
  549.             }
  550.             Endp2Busy = 1;                                               //设置为忙状态
  551.             Enp2IntIn(HIDMouse,sizeof(HIDMouse));
  552.             break;
  553. //键盘数据上传示例
  554.         case 'A':                                                         //A键
  555.             HIDKey[2] = 0x04;                                             //按键开始
  556.             while( Endp1Busy )
  557.             {
  558.                 ;    //如果忙(上一包数据没有传上去),则等待。
  559.             }
  560.             Endp1Busy = 1;                                               //设置为忙状态
  561.             Enp1IntIn(HIDKey,sizeof(HIDKey));
  562.             HIDKey[2] = 0;                                                //按键结束
  563.             while( Endp1Busy )
  564.             {
  565.                 ;    //如果忙(上一包数据没有传上去),则等待。
  566.             }
  567.             Endp1Busy = 1;                                               //设置为忙状态
  568.             Enp1IntIn(HIDKey,sizeof(HIDKey));
  569.             break;
  570.         case 'Q':                                                         //CAP键
  571.             HIDKey[2] = 0x39;
  572.             while( Endp1Busy )
  573.             {
  574.                 ;    //如果忙(上一包数据没有传上去),则等待。
  575.             }
  576.             Endp1Busy = 1;                                               //设置为忙状态
  577.             Enp1IntIn(HIDKey,sizeof(HIDKey));
  578.             HIDKey[2] = 0;                                                //按键结束
  579.             while( Endp1Busy )
  580.             {
  581.                 ;    //如果忙(上一包数据没有传上去),则等待。
  582.             }
  583.             Endp1Busy = 1;                                               //设置为忙状态
  584.             Enp1IntIn(HIDKey,sizeof(HIDKey));
  585.             break;
  586.         default:                                                          //其他
  587.             break;
  588.         }
  589.     }
  590. }
  591. void main()
  592. {
  593.     CfgFsys( );                                                           //CH549时钟选择配置
  594.     mDelaymS(20);                                                         //修改主频等待内部晶振稳定,必加
  595.     mInitSTDIO( );                                                        //串口0初始化
  596.     printf("KM Device start ...\n");
  597.     USBDeviceInit();                                                      //USB设备模式初始化
  598.     EA = 1;                                                               //允许单片机中断
  599.     memset(HIDKey,0,sizeof(HIDKey));                                      //清空缓冲区
  600.     memset(HIDMouse,0,sizeof(HIDMouse));
  601.     while(1)
  602.     {
  603.         if(Ready)
  604.         {
  605.             HIDValueHandle();                                             //串口0,程序会停在getkey函数等待接收一个字符
  606.         }
  607.     }
  608. }


复制代码

CompositeKM.docx (24.24 KB, 下载次数: 41)


null1dd06be447654b10.jpg (36.37 KB, 下载次数: 131)

null1dd06be447654b10.jpg

null-2e9e8452d6d2fded.jpg (176.75 KB, 下载次数: 150)

null-2e9e8452d6d2fded.jpg

评分

参与人数 1黑币 +100 收起 理由
admin + 100 共享资料的黑币奖励!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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