STM32F4学习笔记(一):GPIO配置

        STM32F4的GPIO区别与F1的GPIO配置,每个 I/O 端口位均可自由编程,但 I/O 端口寄存器必须按 32 位字、半字或字节进行访问。 GPIOx_BSRR 寄存器旨在实现对 GPIO ODR 寄存器进行原子读取/修改访问。这样便可确保 在读取和修改访问之间发生中断请求也不会有问题。

        GPIO端口包括 4 个 32 位配置寄存器(GPIOx_MODER、GPIOx_OTYPER、GPIOx_OSPEEDR 和 GPIOx_PUPDR)、2 个 32 位数据寄存器(GPIOx_IDR 和 GPIOx_ODR)、1 个 32 位置位/复位寄存器 (GPIOx_BSRR)、1 个 32 位锁定寄存器 (GPIOx_LCKR) 和 2 个 32 位复用功能选择寄存器(GPIOx_AFRH 和 GPIOx_AFRL)。

一、 GPIO寄存器(端口控制  数据输入输出 置位/复位 锁定 复用)

        I/O 端口控制寄存器
        GPIO 有 4 个 32 位存储器映射的控制寄存器(GPIOx_MODER、GPIOx_OTYPER、 GPIOx_OSPEEDR、GPIOx_PUPDR),可配置多达 16 个 I/O。

        GPIOx_MODER 寄存器用于 选择 I/O 方向(输入、输出、AF、模拟)。 

        MODERy[1:0]:端口 x 配置位 (Port x configuration bits) (y = 0..15)
        这些位通过软件写入,用于配置 I/O 方向模式。
        00:输入(复位状态)
        01:通用输出模式
        10:复用功能模式
        11:模拟模式

        GPIOx_OTYPERGPIOx_OSPEEDR 寄存器分 别用于选择输出类型(推挽或开漏)和速度 (无论采用哪种 I/O 方向,都会直接将 I/O 速度引 脚连接到相应的 GPIOx_OSPEEDR 寄存器位)。无论采用哪种 I/O 方向,GPIOx_PUPDR 寄 存器都用于选择上拉/下拉。

        输出类型配置寄存器OTy[1:0]:端口 x 配置位 (Port x configuration bits) (y = 0..15)
        这些位通过软件写入,用于配置 I/O 端口的输出类型。
        0:输出推挽(复位状态)
        1:输出开漏

        输出速度配置寄存器OSPEEDRy[1:0]:端口 x 配置位 (Port x configuration bits) (y = 0..15)
        这些位通过软件写入,用于配置 I/O 输出速度。
        00:2 MHz(低速)
        01:25 MHz(中速)
        10:50 MHz(快速)
        11:30 pF 时为 100 MHz(高速)(15 pF 时为 80 MHz 输出(最大速度))

        端口上拉/下拉寄存器PUPDRy[1:0]:端口 x 配置位 (Port x configuration bits) (y = 0..15)
        这些位通过软件写入,用于配置 I/O 上拉或下拉。
        00:无上拉或下拉
        01:上拉
        10:下拉
        11:保留


        I/O 端口数据寄存器
        每个 GPIO 都具有 2 个 16 位数据寄存器:输入和输出数据寄存器(GPIOx_IDR GPIOx_ODR)。GPIOx_ODR 用于存储待输出数据,可对其进行读/写访问。通过 I/O 输入的数据存储到输入数据寄存器 (GPIOx_IDR) 中,它是一个只读寄存器。

        端口输入寄存器IDRy[15:0]:端口输入数据 (Port input data) (y = 0..15)
        这些位为只读形式,只能在字模式下访问。它们包含相应 I/O 端口的输入值。

        端口输出寄存器IODRy[15:0]:端口输出数据 (Port output data) (y = 0..15)
        这些位可通过软件读取和写入。
        注意: 对于原子置位 /复位,通过写入 GPIOx_BSRR 寄存器,可分别对 ODR 位进行置位和复位 (x = A..I/)。

     I/O 数据位操作       

        端口置位/复位寄存器GPIOx_BSRR

        BRy:端口 x 复位位 y (Port x reset bit y) (y = 0..15)
        这些位为只写形式,只能在字、半字或字节模式下访问。读取这些位可返回值 0x0000。
        0:不会对相应的 ODRx 位执行任何操作
        1:对相应的 ODRx 位进行复位
        注意: 如果同时对 BSx 和 BRx 置位,则 BSx 的优先级更高。
        位 15:0 BSy:端口 x 置位位 y (Port x set bit y) (y= 0..15)
        这些位为只写形式,只能在字、半字或字节模式下访问。读取这些位可返回值 0x0000。
        0:不会对相应的 ODRx 位执行任何操作
        1:对相应的 ODRx 位进行置位

    I/O锁定机制

        GPIO 端口配置锁定寄存器 (GPIOx_LCKR) (x = A..I)
        GPIO port configuration lock register
        当正确的写序列应用到第 16 位 (LCKK) 时,此寄存器将用于锁定端口位的配置。位 [15:0] 的 值用于锁定 GPIO 的配置。在写序列期间,不能更改 LCKR[15:0] 的值。将 LOCK 序列应用 到某个端口位后,在执行下一次复位之前,将无法对该端口位的值进行修改。
        注意:可使用特定的写序列对 GPIOx_LCKR 寄存器执行写操作。在此写序列期间只允许使用字访问 (32 位长)。
每个锁定位冻结一个特定的配置寄存器(控制寄存器和复用功能寄存器)。

        LCKK[16]:锁定键 (Lock key)
        可随时读取此位。可使用锁定键写序列对其进行修改。
        0:端口配置锁定键未激活。
        1:端口配置锁定键已激活。直到 MCU 复位时,才锁定 GPIOx_LCKR 寄存器。
        锁定键写序列:
        WR LCKR[16] = ‘1’ + LCKR[15:0]
        WR LCKR[16] = ‘0’ + LCKR[15:0]
        WR LCKR[16] = ‘1’ + LCKR[15:0]
        RD LCKR
        RD LCKR[16] = ‘1’(此读操作为可选操作,但它可确认锁定已激活)
        注意: 在锁定键写序列期间,不能更改 LCK[15:0] 的值。
        锁定序列中的任何错误都将中止锁定操作。
        在任一端口位上的第一个锁定序列之后,对 LCKK 位的任何读访问都将返回“1”,直
        到下一次 CPU 复位为止。
        位 15:0 LCKy:端口 x 锁定位 y (Port x lock bit y) (y= 0..15)
        这些位都是读/写位,但只能在 LCKK 位等于“0”时执行写操作。
        0:端口配置未锁定
        1:端口配置已锁定

        GPIO 复用功能低位寄存器 (GPIOx_AFRL) (x = A..I)       GPIO 复用功能高位寄存器 (GPIOx_AFRH) (x = A..I)

        AFRHy:端口 x 位 y 的复用功能选择 (Alternate function selection for port x bit y) (y = 8.0.15)
        这些位通过软件写入,用于配置复用功能 I/O。
        AFRHy 选择:
        0000:AF0      0001:AF1       0010:AF2       0011:AF3 
        0100:AF4      0101:AF5       0110:AF6       0111:AF7
        1000:AF8      1001:AF9       1010:AF10    1011:AF11
        1100:AF12    1101:AF13     1110:AF14     1111:AF15

二、GPIO框图解析

        通过GPIO 硬件结构框图,就可以从整体上深入了解GPIO 外设及它的各种应用模式。该图从最右端看起,最右端就是代表STM32 芯片引出的GPIO 引脚,其余部件都位于芯片内部。

     1. 保护二极管及上、下拉电阻

        引脚的两保护个二级管可以防止引脚外部过高或过低的电压输入,当引脚电压高于VDD_FT 时,上方的二极管导通,当引脚电压低于VSS 时,下方的二极管导通,防止不正常电压引入芯片导致芯片烧毁。尽管有这样的保护,并不意味着STM32 的引脚能直接外接大功率驱动器件,如直接驱动电机,强制驱动要么电机不转,要么导致芯片烧坏,必须要加大功率及隔离电路驱动。具体电压、电流范围可查阅《STM32F4xx 规格书》。
        上拉、下拉电阻,从它的结构我们可以看出,通过上、下拉对应的开关配置,我们可以控制引脚默认状态的电压,开启上拉的时候引脚电压为高电平,开启下拉的时候引脚电压为低电平,这样可以消除引脚不定状态的影响。如引脚外部没有外接器件,或者外部的器件不干扰该引脚电压时,STM32 的引脚都会有这个默认状态。 也可以设置“既不上拉也不下拉模式”,我们也把这种状态称为浮空模式,配置成这个模式时,直接用电压表测量其引脚电压为1 点几伏,这是个不确定值。所以一般来说我们都会选择给引脚设置“上拉模式”或“下拉模式”使它有默认状态。
        STM32 的内部上拉是“弱上拉”,即通过此上拉输出的电流是很弱的,如要求大电流还是需要外部上拉。
通过“上拉/下拉寄存器GPIOx_PUPDR”控制引脚的上、下拉以及浮空模式。

     2. P-MOS 管和N-MOS 管

        GPIO 引脚线路经过上、下拉电阻结构后,向上流向“输入模式”结构,向下流向“输出模式”结构。先看输出模式部分,线路经过一个由P-MOS 和N-MOS 管组成的单元电路。这个结构使GPIO 具有了“推挽输出”和“开漏输出”两种模式。
        所谓的推挽输出模式,是根据这两个MOS 管的工作方式来命名的。在该结构中输入高电平时,上方的P-MOS 导通,下方的N-MOS 关闭,对外输出高电平;而在该结构中输入低电平时,N-MOS 管导通,P-MOS 关闭,对外输出低电平。当引脚高低电平切换时,两个管子轮流导通,一个负责灌电流,一个负责拉电流,使其负载能力和开关速度都比普通的方式有很大的提高。推挽输出的低电平为0 伏,高电平为3.3 伏,参考图 7-2 左侧,它是推挽输出模式时的等效电路。

        而在开漏输出模式时,上方的P-MOS 管完全不工作。如果我们控制输出为0,低电平,则P-MOS 管关闭,N-MOS 管导通,使输出接地,若控制输出为1 (它无法直接输出高电平)时,则P-MOS 管和N-MOS 管都关闭,所以引脚既不输出高电平,也不输出低电平,为高阻态。为正常使用时必须接上拉电阻(可用STM32 的内部上拉,但建议在STM32 外部再接一个上拉电阻),参考图 7-2 中的右侧等效电路。它具“线与”特性,也就是说,若有很多个开漏模式引脚连接到一起时,只有当所有引脚都输出高阻态,才由上拉电阻提供高电平,此高电平的电压为外部上拉电阻所接的电源的电压。若其中一个引脚为低电平,那线路就
相当于短路接地,使得整条线路都为低电平,0 伏。推挽输出模式一般应用在输出电平为0 和3.3 伏而且需要高速切换开关状态的场合。
        在STM32 的应用中,除了必须用开漏模式的场合,我们都习惯使用推挽输出模式。 开漏输出一般应用在I2C、SMBUS 通讯等需要“线与”功能的总线电路中。除此之外,还用在电平不匹配的场合,如需要输出5 伏的高电平,就可以在外部接一个上拉电阻,上拉电源为5 伏,并且把GPIO 设置为开漏模式,当输出高阻态时,由上拉电阻和电源向外输出5 伏的电平。
        通过 “输出类型寄存器GPIOx_OTYPER”可以控制GPIO 端口是推挽模式还是开漏模式。

     3. 输出数据寄存器

        前面提到的双MOS 管结构电路的输入信号,是由GPIO“输出数据寄存器GPIOx_ODR”提供的,因此我们通过修改输出数据寄存器的值就可以修改GPIO 引脚的输出电平。而“置位/复位寄存器GPIOx_BSRR”可以通过修改输出数据寄存器的值从而影响电路的输出。

     4. 复用功能输出

        “复用功能输出”中的“复用”是指STM32 的其它片上外设对GPIO 引脚进行控制,此时GPIO 引脚用作该外设功能的一部分,算是第二用途。从其它外设引出来的“复用功能输出信号”与GPIO 本身的数据据寄存器都连接到双MOS 管结构的输入中,通过图中的梯形结构作为开关切换选择。
        例如我们使用USART 串口通讯时,需要用到某个GPIO 引脚作为通讯发送引脚,这个时候就可以把该GPIO 引脚配置成USART 串口复用功能,由串口外设控制该引脚,发送数据。

     5. 输入数据寄存器

        看GPIO 结构框图的上半部分,它是GPIO 引脚经过上、下拉电阻后引入的,它连接到施密特触发器,信号经过触发器后,模拟信号转化为0、1 的数字信号,然后存储在“输入数据寄存器GPIOx_IDR”中,通过读取该寄存器就可以了解GPIO 引脚的电平状态。

     6. 复用功能输入

        与“复用功能输出”模式类似,在“复用功能输出模式”时,GPIO 引脚的信号传输到STM32 其它片上外设,由该外设读取引脚状态。
        同样,如我们使用USART 串口通讯时,需要用到某个GPIO 引脚作为通讯接收引脚,这个时候就可以把该GPIO 引脚配置成USART 串口复用功能,使USART 可以通过该通讯引脚的接收远端数据。

     7. 模拟输入输出

        当GPIO 引脚用于ADC 采集电压的输入通道时,用作“模拟输入”功能,此时信号是不经过施密特触发器的,因为经过施密特触发器后信号只有0、1 两种状态,所以ADC 外设要采集到原始的模拟信号,信号源输入必须在施密特触发器之前。类似地,当GPIO 引脚用于DAC 作为模拟电压输出通道时,此时作为“模拟输出”功能,DAC 的模拟信号输出就不经过双MOS 管结构了,在GPIO 结构框图的右下角处,模拟信号直接输出到引脚。同时,当GPIO 用于模拟功能时(包括输入输出),引脚的上、下拉电阻是不起作用的,这个时候即使在寄存器配置了上拉或下拉模式,也不会影响到模拟信号的输入输出。

三、GPIO工作模式

    1. 输入模式(上拉/下拉/浮空)

       在输入模式时,施密特触发器打开,输出被禁止。数据寄存器每隔1 个AHB1 时钟周期更新一次,可通过输入数据寄存器GPIOx_IDR 读取I/O 状态。其中AHB1 的时钟如按默认配置一般为180MHz。
       用于输入模式时,可设置为上拉、下拉浮空模式。

        

    2. 输出模式(推挽/开漏,上拉/下拉)

       在输出模式中,输出使能,推挽模式时双MOS 管以方式工作,输出数据寄存器GPIOx_ODR 可控制I/O 输出高低电平。开漏模式时,只有N-MOS 管工作,输出数据寄存器可控制I/O 输出高阻态或低电平。输出速度可配置,有2MHz\25MHz\50MHz\100MHz 的选项。此处的输出速度即I/O 支持的高低电平状态最高切换频率,支持的频率越高,功耗越大,如果功耗要求不严格,把速度设置成最大即可。
       此时施密特触发器是打开的,即输入可用,通过输入数据寄存器GPIOx_IDR 可读取I/O 的实际状态。
       用于输出模式时,可使用上拉、下拉模式或浮空模式。但此时由于输出模式时引脚电平会受到ODR 寄存器影响,而ODR 寄存器对应引脚的位为0,即引脚初始化后默认输出低电平,所以在这种情况下,上拉只起到小幅提高输出电流能力,但不会影响引脚的默认状态(弱上拉)。

     

    3. 复用功能(推挽/开漏,上拉/下拉)

       复用功能模式中,输出使能,输出速度可配置,可工作在开漏及推挽模式,但是输出信号源于其它外设,输出数据寄存器GPIOx_ODR 无效;输入可用,通过输入数据寄存器可获取I/O 实际状态,但一般直接用外设的寄存器来获取该数据信号。

       用于复用功能时,可使用上拉、下拉模式或浮空模式。同输出模式,在这种情况下,初始化后引脚默认输出低电平,上拉只起到小幅提高输出电流能力,但不会影响引脚的默认状态(弱上拉)。

       

4. 模拟输入输出

        模拟输入输出模式中,双MOS 管结构被关闭,施密特触发器停用,上/下拉也被禁止。其它外设通过模拟通道进行输入输出。
        通过对GPIO 寄存器写入不同的参数,就可以改变GPIO 的应用模式,再强调一下,要了解具体寄存器时一定要查阅《STM32F4xx 参考手册》中对应外设的寄存器说明。在GPIO 外设中,通过设置“模式寄存器GPIOx_MODER”可配置GPIO 的输入/输出/复用/模拟模式,“输出类型寄存器GPIOx_OTYPER”配置推挽/开漏模式,配置“输出速度寄存器GPIOx_OSPEEDR”可选2/25/50/100MHz 输出速度,“上/下拉寄存器GPIOx_PUPDR”可配置上拉/下拉/浮空模式,各寄存器的具体参数值见表 7-1。


     注意:在模拟配置中,I/O 引脚不能为 5 V 容忍
     图 23 说明了 I/O 端口位的高阻态模拟输入配置。

     

四、HAL库GPIO配置

 /** 
   * @brief GPIO 初始化结构体类型定义  
   */ 
 typedef struct
 {
     uint32_t Pin;       /*!< 指定要配置的GPIO引脚 */
 
     uint32_t Mode;      /*!< 指定所选引脚的工作模式 */
 
     uint32_t Pull;      /*!< 指定所选引脚的上拉或下拉激活 */
 
     uint32_t Speed;     /*!< 指定所选引脚的速度 */
 
     uint32_t Alternate;  /*!< 要连接到所选引脚的外设 */
 }GPIO_InitTypeDef;


00163 /**
00164   * @brief  Initializes the GPIOx peripheral according to the specified parameters in the GPIO_Init.
00165   * @param  GPIOx where x can be (A..K) to select the GPIO peripheral for STM32F429X device or
00166   *         x can be (A..I) to select the GPIO peripheral for STM32F40XX and STM32F427X devices.
00167   * @param  GPIO_Init pointer to a GPIO_InitTypeDef structure that contains
00168   *         the configuration information for the specified GPIO peripheral.
00169   * @retval None
00170   */
00171 void HAL_GPIO_Init(GPIO_TypeDef  *GPIOx, GPIO_InitTypeDef *GPIO_Init)
00172 {
00173   uint32_t position;
00174   uint32_t ioposition = 0x00U;
00175   uint32_t iocurrent = 0x00U;
00176   uint32_t temp = 0x00U;
00177 
00178   /* Check the parameters 断言检测输入参数 */
00179   assert_param(IS_GPIO_ALL_INSTANCE(GPIOx));
00180   assert_param(IS_GPIO_PIN(GPIO_Init->Pin));
00181   assert_param(IS_GPIO_MODE(GPIO_Init->Mode));
00182   assert_param(IS_GPIO_PULL(GPIO_Init->Pull));
00183 
00184   /* Configure the port pins 配置GPIO引脚 */
00185   for(position = 0U; position < GPIO_NUMBER; position++)
00186   {
00187     /*以下运算是为了通过 GPIO_InitStruct->GPIO_Pin 算出引脚号0-15*/ 
          /*经过运算后pos的pinpos位为1,其余为0,与GPIO_Pin_x宏对应。pinpos变量每次循环加1,*/
00188     ioposition = 0x01U << position;
00189     /* pos与GPIO_InitStruct->Pin做 & 运算,若运算结果currentpin == pos,
          则表示GPIO_InitStruct->Pin的pinpos位也为1,
          从而可知pinpos就是GPIO_InitStruct->Pin对应的引脚号:0-15*/
00190     iocurrent = (uint32_t)(GPIO_Init->Pin) & ioposition;
00191 
00192     if(iocurrent == ioposition)
00193     {
00194       /*--------------------- GPIO Mode Configuration ------------------------*/
00195       /* In case of Alternate function mode selection */
            /* 在复用功能模式选择的情况下 */
00196       if((GPIO_Init->Mode == GPIO_MODE_AF_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_OD))
00197       {
00198         /* Check the Alternate function parameter */
00199         assert_param(IS_GPIO_AF(GPIO_Init->Alternate));
00200         /* Configure Alternate function mapped with the current IO */
              /* 配置与当前IO映射的备用功能 */
00201         temp = GPIOx->AFR[position >> 3U];
00202         temp &= ~(0xFU << ((uint32_t)(position & 0x07U) * 4U)) ;
00203         temp |= ((uint32_t)(GPIO_Init->Alternate) << (((uint32_t)position & 0x07U) * 4U));
00204         GPIOx->AFR[position >> 3U] = temp;
00205       }
00206 
00207       /* Configure IO Direction mode (Input, Output, Alternate or Analog) */
            /* 配置IO方向模式(输入,输出,复用或模拟) */
00208       temp = GPIOx->MODER;
00209       temp &= ~(GPIO_MODER_MODER0 << (position * 2U));
00210       temp |= ((GPIO_Init->Mode & GPIO_MODE) << (position * 2U));
00211       GPIOx->MODER = temp;
00212 
00213       /* In case of Output or Alternate function mode selection */
            /* 在输出或复用功能模式选择的情况下 */
00214       if((GPIO_Init->Mode == GPIO_MODE_OUTPUT_PP) || (GPIO_Init->Mode == GPIO_MODE_AF_PP) ||
00215          (GPIO_Init->Mode == GPIO_MODE_OUTPUT_OD) || (GPIO_Init->Mode == GPIO_MODE_AF_OD))
00216       {
00217         /* Check the Speed parameter */
00218         assert_param(IS_GPIO_SPEED(GPIO_Init->Speed));
00219         /* Configure the IO Speed */
              /* 配置速度参数 */
00220         temp = GPIOx->OSPEEDR; 
00221         temp &= ~(GPIO_OSPEEDER_OSPEEDR0 << (position * 2U));
00222         temp |= (GPIO_Init->Speed << (position * 2U));
00223         GPIOx->OSPEEDR = temp;
00224 
00225         /* Configure the IO Output Type */
              /* 配置IO输出类型 */
00226         temp = GPIOx->OTYPER;
00227         temp &= ~(GPIO_OTYPER_OT_0 << position) ;
00228         temp |= (((GPIO_Init->Mode & GPIO_OUTPUT_TYPE) >> 4U) << position);
00229         GPIOx->OTYPER = temp;
00230       }
00231 
00232       /* Activate the Pull-up or Pull down resistor for the current IO */
            /* 激活当前IO的上拉或下拉电阻 */
00233       temp = GPIOx->PUPDR;
00234       temp &= ~(GPIO_PUPDR_PUPDR0 << (position * 2U));
00235       temp |= ((GPIO_Init->Pull) << (position * 2U));
00236       GPIOx->PUPDR = temp;
00237 
00238       /*--------------------- EXTI Mode Configuration ------------------------*/
00239       /* Configure the External Interrupt or event for the current IO */
            /* 配置外部中断或事件为IO触发源 */
00240       if((GPIO_Init->Mode & EXTI_MODE) == EXTI_MODE)
00241       {
00242         /* Enable SYSCFG Clock */
00243         __HAL_RCC_SYSCFG_CLK_ENABLE();
00244 
00245         temp = SYSCFG->EXTICR[position >> 2U];
00246         temp &= ~(0x0FU << (4U * (position & 0x03U)));
00247         temp |= ((uint32_t)(GPIO_GET_INDEX(GPIOx)) << (4U * (position & 0x03U)));
00248         SYSCFG->EXTICR[position >> 2U] = temp;
00249 
00250         /* Clear EXTI line configuration */
              /* 清除中断线配置 */
00251         temp = EXTI->IMR;
00252         temp &= ~((uint32_t)iocurrent);
00253         if((GPIO_Init->Mode & GPIO_MODE_IT) == GPIO_MODE_IT)
00254         {
00255           temp |= iocurrent;
00256         }
00257         EXTI->IMR = temp;
00258 
00259         temp = EXTI->EMR;
00260         temp &= ~((uint32_t)iocurrent);
00261         if((GPIO_Init->Mode & GPIO_MODE_EVT) == GPIO_MODE_EVT)
00262         {
00263           temp |= iocurrent;
00264         }
00265         EXTI->EMR = temp;
00266 
00267         /* Clear Rising Falling edge configuration */
              /* 清除上升下降沿配置 */
00268         temp = EXTI->RTSR;
00269         temp &= ~((uint32_t)iocurrent);
00270         if((GPIO_Init->Mode & RISING_EDGE) == RISING_EDGE)
00271         {
00272           temp |= iocurrent;
00273         }
00274         EXTI->RTSR = temp;
00275 
00276         temp = EXTI->FTSR;
00277         temp &= ~((uint32_t)iocurrent);
00278         if((GPIO_Init->Mode & FALLING_EDGE) == FALLING_EDGE)
00279         {
00280           temp |= iocurrent;
00281         }
00282         EXTI->FTSR = temp;
00283       }
00284     }
00285   }
00286 }
00287 

 

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值