查看: 2819|回复: 2
收起左侧

第八十三章:CH32V103应用教程——USB模拟鼠标键盘设备

[复制链接]

  离线 

  • TA的每日心情
    慵懒
    2021-7-23 17:16
  • 签到天数: 17 天

    [LV.4]

    发表于 2021-5-1 16:18:01 | 显示全部楼层 |阅读模式

    有人预言,RISC-V或将是继Intel和Arm之后的第三大主流处理器体系。欢迎访问全球首家只专注于RISC-V单片机行业应用的中文网站

    您需要 登录 才可以下载或查看,没有帐号?立即注册

    x
    本帖最后由 草帽王子 于 2021-9-10 18:20 编辑

    本章教程主要使用CH32V103 USB模拟鼠标键盘设备。


    1、USB简介及相关函数介绍

    关于USB具体介绍,可参考前面章节。


    2、硬件设计

    本章教程主要进行USB模拟鼠标键盘实验,仅需用到开发板USB口。


    3、软件设计

    本章程序全在主函数中进行,具体程序如下:
    main.c文件
    1. /********************************** (C) COPYRIGHT *******************************
    2. * File Name          : main.c
    3. * Author             : WCH
    4. * Version            : V1.0.0
    5. * Date               : 2019/10/15
    6. * Description        : Main program body.
    7. *******************************************************************************/
    8. #include "debug.h"
    9. #include "usart.h"
    10. #include "string.h"

    11. #define   DevEP0SIZE   0x40

    12. /* Device Descriptor */
    13. const UINT8  MyDevDescr[] =
    14. {
    15.         0x12,              //设备描述符长度,18字节
    16.         0x01,              //描述符类型,0x01为设备描述符
    17.         0x10, 0x01,        //本设备所使用USB版本协议,因为是小端结构,所以低字节在前,即USB1.1版本为0x10,0x01,USB2.0为0x00,0x02
    18.         0x00,              //类代码,此处不在设备描述符中定义设备类,而在接口描述符中定义设备类。对于大多数标准的USB设备类,该字段通常设置为0,而在接口描述符中的bInterfaceClass中指定接口所实现的功能
    19.         0x00,              //子类代码,当类代码bDeviceClass为0时,下面的子类代码bDeviceSubClass也必须为0。
    20.         0x00,              //设备所使用的协议,协议代码由USB协会规定。当该字段为0时,表示设备不使用类所定义的协议。
    21.         DevEP0SIZE,        //端点0的最大包长,可以取值8、16、32、64,此处为64字节
    22.         0x86, 0x1A,        //厂商ID
    23.         0xe1, 0xe6,        //产品设备ID
    24.         0x00, 0x01,        //设备版本号
    25.         0x01,              //描述厂商的字符串索引值。当该值为0时,表示没有厂商字符串
    26.         0x02,              //描述产品的字符串索引值。当该值为0时,表示没有产品字符串
    27.         0x03,              //描述设备的序列号字符串索引值。当该值为0时,表示没有序列号字符串
    28.         0x01,              //可能的配置数,通常为1
    29. };

    30. const UINT8 KeyRepDesc[] =
    31. {
    32.         0x05, 0x01,         // Usage page Generatic Desktop
    33.         0x09, 0x06,         // Usage keyboard
    34.         0xa1, 0x01,         // Collation Application
    35.         0x05, 0x07,         // Usafe page (key code)
    36.         0x19, 0xe0,         // Usage Min ( E0 -->  L_CTL)
    37.         0x29, 0xe7,         // Usage MAX ( E7 --> R_GUI )
    38.         0x15, 0x00,         // Logical min
    39.         0x25, 0x01,         // Logical max
    40.         0x95, 0x08,         // Report count ( 8 )
    41.         0x75, 0x01,         // Report size  ( 1 )
    42.         0x81, 0x02,         // Input ( Data, Variable, Absolute )
    43.         0x95, 0x08,         // Report count ( 8 )
    44.         0x75, 0x01,         // Report size  ( 1 )
    45.         0x81, 0x01,         // Input ( const )
    46.         0x05, 0x08,         // Usage page( LED )
    47.         0x19, 0x01,         // Usage min ( 1 )
    48.         0x29, 0x03,         // Usage max ( 3 )
    49.         0x95, 0x03,         // Report count ( 3 )
    50.         0x75, 0x01,         // Report size ( 1 )
    51.         0x91, 0x02,         // Output ( Data, Variable, Absolute )
    52.         0x95, 0x01,         // Report count ( 1 )
    53.         0x75, 0x05,         // Report size ( 5 )
    54.         0x91, 0x01,         // Output ( const )
    55.         0x05, 0x07,         // Usage page ( key code )
    56.         0x19, 0x00,         // Usage min ( 0H )
    57.         0x2a, 0xff, 0x00,   // Usage max ( FFH )
    58.         0x15, 0x00,         // Logical min ( 0H )
    59.         0x26, 0xff, 0x00,   // Logical max ( FFH )
    60.         0x95, 0x06,         // Report count ( 6 )
    61.         0x75, 0x08,         // Report size ( 8 )
    62.         0x81, 0x00,         // Input ( Data, Array, Absolute )
    63.         0xc0                // End collection
    64. };

    65. const UINT8  MouseRepDesc[]=
    66. {
    67.         0x05,0x01,
    68.         0x09,0x02,
    69.         0xA1,0x01,
    70.         0x09,0x01,
    71.         0xA1,0x00,
    72.         0x05,0x09,
    73.         0x19,0x01,
    74.         0x29,0x03,
    75.         0x15,0x00,
    76.         0x25,0x01,
    77.         0x95,0x03,
    78.         0x75,0x01,
    79.         0x81,0x02,
    80.         0x95,0x01,
    81.         0x75,0x05,
    82.         0x81,0x03,
    83.         0x05,0x01,
    84.         0x09,0x30,
    85.         0x09,0x31,
    86.         0x09,0x38,
    87.         0x15,0x81,
    88.         0x25,0x7f,
    89.         0x75,0x08,
    90.         0x95,0x03,
    91.         0x81,0x06,
    92.         0xC0,
    93.         0xC0
    94. };

    95. /* Configration Descriptor */
    96. const UINT8  MyCfgDescr[] =
    97. {
    98.         //配置描述符
    99.         0x09,              //配置描述符长度,标准USB配置描述符长度为9字节
    100.         0x02,              //描述符类型,配置描述符为0x02
    101.         0x3b, 0x00,        //配置描述符集合总长度,59字节
    102.         0x02,              //该配置所支持的接口数,2个接口
    103.         0x01,              //表示该配置的值
    104.         0x00,              //描述该配置的字符串的索引值,0x00表示没有字符串
    105.         0xA0,              //描述设备的一些属性,如供电方式和唤醒等,0xA0表示设备总线供电且支持远程唤醒
    106.         0x32,              //设备需要从总线获取的最大电流量,0x32表示最大电流100ma

    107.         //键盘
    108.         //接口描述符,接口描述符不能单独返回,必须附着在配置描述符后一并返回
    109.         0x09,              //接口描述符长度,标准的USB接口描述符长度为9字节
    110.         0x04,              //描述符类型,接口描述符为0x04
    111.         0x00,              //该接口的编号,从0开始,此处为0x00
    112.         0x00,              //该接口的备用编号,通常设置为0
    113.         0x01,              //该接口所使用的端点数,0x01表示使用1个端点。如果该字段为0,则表示没有非0端点,只使用默认的控制端点
    114.         0x03,              //该接口所使用的类,0x03为HID类
    115.         0x01,              //该接口所使用的子类
    116.         0x01,              //该接口所使用的协议
    117.         0x00,              //该接口的字符串的索引值,0x00表示没有字符串

    118.         //HID类描述符,它是一个类描述符,应该跟在接口描述符后面
    119.         0x09,              //该描述符长度,它的大小与该描述符中下级描述符的个数有关。例如只有一个下级描述符时,总长度为9
    120.         0x21,              //描述符类型,HID描述符为0x21
    121.         0x10,0x01,         //HID协议的版本号,这里参看的HID协议是USB HID1.1协议,因此这里为0x0110
    122.         0x00,              //国家代码,是设备所适用的国家。通常我们的键盘是美式键盘,代码为33,即0x21,但此处设置为0x00
    123.         0x01,              //下级描述符的数量,该值至少为1,即至少要有一个报告描述符。下级描述符可以是报告描述符或物理描述符
    124.         0x22,              //下级描述符的类型,报告描述符的编号为0x22,物理描述符编号为0x23
    125.         sizeof(KeyRepDesc)&0xFF, 0x00, //下级描述符的长度

    126.         //端点描述符,端点描述符不能单独返回,必须附着在配置描述符后一并返回
    127.         0x07,              //端点描述符长度,标准的USB端点描述符长度为7字节
    128.         0x05,              //描述符类型,端点描述符为0x05
    129.         0x81,              //该端点的地址,0x81表示端点1作为输入,最高位D7为该端点的传输方向,1为输入,0为输出。D3-D0为端点号,可设置为0-7,D6-4保留,设为0.
    130.         //关于端点属性,最低两位D1-0表示该端点的传输类型,0为控制传输,1为等时传输,2为批量传输,3为中断传输。
    131.         0x03,              //该端点的属性,此处为中断传输方式
    132.         DevEP0SIZE, 0x00,  //该端点支持的最大包长度,此处设置为64字节
    133.         0x0a,              //端点的查询时间。对于中断端点,表示查询的帧间隔数

    134.         //鼠标
    135.         //接口描述符
    136.         0x09,              //接口描述符长度,9字节
    137.         0x04,              //描述符类型,接口描述符为0x04
    138.         0x01,              //该接口的编号,从0开始,此处为0x01
    139.         0x00,              //该接口的备用编号
    140.         0x01,              //该接口所使用的端点数,0x01表示使用1个端点
    141.         0x03,              //该接口所使用的类,0x03为HID类
    142.         0x01,              //该接口所使用的子类
    143.         0x02,              //该接口所使用的协议
    144.         0x00,              //该接口的字符串的索引值,0x00表示没有字符串

    145.         //HID类描述符
    146.         0x09,              //该描述符长度,它的大小与该描述符中下级描述符的个数有关。例如只有一个下级描述符时,总长度为9
    147.         0x21,              //描述符类型,HID描述符为0x21
    148.         0x10,0x01,         //HID协议的版本号,这里参看的HID协议是USB HID1.1协议,因此这里为0x0110
    149.         0x00,              //国家代码,是设备所适用的国家。通常我们的键盘是美式键盘,代码为33,即0x21,但此处设置为0x00
    150.         0x01,              //下级描述符的数量,该值至少为1,即至少要有一个报告描述符。下级描述符可以是报告描述符或物理描述符
    151.         0x22,              //下级描述符的类型,报告描述符的编号为0x22,物理描述符编号为0x23
    152.         sizeof(MouseRepDesc)&0xFF,0x00,  //下级描述符的长度

    153.         //端点描述符
    154.         0x07,              //端点描述符长度,7字节
    155.         0x05,              //描述符类型,端点描述符为0x05
    156.         0x82,              //该端点的地址,0x82表示端点2作为输入
    157.         0x03,              //该端点的属性
    158.         DevEP0SIZE, 0x00,  //该端点支持的最大包长度,64字节
    159.         0x0a,              //端点的查询时间
    160. };

    161. const UINT8  MyProductIDInfo[] = {0x0E,0x03,'K',0,'&',0,'M',0,'1',0,'0',0,'3',0};

    162. /* Language Descriptor */
    163. const UINT8  MyLangDescr[] = { 0x04, 0x03, 0x09, 0x04 };

    164. /* Manufactor Descriptor */
    165. const UINT8  MyManuInfo[] = { 0x0E, 0x03, 'w', 0, 'c', 0, 'h', 0, '.', 0, 'c', 0, 'n', 0 };

    166. /* Product Information */
    167. const UINT8  MyProdInfo[] = { 0x0C, 0x03, 'C', 0, 'H', 0, '5', 0, '5', 0, '9', 0 };

    168. /**********************************************************/
    169. volatile UINT8   Ready = 0;
    170. volatile UINT8   Endp1Busy = 0;  //传输完成控制标志位
    171. volatile UINT8   Endp2Busy = 0;
    172. UINT8   DevConfig;
    173. UINT8   SetupReqCode;
    174. UINT16  SetupReqLen;
    175. UINT8   HIDKey[8];
    176. UINT8   HIDMouse[4];
    177. const   UINT8 *pDescr;

    178. /* Endpoint Buffer */
    179. __attribute__ ((aligned(4))) UINT8 EP0_Databuf[64];     //ep0(64)
    180. __attribute__ ((aligned(4))) UINT8 EP1_Databuf[64+64];  //ep1_out(64)+ep1_in(64)
    181. __attribute__ ((aligned(4))) UINT8 EP2_Databuf[64+64];  //ep2_out(64)+ep2_in(64)

    182. void USBHD_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));

    183. /*******************************************************************************
    184. * Function Name  : USB_DevTransProcess
    185. * Description    : USB device transfer process.
    186. * Input          : None
    187. * Return         : None
    188. *******************************************************************************/
    189. void USB_DevTransProcess( void )
    190. {
    191.     UINT8  len, chtype;
    192.     UINT8  intflag, errflag = 0;

    193.     intflag = R8_USB_INT_FG;

    194.     if( intflag & RB_UIF_TRANSFER )
    195.     {
    196.         switch ( R8_USB_INT_ST & ( MASK_UIS_TOKEN | MASK_UIS_ENDP ) )
    197.         {
    198.             case UIS_TOKEN_SETUP:
    199.                 R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_NAK;
    200.                 len = R8_USB_RX_LEN;

    201.                 if ( len == sizeof( USB_SETUP_REQ ) )
    202.                 {
    203.                     SetupReqLen = pSetupReqPak->wLength;
    204.                     SetupReqCode = pSetupReqPak->bRequest;
    205.                     chtype = pSetupReqPak->bRequestType;

    206.                     len = 0;
    207.                     errflag = 0;

    208.                     if ( ( pSetupReqPak->bRequestType & USB_REQ_TYP_MASK ) != USB_REQ_TYP_STANDARD )
    209.                     {
    210.                         switch(SetupReqCode)
    211.                         {
    212.                             case 0x01:    //GetReport
    213.                                 len = 1;
    214.                                 pEP0_DataBuf[0] = 0xaa;
    215.                                 break;
    216.                             case 0x0a:
    217.                                 R8_UEP0_T_LEN = 0;
    218.                                 break;    //这个一定要有
    219.                             case 0x09:
    220.                                 Ready = 1;
    221.                                 break;
    222.                             default:
    223.                                 errflag = 0xFF;
    224.                         }
    225.                     }
    226.                     else
    227.                     {
    228.                         switch( SetupReqCode )
    229.                         {
    230.                             case USB_GET_DESCRIPTOR:
    231.                             {
    232.                                 switch( ((pSetupReqPak->wValue)>>8) )
    233.                                 {
    234.                                     case USB_DESCR_TYP_DEVICE:
    235.                                         pDescr = MyDevDescr;
    236.                                         len = MyDevDescr[0];
    237.                                         break;

    238.                                     case USB_DESCR_TYP_CONFIG:
    239.                                         pDescr = MyCfgDescr;
    240.                                         len = MyCfgDescr[2];
    241.                                         break;

    242.                                     case USB_DESCR_TYP_STRING:
    243.                                         switch( (pSetupReqPak->wValue)&0xff )
    244.                                         {
    245.                                             case 0:
    246.                                                 pDescr = MyLangDescr;
    247.                                                 len = MyLangDescr[0];
    248.                                                 break;

    249.                                             case 1:
    250.                                                 pDescr = MyManuInfo;
    251.                                                 len = MyManuInfo[0];
    252.                                                 break;

    253.                                             case 2:
    254.                                                 pDescr = MyProdInfo;
    255.                                                 len = MyProdInfo[0];
    256.                                                 break;

    257.                                             case 3:
    258.                                                 pDescr = MyProductIDInfo;
    259.                                                 len = MyProductIDInfo[0];
    260.                                                 break;

    261.                                             default:
    262.                                                 errflag = 0xFF;
    263.                                                 break;
    264.                                         }
    265.                                         break;

    266.                                     case USB_DESCR_TYP_REPORT:
    267.                                         if(((pSetupReqPak->wIndex)&0xff) == 0)          //接口0报表描述符
    268.                                         {
    269.                                             pDescr = KeyRepDesc;                        //数据准备上传
    270.                                             len = sizeof(KeyRepDesc);
    271.                                         }
    272.                                         else if(((pSetupReqPak->wIndex)&0xff) == 1)     //接口1报表描述符
    273.                                         {
    274.                                             pDescr = MouseRepDesc;                      //数据准备上传
    275.                                             len = sizeof(MouseRepDesc);
    276.                                             Ready = 1;                                  //如果有更多接口,该标准位应该在最后一个接口配置完成后有效
    277.                                         }
    278.                                         else len = 0xff;                                //本程序只有2个接口,这句话正常不可能执行
    279.                                         break;

    280.                                     default :
    281.                                         errflag = 0xff;
    282.                                         break;
    283.                                 }

    284.                                 if( SetupReqLen>len )   SetupReqLen = len;
    285.                                 len = (SetupReqLen >= DevEP0SIZE) ? DevEP0SIZE : SetupReqLen;
    286.                                 memcpy( pEP0_DataBuf, pDescr, len );
    287.                                 pDescr += len;
    288.                             }
    289.                                 break;

    290.                             case USB_SET_ADDRESS:
    291.                                 SetupReqLen = (pSetupReqPak->wValue)&0xff;
    292.                                 break;

    293.                             case USB_GET_CONFIGURATION:
    294.                                 pEP0_DataBuf[0] = DevConfig;
    295.                                 if ( SetupReqLen > 1 ) SetupReqLen = 1;
    296.                                 break;

    297.                             case USB_SET_CONFIGURATION:
    298.                                 DevConfig = (pSetupReqPak->wValue)&0xff;
    299.                                 break;

    300.                             case USB_CLEAR_FEATURE:
    301.                                 if ( ( pSetupReqPak->bRequestType & USB_REQ_RECIP_MASK ) == USB_REQ_RECIP_ENDP )
    302.                                 {
    303.                                     switch( (pSetupReqPak->wIndex)&0xff )
    304.                                     {
    305.                                     case 0x82:
    306.                                         R8_UEP2_CTRL = (R8_UEP2_CTRL & ~( RB_UEP_T_TOG|MASK_UEP_T_RES )) | UEP_T_RES_NAK;
    307.                                         break;

    308.                                     case 0x02:
    309.                                         R8_UEP2_CTRL = (R8_UEP2_CTRL & ~( RB_UEP_R_TOG|MASK_UEP_R_RES )) | UEP_R_RES_ACK;
    310.                                         break;

    311.                                     case 0x81:
    312.                                         R8_UEP1_CTRL = (R8_UEP1_CTRL & ~( RB_UEP_T_TOG|MASK_UEP_T_RES )) | UEP_T_RES_NAK;
    313.                                         break;

    314.                                     case 0x01:
    315.                                         R8_UEP1_CTRL = (R8_UEP1_CTRL & ~( RB_UEP_R_TOG|MASK_UEP_R_RES )) | UEP_R_RES_ACK;
    316.                                         break;

    317.                                     default:
    318.                                         errflag = 0xFF;
    319.                                         break;
    320.                                     }
    321.                                 }
    322.                                 else    errflag = 0xFF;
    323.                                 break;

    324.                             case USB_GET_INTERFACE:
    325.                                 pEP0_DataBuf[0] = 0x00;
    326.                                 if ( SetupReqLen > 1 ) SetupReqLen = 1;
    327.                                 break;

    328.                             case USB_GET_STATUS:
    329.                                 pEP0_DataBuf[0] = 0x00;
    330.                                 pEP0_DataBuf[1] = 0x00;
    331.                                 if ( SetupReqLen > 2 ) SetupReqLen = 2;
    332.                                 break;

    333.                             default:
    334.                                 errflag = 0xff;
    335.                                 break;
    336.                         }
    337.                     }
    338.                 }
    339.                 else    errflag = 0xff;

    340.                 if( errflag == 0xff)
    341.                 {
    342.                     R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL;
    343.                 }
    344.                 else
    345.                 {
    346.                     if( chtype & 0x80 )
    347.                     {
    348.                         len = (SetupReqLen>DevEP0SIZE) ? DevEP0SIZE : SetupReqLen;
    349.                         SetupReqLen -= len;
    350.                     }
    351.                     else  len = 0;

    352.                     R8_UEP0_T_LEN = len;
    353.                     R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK;
    354.                 }
    355.                 break;

    356.             case UIS_TOKEN_IN:
    357.                 switch( SetupReqCode )
    358.                 {
    359.                     case USB_GET_DESCRIPTOR:
    360.                         len = SetupReqLen >= DevEP0SIZE ? DevEP0SIZE : SetupReqLen;
    361.                         memcpy( pEP0_DataBuf, pDescr, len );
    362.                         SetupReqLen -= len;
    363.                         pDescr += len;
    364.                         R8_UEP0_T_LEN = len;
    365.                         R8_UEP0_CTRL ^= RB_UEP_T_TOG;
    366.                         break;

    367.                     case USB_SET_ADDRESS:
    368.                         R8_USB_DEV_AD = (R8_USB_DEV_AD&RB_UDA_GP_BIT) | SetupReqLen;
    369.                         R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
    370.                         break;

    371.                     default:
    372.                         R8_UEP0_T_LEN = 0;
    373.                         R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
    374.                         break;
    375.                 }
    376.                 break;

    377.             case UIS_TOKEN_OUT:
    378.                 len = R8_USB_RX_LEN;
    379.                 break;

    380.             case UIS_TOKEN_OUT | 1:
    381.                 if ( R8_USB_INT_ST & RB_UIS_TOG_OK )
    382.                 {
    383.                     len = R8_USB_RX_LEN;
    384.                     DevEP1_OUT_Deal( len );
    385.                 }
    386.                 break;

    387.             case UIS_TOKEN_IN | 1:
    388.                 R8_UEP1_T_LEN = 0;
    389.                 Endp1Busy = 0;
    390.                 R8_UEP1_CTRL = (R8_UEP1_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
    391.                 break;

    392.             case UIS_TOKEN_OUT | 2:
    393.                 if ( R8_USB_INT_ST & RB_UIS_TOG_OK )
    394.                 {
    395.                     len = R8_USB_RX_LEN;
    396.                     DevEP2_OUT_Deal( len );
    397.                 }
    398.                 break;

    399.             case UIS_TOKEN_IN | 2:
    400.                 R8_UEP2_T_LEN = 0;
    401.                 Endp2Busy = 0;
    402.                 R8_UEP2_CTRL = (R8_UEP2_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK;
    403.                 break;

    404.             default :
    405.                 break;
    406.         }
    407.         R8_USB_INT_FG = RB_UIF_TRANSFER;
    408.     }
    409.     else if( intflag & RB_UIF_BUS_RST )
    410.     {
    411.         R8_USB_DEV_AD = 0;
    412.         R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK;
    413.         R8_UEP1_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
    414.         R8_UEP2_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK | RB_UEP_AUTO_TOG;
    415.         R8_USB_INT_FG |= RB_UIF_BUS_RST;
    416.     }
    417.     else if( intflag & RB_UIF_SUSPEND )
    418.     {
    419.         if ( R8_USB_MIS_ST & RB_UMS_SUSPEND ) {;}
    420.         else{;}
    421.         R8_USB_INT_FG = RB_UIF_SUSPEND;
    422.     }
    423.     else
    424.     {
    425.         R8_USB_INT_FG = intflag;
    426.     }
    427. }

    428. void HIDValueHandle()
    429. {
    430.     UINT8 i;
    431.     i = USART_ReceiveData(USART2);
    432.     printf( "%c\n", (UINT8)i );
    433.     switch(i)
    434.     {
    435.     //鼠标数据上传示例
    436.         case 'L':                                               //左键
    437.             HIDMouse[0] = 0x01;
    438.             while( Endp2Busy )
    439.             {
    440.                 ;                                               //如果忙(上一包数据没有传上去),则等待。
    441.             }
    442.             Endp2Busy = 1;                                      //设置为忙状态
    443.             memcpy(pEP2_IN_DataBuf, HIDMouse, 4);
    444.             DevEP2_IN_Deal(4);
    445.             HIDMouse[0] = 0;                                    //抬起
    446.             while( Endp2Busy )
    447.             {
    448.                 ;                                               //如果忙(上一包数据没有传上去),则等待。
    449.             }
    450.             Endp2Busy = 1;                                      //设置为忙状态
    451.             memcpy(pEP2_IN_DataBuf, HIDMouse, 4);
    452.             DevEP2_IN_Deal(4);
    453.             break;
    454.         case 'R':                                               //右键
    455.             HIDMouse[0] = 0x02;
    456.             while( Endp2Busy )
    457.             {
    458.                 ;                                               //如果忙(上一包数据没有传上去),则等待。
    459.             }
    460.             Endp2Busy = 1;                                      //设置为忙状态
    461.             memcpy(pEP2_IN_DataBuf, HIDMouse, 4);
    462.             DevEP2_IN_Deal(4);
    463.             HIDMouse[0] = 0;                                    //抬起
    464.             while( Endp2Busy )
    465.             {
    466.                 ;                                               //如果忙(上一包数据没有传上去),则等待。
    467.             }
    468.             Endp2Busy = 1;                                      //设置为忙状态
    469.             memcpy(pEP2_IN_DataBuf, HIDMouse, 4);
    470.             DevEP2_IN_Deal(4);
    471.             break;
    472.     //键盘数据上传示例
    473.         case 'A':                                               //A键
    474.             HIDKey[2] = 0x04;                                   //按键开始
    475.             while( Endp1Busy )
    476.             {
    477.                 ;                                               //如果忙(上一包数据没有传上去),则等待。
    478.             }
    479.             Endp1Busy = 1;                                      //设置为忙状态
    480.             memcpy(pEP1_IN_DataBuf, HIDKey, 8);
    481.             DevEP1_IN_Deal(8);
    482.             HIDKey[2] = 0;                                      //按键结束
    483.             while( Endp1Busy )
    484.             {
    485.                 ;                                               //如果忙(上一包数据没有传上去),则等待。
    486.             }
    487.             Endp1Busy = 1;                                      //设置为忙状态
    488.             memcpy(pEP1_IN_DataBuf, HIDKey, 8);
    489.             DevEP1_IN_Deal(8);
    490.             break;
    491.         case 'Q':                                               //CAP键
    492.             HIDKey[2] = 0x39;
    493.             while( Endp1Busy )
    494.             {
    495.                 ;                                               //如果忙(上一包数据没有传上去),则等待。
    496.             }
    497.             Endp1Busy = 1;                                      //设置为忙状态
    498.             memcpy(pEP1_IN_DataBuf, HIDKey, 8);
    499.             DevEP1_IN_Deal(8);
    500.             HIDKey[2] = 0;                                      //按键结束
    501.             while( Endp1Busy )
    502.             {
    503.                 ;                                               //如果忙(上一包数据没有传上去),则等待。
    504.             }
    505.             Endp1Busy = 1;                                      //设置为忙状态
    506.             memcpy(pEP1_IN_DataBuf, HIDKey, 8);
    507.             DevEP1_IN_Deal(8);
    508.             break;
    509.         default:                                                //其他
    510.             break;
    511.     }
    512. }
    513. /*******************************************************************************
    514. * Function Name  : Set_USBConfig
    515. * Description    : Set USB clock.
    516. * Input          : None
    517. * Return         : None
    518. *******************************************************************************/
    519. void USBHD_ClockCmd(UINT32 RCC_USBCLKSource,FunctionalState NewState)
    520. {
    521.     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, NewState);
    522.     EXTEN->EXTEN_CTR |= EXTEN_USBHD_IO_EN;
    523.     RCC_USBCLKConfig(RCC_USBCLKSource);                      //USBclk=PLLclk/1.5=48Mhz
    524.     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_USBHD,NewState);
    525. }

    526. /*******************************************************************************
    527. * Function Name  : main
    528. * Description    : Main program.
    529. * Input          : None
    530. * Return         : None
    531. *******************************************************************************/
    532. int main(void)
    533. {
    534.     NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    535.     Delay_Init();
    536.     USART2_Printf_Init(115200);

    537.     printf("SystemClk:%d\r\n",SystemCoreClock);
    538.     printf("USBHD Device Test\r\n");

    539.     pEP0_RAM_Addr = EP0_Databuf;
    540.     pEP1_RAM_Addr = EP1_Databuf;
    541.     pEP2_RAM_Addr = EP2_Databuf;

    542.     USBHD_ClockCmd(RCC_USBCLKSource_PLLCLK_1Div5,ENABLE);
    543.     USB_DeviceInit();
    544.     NVIC_EnableIRQ( USBHD_IRQn );

    545.     while(1)
    546.     {
    547.         printf("Ready1=%d\n",Ready);
    548.         if(Ready)
    549.         {
    550.             HIDValueHandle();
    551.         }
    552.         Delay_Ms(500);
    553.     }
    554. }

    555. /*******************************************************************************
    556. * Function Name  : DevEP1_OUT_Deal
    557. * Description    : Deal device Endpoint 1 OUT.
    558. * Input          : l: Data length.
    559. * Return         : None
    560. *******************************************************************************/
    561. void DevEP1_OUT_Deal( UINT8 l )
    562. {
    563.     ;
    564. }

    565. /*******************************************************************************
    566. * Function Name  : DevEP2_OUT_Deal
    567. * Description    : Deal device Endpoint 2 OUT.
    568. * Input          : l: Data length.
    569. * Return         : None
    570. *******************************************************************************/
    571. void DevEP2_OUT_Deal( UINT8 l )
    572. {
    573.     ;
    574. }

    575. /*******************************************************************************
    576. * Function Name  : USB_IRQHandler
    577. * Description    : This function handles USB exception.
    578. * Input          : None
    579. * Return         : None
    580. *******************************************************************************/
    581. void USBHD_IRQHandler (void)
    582. {
    583.     USB_DevTransProcess();
    584. }
    复制代码
    main.c文件中本人对各种描述符都进行了注释,便于大家理解,有不懂地方可以参考《圈圈教你玩USB》。关于USB设备传输过程,可结合应用手册关于USB寄存器介绍进行理解学习。


    4、下载验证

    将编译好的程序下载到开发板并复位,打开串口调试助手,串口打印如下:
    CH32V CH573单片机芯片-第八十三章:CH32V103应用教程——USB模拟鼠标键盘设备risc-v单片机中文社区(1)
    用公对公USB线将开发板与电脑连接起来,打开设备管理器可以看到端口中多了一个键盘设备和鼠标设备,如图所示:
    CH32V CH573单片机芯片-第八十三章:CH32V103应用教程——USB模拟鼠标键盘设备risc-v单片机中文社区(2)
    CH32V CH573单片机芯片-第八十三章:CH32V103应用教程——USB模拟鼠标键盘设备risc-v单片机中文社区(3)
    串口调试助手发送L,显示如下:
    CH32V CH573单片机芯片-第八十三章:CH32V103应用教程——USB模拟鼠标键盘设备risc-v单片机中文社区(4)

    CH32V103 USB模拟鼠标键盘设备.rar
    CH32V CH573单片机芯片-第八十三章:CH32V103应用教程——USB模拟鼠标键盘设备risc-v单片机中文社区(5) CH32V103 USB模拟鼠标键盘设备.rar (498.8 KB, 下载次数: 18)
    链接:https://pan.baidu.com/s/1QrG4lBJM1QqqlidS6LHZ-g
    提取码:b571
    复制这段内容后打开百度网盘手机App,操作更方便哦







    上一篇:第八十二章:CH32V103应用教程——USB模拟CDC
    下一篇:第八十四章:CH32V103应用教程——USB模拟U盘
    RISCV作者优文
    全球首家只专注于RISC-V单片机行业应用的中文网站
    回复

    使用道具 举报

    RISC-V隐身侠  发表于 2023-10-11 19:54:34
    有关闭电脑重启设备发送键盘数据失败的问题吗?
    全球首家只专注于RISC-V单片机行业应用的中文网站
    回复 支持 反对

    使用道具

      离线 

  • TA的每日心情
    凉风
    2024-1-31 20:50
  • 签到天数: 7 天

    [LV.3]

    发表于 2024-1-20 22:23:50 | 显示全部楼层
    感谢,非常优秀的代码
    全球首家只专注于RISC-V单片机行业应用的中文网站
    高级模式
    B Color Image Link Quote Code Smilies

    本版积分规则

    关闭

    RISC-V单片机中文网上一条 /2 下一条



    版权及免责声明|RISC-V单片机中文网 |网站地图

    GMT+8, 2024-11-26 10:03 , Processed in 0.264504 second(s), 51 queries .

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