WS2812B彩灯 STM32库函数开发:PWM+DMA(stm32f407VET6)

1、概述

WS2812B是一种常见的RGB LED灯带,每个灯珠内部都有一个芯片控制,通过发送特定的时序数据来控制其亮灭。发送数据时,需要按照一定的时序发送24位RGB数据,其中高位在前低位在后,格式为GRB。发送数据时,需要注意不仅仅是发送高电平或低电平,而是要发送占空比不同的PWM波,比如给予一定的高电平和低电平时间。重置码是发送一个持续280us的低电平信号。可以先发送一组24位的数据,然后接一个重置信号表示一组结束。数据采用单总线,归零码的通讯方式, 每个像素点接收24bit数据,溢出的数据传输给下一个像素点。

WS2812B作为一种常见的RGB LED(三色LED)驱动芯片,具有以下优点和缺点:
优点:

  • 集成度高:WS2812B芯片将RGB LED和控制电路集成在一个小型封装中,简化了设计和布线过程。
  • 控制灵活:每个WS2812B芯片都具有独立的控制电路,可以通过单线串联多个LED,并根据需要独立控制每个LED的颜色和亮度。
  • 易于编程:WS2812B芯片与微控制器通信采用简单的串行通信协议,使得编程和控制相对容易。
  • 色彩丰富:每个WS2812B芯片都能够显示256级亮度的红、绿、蓝三个颜色通道,通过调整三个颜色的亮度可以实现丰富多彩的效果。

缺点:

  • 电源需求高:WS2812B芯片对电源的要求较高,供电电源需要稳定而强大,以保证每个芯片的正常工作。
  • 刷新频率限制:由于通信协议的限制,WS2812B的刷新频率相对较低,控制大量LED时可能会出现刷新延迟。
  • 单点故障影响范围大:因为WS2812B芯片串联连接,当某个芯片发生故障时,可能会影响整个串联链路的正常工作。

2、芯片级联方法

典型应用电路:其硬件电路仅需要三根线(5V电源线、GND、DI信号线)。其仅需要一个具有定时器PWM输出功能的GPIO口,即可对多个灯进行控制。
在这里插入图片描述

数据传输示意图:下图中 D1 为 MCU 端发送的数据,D2、D3、D4 为级联电路自动整形转发的数据。
在这里插入图片描述

3、数据传输特性

在这里插入图片描述
如上图所示,当数据线传入灯带后,第一个灯珠截取第一个24位数据自己使用,而后会将其余的数据进行整形后发送给第二颗灯珠,第二颗灯珠会依次截取24位数据并对剩余数据进行整形发送,以此类推。直到最后一组数据被显示为止。每一组24位数根据数据的不同显示不同的颜色和亮度(每个像素点的三基色颜色可实现256级亮度显示, 完成16777216种颜色的全真色彩显示)。
在这里插入图片描述

4、程序实例

根据其电位控制要求,通过软件实现IO控制模拟0码和1码并进行数据传输在理论上是可以实现的,但是在实际过程中,会过于占用CPU资源,所以我们这里采用TIM1+PWM+DMA的控制方式。
通过控制PWM占空比发送0码和1码,额定周期为1.25us,则频率为800Khz
0码PWM占空比:
(0码高电平时间)/(周期)—> 0.4 / 1.25 = 0.32
用占空比乘以定时器重装值加一就是0码的CCR值(代表PWM高电平计数个数)—>
0.32 * (209+1) = 67.2(我实际使用的60,左右相差不太大都可正常使用)
1码PWM占空比:
(1码高电平时间)/(周期)—> 0.8 / 1.25 = 0.64
用占空比乘以定时器重装值加一就是1码的CCR值(代表PWM高电平计数个数)—>
0.64 * (209+1) = 134.4(我实际使用的130,左右相差不太大都可正常使用)

4.1、硬件电路

我在电路设计中,是使用的PE13作为WS2812B的控制引脚,
根据芯片手册可知,PE13是TIM1的CH3通道

在这里插入图片描述

4.2、定时器初始化

下面是定时器1的CH3(PE13)输出PWM的初始化代码
我这里使用的是STM32F407VET6,配置的系统时钟为168MHZ,可根据时钟更改TIM_TimeBaseStructure.TIM_Period的值来修改定时器周期(168MHZ / 210 = 800KHZ)

/*
*函数名称:Timer1_Init
*功能描述:配置TIM1_CH3输出PWM
*传入参数:无
*返回值  :无
*/
void Timer1_Init(void)
{
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);      /*使能GPIOE时钟*/
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);       /*使能TIM1时钟*/

  GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_TIM1);   /*将GPIOE13重映射到TIM1的输出通道上*/
	
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;               /*将引脚功能配置为复用*/
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;               /*推挽输出*/
  GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;                 /*上拉*/
  GPIO_Init(GPIOE, &GPIO_InitStructure);
   
	/* 定时器周期 : T =(arr + 1) * (PSC + 1) / Tck.   arr:周期值 PSC:预分频值  Tck: 系统时钟频率 */
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  TIM_TimeBaseStructure.TIM_Period = 210 - 1;                     /* T = (TIM_Period + 1)*(0+1)/168M,此时800kHz*/
  TIM_TimeBaseStructure.TIM_Prescaler = 0;                        /* 0:不预分频 */
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;         /* 0:时钟分频因子设为1,不分频*/
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;     /*向上计数*/
  TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;                /*重复计数值为0,不使用重复计数*/
  TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

  /* PWM1 Mode configuration: Channel1 */
  TIM_OCInitTypeDef  TIM_OCInitStructure;
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                /*PWM1模式,计数值小于比较值输出高电平,大于输出低电平*/
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;    /*使能输出通道*/
  TIM_OCInitStructure.TIM_Pulse = 0;                               /*设置占空比为0, 1 ~ TIM_TimeBaseStructure.TIM_Period */
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;        /*设置输出极性高电平有效*/
  TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable; /*禁用互补输出通道*/
  TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;      /*设置互补输出通道极性高电平有效*/
  TIM_OCInitStructure.TIM_OCIdleState = TIM_OCNIdleState_Set;      /*设置空闲时输出高电平*/
  TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;   /*设置互补通道空闲时输出低电平*/ 
  TIM_OC3Init(TIM1, &TIM_OCInitStructure);                         /*将上述配置应用到定时器一的通道三上*/
  TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);                /*使能通道三的输出比较寄存器的预装载功能*/

  TIM_Cmd(TIM1, ENABLE);                                           /*使能TIM1定时器*/
  TIM_CtrlPWMOutputs(TIM1,ENABLE);                                 /*使能TIM1的PWM输出*/
}

4.3、DMA初始化

在这里插入图片描述
在这里插入图片描述

下面是DMA初始化代码:

/*
*函数名称:dma2_Init
*功能描述:配置从源地址到TIM1_CCR3的DMA数据传输
*传入参数:无
*返回值  :无
*/
/*注意:当驱动多个彩灯时,将下面数组g_ledDataBuffer和
  DMA_InitStructure.DMA_BufferSize的长度均调大,否则会跳入硬件错误中断*/
uint16_t g_ledDataBuffer[24];
void dma2_Init(void)
{
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);                        /*使能DMA2时钟*/
  DMA_DeInit(DMA2_Stream6);                                                   /*对DMA2_Stream6进行默认值初始化*/
  /* DMA2 Stream6 Config for PWM1 by TIM1_CH1*/
	DMA_InitTypeDef DMA_InitStructure;
  DMA_InitStructure.DMA_Channel = DMA_Channel_0;                              /*配置DMA通道,通道0*/
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(TIM1->CCR3);         /*配置外设基地址:TIM1的CCR3寄存器*/
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)g_ledDataBuffer;          /*配置源数据的基地址*/
  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;                     /*设置搬运方向:存储器到外设*/
  DMA_InitStructure.DMA_BufferSize = 42;                                      /*设置传输数据的大小*/
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;            /*外设基地址不自增*/
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                     /*源数据基地址自增*/
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; /*设置外设数据大小为半字(16bit)*/
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;         /*设置存储器数据大小为半字(16bit)*/
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                               /*设置DMA为普通模式*/
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;                         /*DMA优先级为高*/
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;                      /*禁用DMA的FIFO模式*/
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;               /*设置DMA的FIFO阈值为满*/
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;                 /*设置内存突发传输模式为单次传输*/
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;         /*设置外设突发传输模式为单次传输*/

  DMA_Init(DMA2_Stream6, &DMA_InitStructure);                                 /*将上述配置应用到 DMA2_Stream6*/

  TIM_DMACmd(TIM1, TIM_DMA_CC3, ENABLE);                                      /*将TIM1的DMA请求映射到通道三并使能*/
}

4.4、RGB数据驱动

#define TIMING_ONE          (130)
#define TIMING_ZERO         (60)
/*
*函数名称:RGB_Show
*功能描述:通过DMA控制器从内存中读取数据,然后将数据传输到TIM1的CC3通道,以驱动RGB灯。
*传入参数:
*返回值  :无
*/
void RGB_Show(uint8_t (*color)[3], uint16_t len)
{
  uint8_t i = 0;
  uint16_t memaddr = 0;
  uint16_t buffersize = 0;
  buffersize = (len * 24) + 1;       // 缓冲区字节数 = len(RGB灯个数)*24+1
  while (len)
  {
    for(i = 0; i < 8; i++)/*  green data */
    {
       g_ledDataBuffer[memaddr] = ((color[0][1] << i) & 0x0080) ? TIMING_ONE : TIMING_ZERO;
       memaddr++;
     } 
    for(i = 0; i < 8; i++)/*  red data */
    {   
      g_ledDataBuffer[memaddr] = ((color[0][0] << i) & 0x0080) ? TIMING_ONE : TIMING_ZERO;
			memaddr++;
     }
    for(i = 0; i < 8; i++)/*  blue data */
    {
      g_ledDataBuffer[memaddr] = ((color[0][2] << i) & 0x0080) ? TIMING_ONE : TIMING_ZERO;
      memaddr++;
    }
    len--;
   }
   DMA_SetCurrDataCounter(DMA2_Stream6, buffersize);         /*指定要传输的数据量*/
   TIM_Cmd(TIM1, ENABLE);                                    /*启用TIM1定时器*/
   TIM_DMACmd(TIM1, TIM_DMA_CC3, ENABLE);                    /*将TIM1的DMA请求映射到通道三并使能*/
   DMA_Cmd(DMA2_Stream6, ENABLE);                            /*启用DMA2_Stream6,开始数据传输*/
   while(!DMA_GetFlagStatus(DMA2_Stream6, DMA_FLAG_TCIF6));  /*等待DMA传输完成,使用循环检查DMA传输完成标志*/
   DMA_Cmd(DMA2_Stream6, DISABLE);                           /*禁用DMA2流6,停止数据传输*/
   DMA_ClearFlag(DMA2_Stream6, DMA_FLAG_TCIF6);              /*清除DMA传输完成标志*/
   TIM_Cmd(TIM1, DISABLE);                                   /*禁用TIM1定时器,停止计时*/
}

5、完整代码

5.1、WS2812B.c


#include "WS2812B.h"
#include "DWT_Delay.h"
#include "string.h"

#define TIMING_ONE          (130)
#define TIMING_ZERO         (60)


/*
*函数名称:Timer1_Init
*功能描述:配置TIM1_CH3输出PWM
*传入参数:无
*返回值  :无
*/
void Timer1_Init(void)
{
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOE, ENABLE);      /*使能GPIOE时钟*/
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);       /*使能TIM1时钟*/

  GPIO_PinAFConfig(GPIOE, GPIO_PinSource13, GPIO_AF_TIM1);   /*将GPIOE13重映射到TIM1的输出通道上*/
	
  GPIO_InitTypeDef GPIO_InitStructure;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;               /*将引脚功能配置为复用*/
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_OType=GPIO_OType_PP;               /*推挽输出*/
  GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_UP;                 /*上拉*/
  GPIO_Init(GPIOE, &GPIO_InitStructure);
   
	/* 定时器周期 : T =(arr + 1) * (PSC + 1) / Tck.   arr:周期值 PSC:预分频值  Tck: 系统时钟频率 */
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  TIM_TimeBaseStructure.TIM_Period = 210 - 1;                     /* T = (TIM_Period + 1)*(0+1)/168M  = 800kHz*/
  TIM_TimeBaseStructure.TIM_Prescaler = 0;                        /* 0:不预分频 */
  TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;         /* 0:时钟分频因子设为1,不分频*/
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;     /*向上计数*/
  TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;                /*重复计数值为0,不使用重复计数*/
  TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);

  /* PWM1 Mode configuration: Channel1 */
  TIM_OCInitTypeDef  TIM_OCInitStructure;
  TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                /*PWM1模式,计数值小于比较值输出高电平,大于输出低电平*/
  TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;    /*使能输出通道*/
  TIM_OCInitStructure.TIM_Pulse = 0;                               /*设置占空比为0, 1 ~ TIM_TimeBaseStructure.TIM_Period */
  TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;        /*设置输出极性高电平有效*/
  TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Disable; /*禁用互补输出通道*/
  TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;      /*设置互补输出通道极性高电平有效*/
  TIM_OCInitStructure.TIM_OCIdleState = TIM_OCNIdleState_Set;      /*设置空闲时输出高电平*/
  TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;   /*设置互补通道空闲时输出低电平*/ 
  TIM_OC3Init(TIM1, &TIM_OCInitStructure);                         /*将上述配置应用到定时器一的通道三上*/
  TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);                /*使能通道三的输出比较寄存器的预装载功能*/

  TIM_Cmd(TIM1, ENABLE);                                           /*使能TIM1定时器*/
  TIM_CtrlPWMOutputs(TIM1,ENABLE);                                 /*使能TIM1的PWM输出*/
}


uint16_t g_ledDataBuffer[24];
/*
*函数名称:dma2_Init
*功能描述:配置从源地址到TIM1_CCR3的DMA数据传输
*传入参数:无
*返回值  :无
*/
void dma2_Init(void)
{
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);                        /*使能DMA2时钟*/

  DMA_DeInit(DMA2_Stream6);                                                   /*对DMA2_Stream6进行默认值初始化*/

  /* DMA2 Stream6 Config for PWM1 by TIM1_CH1*/
	DMA_InitTypeDef DMA_InitStructure;
  DMA_InitStructure.DMA_Channel = DMA_Channel_0;                              /*配置DMA通道,通道0*/
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(TIM1->CCR3);         /*配置外设基地址:TIM1的CCR3寄存器*/
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)g_ledDataBuffer;          /*配置源数据的基地址*/
  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;                     /*设置搬运方向:存储器到外设*/
  DMA_InitStructure.DMA_BufferSize = 42;                                      /*设置传输数据的大小*/
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;            /*外设基地址不自增*/
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                     /*源数据基地址自增*/
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; /*设置外设数据大小为半字(16bit)*/
  DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;         /*设置存储器数据大小为半字(16bit)*/
  DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;                               /*设置DMA为普通模式*/
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;                         /*DMA优先级为高*/
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;                      /*禁用DMA的FIFO模式*/
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;               /*设置DMA的FIFO阈值为满*/
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;                 /*设置内存突发传输模式为单次传输*/
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;         /*设置外设突发传输模式为单次传输*/

  DMA_Init(DMA2_Stream6, &DMA_InitStructure);                                 /*将上述配置应用到 DMA2_Stream6*/

  TIM_DMACmd(TIM1, TIM_DMA_CC3, ENABLE);                                      /*将TIM1的DMA请求映射到通道三并使能*/
}


/*
*函数名称:RGB_Show
*功能描述:通过DMA控制器从内存中读取数据,然后将数据传输到TIM1的CC3通道,以驱动RGB灯。
*传入参数:
*返回值  :无
*/
void RGB_Show(uint8_t (*color)[3], uint16_t len)
{
  uint8_t i = 0;
  uint16_t memaddr = 0;
  uint16_t buffersize = 0;
  buffersize = (len * 24) + 1;       // 缓冲区字节数 = len(RGB灯个数)*24+1
  while (len)
  {
    for(i = 0; i < 8; i++)/*  green data */
    {
       g_ledDataBuffer[memaddr] = ((color[0][1] << i) & 0x0080) ? TIMING_ONE : TIMING_ZERO;
       memaddr++;
     } 
    for(i = 0; i < 8; i++)/*  red data */
    {   
      g_ledDataBuffer[memaddr] = ((color[0][0] << i) & 0x0080) ? TIMING_ONE : TIMING_ZERO;
			memaddr++;
     }
    for(i = 0; i < 8; i++)/*  blue data */
    {
      g_ledDataBuffer[memaddr] = ((color[0][2] << i) & 0x0080) ? TIMING_ONE : TIMING_ZERO;
      memaddr++;
    }
    len--;
   }
   DMA_SetCurrDataCounter(DMA2_Stream6, buffersize);         /*指定要传输的数据量*/
   TIM_Cmd(TIM1, ENABLE);                                    /*启用TIM1定时器*/
   TIM_DMACmd(TIM1, TIM_DMA_CC3, ENABLE);                    /*将TIM1的DMA请求映射到通道三并使能*/
   DMA_Cmd(DMA2_Stream6, ENABLE);                            /*启用DMA2_Stream6,开始数据传输*/
   while(!DMA_GetFlagStatus(DMA2_Stream6, DMA_FLAG_TCIF6));  /*等待DMA传输完成,使用循环检查DMA传输完成标志*/
   DMA_Cmd(DMA2_Stream6, DISABLE);                           /*禁用DMA2流6,停止数据传输*/
   DMA_ClearFlag(DMA2_Stream6, DMA_FLAG_TCIF6);              /*清除DMA传输完成标志*/
   TIM_Cmd(TIM1, DISABLE);                                   /*禁用TIM1定时器,停止计时*/
}

5.2、WS2812B.h

#ifndef __WS2818B_H
#define __WS2812B_H
#include "stm32f4xx.h"                  // Device header
void Timer1_Init(void);
void dma2_Init(void);
void RGB_Show(uint8_t (*color)[3], uint16_t len);
#endif

5.3、main.c

#include "stm32f4xx.h"                  // Device header
#include "DWT_Delay.h"
#include "WS2812B.h"

uint8_t rgbRed[][3] = {{0xff, 0xff, 0x99}};
uint8_t rgbRed1[][3] = {{0x20, 0x20, 0x20}};
uint8_t rgbRed2[][3] = {{0x33, 0x00, 0x33}};
uint8_t rgbRed3[][3] = {{0xFF, 0x33, 0xff}};
int main(void)
{
	DWT_Init();
	Timer1_Init();
	dma2_Init();
	while(1)
	{
	RGB_Show(rgbRed,1);DWT_DelayMS(1000);
	RGB_Show(rgbRed1,1);DWT_DelayMS(1000);
	RGB_Show(rgbRed2,1);DWT_DelayMS(1000);
	RGB_Show(rgbRed3,1);DWT_DelayMS(1000);
	RGB_Show(rgbRed,1);DWT_DelayMS(1000);
	}
}
  • 27
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值