AT9G45的pwm驱动有问题,快来解救小弟.

在使用AT9G45芯片进行PWM驱动时遇到了困难,文章主要聚焦于头文件的内容,探讨可能存在的struct对齐问题、div模块功能、function调用以及file的相关错误,寻求解决方案。
摘要由CSDN通过智能技术生成

 AT9G45的pwm,头文件

#ifndef AT91_PWM_H
#define AT91_PWM_H

#define PWMC_BASE 0xfffb8000

/****************  pwm模式寄存器偏移0x00  *****************/
#define PWM_MR_OFF              0x00000000    ///< PWM Mode Register offset.
#define PWM_MR     (*((volatile unsigned long *)(PWMC_BASE + PWM_MR_OFF))) ///< PWM Mode Register.
#define PWM_MR_DIVA_MASK        0x000000FF    ///< PWM Mode Divide factor A Mask.
#define PWM_MR_DIVA_SHIFT       0             ///< PWM Mode Divide factor A LSB.
#define PWM_MR_DIVB_MASK        0x00FF0000    ///< PWM Mode Divide factor B Mask.
#define PWM_MR_DIVB_SHIFT       16            ///< PWM Mode Divide factor B LSB.

#define PWM_MR_PREA_MASK        0x00000F00    ///< PWM Mode prescaler A Mask.
#define PWM_MR_PREA_SHIFT       8             ///< PWM Mode prescaler A LSB.
#define PWM_MR_PREB_MASK        0x0F000000    ///< PWM Mode prescaler B Mask.
#define PWM_MR_PREB_SHIFT       24            ///< PWM Mode prescaler B LSB.

#define PWM_MR_PRE_MCK          0             ///< PWM Mode prescaler set to MCK.
#define PWM_MR_PRE_MCK_DIV2     1             ///< PWM Mode prescaler set to MCK/2.
#define PWM_MR_PRE_MCK_DIV4     2             ///< PWM Mode prescaler set to MCK/4.
#define PWM_MR_PRE_MCK_DIV8     3             ///< PWM Mode prescaler set to MCK/8.
#define PWM_MR_PRE_MCK_DIV16    4             ///< PWM Mode prescaler set to MCK/16.
#define PWM_MR_PRE_MCK_DIV32    5             ///< PWM Mode prescaler set to MCK/32.
#define PWM_MR_PRE_MCK_DIV64    6             ///< PWM Mode prescaler set to MCK/64.
#define PWM_MR_PRE_MCK_DIV128   7             ///< PWM Mode prescaler set to MCK/128.
#define PWM_MR_PRE_MCK_DIV256   8             ///< PWM Mode prescaler set to MCK/256.
#define PWM_MR_PRE_MCK_DIV512   9             ///< PWM Mode prescaler set to MCK/512.
#define PWM_MR_PRE_MCK_DIV1024  10            ///< PWM Mode prescaler set to MCK/1024.

#define PWM_CHID_MASK           0x0000000F
#define PWM_CHID0               0
#define PWM_CHID1               1
#define PWM_CHID2               2
#define PWM_CHID3               3

/***********************  pwm使能寄存器偏移0x04  *****************/
#define PWM_ENA_OFF             0x00000004    ///< PWM Enable Register offset.
#define PWM_ENA     (*((volatile unsigned long *)(PWMC_BASE + PWM_ENA_OFF))) ///< PWM Enable Register.


/***********************  pwm去使能寄存器0x08  *****************/
#define PWM_DIS_OFF             0x00000008    ///< PWM Disable Register offset.
#define PWM_DIS     (*((volatile unsigned long *)(PWMC_BASE + PWM_DIS_OFF))) ///< PWM Disable Register.

/*********************  pwm状态寄存器0x0C  *****************/
#define PWM_SR_OFF              0x0000000C    ///< PWM Status Register offset.
#define PWM_SR      (*((volatile unsigned long *)(PWMC_BASE + PWM_SR_OFF)))  ///< PWM Status Register.

/**********************  pwm中断使能寄存器0x10 *****************/
#define PWM_IER_OFF             0x00000010    ///< PWM Interrupt Enable Register offset.
#define PWM_IER     (*((volatile unsigned long *)(PWMC_BASE + PWM_IER_OFF))) ///< PWM Interrupt Enable Register.

/**********************  pwm中断去使能寄存器0x14  *****************/
#define PWM_IDR_OFF             0x00000014    ///< PWM Interrupt Disable Register offset.
#define PWM_IDR     (*((volatile unsigned long *)(PWMC_BASE + PWM_IDR_OFF))) ///< PWM Interrupt Disable Register.


/**********************  pwm中断掩码寄存器0x18  *****************/
#define PWM_IMR_OFF             0x00000018    ///< PWM Interrupt Mask Register offset.
#define PWM_IMR     (*((volatile unsigned long *)(PWMC_BASE + PWM_IMR_OFF))) ///< PWM Interrupt Mask Register.

/**********************  pwm中断状态寄存器0x1c  *****************/
#define PWM_ISR_OFF             0x0000001C    ///< PWM Interrupt Status Register offset.
#define PWM_ISR     (*((volatile unsigned long *)(PWMC_BASE + PWM_ISR_OFF))) ///< PWM Interrupt Status Register.

/**********************  pwm通道模式寄存器 0x200+ch_num*0x20+0x00  *****************/
#define PWM_CH0_OFF             0x00000200    ///< PWM Channel 0 registers offset.
#define PWM_CH1_OFF             0x00000220    ///< PWM Channel 1 registers offset.
#define PWM_CH2_OFF             0x00000240    ///< PWM Channel 2 registers offset.
#define PWM_CH3_OFF             0x00000260    ///< PWM Channel 3 registers offset.

#define PWM_CMR_OFF             0x00000000    ///< PWM Channel Mode Register offset.
#define PWM_CMR0    (*((volatile unsigned long *)(PWMC_BASE + PWM_CMR_OFF + PWM_CH0_OFF))) ///< PWM Channel 0 Mode Register.
#define PWM_CMR1    (*((volatile unsigned long *)(PWMC_BASE + PWM_CMR_OFF + PWM_CH1_OFF))) ///< PWM Channel 1 Mode Register.
#define PWM_CMR2    (*((volatile unsigned long *)(PWMC_BASE + PWM_CMR_OFF + PWM_CH2_OFF))) ///< PWM Channel 2 Mode Register.
#define PWM_CMR3    (*((volatile unsigned long *)(PWMC_BASE + PWM_CMR_OFF + PWM_CH3_OFF))) ///< PWM Channel 3 Mode Register.



#define PWM_CPRE_MCK_MASK       0x0000000F    ///< PWM Mode prescaler mask.
#define PWM_CPRE_MCK            0             ///< PWM Mode prescaler set to MCK.
#define PWM_CPRE_MCK_DIV2       1             ///< PWM Mode prescaler set to MCK/2.
#define PWM_CPRE_MCK_DIV4       2             ///< PWM Mode prescaler set to MCK/4.
#define PWM_CPRE_MCK_DIV8       3             ///< PWM Mode prescaler set to MCK/8.
#define PWM_CPRE_MCK_DIV16      4             ///< PWM Mode prescaler set to MCK/16.
#define PWM_CPRE_MCK_DIV32      5             ///< PWM Mode prescaler set to MCK/32.
#define PWM_CPRE_MCK_DIV64      6             ///< PWM Mode prescaler set to MCK/64.
#define PWM_CPRE_MCK_DIV128     7             ///< PWM Mode prescaler set to MCK/128.
#define PWM_CPRE_MCK_DIV256     8             ///< PWM Mode prescaler set to MCK/256.
#define PWM_CPRE_MCK_DIV512     9             ///< PWM Mode prescaler set to MCK/512.
#define PWM_CPRE_MCK_DIV1024    10            ///< PWM Mode prescaler set to MCK/1024.
#define PWM_CPRE_CLKA           11            ///< PWM Mode prescaler set to CLKA.
#define PWM_CPRE_CLKB           12            ///< PWM Mode prescaler set to CLKB.
#define 	AT91C_PWMC_CPRE_MCKB                 0xC /**< (PWMC_CH)  */ 
#define PWM_CALG                8             ///< PWM Mode channel alignment.
#define PWM_CPOL                9             ///< PWM Mode channel polarity.
#define PWM_CPD                 10            ///< PWM Mode channel update period.


#define PWM_CDTY_OFF            0x00000004    ///< PWM Channel Duty Cycle Register offset.
#define PWM_CDTY0   (*((volatile unsigned long *)(PWMC_BASE + PWM_CDTY_OFF + PWM_CH0_OFF))) ///< PWM Channel 0 Duty Cycle Register.
#define PWM_CDTY1   (*((volatile unsigned long *)(PWMC_BASE + PWM_CDTY_OFF + PWM_CH1_OFF))) ///< PWM Channel 1 Duty Cycle Register.
#define PWM_CDTY2   (*((volatile unsigned long *)(PWMC_BASE + PWM_CDTY_OFF + PWM_CH2_OFF))) ///< PWM Channel 2 Duty Cycle Register.
#define PWM_CDTY3   (*((volatile unsigned long *)(PWMC_BASE + PWM_CDTY_OFF + PWM_CH3_OFF))) ///< PWM Channel 3 Duty Cycle Register.

#define PWM_CPRD_OFF            0x00000008    ///< PWM Channel Period Register offset.
#define PWM_CPRD0   (*((volatile unsigned long *)(PWMC_BASE + PWM_CPRD_OFF + PWM_CH0_OFF))) ///< PWM Channel 0 Period Register.
#define PWM_CPRD1   (*((volatile unsigned long *)(PWMC_BASE + PWM_CPRD_OFF + PWM_CH1_OFF))) ///< PWM Channel 1 Period Register.
#define PWM_CPRD2   (*((volatile unsigned long *)(PWMC_BASE + PWM_CPRD_OFF + PWM_CH2_OFF))) ///< PWM Channel 2 Period Register.
#define PWM_CPRD3   (*((volatile unsigned long *)(PWMC_BASE + PWM_CPRD_OFF + PWM_CH3_OFF))) ///< PWM Channel 3 Period Register.

#define PWM_CCNT_OFF            0x0000000C    ///< PWM Channel Counter Register offset.
#define PWM_CCNT0   (*((volatile unsigned long *)(PWMC_BASE + PWM_CCNT_OFF + PWM_CH0_OFF))) ///< PWM Channel 0 Counter Register.00204
#define PWM_CCNT1   (*((volatile unsigned long *)(PWMC_BASE + PWM_CCNT_OFF + PWM_CH1_OFF))) ///< PWM Channel 1 Counter Register.
#define PWM_CCNT2   (*((volatile unsigned long *)(PWMC_BASE + PWM_CCNT_OFF + PWM_CH2_OFF))) ///< PWM Channel 2 Counter Register.
#define PWM_CCNT3   (*((volatile unsigned long *)(PWMC_BASE + PWM_CCNT_OFF + PWM_CH3_OFF))) ///< PWM Channel 3 Counter Register.

#define PWM_CUPD_OFF            0x00000010    ///< PWM Channel Update Register offset.
#define PWM_CUPD0   (*((volatile unsigned long *)(PWMC_BASE + PWM_CUPD_OFF + PWM_CH0_OFF))) ///< PWM Channel 0 Update Register.
#define PWM_CUPD1   (*((volatile unsigned long *)(PWMC_BASE + PWM_CUPD_OFF + PWM_CH1_OFF))) ///< PWM Channel 1 Update Register.
#define PWM_CUPD2   (*((volatile unsigned long *)(PWMC_BASE + PWM_CUPD_OFF + PWM_CH2_OFF))) ///< PWM Channel 2 Update Register.
#define PWM_CUPD3   (*((volatile unsigned long *)(PWMC_BASE + PWM_CUPD_OFF + PWM_CH3_OFF))) ///< PWM Channel 3 Update Register.

extern void PWMC_ConfigureChannel( 
    unsigned char channel, 
    unsigned int prescaler, 
    unsigned int alignment, 
    unsigned int polarity); 
 
extern void PWMC_ConfigureClocks 
    (unsigned int clka, 
     unsigned int clkb, 
     unsigned int mck); 
 
void PWMC_SetPeriod(unsigned char channel, unsigned short period); 
void PWMC_SetDutyCycle(unsigned char channel, unsigned short duty); 
void PWMC_EnableChannel(unsigned char channel); 
void PWMC_DisableChannel(unsigned char channel); 
void PWMC_EnableChannelIt(unsigned char channel); 
void PWMC_DisableChannelIt(unsigned char channel); 
unsigned short FindClockConfiguration(unsigned int frequency, unsigned int mck);

#define trace_DEBUG                     0 
#define trace_INFO                      1 
#define trace_WARNING                   2 
#define trace_ERROR                     3 
#define trace_FATAL                     4 
#define trace_LEVEL                     0 

#define trace_CONFIGURE(mode, baudrate, mck) { \
        const Pin pinsDbgu[] = {PINS_DBGU}; \
        PIO_Configure(pinsDbgu, PIO_LISTSIZE(pinsDbgu)); \
        DBGU_Configure(mode, baudrate, mck); \
    } 

#define trace_LOG(level, ...) { \
        if (level >= trace_LEVEL) { \
            printk(__VA_ARGS__); \
        } \
    } 


#define ASSERT(condition, ...)  { \
        if (!(condition)) { \
            printk(__VA_ARGS__); \
            while (1); \
        } \
    } 
	
#define SANITY_ERROR            "Sanity check failed at %s:%d\n\r" 
#define SANITY_CHECK(condition) ASSERT(condition, SANITY_ERROR, __FILE__, __LINE__) 


#endif /* AT91_PWM_H */

at9g45库文件:

#include "at91_pwm.h"  




unsigned short FindClockConfiguration(   
    unsigned int frequency,   
    unsigned int mck)   
{   
    unsigned int divisors[11] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024};   
    unsigned char divisor = 0;   
    unsigned int prescaler;   
   
    SANITY_CHECK(frequency < mck);
   
    // Find prescaler and divisor values   
    prescaler = (mck / divisors[divisor]) / frequency;   
    while ((prescaler > 255) && (divisor < 11)) {   
   
        divisor++;   
        prescaler = (mck / divisors[divisor]) / frequency;   
    }   
   
    // Return result   
    if (divisor < 11) {   
   
        trace_LOG(trace_DEBUG, "-D- Found divisor=%d and prescaler=%d for freq=%dHz\n\r",   
                  divisors[divisor], prescaler, frequency);   
        return prescaler | (divisor << 8);   
    }   
    else {   
   
        return 0;   
    }   
}   
//------------------------------------------------------------------------------   
//         Global functions   
//------------------------------------------------------------------------------   
   
//------------------------------------------------------------------------------   
/// Configures PWM a channel with the given parameters.   
/// The PWM controller must have been clocked in the PMC prior to calling this   
/// function.   
/// \param channel  Channel number.   
/// \param prescaler  Channel prescaler.   
/// \param alignment  Channel alignment.   
/// \param polarity  Channel polarity.   
//------------------------------------------------------------------------------   
void PWMC_ConfigureChannel(   
    unsigned char channel,   
    unsigned int prescaler,   
    unsigned int alignment,   
    unsigned int polarity)   
{   
    SANITY_CHECK(prescaler < PWM_CPRE_CLKB);   
    SANITY_CHECK((alignment & ~(1 << PWM_CALG)) == 0);   
    SANITY_CHECK((polarity & ~(1<<PWM_CPOL)) == 0);   
   
    // Disable channel   
    PWM_DIS |= (1 << channel);
   
    // Configure channel   
    PWM_CMR0 = prescaler | alignment | polarity;   
}   
   
//------------------------------------------------------------------------------   
/// Configures PWM clocks A & B to run at the given frequencies. This function   
/// finds the best MCK divisor and prescaler values automatically.   
/// \param clka  Desired clock A frequency (0 if not used).   
/// \param clkb  Desired clock B frequency (0 if not used).   
/// \param mck  Master clock frequency.   
//------------------------------------------------------------------------------   
void PWMC_ConfigureClocks(unsigned int clka, unsigned int clkb, unsigned int mck)   
{   
    unsigned int mode = 0;   
    unsigned int result;   
   
    // Clock A   
    if (clka != 0) {   
   
        result = FindClockConfiguration(clka, mck);   
        ASSERT(result != 0, "-F- Could not generated the desired PWM frequency (%dHz)\n\r", clka);   
        mode |= result;   
    }   
   
    // Clock B   
    if (clkb != 0) {   
   
        result = FindClockConfiguration(clkb, mck);   
        ASSERT(result != 0, "-F- Could not generated the desired PWM frequency (%dHz)\n\r", clkb);   
        mode |= (result << 16);   
    }   
   
    // Configure clocks   
    trace_LOG(trace_DEBUG, "-D- Setting PWMC_MR = 0x%08X\n\r", mode);   
    PWM_MR = mode;   
}   
   
//------------------------------------------------------------------------------   
/// Sets the period value used by a PWM channel. This function writes directly   
/// to the CPRD register if the channel is disabled; otherwise, it uses the   
/// update register CUPD.   
/// \param channel  Channel number.   
/// \param period  Period value.   
//------------------------------------------------------------------------------   
void PWMC_SetPeriod(unsigned char channel, unsigned short period)   
{   
    // If channel is disabled, write to CPRD   
    if ((PWM_SR & (1 << channel)) == 0) {   
   
        PWM_CPRD0 = period;   
    }   
    // Otherwise use update register   
    else {   
   
        PWM_CMR0 |= (1 << PWM_CPD);   
        PWM_CUPD0 = period;   
    }   
}   
   
//------------------------------------------------------------------------------   
/// Sets the duty cycle used by a PWM channel. This function writes directly to   
/// the CDTY register if the channel is disabled; otherwise it uses the   
/// update register CUPD.   
/// Note that the duty cycle must always be inferior or equal to the channel   
/// period.   
/// \param channel  Channel number.   
/// \param duty  Duty cycle value.   
//------------------------------------------------------------------------------   
void PWMC_SetDutyCycle(unsigned char channel, unsigned short duty)   
{   
    SANITY_CHECK(duty <= PWM_CPRD0);   
   
 
    ASSERT(duty > 0, "-F- Duty cycle value 0 is not permitted on SAM7S chips.\n\r");   
	
		
    ASSERT((duty > 1) || (PWM_CMR0 & (1 << PWM_CALG)),   
           "-F- Duty cycle value 1 is not permitted in left-aligned mode on SAM7S chips.\n\r");   

   
    // If channel is disabled, write to CDTY   
    if ((PWM_SR & (1 << channel)) == 0) {   
   
        PWM_CDTY0 = duty;   
    }   
    // Otherwise use update register   
    else {   
   
        PWM_CMR0 &= ~(1 << PWM_CPD);   
        PWM_CUPD0 = duty;   
    }   
}   
   
//------------------------------------------------------------------------------   
/// Enables the given PWM channel. This does NOT enable the corresponding pin;   
/// this must be done in the user code.   
/// \param channel  Channel number.   
//------------------------------------------------------------------------------   
void PWMC_EnableChannel(unsigned char channel)   
{   
    PWM_ENA |= 1 << channel;   
}   
   
//------------------------------------------------------------------------------   
/// Disables the given PWM channel.   
/// \param channel  Channel number.   
//------------------------------------------------------------------------------   
void PWMC_DisableChannel(unsigned char channel)   
{   
    PWM_DIS |= 1 << channel;   
}   
   
//------------------------------------------------------------------------------   
/// Enables the period interrupt for the given PWM channel.   
/// \param channel  Channel number.   
//------------------------------------------------------------------------------   
void PWMC_EnableChannelIt(unsigned char channel)   
{   
    PWM_IER |= 1 << channel;   
}   
   
//------------------------------------------------------------------------------   
/// Disables the period interrupt for the given PWM channel.   
/// \param channel  Channel number.   
//------------------------------------------------------------------------------   
void PWMC_DisableChannelIt(unsigned char channel)   
{   
    PWM_IDR |= 1 << channel;   
}   


at9g45,驱动文件:

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/fs.h>		           /* everything... */
#include <linux/cdev.h>                /* cdev...*/
#include <linux/gpio.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include "at91_pwm.h"
#include "at91_pwm.c"

#define DEVICE_NAME "mypwm"

static int led_major = 0;
static int led_minor = 0;
struct cdev *led_device;

static void PWM_Set_Freq(int arg)
{
	at91_set_gpio_output(AT91_PIN_PD15, 0);	//设置PD15为输出模式
	at91_set_gpio_value(AT91_PIN_PD15, 0);	//设置PD15输出为0,表示点亮
	at91_set_B_periph(AT91_PIN_PD24, 1);	/* enable PWM0 */

	
	PWMC_ConfigureChannel(0, 1, 2, 3);
	PWMC_ConfigureClocks(1000, 500, 10);
	PWMC_SetPeriod(0, 1);
	PWMC_SetDutyCycle(0, 50);
}

static void PWM_Stop(void)
{
	at91_set_gpio_output(AT91_PIN_PD24, 0);	
	at91_set_gpio_value(AT91_PIN_PD24, 1);

	return ;
}

		   
static int myled_open(struct inode *inode, struct file *filp)
{
	PWMC_EnableChannel(0);//这一步在测试驱动的时候总是报内存操作错误
	at91_set_B_periph(AT91_PIN_PD24, 1);/* enable PWM0 */

	return 0;
}

static int myled_release(struct inode *inode, struct file *filp)
{
	PWMC_DisableChannel(0); //这一步在测试驱动的时候总是报内存操作错误
	return 0;
}

static int myled_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg)
{
	if (arg > 4)
	{
		return -1;
	}
	
	switch (cmd)
	{
		case 0:
			if (arg == 0)
				return -1;
			PWM_Set_Freq(arg);
			break;
			//通过cmd命令控制PD15
		case 1:
			PWM_Stop();
			break;
	}
	return 0;
}

struct file_operations led_fops = 
{
	.owner =    THIS_MODULE,
	.open =     myled_open,
	.release =  myled_release,
	.ioctl = myled_ioctl,
};


static void __exit my_led_exit(void)
{
    dev_t devno = MKDEV(led_major, led_minor);	//通过主次设备号获得设备号
	
	if (led_device)
	{
		cdev_del(led_device);	//删除设备号
		
		kfree(led_device);	//释放设备号空间
		led_device = NULL;	//设置为空, 防止再次被调用
	}
	
	unregister_chrdev_region(devno, 1);	//卸载主设备号
	

    return;
}

static int __init my_led_init(void)
{
	int result = 0;	//用来返回结果值
	dev_t dev = 0;	//设备号
	
	/***********************分配主次设备号******************/
	result = alloc_chrdev_region(&dev, led_minor, 1, DEVICE_NAME);	//自动分配主设备号
	led_major = MAJOR(dev);	//得到主设备号
	
	if (result < 0)
	{
		printk(KERN_WARNING "wfet_kb: can't get major %d\n", led_major);
		return result;
	}
	
	/*********************注册字符设备*************************/
	led_device = kmalloc(sizeof(struct cdev), GFP_KERNEL);	//字符设备的全局结构占用的内存要用kmalloc或kzalloc申请
	
	if(!led_device)
	{
		result = -ENOMEM;
		unregister_chrdev_region(dev, 1);
		return result;
	}
	memset(led_device, 0, sizeof(struct cdev));
	
	cdev_init(led_device, &led_fops);	//字符设备初始化
	led_device->owner = THIS_MODULE;
	
	result = cdev_add(led_device, dev, 1);	//字符设备添加
	if(result)
	{
		printk(KERN_NOTICE "Error %d adding LED device, major_%d", result, MAJOR(dev));
		kfree(led_device);	//释放空间
		unregister_chrdev_region(dev, 1);	//注销设备号
		return result;
	}

    return 0;
}


module_init(my_led_init)
module_exit(my_led_exit)

MODULE_LICENSE("GPL");

at9g45测试文件:

#include <stdio.h>
#include "at91_ioctl.h"

int main(int argc, char** argv)
{
    int fp;

    fp = open("/dev/mypwm", 0);
    if(fp < 0)
    {
        printf("Open error!\n");
        return -1;
    }

    ioctl(fp, atoi(argv[1]));

    close(fp);

    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值