msp430f5529库函数总结

msp430f5529库函数总结

说好的做完电设发源码,结果托更的时间有点长看,作为补偿这边博客写的详尽一些,希望各位能够看完就会用。

吐槽一下,TI官方公布的库函数只有几个示例,我在比赛前自己移植了一边所有的基础功能,比如uart,iic,spi,pwm,定时器等,iic和spi最为难调,也不知道底层写的怎么样,只能通过示波器看现象,按照经验调。

源码链接:https://download.csdn.net/download/YOUNGAAAAA/85007021

先介绍一下msp430f5529:

在这里插入图片描述
板载一个32.768K的RTC时钟XTAL1和一个4MHz 的时钟
在这里插入图片描述

GPIO:
P1、P2支持中断,分别公用一个中断向量。
在这里插入图片描述

在这里插入图片描述
Pwm引脚:

在这里插入图片描述
中断:
在这里插入图片描述
定时器:
在这里插入图片描述
在这里插入图片描述

时钟

这一款芯片主打低功耗,如果作为电赛人推荐用432,功能多,主频还高。缺点显而易见就是主频低,如果全低功耗的情况下系统时钟只有1Mhz,你没看错,这跑个锤子。

所以第一步先要将主频拉高,再往前一步说就是要走出低功耗的范围,将内核电压拉高。

直接上代码:

void clock_init(unsigned char Fre)
{

    P5SEL |= BIT2|BIT3|BIT4|BIT5;//开启外部两个时钟

    UCSCTL6 |= XCAP_3|XT1OFF;          // XT1 相关 配置
    UCSCTL6 |= XT2DRIVE_0 |XT2OFF;     // XT2 相关 配置
//以下是提升核心电压部分的代码
    PMMCTL0_H = 0xA5;                                         //开PMM电源管理
    SVSMLCTL |= SVSMLRRL_1 + SVMLE;                            //配置SVML电压
    PMMCTL0 =  PMMPW + PMMCOREV_3;                             //配置内核电压
    while((PMMIFG & SVSMLDLYIFG ) == 0);                       //等待设置完成
    PMMIFG &= ~(SVMLVLRIFG + SVMLIFG + SVSMLDLYIFG);
    if((PMMIFG & SVMLIFG) == 1)                                //判断内核电压是否上升到VSVML
         while((PMMIFG & SVMLVLRIFG) == 0);                    //如果没有等待
    SVSMLCTL &= ~SVMLE;                                        //关掉SVML模块
    PMMCTL0_H = 0X00;

    __bis_SR_register(SCG0);                 //该语法为固定格式,意为将括号内的变量置位,SCG0与系统工作模式有关,此时 MCLK 暂停工作
    UCSCTL0 = 0;                             //先清零,FLL 运行时,该寄存器系统会自动配置,不用管
    UCSCTL6 = (UCSCTL6&(~(XT2OFF|XT1OFF))|XCAP_3|XT2DRIVE_0);
    UCSCTL3 = (5<<4)|(2<<0);                 // 选择 XTAL2 的时钟信号作为参考信号 并且分频到1MHz
    if(Fre < 5)
        UCSCTL1 = DCORSEL_2;
    else if(Fre<15)
        UCSCTL1 = DCORSEL_4;
    else
        UCSCTL1 = DCORSEL_7;
   UCSCTL2 = (Fre-1);
    __bic_SR_register(SCG0);
    __delay_cycles(782000);
    while (SFRIFG1 & OFIFG) {                               // Check OFIFG fault flag
      UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + DCOFFG);           // Clear OSC flaut Flags
      SFRIFG1 &= ~OFIFG;                                    // Clear OFIFG fault flag
    }
    UCSCTL4 = UCSCTL4&(~(SELS_7|SELM_7))|SELS_3|SELM_3;
}

只需要再初始化的时候将这个函数加上即可,代替原有的clock_init(frequency Mhz);
比如这里超频到40Mhz,实测不要超过44Mhz,不然系统运行很不稳定。
在这里插入图片描述

定时器

TIMB(1ms周期定时器,用作控制中断), TIMA0(4路pwm输出 20khz 用于电驱),TIMA1(50hz pwm输出,舵机控制),TIMA2(输入捕获)四个定时器都用上了

void TimerBInit(void)//40M/10/4000 = 1ms
{
    Timer_B_initUpModeParam paramB = {0};
    paramB.clockSource = TIMER_B_CLOCKSOURCE_SMCLK;
    paramB.clockSourceDivider = TIMER_B_CLOCKSOURCE_DIVIDER_10;
    paramB.timerPeriod = 4000;
    paramB.timerInterruptEnable_TBIE = TIMER_B_TBIE_INTERRUPT_DISABLE;
    paramB.captureCompareInterruptEnable_CCR0_CCIE = TIMER_B_CCIE_CCR0_INTERRUPT_ENABLE;
    paramB.timerClear = TIMER_B_DO_CLEAR;
    paramB.startTimer = true;
    Timer_B_initUpMode(TIMER_B0_BASE,&paramB);
    Timer_B_startCounter( TIMER_B0_BASE,TIMER_B_UP_MODE);
}



void timerA0PWMInit(void) //40Mhz/1/2000=20khz
{
    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P1,GPIO_PIN2+GPIO_PIN3+GPIO_PIN4+GPIO_PIN5);//初始化GPIO
    Timer_A_outputPWMParam param;
    param.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;//选择时钟源
    param.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;//时钟源不分频
    param.timerPeriod = 2000;//定时器装载值
    param.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;//初始化捕获比较寄存器1,对应通道TA0.1
    param.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;//选择输出模式
    param.dutyCycle = 1000;//
    Timer_A_outputPWM(TIMER_A0_BASE,&param);

    param.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_2;//初始化捕获比较寄存器2,对应通道TA0.2
    Timer_A_outputPWM(TIMER_A0_BASE,&param);
    param.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_3;//初始化捕获比较寄存器2,对应通道TA0.3
    Timer_A_outputPWM(TIMER_A0_BASE,&param);
    param.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_4;//初始化捕获比较寄存器2,对应通道TA0.4
    Timer_A_outputPWM(TIMER_A0_BASE,&param);
}

void timerA1PWMInit(void)  //40M/40/20000=50hz
{
    GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P2,GPIO_PIN0);
    Timer_A_outputPWMParam param1;
    param1.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;//选择时钟源
    param1.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_40;//时钟源不分频
    param1.timerPeriod = 20000;//定时器装载值
    param1.compareRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;//初始化捕获比较寄存器1,对应通道TA0.1
    param1.compareOutputMode = TIMER_A_OUTPUTMODE_RESET_SET;//选择输出模式
    param1.dutyCycle = 0;//
    Timer_A_outputPWM(TIMER_A1_BASE,&param1);

//    Timer_A_initUpModeParam param = {0};
//    param.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;
//    param.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_10;
//    param.timerPeriod = 4000;
//    param.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_DISABLE;
//    param.captureCompareInterruptEnable_CCR0_CCIE = TIMER_A_CCIE_CCR0_INTERRUPT_ENABLE;
//    param.timerClear = TIMER_A_DO_CLEAR;
//    param.startTimer = true;
//    Timer_A_initUpMode(TIMER_A1_BASE,&param);
//    Timer_A_startCounter( TIMER_A1_BASE,TIMER_A_UP_MODE);

}

void TimerA2CaptureInit(void) //40/1
{
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P2, GPIO_PIN4 + GPIO_PIN5);

    Timer_A_initContinuousModeParam param0 = {0};
    param0.clockSource = TIMER_A_CLOCKSOURCE_SMCLK;
    param0.clockSourceDivider = TIMER_A_CLOCKSOURCE_DIVIDER_1;
    param0.timerInterruptEnable_TAIE = TIMER_A_TAIE_INTERRUPT_ENABLE;
    param0.timerClear = TIMER_A_DO_CLEAR;
    param0.startTimer = true;
    Timer_A_initContinuousMode(TIMER_A2_BASE,&param0);

    Timer_A_initCaptureModeParam param1 = {0};
    param1.captureRegister = TIMER_A_CAPTURECOMPARE_REGISTER_1;
    param1.captureMode = TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE;
    param1.captureInputSelect = TIMER_A_CAPTURE_INPUTSELECT_CCIxA;
    param1.synchronizeCaptureSource = TIMER_A_CAPTURE_SYNCHRONOUS;
    param1.captureInterruptEnable = TIMER_A_CAPTURECOMPARE_INTERRUPT_ENABLE;
    param1.captureOutputMode = TIMER_A_OUTPUTMODE_OUTBITVALUE;
    Timer_A_initCaptureMode(TIMER_A2_BASE,&param1);

    param1.captureRegister =  TIMER_A_CAPTURECOMPARE_REGISTER_2;//Two capture intputs PWM cannot start or end in the same time.
    param1.captureMode = TIMER_A_CAPTUREMODE_RISING_AND_FALLING_EDGE;
    Timer_A_initCaptureMode(TIMER_A2_BASE,&param1);
}

uart

两个串口,应该够用了,接收中断是必须开的,不然在哪放接收处理函数。

void Usart1Init(void)
{
  GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P4, GPIO_PIN5);
  GPIO_setAsPeripheralModuleFunctionOutputPin(GPIO_PORT_P4, GPIO_PIN4);

  //Baudrate = 115200, clock freq = 4MHz
  //UCBRx = 34, UCBRFx = 6, UCBRSx = 0, UCOS16 = 0
  USCI_A_UART_initParam param = {0};
  param.selectClockSource = USCI_A_UART_CLOCKSOURCE_SMCLK;
  param.clockPrescalar = 347;
  param.firstModReg = 2;
  param.secondModReg = 0;
  param.parity = USCI_A_UART_NO_PARITY;
  param.msborLsbFirst = USCI_A_UART_LSB_FIRST;
  param.numberofStopBits = USCI_A_UART_ONE_STOP_BIT;
  param.uartMode = USCI_A_UART_MODE;
  param.overSampling = USCI_A_UART_LOW_FREQUENCY_BAUDRATE_GENERATION;

  if (STATUS_FAIL == USCI_A_UART_init(USCI_A1_BASE, &param))
  {
      return;
  }

  //Enable UART module for operation
  USCI_A_UART_enable(USCI_A1_BASE);

  //Enable Receive Interrupt
  USCI_A_UART_clearInterrupt(USCI_A1_BASE,USCI_A_UART_RECEIVE_INTERRUPT);
  USCI_A_UART_enableInterrupt(USCI_A1_BASE,USCI_A_UART_RECEIVE_INTERRUPT);
}

void Usart0Init(void)
{
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P3,GPIO_PIN4 + GPIO_PIN3);
    USCI_A_UART_initParam param = {0};
    param.selectClockSource = USCI_A_UART_CLOCKSOURCE_SMCLK;
    param.clockPrescalar = 347;
    param.firstModReg = 2;
    param.secondModReg = 0;
    param.parity = USCI_A_UART_NO_PARITY;
    param.msborLsbFirst = USCI_A_UART_LSB_FIRST;
    param.numberofStopBits = USCI_A_UART_ONE_STOP_BIT;
    param.uartMode = USCI_A_UART_MODE;
    param.overSampling = USCI_A_UART_LOW_FREQUENCY_BAUDRATE_GENERATION;

    if (STATUS_FAIL == USCI_A_UART_init(USCI_A0_BASE, &param)){
        return;
    }

    //Enable UART module for operation
      USCI_A_UART_enable(USCI_A0_BASE);

    //Enable Receive Interrupt
      USCI_A_UART_clearInterrupt(USCI_A0_BASE,USCI_A_UART_RECEIVE_INTERRUPT);
      USCI_A_UART_enableInterrupt(USCI_A0_BASE,USCI_A_UART_RECEIVE_INTERRUPT);
}

uart必须支持printf,配置不难

/*printf redefine*/

int fputc(int ch,FILE *f)
{
    UCA1TXBUF = ch&0xff;
    while(!(UCA1IFG & UCTXIFG));//等待发送完成
     return ch;
}
int fputs(const char *_ptr, register FILE *_fp)
{
  unsigned int i, len;

  len = strlen(_ptr);

  for(i=0 ; i<len ; i++){
    UCA1TXBUF = _ptr[i]&0xff;
    while(!(UCA1IFG & UCTXIFG));//等待发送完成

  }

  return len;
}


void send0(unsigned char *ptr)    //Send string.
{
    while(*ptr != '\0')
    {
        USCI_A_UART_transmitData(USCI_A0_BASE,*ptr);
        ptr++;
    }
}

ADC

adc初始化(6路)和读取函数(平均滤波);

void ADC12AInit(void)   //40Mhz / 8 =5Mhz
{
    GPIO_setAsPeripheralModuleFunctionInputPin(GPIO_PORT_P6, GPIO_PIN1+GPIO_PIN2 + GPIO_PIN3 + GPIO_PIN4 + GPIO_PIN5 + GPIO_PIN6);
    // Initialize ADC12 with ADC12’s built-in oscillator
    ADC12_A_init (ADC12_A_BASE,ADC12_A_SAMPLEHOLDSOURCE_SC,ADC12_A_CLOCKSOURCE_SMCLK,ADC12_A_CLOCKDIVIDER_3);
    //Switch ON ADC12
    ADC12_A_enable(ADC12_A_BASE);
    // Setup sampling timer to sample-and-hold for 16 clock cycles
    ADC12_A_setupSamplingTimer (ADC12_A_BASE,ADC12_A_CYCLEHOLD_64_CYCLES,ADC12_A_CYCLEHOLD_4_CYCLES,ADC12_A_MULTIPLESAMPLESENABLE);
    // Configure the Input to the Memory Buffer with the specified Reference Voltages
    ADC12_A_configureMemoryParam param = {0};
    param.memoryBufferControlIndex = ADC12_A_MEMORY_2;
    param.inputSourceSelect = ADC12_A_INPUT_A2;
    param.positiveRefVoltageSourceSelect = ADC12_A_VREFPOS_AVCC;
    param.negativeRefVoltageSourceSelect = ADC12_A_VREFNEG_AVSS;
    param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
    ADC12_A_configureMemory(ADC12_A_BASE ,&param);

    param.memoryBufferControlIndex = ADC12_A_MEMORY_3;
    param.inputSourceSelect = ADC12_A_INPUT_A3;
    param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
    ADC12_A_configureMemory(ADC12_A_BASE ,&param);


    param.memoryBufferControlIndex = ADC12_A_MEMORY_1;
    param.inputSourceSelect = ADC12_A_INPUT_A1;
    param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
    ADC12_A_configureMemory(ADC12_A_BASE ,&param);

    param.memoryBufferControlIndex = ADC12_A_MEMORY_4;
    param.inputSourceSelect = ADC12_A_INPUT_A4;
    param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
    ADC12_A_configureMemory(ADC12_A_BASE ,&param);

    param.memoryBufferControlIndex = ADC12_A_MEMORY_5;
    param.inputSourceSelect = ADC12_A_INPUT_A5;
    param.endOfSequence = ADC12_A_NOTENDOFSEQUENCE;
    ADC12_A_configureMemory(ADC12_A_BASE ,&param);

    param.memoryBufferControlIndex = ADC12_A_MEMORY_6;
    param.inputSourceSelect = ADC12_A_INPUT_A6;
    param.endOfSequence = ADC12_A_ENDOFSEQUENCE;
    ADC12_A_configureMemory(ADC12_A_BASE ,&param);
}

void ADCRead(void)
{
    int i;
    for(i=0;i<7;i++) ADCValue[i]=0;
    for(i=0;i<10;i++)
    {
        // Start a single conversion, no repeating or sequences.
        ADC12_A_startConversion (ADC12_A_BASE,ADC12_A_MEMORY_1,ADC12_A_SEQOFCHANNELS);
        // Wait for the Interrupt Flag to assert
        while( !(ADC12_A_getInterruptStatus(ADC12_A_BASE,ADC12_A_IFG1)) );
        // Clear the Interrupt Flag and start another conversion
        ADC12_A_clearInterrupt(ADC12_A_BASE,ADC12_A_IFG1);
//        ADCValue[0] += 0.1*ADC12MEM0;
        ADCValue[0] += 0.1*ADC12MEM1;
        ADCValue[1] += 0.1*ADC12MEM2;
        ADCValue[2] += 0.1*ADC12MEM3;
        ADCValue[3] += 0.1*ADC12MEM4;
        ADCValue[4] += 0.1*ADC12MEM5;
        ADCValue[5] += 0.1*ADC12MEM6;
       for(i=0;i<9;i++)
       {
           ADCVfinal[i] = ADCValue[i]*3.3/4096;
           ADCVfinal[i] = ADCVfinal[i]*10;
       }
    }
}

可能有人会发现为啥没有ADC12_A_MEMORY_0,问就是有bug调不出来。未知问题就这个用不了。

iic

iic实测是有点bug的,谨慎使用,本来是用它来驱动oled屏幕,用是能用,出奇的慢,其他设备iic通过没试过。

void iic_init()
{
    GPIO_setAsOutputPin(GPIO_PORT_P3,GPIO_PIN1);
    uint8_t i=0;
          // 输出9个时钟以恢复I2C总线状态
          for(  i= 0; i <9 ; i++)
          {
              GPIO_setOutputHighOnPin(GPIO_PORT_P3,GPIO_PIN1);
            __delay_cycles(8000);
              GPIO_setOutputLowOnPin(GPIO_PORT_P3,GPIO_PIN1);
            __delay_cycles(8000);
          }


    GPIO_setAsPeripheralModuleFunctionInputPin(
        GPIO_PORT_P3,
        GPIO_PIN1 + GPIO_PIN0
        );
    //Initialize transmit data packet
    transmitData = 0x01;
    //Initialize Master
    USCI_B_I2C_initMasterParam param = {0};
    param.selectClockSource = USCI_B_I2C_CLOCKSOURCE_SMCLK;
    param.i2cClk = UCS_getSMCLK();
    param.dataRate = USCI_B_I2C_SET_DATA_RATE_100KBPS;
    USCI_B_I2C_initMaster(USCI_B0_BASE, &param);

    //Specify slave address
    USCI_B_I2C_setSlaveAddress(USCI_B0_BASE,
        SLAVE_ADDRESS
        );

    //Set in transmit mode
    USCI_B_I2C_setMode(USCI_B0_BASE,
        USCI_B_I2C_TRANSMIT_MODE
        );

    //Enable I2C Module to start operations
    USCI_B_I2C_enable(USCI_B0_BASE);


}

spi

spi没啥问题,这样配置也差不多了。用于ICM20602,所以初始化了一些其他io。

void spi_init(void)
{
    //Set P1.1 for slave reset
    GPIO_setAsOutputPin(GPIO_PORT_P7,GPIO_PIN4);
    //P3.5,4,0 option select
    GPIO_setAsPeripheralModuleFunctionInputPin(
        GPIO_PORT_P3,
        GPIO_PIN1 + GPIO_PIN2 + GPIO_PIN0
        );
    //Initialize Master
    USCI_B_SPI_initMasterParam param = {0};
    param.selectClockSource = USCI_B_SPI_CLOCKSOURCE_SMCLK;
    param.clockSourceFrequency = UCS_getSMCLK();
    param.desiredSpiClock = SPICLK;
    param.msbFirst = USCI_B_SPI_MSB_FIRST;
    param.clockPhase = USCI_B_SPI_PHASE_DATA_CHANGED_ONFIRST_CAPTURED_ON_NEXT;
    param.clockPolarity = USCI_B_SPI_CLOCKPOLARITY_INACTIVITY_HIGH;
    returnValue =  USCI_B_SPI_initMaster(USCI_B0_BASE, &param);

    if (STATUS_FAIL == returnValue){
        return;
    }

    //Enable SPI module
    USCI_B_SPI_enable(USCI_B0_BASE);

    //Enable Receive interrupt
    USCI_B_SPI_clearInterrupt(USCI_B0_BASE, USCI_B_SPI_RECEIVE_INTERRUPT);
    USCI_B_SPI_enableInterrupt(USCI_B0_BASE, USCI_B_SPI_RECEIVE_INTERRUPT);

    //LED On
    GPIO_setOutputHighOnPin(GPIO_PORT_P1,GPIO_PIN0);
    GPIO_setOutputHighOnPin(GPIO_PORT_P7,GPIO_PIN4);
    //Wait for slave to initialize
    __delay_cycles(100);

    //USCI_A0 TX buffer ready?
    while (!USCI_B_SPI_getInterruptStatus(USCI_B0_BASE,
               USCI_B_SPI_TRANSMIT_INTERRUPT)) ;



}

外部中断

这段代码最后那一部分是自己写的软件编码器设定的参数,和控制代码放在一个定时中断就可以用,有兴趣的下载源码看看,写了几天,效果和输入捕获的没差别,还能省一个定时器。

void EXIT_init(void)
{
    //Enable internal resistance as pull-down resistance and interrupt enabled
    GPIO_setAsInputPinWithPullDownResistor(GPIO_PORT_P2,GPIO_PIN3);
    GPIO_enableInterrupt(GPIO_PORT_P2,GPIO_PIN3);
    GPIO_setAsInputPinWithPullDownResistor(GPIO_PORT_P2,GPIO_PIN6);
    GPIO_enableInterrupt(GPIO_PORT_P2,GPIO_PIN6);

    GPIO_selectInterruptEdge(GPIO_PORT_P2,GPIO_PIN3,GPIO_LOW_TO_HIGH_TRANSITION);
    GPIO_selectInterruptEdge(GPIO_PORT_P2,GPIO_PIN6,GPIO_LOW_TO_HIGH_TRANSITION);

    // IFG cleared
    GPIO_clearInterrupt(GPIO_PORT_P2,GPIO_PIN3);
    GPIO_clearInterrupt(GPIO_PORT_P2,GPIO_PIN6);

    //dir config
    GPIO_setAsInputPin(GPIO_PORT_P4,GPIO_PIN3);
    GPIO_setAsInputPin(GPIO_PORT_P8,GPIO_PIN1);


    encoder1.M=0;
    encoder1.M_speed=0;
    encoder1.T = 0;
    encoder1.T_count=0;
    encoder1.T_sum=0;
    encoder1.T_time=0;
    encoder1.index = 0;
    encoder1.EXTI_FLAG = 0;

    encoder2.M=0;
    encoder2.M_speed=0;
    encoder2.T = 0;
    encoder2.T_count=0;
    encoder2.T_sum=0;
    encoder2.T_time=0;
    encoder2.index = 0;
    encoder2.EXTI_FLAG = 0;

}

在这里插入图片描述
中断配置再isr.c,定时器中断,外部中断等,硬件编码器,软件编码器都在。

有需求自己拿哈,望各位电赛人取得好成绩。

私戳的话不一定能及时看到,比较佛系。

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值