STM32CubeMX实现USB HID keyboard(鼠标改键盘)

参考文章

STM32CubeMX学习笔记(45)——USB接口使用(HID鼠标)
STM32-USB学习系列(六):USB-HID键盘的实现以及键盘报文描述符的简介
HID设备(USB键鼠/扫码枪)转串口(UART)键盘键值及字符处理示例——CH9350
本文对在以上三篇文章中引用的内容进行整合,并通过实践验证了各个步骤的可行性,增加了代码修改方面的相关细节

创建CubeMX工程

一、新建工程

  1. 打开 STM32CubeMX 软件,点击“新建工程”
    在这里插入图片描述
  2. 选择 MCU 和封装
    在这里插入图片描述
  3. 配置时钟
    RCC 设置,选择 HSE(外部高速时钟) 为 Crystal/Ceramic Resonator(晶振/陶瓷谐振器)
    在这里插入图片描述
    选择 Clock Configuration,配置系统时钟 SYSCLK 为 72MHz
    修改 HCLK 的值为 72 后,输入回车,软件会自动修改所有配置
    在这里插入图片描述
  4. 配置调试模式
    非常重要的一步,否则会造成第一次烧录程序后续无法识别调试器
    SYS 设置,选择 Debug 为 Serial Wire
    在这里插入图片描述

二、USB

  1. 参数配置
    Connectivity 中选择 USB 设置,并勾选 Device (FS) 激活 USB 设备。
    “FS” stands for “Full Speed”.
    在这里插入图片描述

    Parameter Settings 进行具体参数配置。
    在这里插入图片描述
    Speed: Full Speed 12MBit/s(固定为全速)
    Low Power: 默认 Disabled(在任何不需要使用usb模块的时候,通过写控制寄存器总可以使usb模块置于低功耗模式(low power mode ,suspend模式)。在这种模式下,不产生任何静态电流消耗,同时usb时钟也会减慢或停止。通过对usb线上数据传输的检测,可以在低功耗模式下唤醒usb模块。也可以将一特定的中断输入源直接连接到唤醒引脚上,以使系统能立即恢复正常的时钟系统,并支持直接启动或停止时钟系统。)

  2. 引脚配置
    USB 的 DP 引脚必须上拉 1.5K 欧的电阻,电脑才能检测到 USB,否则检测不到。
    在这里插入图片描述

    野火:需要将 PD6 配置为低电平使能 USB
    在这里插入图片描述
    在右边图中找到 PD6 引脚,选择 GPIO_Output
    在这里插入图片描述

    GPIO output level 中选择 Low 输出低电平。
    在这里插入图片描述

    正点原子:只需将排针4–6和3–5分别用跳线帽相连
    在这里插入图片描述
    由于本次需要实现USB HID keyboard,故需要使用开关KEY0~2。可参照以上的GPIO配置步骤将相应的引脚配置为GPIO_Input,Pull_up。

  3. 配置时钟
    选择 Clock Configuration,USB 时钟配置为 48MHz,且来源最好是外部晶振分频得到。
    在这里插入图片描述

  4. USB Device

    USB有主机(Host)和设备(Device)之分。一般电脑的USB接口为主机接口,而键盘、鼠标、U盘等则为设备。
    部分型号的STM32芯片有1~2个USB接口。像STM32F103系列的有一个USB
    Device接口,STM32F407系列的有2个USB接口,既可以作为HOST,又可以作为Device,还可以作为OTG接口。

    Middleware 中选择 USB_DEVICE 设置,在 Class For FS IP 设备类别选择 Human Interface Device Class (HID)人机接口设备。
    在这里插入图片描述

    参数配置保持默认。
    在这里插入图片描述
    HID_FS_BINTERVAL(主机读取设备数据时间间隔)0xA(STM32将数据发送到一个缓存区,而不是直接发送到上位机,而上位机每隔一端时间会来访问缓冲区读取数据。读取时间间隔过快会导致多次数据发送,过慢会导致数据丢失)
    USBD_MAX_NUM_INTERFACES (Maximum number of supported interfaces)(最大支持HID设备的接口数)1(应为现在只有鼠标,所以1就行,如果是需要同时键盘,鼠标,手柄之类的,根据数量选择即可)

    设备描述符保持默认。
    在这里插入图片描述

三、生成代码

  1. 输入项目名和项目路径
    在这里插入图片描述
  2. 选择应用的 IDE 开发环境 MDK-ARM V5
    在这里插入图片描述
  3. 每个外设生成独立的 ’.c/.h’ 文件
    不选:所有初始化代码都生成在 main.c
    勾选:初始化代码生成在对应的外设文件。 如 GPIO 初始化代码生成在 gpio.c 中。
    在这里插入图片描述
  4. 点击 GENERATE CODE 生成代码
    在这里插入图片描述

四、了解usbd_hid.c

打开工程文件夹Middlewares/USB_Device_Libraryusbd_hid.c文件
在这里插入图片描述

  1. USB HID描述符
    HID设备的描述符除了5个USB的标准描述符(设备描述符、配置描述符、接口描述符、端点描述符、字符串描述符)外,还包括3个HID设备类特定的描述符:HID描述符、报告描述符(Report)、实体描述符(Physical)。
    他们之间的层次关系如图:
    在这里插入图片描述
    打开usbd_hid.c文件,找到USBD_HID_CfgFSDesc配置全速(Full Speed)描述符数组定义处(由于配置USB设备时将其置为了全速,所以不用管USBD_HID_CfgHSDesc(High Speed))

    • 配置描述符
    bNumInterfaces表示这个设备有多少个接口。
    MaxPower 100 mA表示这个设备需要从总线上获取100mA电流。

    /* USB HID device FS Configuration Descriptor */
    __ALIGN_BEGIN static uint8_t USBD_HID_CfgFSDesc[USB_HID_CONFIG_DESC_SIZ]  __ALIGN_END =
    {
      0x09, /* bLength: Configuration Descriptor size */
      USB_DESC_TYPE_CONFIGURATION, /* bDescriptorType: Configuration */
      USB_HID_CONFIG_DESC_SIZ,
      /* wTotalLength: Bytes returned */
      0x00,
      0x01,         /*bNumInterfaces: 1 interface*/
      0x01,         /*bConfigurationValue: Configuration value*/
      0x00,         /*iConfiguration: Index of string descriptor describing
      the configuration*/
      0xE0,         /*bmAttributes: bus powered and Support Remote Wake-up */
      0x32,         /*MaxPower 100 mA: this current is used for detecting Vbus*/
    

    • 接口描述符
    bInterfaceClass的值必须是 0x03
    bInterfaceSubClass的值为 0 或 1, 为1表示HID设备是一个启动设备(BootDevice, 一般对PC机有意义,意思是BIOS启动时能识别所使用的HID设备,且只有标准鼠标或者键盘才能称为BootDevice),为0表示HID设备是操作系统启动厚才能识别使用的设备。
    bInterfaceProtocol的值为 2 表示鼠标接口:(0 — NONE,1 — Keyboard(键盘),2 — Mouse (鼠标),3~255 Reserved)

      /************** Descriptor of Joystick Mouse interface ****************/
      /* 09 */
      0x09,         /*bLength: Interface Descriptor size*/
      USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
      0x00,         /*bInterfaceNumber: Number of Interface*/
      0x00,         /*bAlternateSetting: Alternate setting*/
      0x01,         /*bNumEndpoints*/
      0x03,         /*bInterfaceClass: HID*/
      0x01,         /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
      0x02,         /*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
      0,            /*iInterface: Index of string descriptor*/
    

    • HID描述符
    HID描述符关联于接口描述符,因而如果一个设备只有一个接口描述符,则无论它有几个端点描述符,HID设备只有一个HID描述符。HID设备描述符主要描述HID规范的版本号, HID通信所使用的额外描述符,报告描述符的长度等。

      /******************** Descriptor of Joystick Mouse HID ********************/
      /* 18 */
      0x09,         /*bLength: HID Descriptor size*/
      HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
      0x11,         /*bcdHID: HID Class Spec release number*/
      0x01,
      0x00,         /*bCountryCode: Hardware target country*/
      0x01,         /*bNumDescriptors: Number of HID class descriptors to follow*/
      0x22,         /*bDescriptorType*/
      HID_MOUSE_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
      0x00,
    

    • 端点描述符
    bEndpointAddress表示端点地址,表示当前这个接口所需要的端点资源,输入(相对于主机而言)端点最高位为1,输出(相对于主机而言)端点最高位为0。HID设备一般都是使用中断端点进行数据传输。
    wMaxPacketSize表示该端点上数据传输的数量。
    bInterval表示主机查询设备数据的时间间隔,如果设置的太长,则键盘输入延迟很高。

  2. 报告描述符
    下载 HID Descriptor Tool (DT) HID描述符工具:
    官网下载:https://usb.org/sites/default/files/documents/dt2_4.zip
    百度网盘:https://pan.baidu.com/s/1ayjdQtc7e9NWwYJqdp0pXA?pwd=4ghb 提取码:4ghb
    打开 FileOpen...mouse.hid (键盘应该使用keybrd.hid,但本文为在程序中保留鼠标相关内容,故在mouse.hid中直接进行修改)
    在这里插入图片描述

    我们可以看到HID鼠标的描述符情况:
    在这里插入图片描述

    打开usbd_hid.c文件,找到HID_MOUSE_ReportDesc数组定义处(默认生产HID设备为Mouse,所以需要增加键盘数组)。
    在这里插入图片描述

更改代码实现鼠标改键盘

  1. 修改HID的接口描述符与报文描述符
    注意:端点描述符不做修改!即 HID_EPIN_SIZE 还是0x04 (对应4字节大小,后面在发送键盘报文的时候,需要将键盘的报文大小修改为 4个字节的数组或者结构体)
    usbd_hid.h中引入宏定义USE_KEYBOARD_HIDHID_KEYBOARD_REPORT_DESC_SIZE

    #define USE_KEYBOARD_HID 1	//WY: 1=enable; 0=disable
    		
    #define HID_EPIN_ADDR                 0x81U
    #define HID_EPIN_SIZE                 0x04U
    	
    #define USB_HID_CONFIG_DESC_SIZ       34U
    #define USB_HID_DESC_SIZ              9U
    #define HID_MOUSE_REPORT_DESC_SIZE    74U
    #define HID_KEYBOARD_REPORT_DESC_SIZE	63U	//WY: for keyboard
    

    USBD_HID_CfgFSDesc中修改

      /************** Descriptor of Joystick Mouse interface ****************/
      /* 09 */
      0x09,         /*bLength: Interface Descriptor size*/
      USB_DESC_TYPE_INTERFACE,/*bDescriptorType: Interface descriptor type*/
      0x00,         /*bInterfaceNumber: Number of Interface*/
      0x00,         /*bAlternateSetting: Alternate setting*/
      0x01,         /*bNumEndpoints*/
      0x03,         /*bInterfaceClass: HID*/
      0x01,         /*bInterfaceSubClass : 1=BOOT, 0=no boot*/
    #if(USE_KEYBOARD_HID)
      0x01,         //WY: nInterfaceProtocol: keyboard
    #else
      0x02,		/*nInterfaceProtocol : 0=none, 1=keyboard, 2=mouse*/
    #endif
      0,            /*iInterface: Index of string descriptor*/
    
      /******************** Descriptor of Joystick Mouse HID ********************/
      /* 18 */
      0x09,         /*bLength: HID Descriptor size*/
      HID_DESCRIPTOR_TYPE, /*bDescriptorType: HID*/
      0x11,         /*bcdHID: HID Class Spec release number*/
      0x01,
      0x00,         /*bCountryCode: Hardware target country*/
      0x01,         /*bNumDescriptors: Number of HID class descriptors to follow*/
      0x22,         /*bDescriptorType*/
    #if(USE_KEYBOARD_HID)
      HID_KEYBOARD_REPORT_DESC_SIZE,
    #else
      HID_MOUSE_REPORT_DESC_SIZE,/*wItemLength: Total length of Report descriptor*/
    #endif
      0x00,
    
  2. 修改USBD_HID_Setup函数
    在HID Setup的过程中会获取对应键盘报文描述符

     case USB_REQ_GET_DESCRIPTOR:
              if (req->wValue >> 8 == HID_REPORT_DESC)
              {
    #if(USE_KEYBOARD_HID)
    			len = MIN(HID_KEYBOARD_REPORT_DESC_SIZE, req->wLength);
                pbuf = HID_KEYBOARD_ReportDesc;
    #else
                len = MIN(HID_MOUSE_REPORT_DESC_SIZE, req->wLength);
                pbuf = HID_MOUSE_ReportDesc;
    #endif
              }
    
  3. 添加以及修改键盘报文描述符
    注意:修改部分为最后面按键输入描述部分,将后面6个按键缩减为2个按键(即:从6个字节缩减到2个字节),配合上前面2个字节的输入报告,正好是4个字节,刚好符合原来HID端点描述符一次最多发送的大小
    将原有HID_MOUSE_ReportDesc的内容注释掉,并在其后增加以下定义

    __ALIGN_BEGIN static uint8_t HID_KEYBOARD_ReportDesc[HID_KEYBOARD_REPORT_DESC_SIZE]  __ALIGN_END =
    {
    	0x05, 0x01,                    // USAGE_PAGE (Generic Desktop)
    	0x09, 0x06,                    // USAGE (Keyboard)		   /* 用途为键盘 */
    	0xa1, 0x01,                    // COLLECTION (Application) /* 表示应用结合,必须以END_COLLECTION来结束 */
    	0x05, 0x07,                    //   USAGE_PAGE (Keyboard)  /* 用途页为按键 */
    	0x19, 0xe0,                    //   USAGE_MINIMUM (Keyboard LeftControl)  /* 用途最小值 左Ctrl */
    	0x29, 0xe7,                    //   USAGE_MAXIMUM (Keyboard Right GUI)	  /* 用途最大值 右GUI */
    	0x15, 0x00,                    //   LOGICAL_MINIMUM (0)	   /* 逻辑最小值 0 */
    	0x25, 0x01,                    //   LOGICAL_MAXIMUM (1)	   /* 逻辑最大值 1 */
    	0x75, 0x01,                    //   REPORT_SIZE (1)      /* 报告位大小(这个字段的宽度为1bit) */
    	0x95, 0x08,                    //   REPORT_COUNT (8) 	 /* 输入报告第一个字节(报告位大小 8bit) */
    	0x81, 0x02,                    //   INPUT (Data,Var,Abs) /* 报告为输入用 , 从左ctrl到右GUI 8bit刚好构成1个字节*/
    	 
    	0x95, 0x01,                    //   REPORT_COUNT (1)	 /* 报告位数量  1个 */
    	0x75, 0x08,                    //   REPORT_SIZE (8)      /* 输入报告的第二给字节(报告位大小 8bit) */
    	0x81, 0x03,                    //   INPUT (Cnst,Var,Abs) /* 输入用的保留位,设备必须返回0 */
    	 
    	0x95, 0x05,                    //   REPORT_COUNT (5)     /* 报告位数量 5个 */
    	0x75, 0x01,                    //   REPORT_SIZE (1)		 /* 报告位大小,1bit */
    	0x05, 0x08,                    //   USAGE_PAGE (LEDs)    /* 用途为LED */
    	0x19, 0x01,                    //   USAGE_MINIMUM (Num Lock) /* 用途最小值 NUM Lock LED灯 */
    	0x29, 0x05,                    //   USAGE_MAXIMUM (Kana)  /* 用途最大值 Kana 灯 */
    	0x91, 0x02,                    //   OUTPUT (Data,Var,Abs) /* 输出用途,用于控制LED等 */
    	 
    	0x95, 0x01,                    //   REPORT_COUNT (1)     /* 报告位数量 1个 */
    	0x75, 0x03,                    //   REPORT_SIZE (3)      /* 报告位大小 3bit */
    	0x91, 0x03,                    //   OUTPUT (Cnst,Var,Abs)/* 用于字节补齐,跟前面5个bit进行补齐 */
    	 
    	0x95, 0x02,                    //   REPORT_COUNT (6)  /* 报告位数量 6个*/
    	0x75, 0x08,                  	//   REPORT_SIZE (8)		 /* 报告位大小 8bit */
    	0x15, 0x00,                    //   LOGICAL_MINIMUM (0)		 /* 逻辑最小值0 */
    	0x25, 0xFF,                    //   LOGICAL_MAXIMUM (255)    /* 逻辑最大值255 */
    	0x05, 0x07,                    //   USAGE_PAGE (Keyboard)    /* 用途页为按键 */
    	0x19, 0x00,                    //   USAGE_MINIMUM (Reserved (no event indicated)) /* 使用值最小为0 */
    	0x29, 0x65,                    //   USAGE_MAXIMUM (Keyboard Application)		  /* 使用值最大为65 */
    	0x81, 0x00,                    //   INPUT (Data,Ary,Abs)	 /* 输入用,变量,数组,绝对值 */
    	0xc0  						   								 /* END_COLLECTION */
    };
    

键码值(keyCode)

  1. 以键盘为例(扫码枪一般模拟键盘输入)报文示例如下:
    在这里插入图片描述
    报文前三个字节的固定内容可自动生成,故代码中只需通过后8个字节传递正确的键码值,例如在main.c中定义:

    uint8_t txbuffer[8]= {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
    uint8_t sendbuffer_Enter[8]={0x00,0x00,0x28,0x00,0x00,0x00,0x00,0x00};
    uint8_t sendbuffer_Aa[8]={0x00,0x00,0x04,0x00,0x00,0x00,0x00,0x00};
    uint8_t sendbuffer_Space[8]={0x00,0x00,0x2C,0x00,0x00,0x00,0x00,0x00};
    

    发送报文使用USBD_HID_SendReport函数,为使代码友好易读,故在usb_device.c中对此函数进行封装,以便在main函数中直接调用:

    uint8_t MX_USB_DEVICE_Send(uint8_t *sendbuffer)
    {	
    	return USBD_HID_SendReport(&hUsbDeviceFS,sendbuffer,8);	//Full speed
    }
    
  2. 全键盘码值表如下提供参考:

    //Keybord keyvalue define
    #define KEY_NULL 0x00          // NULL
    #define KEY_A 0x04             // A
    #define KEY_B 0x05             // B
    #define KEY_C 0x06             // C
    #define KEY_D 0x07             // D
    #define KEY_E 0x08             // E
    #define KEY_F 0x09             // F
    #define KEY_G 0x0A             // G
    #define KEY_H 0x0B             // H
    #define KEY_I 0x0C             // I
    #define KEY_J 0x0D             // J
    #define KEY_K 0x0E             // K
    #define KEY_L 0x0F             // L
    #define KEY_M 0x10             // M
    #define KEY_N 0x11             // N
    #define KEY_O 0x12             // O
    #define KEY_P 0x13             // P
    #define KEY_Q 0x14             // Q
    #define KEY_R 0x15             // R
    #define KEY_S 0x16             // S
    #define KEY_T 0x17             // T
    #define KEY_U 0x18             // U
    #define KEY_V 0x19             // V
    #define KEY_W 0x1A             // W
    #define KEY_X 0x1B             // X
    #define KEY_Y 0x1C             // Y
    #define KEY_Z 0x1D             // Z
    #define KEY_1 0x1E             // 1 and !
    #define KEY_2 0x1F             // 2 and @
    #define KEY_3 0x20             // 3 and #
    #define KEY_4 0x21             // 4 and $
    #define KEY_5 0x22             // 5 and %
    #define KEY_6 0x23             // 6 and ^
    #define KEY_7 0x24             // 7 and &
    #define KEY_8 0x25             // 8 and *
    #define KEY_9 0x26             // 9 and (
    #define KEY_0 0x27             // 10 and )
    #define KEY_ENTER 0x28         // ENTER
    #define KEY_ESC 0x29           // ESC
    #define KEY_BACKSPACE 0x2A     // BACKSPACE
    #define KEY_TAB 0x2B           // TAB
    #define KEY_SPACE 0x2C         // SPACE
    #define KEY_SUB 0x2D           // - and _
    #define KEY_EQUAL 0x2E         // = and +
    #define KEY_LEFT_BRACKET 0x2F  // [ and {
    #define KEY_RIGHT_BRACKET 0x30 // ] and }
    #define KEY_VERTICAL_LINE 0x31 // "\" and |
    #define KEY_WAVE 0x32          // ` and ~
    #define KEY_SEMICOLON 0x33     // ; and :
    #define KEY_QUOTE 0x34         // ' and "
    #define KEY_THROW 0x35         // ~ and `
    #define KEY_COMMA 0x36         // , and <
    #define KEY_DOT 0x37           // . and >
    #define KEY_QUESTION 0x38      // / and ?
    #define KEY_CAPS_LOCK 0x39     // CAPS
    #define KEY_F1 0x3A
    #define KEY_F2 0x3B
    #define KEY_F3 0x3C
    #define KEY_F4 0x3D
    #define KEY_F5 0x3E
    #define KEY_F6 0x3F
    #define KEY_F7 0x40
    #define KEY_F8 0x41
    #define KEY_F9 0x42
    #define KEY_F10 0x43
    #define KEY_F11 0x44
    #define KEY_F12 0x45
    #define KEY_PRT_SCR 0x46
    #define KEY_SCOLL_LOCK 0x47
    #define KEY_PAUSE 0x48
    #define KEY_INS 0x49
    #define KEY_HOME 0x4A
    #define KEY_PAGEUP 0x4B
    #define KEY_DEL 0x4C
    #define KEY_END 0x4D
    #define KEY_PAGEDOWN 0x4E
    #define KEY_RIGHT_ARROW 0x4F
    #define KEY_LEFT_ARROW 0x50
    #define KEY_DOWN_ARROW 0x51
    #define KEY_UP_ARROW 0x52
    //Num Pad
    #define KEY_PAD_NUMLOCK 0x53
    #define KEY_PAD_DIV 0x54
    #define KEY_PAD_MUL 0x55
    #define KEY_PAD_SUB 0x56
    #define KEY_PAD_ADD 0x57
    #define KEY_PAD_ENTER 0x58
    #define KEY_PAD_1 0x59
    #define KEY_PAD_2 0x5A
    #define KEY_PAD_3 0x5B
    #define KEY_PAD_4 0x5C
    #define KEY_PAD_5 0x5D
    #define KEY_PAD_6 0x5E
    #define KEY_PAD_7 0x5F
    #define KEY_PAD_8 0x60
    #define KEY_PAD_9 0x61
    #define KEY_PAD_0 0x62
    #define KEY_PAD_DOT 0x63
    #define KEY_PRESSED 0x00
    #define KEY_RELEASED 0x01
    // Control
    #define KEY_LCTRL 0xE0  // left ctrl // #define KEY_LCTRL 0x01
    #define KEY_LALT 0xE2   // left Alt // #define KEY_LALT 0x04
    #define KEY_LSHFIT 0xE1 // left Shift // #define KEY_LSHFIT 0x02
    #define KEY_LWIN 0xE3   // left windows // #define KEY_LWIN 0x08
    #define KEY_RWIN 0xE7   // right windows // #define KEY_RWIN 0x80
    #define KEY_RSHIFT 0xE5 // right Shift // #define KEY_RSHIFT 0x20
    #define KEY_RALT 0xE6   // right Alt // #define KEY_RALT 0x40
    #define KEY_RCTRL 0xE4  // right Ctrl // #define KEY_RCTRL 0x10
    #define KEY_APP 0x65    // Application // #define KEY_APP 0x65
    #define KEY_K14 0x89    // international key
    #define KEY_KR_L 0x91
    #define KEY_K107 0x85
    #define KEY_K45 0x64
    #define KEY_K42 0x32
    #define KEY_K131 0x8b
    #define KEY_K132 0x8a
    #define KEY_K133 0x88
    #define KEY_K56 0x87
    #define KEY_KR_R 0x90
    

补充

电脑设备管理器显示“未知USB设备(设备描述符请求失败)”时:
个人经验:
最好在CubeMX程序第一次生成之后(无改动)确认是否能识别设备,若此时识别成功,则之后再遇“未知USB设备(设备描述符请求失败)”问题时,重新插拔USB接口即可恢复正常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值