STM32 USB HID开发实战心得与技巧

AI助手已提取文章相关产品:

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:本文作者分享了通过STM32微控制器实现USB设备端HID类协议的编程经验。介绍了USB基础知识、STM32与USB的结合、USB HID协议要点、例程修改、枚举过程、实战应用以及调试与优化。强调了理论与实践结合的重要性,并通过具体案例说明了如何创建自定义USB设备,如定制化的输入设备或数据传输工具。
stm32_usb_hid_学习心得

1. USB基础知识

1.1 USB技术的发展历程

1.1.1 从USB 1.0到USB 4.0的技术演进

USB(通用串行总线)技术自1996年首次推出以来,经历了多个版本的演进,不断提高数据传输速度和效率。USB 1.0的速度为1.5 Mbps(低速)和12 Mbps(高速)。随着技术的发展,USB 2.0带来了480 Mbps的带宽,而USB 3.0则增至5 Gbps。最新的USB 4.0标准甚至支持高达40 Gbps的速度,并加入了对Thunderbolt协议的兼容性。

1.1.2 USB技术的标准化组织

USB技术的标准化工作由USB实施者论坛(USB-IF)负责。该组织制定了一系列规范,确保不同厂商生产的USB设备能够实现互操作性。USB-IF还负责测试和认证USB产品,以保证符合行业标准。

1.2 USB的架构与通信原理

1.2.1 USB系统的基本组件

USB系统主要由主机(Host)、USB集线器(Hub)和USB设备(Device)组成。主机负责控制整个USB系统的通信和数据流,集线器作为扩展端口使用,设备则可以是各种外围设备,如键盘、鼠标等。

1.2.2 USB的通信协议和数据传输方式

USB通信遵循严格的协议,包括设备请求、数据传输和错误处理。数据传输方式包括控制传输、批量传输、中断传输和同步传输,每种方式针对不同的应用需求和数据传输特性进行了优化。

1.3 USB的设备类型与配置

1.3.1 主机和设备的基本概念

USB主机通常是指连接了USB设备的计算机或其他智能设备,它们负责发起数据传输请求,并管理整个USB系统。USB设备则响应主机的请求,进行数据的发送或接收。

1.3.2 USB设备的配置与枚举过程

每个USB设备都有一个或多个配置,每个配置可以定义不同的接口和端点,以支持不同的数据传输类型。设备枚举是指主机识别连接的USB设备,并加载相应的驱动程序的过程,它是设备与主机通信前的必要步骤。

以上为第一章的内容,由浅入深介绍了USB的基础知识,包括技术发展历程、系统架构与通信原理、以及设备类型与配置。第二章将继续深入探讨STM32微控制器如何与USB设备模式结合。

2. STM32与USB设备模式

2.1 STM32的USB硬件支持

STM32系列微控制器由STMicroelectronics生产,广泛应用于嵌入式系统中。该系列的芯片提供了对USB接口的支持,使得开发USB相关的设备变得简单和高效。STM32的USB硬件支持主要体现在其硬件抽象层(HAL)和硬件外设特性中。

2.1.1 STM32系列芯片的USB接口特性

STM32系列芯片中的USB接口支持多种USB标准:全速(12 Mbps)和低速(1.5 Mbps)设备。为了实现这一支持,STM32的USB硬件模块具备以下特性:

  • 全双工通信能力,符合USB 2.0规范。
  • 集成的SOF(Start of Frame)包生成器。
  • 可编程的时钟恢复和数据包处理机制。
  • 硬件支持批量、中断和控制传输类型。
  • 多个交易缓冲区,用于同时处理多个事务。
// 初始化代码示例
#include "stm32f1xx_hal.h"

// 在此部分进行USB初始化
MX_USB_DEVICE_Init();

代码解释: MX_USB_DEVICE_Init() 函数是用户应用程序中实现USB设备初始化的函数,具体实现取决于具体的芯片型号和所使用的库。

2.1.2 如何在STM32上启用USB功能

启用STM32的USB功能一般涉及到几个步骤:

  • 配置USB时钟和引脚。
  • 初始化USB硬件外设。
  • 注册USB设备类或实现USB协议栈。

STM32CubeMX工具能够自动生成初始化代码,从而帮助开发人员轻松地配置USB功能。

// 简化的USB初始化伪代码
void MX_USB_Init(void) {
  // 1. 使能USB时钟
  __HAL_RCC_USB_CLK_ENABLE();
  // 2. 配置USB引脚
  // 此处需要根据实际硬件配置相应的GPIO
  // 3. 初始化USB硬件外设
  // 使用STM32CubeMX生成的初始化代码
  // 4. 注册USB设备类
  // 用户自定义代码,用于注册HID、Mass Storage等USB设备类
}

2.2 STM32的USB设备模式架构

在USB设备模式下,STM32芯片作为USB设备与主机通信,主要负责处理主机的控制指令和数据传输。其架构可分解为数据流和控制流程,以及固件编程要点。

2.2.1 设备模式下的数据流和控制流程

STM32作为USB设备模式时,USB数据流和控制流程如下:

  • 设备枚举过程:STM32响应主机发送的设备请求,包括获取设备描述符、配置描述符等。
  • 数据传输过程:STM32根据主机的请求发送或接收数据,遵循所注册设备类的协议规定。
graph LR
A[STM32 USB设备] -->|枚举| B[USB主机]
A -->|数据传输| B
B -->|设备请求| A
B -->|数据请求| A

该流程图展示了STM32在设备模式下与USB主机的交互过程。

2.2.2 STM32 USB设备端的固件编程要点

固件编程要点包括但不限于:

  • USB设备端的中断处理。
  • 控制端点的请求处理。
  • 数据端点的批量和中断传输处理。
  • 错误处理和重试机制。
// USB中断处理伪代码
void USB_IRQHandler(void) {
  // 检查是否是USB中断
  if(__HAL_USB_GET_FLAG(&hUsbDeviceFS, USB_FLAG_CTR)) {
    // 清除中断标志
    __HAL_USB_CLEAR_FLAG(&hUsbDeviceFS, USB_FLAG_CTR);
    // 处理控制端点请求
    USBD_Ctl.iso_in_state = 0;
    USBD_Ctl.iso_out_state = 0;
    USBD_Ctl.handler(&USBD_Device, USBD_Ctl.setup);
  }
}

代码逻辑解读:中断处理函数 USB_IRQHandler 检查USB中断标志位,并在确认是USB中断后清除标志位,接着调用控制端点处理函数。

2.3 USB设备模式下的电源管理

STM32芯片在USB设备模式下需要有效管理电源消耗,以优化能效并延长电池寿命。

2.3.1 STM32的USB电源管理策略

STM32的USB电源管理策略涉及:

  • 进入低功耗模式。
  • 监听USB活动并唤醒。
  • 根据USB事件(如SUSPEND、RESUME)切换电源状态。
// 进入低功耗模式伪代码
void Enter_Low_Power_Mode(void) {
  // 在USB暂停时进入低功耗模式
  if(USB悬起) {
    // 设置时钟和电源管理,进入低功耗模式
    HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
  }
}

代码逻辑解读:当USB设备检测到悬起事件时,通过调用 HAL_PWR_EnterSTOPMode 函数进入STOP模式,这是一种低功耗状态。

2.3.2 设备模式下的节能技术

节能技术的实现方法有:

  • 使用STM32的电源控制寄存器。
  • 利用USB的Suspend/Resume信号控制设备功耗。
  • 在软件中实现智能电源管理算法。
// 电源控制寄存器设置伪代码
void Set_Power_Control_Registers(void) {
  // 根据需要设置电源控制寄存器
  // 例如,启用或禁用某些外设的电源
}

代码逻辑解读:通过编程设置电源控制寄存器,可以在硬件层面控制各个外设模块的电源,从而实现更细致的电源管理。

结语

本章从STM32芯片的USB硬件支持开始,深入探讨了在设备模式下的架构特点、电源管理策略以及固件编程要点。通过逐步的分解,我们了解了USB设备模式的具体实现方法和优化技巧,这为下一章USB HID协议的介绍和应用开发打下了坚实的基础。

3. USB HID协议概述

3.1 HID协议的作用和特点

3.1.1 HID类设备的定义和应用场景

HID(Human Interface Device)类设备,顾名思义,是指那些与人类用户直接交互的电子设备。这类设备提供了一种简单而统一的方式来传递用户输入信息至主机,同时接收来自主机的控制信息。HID类设备广泛应用于我们的日常生活中,例如键盘、鼠标、游戏手柄、条码扫描器、触摸屏等。HID设备的设计初衷是简化和标准化输入设备的通信协议,使它们可以在各种操作系统上无缝工作,无需安装复杂的驱动程序。

HID协议被设计为“即插即用”(Plug and Play),这意味着用户在连接HID设备时,操作系统能自动识别该设备并安装必要的驱动程序,从而在短时间内开始使用设备。HID类设备的使用范围广泛,它们通常是低速或全速设备,数据传输需求不高,但对实时性和可靠性有着严格的要求。

3.1.2 HID协议的基本组成和数据交换流程

HID协议的核心组成包括:

  • HID报告描述符:定义了设备如何发送和接收数据。
  • HID输入报告:从HID设备发送到主机的数据。
  • HID输出报告:从主机发送到HID设备的数据。
  • HID特征报告:用于实现双向、非用户输入的通信。

数据交换流程大致如下:

  1. 设备连接和初始化:HID设备连接到主机后,操作系统识别该设备并发送一系列命令进行设备枚举,包括请求设备描述符、配置描述符和报告描述符。
  2. 报告描述符交换:操作系统分析报告描述符,以理解设备如何构造输入、输出和特征报告。
  3. 数据通信:一旦设备初始化完成,主机和设备之间就可以开始数据通信,通常是由主机周期性地轮询HID设备以获取输入报告,同时也可以发送输出报告给HID设备。
  4. 断开连接:设备断开连接时,操作系统会接收到一个通知,并进行清理工作,比如断开设备驱动的关联。

HID协议允许操作系统在几乎不干预的情况下处理数据,让设备制造商能够将主要精力放在设备的用户交互设计上,而无需担心底层通信协议的细节。

3.2 HID类设备通信协议细节

3.2.1 HID报告描述符的结构和解析

HID报告描述符是HID协议中非常关键的组成部分,它使用一组标准化的字段来定义设备的数据交换格式。报告描述符的结构如下:

  • 使用报告ID来唯一标识报告类型。
  • 使用项目列表来详细描述报告中的数据格式。
  • 每个项目可以定义数据字段的用途(如按键、数值或字符串)、长度、范围、间隔和偏移量等信息。

解析HID报告描述符通常需要对HID规范有深入理解。一个典型的解析过程包括以下步骤:

  1. 读取报告描述符:使用USB主机API函数读取HID设备的报告描述符数据。
  2. 分析项目字段:根据HID规范解析每个项目字段,提取出有用的信息,如数据项的数量、长度、用途等。
  3. 创建数据结构:基于解析出的信息,构建与报告描述符相匹配的数据结构,用于后续的数据处理。

示例代码片段如下(假设使用C语言和USB库):

// 假设device_report_descriptor是已从HID设备获取的报告描述符
uint8_t *device_report_descriptor;
// 获取报告描述符长度
int descriptor_length = ...;
// 解析报告描述符到结构体(结构体需要根据HID规范自定义)
HID_ReportDescriptor *parsed_descriptor = parse HID_report(device_report_descriptor, descriptor_length);

// 解析函数的逻辑分析
// parse HID_report()函数会遍历报告描述符的每个字节,根据HID规范中的定义,识别并构建出设备报告描述符的结构体。

3.2.2 HID设备的数据传输机制

HID设备的数据传输机制主要是基于报告的概念,数据在主机和设备之间以报告的形式进行交换。HID设备可以发送三种类型的报告:

  • 输入报告:由设备发送给主机,例如键盘的按键动作。
  • 输出报告:由主机发送给设备,用于控制设备,例如控制键盘的LED指示灯。
  • 特征报告:用于交换配置信息,这种报告的双向传输可以提供设备的额外功能,例如读取或设置游戏控制器的震动力度。

设备报告的格式在报告描述符中定义,主机通过特定的HID类请求与设备交换报告数据。主机通常使用USB中断传输来定时获取输入报告,确保输入数据的实时性和准确性。输出报告和特征报告通常是由主机来控制,当需要发送数据时,主机通过控制传输方式发送报告。

对于开发者来说,理解如何构建和解析HID报告是实现HID类设备开发的关键。

3.3 HID类设备的开发与调试

3.3.1 开发过程中需要注意的问题

在开发HID类设备时,有几点是特别需要注意的:

  • 设备的兼容性:确保设备能够兼容不同的操作系统和平台。
  • 报告描述符的正确性:报告描述符是设备与主机通信的基础,需要保证其正确无误。
  • 数据传输的实时性:HID设备对于数据传输的实时性有较高要求,要确保及时响应。
  • 电源管理:考虑到设备的电池寿命,需要合理设计电源管理策略。
  • 调试和测试:在开发过程中,需要对设备进行充分的调试和测试,确保其稳定性和可靠性。

3.3.2 常见的调试工具和方法

在开发HID类设备时,可以使用以下工具和方法来辅助调试:

  • USB分析仪:监控USB总线上的所有通信,有助于快速定位数据传输问题。
  • 逻辑分析仪:跟踪HID设备的硬件信号,有助于解决硬件相关的问题。
  • 专业调试软件:例如HIDmaker、HID Descriptor Tool等,用于生成和验证报告描述符。
  • 操作系统自带的调试工具:例如在Windows中可以使用HID监视器工具来监视HID设备和报告。

通过这些工具和方法,开发人员可以有效地跟踪和诊断HID设备的开发过程中的问题,确保最终产品的稳定性和可靠性。

在本章节的介绍中,我们通过详细地了解了USB HID协议的核心内容、通信协议细节,以及在开发过程中应该注意的问题。通过具体代码和工具的使用,相信读者能够更好地理解如何处理HID类设备的开发与调试工作。

4. STM32 USB例程修改技巧

4.1 STM32 USB库的安装与配置

4.1.1 如何下载和安装STM32 USB库

在进行STM32 USB相关的开发之前,首先需要下载和安装STM32 USB库。这一环节对于后续开发工作至关重要,因此需要遵循一定的步骤以确保安装过程顺利。

  1. 访问官方网站或库的存储库 :首先,访问ST官方网站或者STM32CubeMX下载页面,找到USB库的下载链接。STM32 USB库通常是作为STM32Cube的一部分提供。

  2. 下载对应版本 :根据开发板型号或者开发需求,选择合适版本的USB库下载。如果你使用的是STM32CubeMX工具,那么可以自动下载所需的库。

  3. 解压缩 :下载完成后,将库文件解压到本地目录。

  4. 集成到开发环境 :将解压后的库文件集成到你的IDE环境中。如果使用的是Keil MDK,可以通过Project—Options for Target—C/C++标签页中添加库文件路径。

  5. 配置项目 :在项目中加入USB库支持,可能需要在项目设置中添加库文件和头文件路径。

  6. 验证安装 :创建一个简单的USB例程,编译并下载到开发板上运行,如果一切正常,那么表明库安装成功。

4.1.2 配置STM32 USB库的环境变量

环境变量的配置是确保开发环境识别和正确加载USB库的关键步骤。这个过程可能会根据不同的操作系统和开发环境有所差异。

  1. 操作系统环境变量设置 :对于Windows系统,需要在系统属性的高级选项卡中设置环境变量。对于Linux或macOS,通常在shell配置文件中设置。

  2. 路径添加 :添加USB库源代码和头文件路径到环境变量中,这样编译器在编译过程中就能找到相应的文件。

  3. 确认环境变量设置 :重启开发环境,验证环境变量是否已经正确设置。在项目配置中检查库文件路径是否被正确识别。

  4. 开发环境设置 :在IDE中设置环境变量,如Keil中的“Options for Target”—“C/C++”标签页中可以指定库文件的路径。

  5. 测试配置 :为了测试环境变量配置是否成功,可以在代码中包含USB库的头文件并尝试编译,看是否会出现找不到文件的错误。

4.2 STM32 USB例程的分析与调整

4.2.1 理解现有USB例程的架构和流程

在着手修改STM32的USB例程之前,需要对现有例程的架构和流程有充分的了解。这包括对USB设备模式的固件编程要点和通信协议的理解。

  1. 阅读文档 :开始修改之前,仔细阅读STM32的USB库文档以及提供的例程,了解其设计意图和实现机制。

  2. 架构解析 :理解USB库的架构,包括其提供的抽象层、API接口和回调函数等。

  3. 流程图 :画出例程的工作流程图,以助于理解整个数据流向和控制逻辑。

  4. 实例分析 :通过分析一个简单的USB例程,比如HID键盘或鼠标例程,来获得整体的理解。

  5. 编译和运行 :下载例程到开发板上,观察其表现,与预期的工作流程进行比对。

4.2.2 针对不同需求修改例程的策略

一旦理解了例程的基本架构和流程,接下来就是根据实际需求对其进行修改。在这一部分,将讨论如何调整代码以适应不同的开发需求。

  1. 需求分析 :首先,明确你的修改需求。这可能涉及到数据传输的优化、功能的增加或减少等。

  2. 代码修改 :在代码中进行修改。这可能需要调整USB配置、添加新的回调函数、修改数据处理逻辑等。

  3. 代码注释 :在修改代码的同时,确保代码注释完整。这有助于其他开发者理解你的修改意图。

  4. 模块化处理 :对于大块的代码,考虑模块化处理,将复杂的逻辑分拆成小块,便于管理和维护。

  5. 测试验证 :修改代码后,进行充分的单元测试和集成测试,确保修改没有引入新的问题。

4.3 常见问题的解决方案

4.3.1 USB连接和枚举失败的排查

USB连接和枚举失败是开发中常见的问题,以下是排查和解决这些问题的步骤。

  1. 硬件检查 :首先检查USB连接线是否完好,以及硬件连接是否正确。

  2. 日志分析 :使用USB抓包工具或者查看开发板上的调试日志,分析枚举过程中的错误信息。

  3. 固件检查 :检查固件中的USB描述符是否正确配置,尤其是VID和PID是否与实际设备匹配。

  4. 库文件检查 :确认使用的USB库文件是否是最新的,或者是否与开发板硬件兼容。

  5. 系统配置 :检查操作系统是否已经安装了正确的USB设备驱动。

4.3.2 传输速率和稳定性问题的应对

在USB开发中,传输速率和稳定性是保证产品质量的重要因素。针对这些问题,可以采取以下策略。

  1. 传输优化 :针对不同的USB传输类型(控制、批量、中断或同步),选择合适的缓冲区大小和传输策略。

  2. 固件优化 :在固件中合理安排任务执行顺序,避免在USB通信任务中进行重计算或复杂操作。

  3. 驱动优化 :确保USB设备驱动是最新的,并针对系统环境进行优化。

  4. 硬件升级 :对于一些不可解决的稳定性问题,可能需要考虑硬件方面的升级,如使用高速USB控制器。

  5. 压力测试 :进行压力测试,模拟在高负荷下设备的表现,找出性能瓶颈并进行优化。

通过上述步骤,可以对STM32 USB例程进行有效的修改和优化,以满足特定的开发需求。在实践过程中,开发者应持续测试和调整,以达到最佳性能。

5. 实战应用案例分析

5.1 构建一个USB HID键盘应用

构建一个USB HID(人机接口设备)键盘应用是一个复杂的工程项目,涉及硬件选择、固件编程、系统配置等多个方面。我们需要确保我们的USB设备被操作系统正确识别为一个键盘,然后处理按键事件,最终将这些事件发送给主机。

5.1.1 设计USB HID键盘的工作流程

首先,设计一个USB HID键盘的工作流程,需要明确以下几个步骤:

  1. 设计电路和选择合适的微控制器(如STM32);
  2. 在微控制器上编写固件,实现USB HID类设备规范;
  3. 配置STM32的USB设备模式和HID端点;
  4. 编写代码处理键盘输入,并将其格式化为HID报告;
  5. 在主机上测试键盘功能,确保输入能够正确反映。

5.1.2 编程实现键盘的输入功能

为了实现键盘的输入功能,我们需要关注以下几个核心部分:

  • 初始化USB设备为HID类设备;
  • 实现键盘扫描矩阵的读取和按键事件的检测;
  • 将按键事件转换成HID报告并通过USB发送。
// 示例代码片段:初始化USB为HID类设备
#include "usb_device.h"

USBDevice医疗器械;

void USB_initHID() {
    // 这里需要初始化USB设备,设置为HID类
    // 在STM32中,这通常涉及配置USB硬件寄存器
    // 并且调用USB库提供的初始化函数
}

void sendHIDReport(uint8_t* reportBuffer, uint16_t reportSize) {
    // 将HID报告发送到主机
    // 这里需要调用STM32 USB库中提供的相关函数
}

// 在主循环中处理按键事件并发送HID报告
for (;;) {
    // 假设getKeypadInput()为从键盘矩阵读取输入的函数
    uint8_t input = getKeypadInput();
    // 假设createHIDReport()为根据按键输入生成HID报告的函数
    uint8_t reportBuffer[8];
    createHIDReport(reportBuffer, input);

    sendHIDReport(reportBuffer, 8);
}

接下来,我们需要针对STM32的USB库进行编程,实现上述流程。

5.2 枚举过程详解与实战应用

5.2.1 详细解析USB设备的枚举过程

USB设备枚举过程是USB通信中一个关键步骤。在枚举过程中,主机发现新设备、下载设备描述符、配置设备,并最终使设备投入使用。这个过程通常包括以下几个阶段:

  1. 设备复位和地址分配;
  2. 下载设备描述符;
  3. 配置设备;
  4. 设备可用。

5.2.2 在实战中优化枚举效率和兼容性

为了优化枚举效率和兼容性,我们可以采取以下措施:

  • 确保USB描述符符合标准且无错误;
  • 合理配置设备的端点缓冲区大小;
  • 使用可靠的连接和通信协议,例如USB 2.0高速模式;
  • 在固件中实现适当的超时和重试机制。
// 示例代码片段:USB描述符的配置
// USB Device Descriptor
__ALIGN_BEGIN static uint8_t USBD_DeviceDesc[USB_LEN_DEV_DESC] __ALIGN_END = {
    0x12,                         // bLength
    USB DESC_TYPE_DEVICE,         // bDescriptorType
    0x0200,                       // bcdUSB
    0x02,                         // bDeviceClass
    0x00,                         // bDeviceSubClass
    0x00,                         // bDeviceProtocol
    USB_MAX_EP0_SIZE,             // bMaxPacketSize
    LOBYTE(USBD_VendorID),        // idVendor
    HIBYTE(USBD_VendorID),        // idVendor
    LOBYTE(USBD_ProductID),       // idProduct
    HIBYTE(USBD_ProductID),       // idProduct
    0x0000,                       // bcdDevice rel. 2.00
    USBD_IDX_MFC_STR,             // Index of manufacturer string
    USBD_IDX_PRODUCT_STR,         // Index of product string
    USBD_IDX_SERIAL_STR,          // Index of serial number string
    USBD_MAX_NUM_CONFIGURATION   // bNumConfigurations
};

// 其他描述符配置...

通过上述步骤,我们可以提高设备的枚举效率和改善与不同主机的兼容性。

5.3 调试与优化方法

5.3.1 使用调试工具分析问题

使用调试工具是USB开发过程中的重要一步。我们可以通过以下方式使用调试工具:

  • 使用逻辑分析仪捕获USB通信数据;
  • 使用集成开发环境中的调试器单步执行代码;
  • 使用USB抓包软件分析数据传输。

5.3.2 对系统性能和稳定性进行优化

对系统性能和稳定性的优化,我们考虑以下几个方面:

  • 精简代码,减少不必要的CPU占用和内存使用;
  • 优化中断处理和调度机制,减少响应时间;
  • 检查并修复潜在的电源管理问题,避免不稳定因素;
  • 通过固件升级处理已知的兼容性问题。

通过这些方法,我们可以确保USB HID键盘应用既稳定又高效,满足用户的需求。

在上述章节中,我们深入了解了如何构建USB HID键盘应用,并且涵盖了从枚举过程到调试优化的关键技术点。这些知识和经验,对IT和相关行业从业者的实战应用具有重要参考价值。

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

简介:本文作者分享了通过STM32微控制器实现USB设备端HID类协议的编程经验。介绍了USB基础知识、STM32与USB的结合、USB HID协议要点、例程修改、枚举过程、实战应用以及调试与优化。强调了理论与实践结合的重要性,并通过具体案例说明了如何创建自定义USB设备,如定制化的输入设备或数据传输工具。


本文还有配套的精品资源,点击获取
menu-r.4af5f7ec.gif

您可能感兴趣的与本文相关内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值