STM32F407 Timer+DAC+DMA输出任意波形(正弦波)

STM32F407 Timer+DAC+DMA输出任意波形(正弦波)

前言

我们知道STM32F407是有两个DAC的,也就是可以同时输出两个不同的信号。本文将介绍通过定时器触发DAC输出实现频率可控,同时利用DMA实现波形可控,充分利用外设,减轻CPU负担。


这里我们准备利用TIM4的update触发PA4上的DAC_CH1和DMA1_CH7_Stream5搬运DA
值输出正弦波



DAC配置

DAC的配置需要着重注意触发方式的配置,也就是DAC_InitStructure.DAC_Trigger ,我们将它配置成DAC_Trigger_T4_TRGO
在这里插入图片描述

	GPIO_InitTypeDef  GPIO_InitStructure;	//GPIO结构体
	DAC_InitTypeDef DAC_InitStructure;		//DAC结构体
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);	//使能GPIOA时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);		//使能DAC时钟
	//GPIO配置初始化 PA4
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;				//PIN4
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;			//模拟模式		
//	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
//	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;		//浮空输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);					//GPIO结构体初始化
	
	//DAC配置初始化
	DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0;
	DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
	DAC_InitStructure.DAC_Trigger = DAC_Trigger_T4_TRGO; 			//定时器触发转换
	DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
	DAC_Init(DAC_Channel_1, &DAC_InitStructure);					//DAC1初始化
		//DAC设置数据对齐
	DAC_SetChannel1Data(DAC_Align_12b_R, 0);						//右对齐

	DAC_Cmd(DAC_Channel_1,ENABLE); 		//DAC1 使能


Timer配置

定时器着重注意TIM_SelectOutputTrigger()语句,我们将其配置为TIM_TRGOSource_Update,意为当定时器更新时向外触发。

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); 			//TIM4 时钟使能
	                                                                
	TIM_InternalClockConfig(TIM4);	                                
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;	            //时基结构体
	TIM_TimeBaseInitStructure.TIM_Period = arr; 					//设置自动重装载值
	TIM_TimeBaseInitStructure.TIM_Prescaler =psc; 					//设置预分频值
	TIM_TimeBaseInitStructure.TIM_ClockDivision = 0; 				//设置时钟分割
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
	                                                                
	TIM_SelectOutputTrigger(TIM4,TIM_TRGOSource_Update);			//更新溢出向外触发
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStructure); 			//时基初始化
	TIM_Cmd(TIM4, ENABLE);                                          //定时器使能

DMA配置

我们利用一个数组存储DA值,利用DMA将其搬运至DA输出的寄存器上。这里我存的一个周期24个点的正弦波。

#define DA1_Value_Length 24
const uint16_t DA1_Value[DA1_Value_Length] = {
	
0		,
65      ,
262     ,
563     ,
953     ,
1410    ,
1890    ,
2379    ,
2824    ,
3209    ,
3506    ,
3687    ,
3747    ,
3678    ,
3484    ,
3183    ,
2791    ,
2340    ,
1855    ,
1369    ,
920     ,
534     ,
240     ,
57   

};

DMA通过查询手册可知,我们需要配置DMA1channel7stream5
在这里插入图片描述

	DMA_InitTypeDef DMA_InitStructure;		//DMA结构体
	
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);		//使能DMA1时钟

	//DMA配置初始化
	DMA_InitStructure.DMA_Channel = DMA_Channel_7;				//DMA_CH7
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; 			//循环模式
	DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;		//内存到外设
	DMA_InitStructure.DMA_BufferSize = DA1_Value_Length;		//传输次数:数组长度
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;		//优先级
		//DMA_FIFO
	DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
	DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
	
	DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)DA1_Value; 		//内存地址:输出DA值数组
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;	//16 bit
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;				//内存自增

	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(DAC->DHR12R1); 		//外设地址:DAC1地址
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;	//16 bit
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;			//外设不自增
	DMA_Init(DMA1_Stream5,&DMA_InitStructure);									//DMA1_Stream5 初始化
	
	DMA_Cmd(DMA1_Stream5,ENABLE);		//DMA1_Stream5 使能

DMA从内存到外设。内存地址DMA_InitStructure.DMA_Memory0BaseAddr 配置成我们设定的数组,写上我们数组的地址。外设地址DMA_InitStructure.DMA_PeripheralBaseAddr为DA输出的寄存器地址也就是(uint32_t)&(DAC->DHR12R1)。很明显,我们需要遍历数组的值搬运至DA输出的寄存器来输出波形,所以内存需要自增而外设不自增。12位精度的DA值,所以长度配置为16位HalfWord

可能会有人好奇为什么地址是(uint32_t)&(DAC->DHR12R1),其实我们可以看一下这个函数:

void DAC_SetChannel1Data(uint32_t DAC_Align, uint16_t Data);

我们知道这个函数就是来设置输出的值的。点开看看,可以发现是在对数据的对齐进行一些处理操作,里面就出现了有关DHR12R1的字眼。
在这里插入图片描述
或者更直接一点看手册,写得很明白。
在这里插入图片描述
记得打通DAC和DMA的通道:

DAC_DMACmd(DAC_Channel_1, ENABLE); //DAC1_DMA 使能



完整代码

这里奉上完整的代码,并且同时配置了两个通道,另外一个通道的配置方法相同。

DAC+DMA:

#include "DACDMA.h"

//!!!需TIM触发转换,请额外配置TIM
//此处默认DAC1:TIM4;DAC2:TIM5;
//输出频率 f = 84M/(TIM_Period * TIM_Prescaler * DA_Value_Length)

//输出的DA值数组
//PA4
const uint16_t DA1_Value[DA1_Value_Length] = {
	
0		,
65      ,
262     ,
563     ,
953     ,
1410    ,
1890    ,
2379    ,
2824    ,
3209    ,
3506    ,
3687    ,
3747    ,
3678    ,
3484    ,
3183    ,
2791    ,
2340    ,
1855    ,
1369    ,
920     ,
534     ,
240     ,
57   

};
//PA5
const uint16_t DA2_Value[DA2_Value_Length] = {
0		,
65      ,
262     ,
563     ,
953     ,
1410    ,
1890    ,
2379    ,
2824    ,
3209    ,
3506    ,
3687    ,
3747    ,
3678    ,
3484    ,
3183    ,
2791    ,
2340    ,
1855    ,
1369    ,
920     ,
534     ,
240     ,
57      
	
};



//DAC1; PA4; DMA_CH7; DMA1_Stream5; TIM4;
void DA1_Init(){
	//结构体定义
	GPIO_InitTypeDef  GPIO_InitStructure;	//GPIO结构体
	DAC_InitTypeDef DAC_InitStructure;		//DAC结构体
	DMA_InitTypeDef DMA_InitStructure;		//DMA结构体
	
	//时钟使能
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);	//使能GPIOA时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);		//使能DAC时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);		//使能DMA1时钟
	
	//GPIO配置初始化 PA4
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;				//PIN4
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;			//模拟模式		
//	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
//	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;		//浮空输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);					//GPIO结构体初始化
	
	//DAC配置初始化
	DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0;
	DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
	DAC_InitStructure.DAC_Trigger = DAC_Trigger_T4_TRGO; 			//!!!定时器触发转换 一次转移数组里的一个数据 TIM4
	DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;
	DAC_Init(DAC_Channel_1, &DAC_InitStructure);					//DAC1初始化
		//DAC设置数据对齐
	DAC_SetChannel1Data(DAC_Align_12b_R, 0);						//右对齐


	//DMA配置初始化
	DMA_InitStructure.DMA_Channel = DMA_Channel_7;				//DMA_CH7
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; 			//循环模式
	DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;		//内存到外设
	DMA_InitStructure.DMA_BufferSize = DA1_Value_Length;		//传输次数:数组长度
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;		//优先级
		//DMA_FIFO
	DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
	DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
	
	DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)DA1_Value; 		//内存地址:输出DA值数组
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;	//16 bit
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;				//内存自增

	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(DAC->DHR12R1); 		//外设地址:DAC1地址
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;	//16 bit
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;			//外设不自增
	DMA_Init(DMA1_Stream5,&DMA_InitStructure);									//DMA1_Stream5 初始化
	
	DMA_Cmd(DMA1_Stream5,ENABLE);		//DMA1_Stream5 使能
	DAC_DMACmd(DAC_Channel_1, ENABLE);	//DAC1_DMA 使能  	
	DAC_Cmd(DAC_Channel_1,ENABLE); 		//DAC1 使能

}

//DAC1; PA5; DMA_CH7; DMA1_Stream6; TIM5;
void DA2_Init(){
	//结构体定义
	GPIO_InitTypeDef  GPIO_InitStructure;	//GPIO结构体
	DAC_InitTypeDef DAC_InitStructure;		//DAC结构体
	DMA_InitTypeDef DMA_InitStructure;      //DMA结构体

	//时钟使能
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);	//使能GPIOA时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);     //使能DAC时钟
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1,ENABLE);     //使能DMA1时钟
	
	//GPIO配置初始化
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;				//PIN5
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;            //模拟模式		
//	GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;          
//	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;      
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;        //浮空输入
	GPIO_Init(GPIOA, &GPIO_InitStructure);                  //GPIO结构体初始化
	
	//DAC配置初始化
	DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0;
	DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;
	DAC_InitStructure.DAC_Trigger = DAC_Trigger_T5_TRGO;					//!!!定时器触发转换 一次转移数组里的一个数据 TIM5
	DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;         
	DAC_Init(DAC_Channel_2, &DAC_InitStructure);                            //DAC2初始化
		//DAC设置数据对齐
	DAC_SetChannel2Data(DAC_Align_12b_R, 0);								//右对齐
	
	
	//DMA配置初始化
	DMA_InitStructure.DMA_Channel = DMA_Channel_7;							//DMA_CH7
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;                         //循环模式
	DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;                 //内存到外设
	DMA_InitStructure.DMA_BufferSize = DA2_Value_Length;                    //传输次数:数组长度
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;                   //优先级
		//DMA_FIFO
	DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
	DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
	
	DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)DA2_Value;			//内存地址:输出DA值数组
	DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;             
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;     //16 bit
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;                 //内存自增

	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(DAC->DHR12R2);			//外设地址:DAC2地址
	DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;             
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;     //16 bit
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;                //外设不自增
	DMA_Init(DMA1_Stream6,&DMA_InitStructure);			                            //DMA1_Stream6 初始化 
	
	DMA_Cmd(DMA1_Stream6,ENABLE);				//DMA1_Stream6 使能
	DAC_DMACmd(DAC_Channel_2, ENABLE);          //DAC2_DMA 使能  	
	DAC_Cmd(DAC_Channel_2,ENABLE);              //DAC2 使能
}


//获取输出数据
uint16_t DA1_GetValue(){

	return DAC_GetDataOutputValue(DAC_Channel_1);

}

uint16_t DA2_GetValue(){

	return DAC_GetDataOutputValue(DAC_Channel_2);

}
#ifndef __DACDMA_H__
#define __DACDMA_H__

#include "stm32f4xx.h"                  // Device header

//!!!需TIM触发转换,请额外配置TIM
#define DA1_Value_Length 24
#define DA2_Value_Length 24

void DA1_Init();
void DA2_Init();

uint16_t DA1_GetValue();
uint16_t DA2_GetValue();


#endif

Timer:

#include "TimerBase.h"

//主频84M

//TIM4 16bit
void TIM4_Init(uint16_t arr, uint16_t psc){
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4,ENABLE); 			//TIM4 时钟使能
	                                                                
	TIM_InternalClockConfig(TIM4);	                                
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;	            //时基结构体
	TIM_TimeBaseInitStructure.TIM_Period = arr; 					//设置自动重装载值
	TIM_TimeBaseInitStructure.TIM_Prescaler =psc; 					//设置预分频值
	TIM_TimeBaseInitStructure.TIM_ClockDivision = 0; 				//设置时钟分割
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
	                                                                
	TIM_SelectOutputTrigger(TIM4,TIM_TRGOSource_Update);			//更新溢出向外触发
	TIM_TimeBaseInit(TIM4, &TIM_TimeBaseInitStructure); 			//时基初始化
	TIM_Cmd(TIM4, ENABLE);                                          //定时器使能
}


//TIM5 32bit
void TIM5_Init(uint16_t arr, uint16_t psc){
	
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE); 			//TIM5 时钟使能
	                                                                
	TIM_InternalClockConfig(TIM5);                                  
	TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;				//时基结构体
	TIM_TimeBaseInitStructure.TIM_Period = arr;                     //设置自动重装载值
	TIM_TimeBaseInitStructure.TIM_Prescaler =psc;                   //设置预分频值
	TIM_TimeBaseInitStructure.TIM_ClockDivision = 0;                //设置时钟分割
	TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
	                                                                
	TIM_SelectOutputTrigger(TIM5,TIM_TRGOSource_Update);            //更新溢出向外触发
	TIM_TimeBaseInit(TIM5, &TIM_TimeBaseInitStructure);             //时基初始化
	TIM_Cmd(TIM5, ENABLE);                                          //定时器使能
}


#ifndef __TIMERBASE_H__
#define __TIMERBASE_H__

#include "stm32f4xx.h"                  // Device header

void TIM4_Init(uint16_t arr, uint16_t psc);
void TIM5_Init(uint16_t arr, uint16_t psc);


#endif

main:

#include "stm32f4xx.h"                  // Device header
#include "delay.h"
#include "usart.h"
#include "DACDMA.h"
#include "TimerBase.h"

int main(){
	delay_init(168);
	uart_init(9600);
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	
	printf("Start !\r\n");
	

	TIM4_Init(700-1, 1-1);//5KHz
	DA1_Init();//PA4
	
	TIM5_Init(350-1, 1-1);//10KHz
	DA2_Init();//PA5
	
	while(1){
			
		
	}

}



频率计算

实际上,每次定时器的更新只会触发一个DA值的输出,所以输出频率会受到DA数组长度的影响。公式为:

输出频率 f = 84M/(TIM_Period * TIM_Prescaler * DA_Value_Length)


波形控制

根据原理,很容易知道可以通过改变数组DA1_Value[]里面的值来达到控制波形的目的。
注意输出的电压与DA值有这样的关系:

Voltage = DA_Value*3.3V/4096


实践

来看一下输出的结果:
当:

TIM_Period = 700 - 1
TIM_Prescaler = 1-1
DA_Value_Length = 24

根据公式可知输出频率为 f=5KHz
在这里插入图片描述

当:

TIM_Period = 350 - 1
TIM_Prescaler = 1-1
DA_Value_Length = 24

根据公式可知输出频率为 f=10KHz
在这里插入图片描述



正弦波DA值制表

至于生成DA值数组的方法,应该有很多,这里可以浅浅介绍两种。

ADC采集法

直接利用ADC进行采集。方法可以参考一下这个文章:
Timer+ADC+DMA采集

函数生成法

利用函数生成。这里是生成的0到4095的正弦函数。

#include <stdio.h>
#include <math.h>

#define PI 3.14

#define Sine_Array_length 24    //数组长度,即生成的点数
unsigned int Sine_Array[Sine_Array_length] ={0};

void SineWave_Data(unsigned int cycle ,unsigned  int*D,float Um)//周期:生成的点数;指针:数组的地址;幅度
{
    unsigned int i;
    for( i=0;i<cycle;i++)
    {
        D[i]=(unsigned int)((Um*sin(( 1.0*i/(cycle-1))*2*PI)+Um));
    }
}

unsigned int j;
void main(){

    SineWave_Data(Sine_Array_length, Sine_Array, 2048);

    for ( j = 0; j < Sine_Array_length; j++)
    {
        printf("%d,", Sine_Array[j]);
    }
    

}

结语

在配置过程中,要仔细查看手册,注意其各自对应关系。Timer和DAC注意触发的配置,DMA注意外设地址和内存地址的配置以及是否自增。同时还要注意输出正弦波频率的计算。最后最后,注意使能!!

ps.

以上内容均为本人个人理解和实践做出的总结。文笔较差,还望包涵 。如有错误或表达不当之处,欢迎指正! 感谢。



要实现任意波形发生器,可以使用STM32F407微控制器的DACDMATimer功能。 首先,DAC(数字模拟转换器)是用来将数字信号转换为模拟电压输出的设备。STM32F407具有多个DAC通道,每个通道都可以输出一个模拟电压。我们可以使用DAC通道输出的电压值来生成波形。 接下来,我们可以使用DMA(直接内存访问)功能,将要输出波形数据传输到DAC的数据寄存器中。通过使用DMA,我们可以实现高效的数据传输而无需CPU的干预。可以将波形数据存储在内存数组中,并使用DMA将这些数据发送给DAC通道。 最后,我们可以使用Timer(定时器)功能来控制波形输出频率。定时器可以产生特定的定时脉冲,用于触发DAC输出的更新。通过配置定时器的预分频器和计数器,在每个定时器更新事件后触发DAC通道输出的更新。这样,我们可以控制波形输出频率。 具体实现的步骤如下: 1. 配置DAC通道及其输出引脚,并设置DAC工作模式。 2. 配置DMA控制器,设置传输方向为内存到外设,选择波形数据的内存地址和DAC数据寄存器的外设地址。 3. 准备波形数据,可以是正弦波、方波或其他自定义波形,将波形数据存储在内存数组中。 4. 配置定时器,设置预分频器和计数器的值,以控制波形输出频率。 5. 启动DMA和定时器,开始产生波形。 通过使用STM32F407DACDMA和定时器功能,可以实现一个任意波形发生器。能够灵活生成各种形状的波形,并且输出频率可以自由调节。这样的实现可以应用于音频信号发生器、信号调试等领域。
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值