【2024电赛H题自动行使小车】 省一获奖方案整理汇总

目录

二、赛题分析

三、方案框架

四、电机驱动

1、PWM波配置

2、IN1、IN2配置

3、自定义函数用以修改PWM波占空比

4、自定义函数用以驱动电机

五、编码器读取

1、编码器IO口配置

2、定时中断配置

3、中断读取编码器

4、定时器定时读取编码器数值 

六、陀螺仪巡航角获取

七、八路灰度返回值读取

八、PID速度环与差速环

1、速度环

2、差速环

3、将差速环加入速度环

九、运动模式整合

1、模式一(AB)

2、模式二(ABCDA)

3、模式三(ACBDA)

4、模式四(ACBDAx4)

十、按键等其余外设配置

1、按键

2、声光模块

3、电机驱动板使能

4、OLED

十一、整体主控(main函数)

十二、源码分享

十三、结语

一、前言

 2024年全国电赛也是落下帷幕了,各省获奖名单陆续出炉,不知道大家有没有拿到满意的成绩。电赛总是充满遗憾的,但只要有所收获,就不算白来。电赛的故事不是三言两语能概括的,但我始终相信学无止境,因而在此将参赛方案整理并开源,也希望能和各位读者共同探讨,共同进步。

二、赛题分析

2024年H题自动行驶小车,题目如下:

2038b0bfba4142bba64bb06f7e992785.png

3ef7bbf744f743f4b6f7fa3fda59f8f3.png

54adebf6e0de4991966eed84ed8e4f3e.png

相较于往年的小车题,今年的题目其实是偏简单的,难点主要有两个:

1、限定使用TI MSPM0系列的板子

2、在不使用摄像头的情况下实现白色区域的自动寻路

对于第一个问题,我向大家推荐两个解决方案:

1、【2024电赛】 TI MSPM0快速入门课 

2、 LP-MSPM03507学习资料汇总

链接一是B站UP主Torris的入门视频,讲的非常清晰,推荐给大家

链接二是南极熊学长整理的M0资料,非常全面,后续我也会整理一份G3507的学习笔记供大家交流学习

 对于第二个问题,我使用的解决方案是使用高精度陀螺仪模块(MPU6050、JY61P、GY25等),通过巡航角来判断小车的行驶方向。

解决了这两个最大的难题之后,就可以根据题目出一个大致方案了。

三、方案框架

5dc12330376640a293e6324309b68707.jpeg

 这里我使用的陀螺仪是JY61P,不推荐大家使用MPU6050,零漂太严重,想用的话需要用算法去零漂,这里就不过多介绍了。

思路很简单,有线靠灰度寻线,没线靠巡航角找角度。

接下来我会对各个模块的代码进行简单的整理讲解,文章本意是与大家交流,如有不足之处也希望大家多多包涵。

文末代码开源,可根据代码分析学习。

四、电机驱动

1、PWM波配置

a7fb248b31204caaba66293b976337d7.png

 其中,PWM Period Count就是定时器计数周期的计数值,也就是重装载值,相当于32中的ARR。

 Calculated PWM Frequency为系统计算出的PWM实际输出频率,驱动电机建议在15k~20k之间。

2fa6290d6cd14477911a8bd874f235c2.png

 我们需要两个PWM波,所以开启了两个通道,计数模式对我们影响不大,这里选择向下计数。

通道1设置与通道0完全一致。

2、IN1、IN2配置

da6fd6cb5e3e4ce9b770db868cb7aac7.png

其余三个引脚配置均相同,仅需配置IO口名称及模式。

3、自定义函数用以修改PWM波占空比

/********************************************
函数功能:修改PWM波占空比
参数:  duty:占空比0~100
        channel:通道选择
返回值:无
********************************************/
void set_Duty(uint8_t duty,uint8_t channel)
{
    uint32_t CompareValue;
    CompareValue = 2500 - 2500/100*duty;                  //占空比转换

    if(channel == 0)                                 
    {
        DL_Timer_setCaptureCompareValue(PWM_0_INST,CompareValue,DL_TIMER_CC_0_INDEX);
    }
    else if(channel == 1)
    {
        DL_Timer_setCaptureCompareValue(PWM_0_INST,CompareValue,DL_TIMER_CC_1_INDEX);           
    }
}

这里我选择直接直接输入占空比,将其转换为Counter Compare Value

注意,占空比转换公式中的2500须等于PWM波配置中的PWM Period Count值。

4、自定义函数用以驱动电机

/********************************************
函数功能:输入PWM波占空比驱动电机
参数:  motor_left:左轮目标占空比
        motor_right:右轮目标占空比
返回值:无
********************************************/
void Set_Pwm(int motor_left,int motor_right)
{
	if(motor_left > 0)	//前进
	{
        AIN10;
		AIN21;
	}
	else				//后退
	{
		AIN11;
		AIN20;
	}
    set_Duty(myabs(motor_left),1);

	if(motor_right > 0) //前进
	{
		BIN10;
		BIN21;
	}
	else				//后退
	{
        BIN11;
		BIN20;
	}
    set_Duty(myabs(motor_right),0);
}

其中AIN11、AIN10等均为宏定义,就是根据输入转速值的正负将引脚置高或置低。

48cc840b062c44399fe43f4c05e12a65.png

这样电机驱动部分就完成了,现在就可以让小车跑起来了。

五、编码器读取

编码器的数值的读取是小车控制中最重要的一环,我们需要根据编码器的返回值判断电机是否到达了我们需要的转速。

1、编码器IO口配置

4647a12d5b27422384063fe1d9367410.png

两个电机各须两个引脚,因此我们开启两个引脚组分别读取两个电机的编码器数值。

7c6007c0fc5b4a208e2f1b310684bacd.png

 这里开启引脚的外部中断用以读取编码器电平,其余三个引脚同理。

2、定时中断配置

完成引脚配置后,我们只能读取编码器高低电平的转换,因此我们还需要一个定时器用以读取一段时间内的编码器数值。

684bf471a79d458a994ed5e3407b1c23.png

这里我们选择50ms的计数周期,建议周期设置为20~50ms。

2b16d4b64ddb49838adddc302c24e707.png

3、中断读取编码器

这里使用四分频的编码器读取方式,对四分频读取不了解的同学可以看南极熊学长的博客

【STM32+HAL】直流电机PID控制

/********************************************
函数功能:中断读取编码器
参数:无
返回值:无
********************************************/
void GROUP1_IRQHandler(void)                    //中断服务函数
{
    /**********************编码器读取***********************/
    gpioA = DL_GPIO_getEnabledInterruptStatus(GPIOA,GPIO_EncoderA_PIN_0_PIN | GPIO_EncoderA_PIN_1_PIN);
    gpioB = DL_GPIO_getEnabledInterruptStatus(GPIOB,GPIO_EncoderB_PIN_2_PIN | GPIO_EncoderB_PIN_3_PIN);
    if((gpioA & GPIO_EncoderA_PIN_0_PIN) == GPIO_EncoderA_PIN_0_PIN)
    {
        //Pin0上升沿
        if(!DL_GPIO_readPins(GPIOA,GPIO_EncoderA_PIN_1_PIN))//P1为高电平
        {
            gEncoderCount_left--;
        }
        else//P1为低电平
        {
            gEncoderCount_left++;
        }
    }
    else if((gpioA & GPIO_EncoderA_PIN_1_PIN) == GPIO_EncoderA_PIN_1_PIN)
    {
        //Pin1上升沿
        if(!DL_GPIO_readPins(GPIOA,GPIO_EncoderA_PIN_0_PIN))//P0为高电平
        {
            gEncoderCount_left++;
        }
        else//P1为低电平
        {
            gEncoderCount_left--;
        }
    }

    if((gpioB & GPIO_EncoderB_PIN_2_PIN) != 0)
    {
        if(!DL_GPIO_readPins(GPIOB,GPIO_EncoderB_PIN_3_PIN))
        {
            gEncoderCount_right--;
        }
        else
        {
            gEncoderCount_right++;
        }
    }
    else if((gpioB & GPIO_EncoderB_PIN_3_PIN) != 0)
    {
        if(!DL_GPIO_readPins(GPIOB,GPIO_EncoderB_PIN_2_PIN))
        {
            gEncoderCount_right++;
        }
        else
        {
            gEncoderCount_right--;
        }
    }
    DL_GPIO_clearInterruptStatus(GPIOA, GPIO_EncoderA_PIN_0_PIN|GPIO_EncoderA_PIN_1_PIN);
    DL_GPIO_clearInterruptStatus(GPIOB, GPIO_EncoderB_PIN_2_PIN|GPIO_EncoderB_PIN_3_PIN);
}

其中,gEncoderCount_leftgEncoderCount_right均为全局变量,用以计数编码器数值。

4、定时器定时读取编码器数值 

dd119c6427764523a7b339fd78186664.png

每50ms读取一次外部中断中的编码器计数值并将计数值清零

我们得到了电机的转速,接下来就可以对小车进行控制了。

六、陀螺仪巡航角获取

我们使用的陀螺仪JY61P可以直接通过串口获取返回值,这里我们选择用串口中断,想提高传输效率也可以选择使用DMA。

bfebedf2f46f497c906ed5cb023909ec.png

代码用的是官方提供的例程,这里就不贴了,大家可以直接在工程中查看。

七、八路灰度返回值读取

灰度返回值为高低电平,直接用IO口读取即可。

f1c683e4ec084f3891375c6e0d3ef1f0.png

这里我们直接使用宏定义读取返回值。

#define P1			DL_GPIO_readPins(GPIO_Gray_PIN_Gray_1_PORT,GPIO_Gray_PIN_Gray_1_PIN)
#define P2			DL_GPIO_readPins(GPIO_Gray_PIN_Gray_2_PORT,GPIO_Gray_PIN_Gray_2_PIN)
#define P3			DL_GPIO_readPins(GPIO_Gray_PIN_Gray_3_PORT,GPIO_Gray_PIN_Gray_3_PIN)
#define P4			DL_GPIO_readPins(GPIO_Gray_PIN_Gray_4_PORT,GPIO_Gray_PIN_Gray_4_PIN)
#define P5			DL_GPIO_readPins(GPIO_Gray_PIN_Gray_5_PORT,GPIO_Gray_PIN_Gray_5_PIN)
#define P6			DL_GPIO_readPins(GPIO_Gray_PIN_Gray_6_PORT,GPIO_Gray_PIN_Gray_6_PIN)
#define P7			DL_GPIO_readPins(GPIO_Gray_PIN_Gray_7_PORT,GPIO_Gray_PIN_Gray_7_PIN)
#define P8			DL_GPIO_readPins(GPIO_Gray_PIN_Gray_8_PORT,GPIO_Gray_PIN_Gray_8_PIN)

那么我们就得到了八路灰度的返回值,这也是巡线的基础。

八、PID速度环与差速环

1、速度环

速度环的作用是使电机到达指定转速,在实际中,占空比相同的PWM波在不同电机上的转速可能会有差异,速度环可以减小电机本身带来的影响。

ab959620936f4286944827b8c3da8748.png

这只是最基础的PID用法,本工程也只使用到了P环,这里就不详细解释了。

2、差速环

有了速度环,我们还需要一个差速环来给左右电机一个差速,这样才能让小车转向。

灰度循迹的差速环是根据检测到黑色的位置给电机差速,比如最右侧的光电检测到了黑色,说明小车偏左,那么就给左轮一个正向差速,给右轮一个反向差速,让小车回到轨道上。

/********************************************
函数功能:差速环返回值
参数:  无
返回值:差速值
********************************************/
int xunji(void)			//输出差速,左轮速度为middle+x,右轮速度为middle-x
{
    if(P4!=0)  return -8;
	else if(P5!=0)  return 8;
    else if(P3!=0)  return -12;
	else if(P6!=0)  return 12;
	else if(P2!=0)  return -16;
	else if(P7!=0)  return 16;
	else if(P1!=0)  return -28;
	else if(P8!=0)  return 28;
	return 0;
}

陀螺仪的差速环我选择直接使用巡航角的数值,因为陀螺仪的返回值是-180~180,所以在0附近时巡航角本身就存在正负,同时因为我选择的PWM改变范围是0~100,所以我们不需要对偏差值进行转换,直接作为差速输入给速度环即可,下面是代码示例。

if (n%2==0)
        {
            if(Yaw<0) bias = 180 - myabs(Yaw);      //当走过白色区域为偶数时,须将+180和-180转化为0+和0-
            else bias = Yaw - 180;
        }
        else if(n%2==1)
        {
            bias = Yaw;                         //当走过白色区域为奇数时,不需要转化
        }

3、将差速环加入速度环

Speed_Middle为基准速度值,也就是走直线时的速度,在基准上加上差速环返回值,在将目标值targetAtargetB输入速度环,从而控制小车循迹及走直线。

    targetA = Speed_Middle+bias;
	targetB = Speed_Middle-bias;
    CurrentA = (float)gEncoderVal_left/3; //left
	CurrentB = (float)gEncoderVal_right/3; //right
	Motor_Left  = (int)PWM_Limit(PID_A(CurrentA,targetA),Limit, -Limit);
	Motor_Right = (int)PWM_Limit(PID_B(CurrentB,targetB),Limit, -Limit);		//PWM限幅
	Set_Pwm(Motor_Left, Motor_Right);

速度环及差速环的完成,意味着小车已经可以巡线和走直线了,那么接下来就可以按照题目要求让小车动起来了。

九、运动模式整合

1、模式一(AB)

第一问走直线,只需要用到陀螺仪。

其中ledbeginledflag用于声光模块,使用定时中断使声光运行500ms。

void Control_AB(void)                       //模式一
{
    int Motor_Left, Motor_Right;            //电机赋值
    float bias;                             //差速值

    bias = Yaw;                             //直接将陀螺仪偏差值作为差速值
    
    if ((P1!=0 || P2!=0 || P3!=0 || P4!=0 || P5!=0 || P6!=0 || P7!=0 || P8!=0)&&a==0)   //任一光电检测到黑色就停止
    {
        DL_GPIO_clearPins(GPIO_STBY_PORT,GPIO_STBY_PIN_STBY_PIN);
        ledbegin=1;
        a=1;                //停止标志位,判断是否已经停止,使此if仅进入一次
    }

    if (ledflag==1) DL_GPIO_setPins(GPIO_LED_PORT,GPIO_LED_PIN_LED_PIN);    //声光模块驱动判断
    else DL_GPIO_clearPins(GPIO_LED_PORT,GPIO_LED_PIN_LED_PIN);

    targetA = Speed_Middle+bias;                //基于基准值给电机差速
	targetB = Speed_Middle-bias;
    CurrentA = (float)gEncoderVal_left/3;       //左轮当前转速
	CurrentB = (float)gEncoderVal_right/3;      //右轮当前转速
	Motor_Left  = (int)PWM_Limit(PID_A(CurrentA,targetA),Limit, -Limit);
	Motor_Right = (int)PWM_Limit(PID_B(CurrentB,targetB),Limit, -Limit);		//PWM限幅
	Set_Pwm(Motor_Left, Motor_Right);
}

2、模式二(ABCDA)

第二问需要结合灰度和陀螺仪,根据返回值切换模式并寻路。

void Control_ABCDA(void)                    //模式二
{
	int Motor_Left, Motor_Right;            //电机赋值
    float bias;                             //差速值
    
    if(m==6)                                //m为模式切换计数值,用于判断是否跑完全程
    {
        DL_GPIO_clearPins(GPIO_STBY_PORT,GPIO_STBY_PIN_STBY_PIN);
    }

    if (ledflag==1) DL_GPIO_setPins(GPIO_LED_PORT,GPIO_LED_PIN_LED_PIN);    //声光模块驱动判断
    else DL_GPIO_clearPins(GPIO_LED_PORT,GPIO_LED_PIN_LED_PIN);

    if (P1==0 && P2==0 && P3==0 && P4==0 && P5==0 && P6==0 && P7==0 && P8==0) timebegin=1;  //给小车一个出弯延时,使转向时小车中心位于点上
    else whiteflag=0;
    
    if (whiteflag==1)           //在白色区域时,小车根据陀螺仪返回值走直线
    {
        ledflag2=0;
        if(ledflag1==0)
        {
            ledflag1=1;
            ledbegin=1;
            m++;
        }

        if (n%2==0)
        {
            if(Yaw<0) bias = 180 - myabs(Yaw);      //当走过白色区域为偶数时,须将+180和-180转化为0+和0-
            else bias = Yaw - 180;
        }
        else if(n%2==1)
        {
            bias = Yaw;                         //当走过白色区域为奇数时,不需要转化
        }
        flag=0;
    }
    else if(whiteflag==0)       //在黑线区域小车根据灰度返回值循迹
    {
        ledflag1=0;
        if(ledflag2==0)
        {
            ledflag2=1;
            ledbegin=1;
            m++;
        }

        if(flag==0)
        {
            flag=1;
            n=n+1;
        }
        bias = xunji();         //差速为灰度返回值
        whiteflag=0;
    }

    targetA = Speed_Middle+bias;
	targetB = Speed_Middle-bias;
    CurrentA = (float)gEncoderVal_left/3;       //左轮当前转速
	CurrentB = (float)gEncoderVal_right/3;      //右轮当前转速
	Motor_Left  = (int)PWM_Limit(PID_A(CurrentA,targetA),Limit, -Limit);
	Motor_Right = (int)PWM_Limit(PID_B(CurrentB,targetB),Limit, -Limit);		//PWM限幅
	Set_Pwm(Motor_Left, Motor_Right);
}

3、模式三(ACBDA)

第三问的难点在于在出弯时如何让小车精准的转向,这里我们使用陀螺仪使小车走固定角度,通过出弯时快速转向来提高准确性。

同时,因为我们使用八路灰度进行入弯判断,在入弯时,小车一旦向内偏离就会使外侧光电先识别到,从而直接漂出轨道,如图:

9f83442edd7e47cbb717d696a63b628c.jpeg

对此我的解决方案是,在模式三及模式四中,我们只使用半边的灰度来进行循迹,从A到C时使用左半边,从B到D时使用右半边。

void Control_ACBDA(void)                //模式三
{
    int Motor_Left, Motor_Right;        //电机赋值
    float bias;                         //差速值

    if(m==6)                            //m为模式切换计数值,用于判断是否跑完全程
    {
        DL_GPIO_clearPins(GPIO_STBY_PORT,GPIO_STBY_PIN_STBY_PIN);
    }

    if (ledflag==1) DL_GPIO_setPins(GPIO_LED_PORT,GPIO_LED_PIN_LED_PIN);
    else DL_GPIO_clearPins(GPIO_LED_PORT,GPIO_LED_PIN_LED_PIN);

    if (P1==0 && P2==0 && P3==0 && P4==0 && P5==0 && P6==0 && P7==0 && P8==0) timebegin1=1;
    else whiteflag1=0;

    if (whiteflag1==1) 
    {
        ledflag2=0;
        if(ledflag1==0)
        {
            ledflag1=1;
            ledbegin=1;
            m++;
        }

        if (n%2==0)
        {
            bias = Yaw + 105;                       //以A到C的方向为0,B到D的巡航角为-103~-106,具体数值根据实际自行调整
        }
        else if(n%2==1)
        {
            bias = Yaw;
        }
        flag=0;
    }
    else if(whiteflag1==0)
    {
        ledflag1=0;
        if(ledflag2==0)
        {
            ledflag2=1;
            ledbegin=1;
            m++;
        }

        if(flag==0)
        {
            flag=1;
            n=n+1;
        }

        if(n%2==1) bias = xunji_right();                //从B到D时使用右半边灰度       
        else if(n%2==0) bias = xunji_left();            //从A到C时使用左半边灰度
        
        whiteflag1=0;
    }


    targetA = Speed_Middle+bias;
	targetB = Speed_Middle-bias;
    CurrentA = (float)gEncoderVal_left/3; //left
	CurrentB = (float)gEncoderVal_right/3; //right
	Motor_Left  = (int)PWM_Limit(PID_A(CurrentA,targetA),Limit, -Limit);
	Motor_Right = (int)PWM_Limit(PID_B(CurrentB,targetB),Limit, -Limit);		//PWM限幅
	Set_Pwm(Motor_Left, Motor_Right);
}

4、模式四(ACBDAx4)

模式四与模式三差别不大,只需要参数微调,就不放了,大家可以直接去工程中对比学习。

十、按键等其余外设配置

1、按键

06630424c64d4215940950b79dae4102.png

2、声光模块

b1e7ea4809c6426a876a5672d61538a9.png

3、电机驱动板使能

0c4971922159494093ddcb879a22e459.png

4、OLED

我们将当前模式、当前巡航角显示在了OLED上,使用软件I2C进行通信。

48b8b5138e494dcb81718b357f72f9ae.png

十一、整体主控(main函数)

本工程中的整体控制是放在了main函数中,包括电机控制函数也放在main函数中,这样的好处是控制周期短,但也容易被打断,大家也可以再开一个定时器用于调用控制函数,当然定时器周期需尽可能短。

extern float Yaw;

int main(void)
{
    uint8_t a=5;
    int mode=0;             //小车运动模式
    int begin=0;            //小车启动标志位
    SYSCFG_DL_init();
 
    NVIC_EnableIRQ(TIMER_Encoder_Read_INST_INT_IRQN);           //开启定时器
    NVIC_EnableIRQ(GPIO_EncoderA_INT_IRQN);                     //开启编码器外部中断
    NVIC_EnableIRQ(GPIO_EncoderB_INT_IRQN);
    DL_Timer_startCounter(TIMER_Encoder_Read_INST);             //开启定时中断用于读取编码器数据
    DL_Timer_startCounter(PWM_0_INST);                          //pwm定时器初始化
    OLED_Init();		                                        //初始化OLED
    NVIC_EnableIRQ(UART_JY61P_INST_INT_IRQN);                   //使能中断
    Serial_JY61P_Zero_Yaw();                                    //复位陀螺仪,使上电时位置为0

    while (1) 
    {
        OLED_ClearArea(0,0,79,40);                                                  //刷新oled
        if(!DL_GPIO_readPins(GPIO_Key_PIN_S2_PORT, GPIO_Key_PIN_S2_PIN))            //模式切换
        {
            Delay_ms(10);
            if(!DL_GPIO_readPins(GPIO_Key_PIN_S2_PORT, GPIO_Key_PIN_S2_PIN))
            {
                 mode = (mode + 1)%4;
            }
            while(!DL_GPIO_readPins(GPIO_Key_PIN_S2_PORT, GPIO_Key_PIN_S2_PIN));
        }
        else if(!DL_GPIO_readPins(GPIO_Key_PIN_S1_PORT, GPIO_Key_PIN_S1_PIN))       //小车启动
        {
            Delay_ms(10);
            if(!DL_GPIO_readPins(GPIO_Key_PIN_S1_PORT, GPIO_Key_PIN_S1_PIN))
            {
                Delay_ms(2000);                                                     //启动延时
                DL_GPIO_setPins(GPIO_STBY_PORT,GPIO_STBY_PIN_STBY_PIN);
                begin=1;
            }
            while(!DL_GPIO_readPins(GPIO_Key_PIN_S1_PORT, GPIO_Key_PIN_S1_PIN));
        }
        
        if (mode==0)
        {
            OLED_ShowString(0, 0, "AB",OLED_8X16);                          //在OLED上显示当前模式
            OLED_Printf(0, 40, OLED_6X8, "Yaw:%5.2f",Yaw);                  //显示当前巡航角
            OLED_Update();
            if (begin==1)
            {
                Control_AB();
            }
        }
        else if(mode==1)
        {
            OLED_ShowString(0, 0, "ABCDA",OLED_8X16);
            OLED_Printf(0, 40, OLED_6X8, "Yaw:%5.2f",Yaw);
            OLED_Update();
            if (begin==1)
            {
                Control_ABCDA();
            }
        }
        else if(mode==2)
        {
            OLED_ShowString(0, 0, "ACBDA",OLED_8X16);
            OLED_Printf(0, 40, OLED_6X8, "Yaw:%5.2f",Yaw);
            OLED_Update();
            if (begin==1)
            {
                Control_ACBDA();
            }
        }
        else if(mode==3)
        {
            OLED_ShowString(0, 0, "ACBDAx4",OLED_8X16);
            OLED_Printf(0, 40, OLED_6X8, "Yaw:%5.2f",Yaw);
            OLED_Update();
            if (begin==1)
            {
                Control_ACBDAx4();
            }
        }  
    }
}

十二、源码分享

百度网盘:提取码:qs65

CSDN:【2024电赛H题】自动行驶小车

十三、结语

学无止境,希望每一位读者都能够有所收获,有不足之处也欢迎大家在评论区留言或者私信。

大家也可以去看看南极熊学长的方案,方案无好坏,各有优缺,希望大家融会贯通,精益求精。

指路:2024年电赛H题自动行驶小车

如有疑问或想交流学习心得,欢迎加入交流群751950234,群内不定期更新代码。

评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值