STM32串口USART

一、通用同步异步收发器(USART) 

        通用同步异步收发器(USART)提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的 外部设备之间进行全双工数据交换。USART利用分数波特率发生器提供宽范围的波特率选择。 它支持同步单向通信和半双工单线通信,也支持LIN(局部互连网),智能卡协议和IrDA(红外数据 组织)SIR ENDEC规范,以及调制解调器(CTS/RTS)操作。它还允许多处理器通信。 使用多缓冲器配置的DMA方式,可以实现高速数据通信。 

        接口通过三个引脚与其他设备连接在一起。任何USART双向通信至少需要两个脚:接收数据输入(RX)和发送数据输出(TX)。 RX:接收数据串行输。通过过采样技术来区别数据和噪音,从而恢复数据。 TX:发送数据输出。当发送器被禁止时,输出引脚恢复到它的I/O端口配置。当发送器被激活, 并且不发送数据时,TX引脚处于高电平。在单线和智能卡模式里,此I/O口被同时用于数据的发送和接收。 

       串口设置的一般步骤可以总结为如下几个步骤:

      1) 串口时钟使能,GPIO 时钟使能

      2) 串口复位

      3) GPIO 端口模式设置

      4) 串口参数初始化

      5) 开启中断并且初始化 NVIC(如果需要开启中断才需要这个步骤)

      6) 使能串口

      7) 编写中断处理函数  

void uart_init(u32 bound){
  //GPIO端口设置,bound:波特率
  GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE);	//使能USART1,GPIOA时钟
  
	//USART1_TX   GPIOA.9
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9
   
  //USART1_RX	  GPIOA.10初始化
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  

  //Usart1 NVIC 配置
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
  
   //USART 初始化设置

	USART_InitStructure.USART_BaudRate = bound;//串口波特率
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式

  USART_Init(USART1, &USART_InitStructure); //初始化串口1
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接受中断
  USART_Cmd(USART1, ENABLE);                    //使能串口1 

}

 串口中断服务函数

void USART1_IRQHandler(void)  //串口1中断服务程序
	{
	u8 Res;
#if SYSTEM_SUPPORT_OS 		//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntEnter();    
#endif
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)  //接收中断(接收到的数据必须是0x0d 0x0a结尾)
	{
		Res =USART_ReceiveData(USART1);	//读取接收到的数据
		
		if((USART_RX_STA&0x8000)==0)//接收未完成,第15位
		{
			if(USART_RX_STA&0x4000)//接收到了0x0d,第14位
				{
				if(Res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
				else USART_RX_STA|=0x8000;	//接收完成了 
				}
				
			else //还没收到0X0D
				{	
				if(Res==0x0d)USART_RX_STA|=0x4000;
				else
					{
					USART_RX_BUF[USART_RX_STA&0X3FFF]=Res ;
					USART_RX_STA++;
					if(USART_RX_STA>(USART_REC_LEN-1))USART_RX_STA=0;//接收数据错误,重新开始接收	  
					}		 
				}
			}   		 
     } 
#if SYSTEM_SUPPORT_OS 	//如果SYSTEM_SUPPORT_OS为真,则需要支持OS.
	OSIntExit();  											 
#endif
} 
#endif	

主函数

int main(void)
 {		
 	u16 t;  
	u16 len;	
	u16 times=0;
	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 //串口初始化为115200
 	LED_Init();			     //LED端口初始化
	KEY_Init();          //初始化与按键连接的硬件接口
 	while(1)
	{
		if(USART_RX_STA&0x8000)
		{					   
			len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
			printf("\r\n您发送的消息为:\r\n\r\n");
			for(t=0;t<len;t++)
			{
				USART_SendData(USART1, USART_RX_BUF[t]);//向串口1发送数据
				while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
			}
			printf("\r\n\r\n");//插入换行
			USART_RX_STA=0;
		}
		
		else
		{
			times++;
			if(times%5000==0)
			{
				printf("\r\n精英STM32开发板 串口实验\r\n");
				printf("正点原子@ALIENTEK\r\n\r\n");
			}
			if(times%200==0)printf("请输入数据,以回车键结束\n");  
			if(times%30==0)LED1=!LED1;//闪烁LED,提示系统正在运行.
			delay_ms(10);   
		}
	}	 
 }

二、  STM32F1 的串口实现 485 通信(半双工)

        485(一般称作 RS485/EIA-485)是隶属于 OSI 模型物理层的电气特性规定为 2 线,半双工, 多点通信的标准。它的电气特性和 RS-232 大不一样。用缆线两端的电压差值来表示传递信号。 RS485 仅仅规定了接受端和发送端的电气特性。它没有规定或推荐任何数据协议。 RS485 的特点包括:

        1) 接口电平低,不易损坏芯片。RS485 的电气特性:逻辑“1”以两线间的电压差为+(2~6)V 表示;逻辑“0”以两线间的电压差为-(2~6)V 表示。接口信号电平比 RS232 降低了, 不易损坏接口电路的芯片,且该电平与 TTL 电平兼容,可方便与 TTL 电路连接。    

        2) 传输速率高。10 米时,RS485 的数据最高传输速率可达 35Mbps,在 1200m 时,传输  速度可达 100Kbps。

        3) 抗干扰能力强。RS485 接口是采用平衡驱动器和差分接收器的组合,抗共模干扰能力 增强,即抗噪声干扰性好。

        4) 传输距离远,支持节点多。RS485 总线最长可以传输 1200m 以上(速率≤100Kbps) 一般最大支持 32 个节点,如果使用特制的 485 芯片,可以达到 128 个或者 256 个节点, 最大的可以支持到 400 个节点。 RS485 推荐使用在点对点网络中,线型,总线型,不能是星型,环型网络。理想情况下 RS485 需要 2 个匹配电阻,其阻值要求等于传输电缆的特性阻抗(一般为 120Ω)。没有特性阻抗的话, 当所有的设备都静止或者没有能量的时候就会产生噪声,而且线移需要双端的电压差。没有终 接电阻的话,会使得较快速的发送端产生多个数据信号的边缘,导致数据传输出错。

       我们只需要配置好串口 2,就可以实现正常的 485 通信了,串口 2 的配置和串口 1 基本类似,只是串口的时钟来自 APB1,最大频率为 36Mhz。 

void RS485_Init(u32 bound)
{  
  GPIO_InitTypeDef GPIO_InitStructure;
  USART_InitTypeDef USART_InitStructure;
 	NVIC_InitTypeDef NVIC_InitStructure;
 
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD, ENABLE);//使能GPIOA,D时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//使能USART2时钟
	
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;				 //PD7端口配置
 	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; 		 //推挽输出
 	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
 	GPIO_Init(GPIOD, &GPIO_InitStructure);
 
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;	//PA2
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽
  GPIO_Init(GPIOA, &GPIO_InitStructure);
   
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);  

	RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2,ENABLE);//复位串口2
	RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2,DISABLE);//停止复位
 
	
 #ifdef EN_USART2_RX		  	//如果使能了接收
	USART_InitStructure.USART_BaudRate = bound;//波特率设置
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;//8位数据长度
	USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
	USART_InitStructure.USART_Parity = USART_Parity_No;///奇偶校验位
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
	USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收发模式

  USART_Init(USART2, &USART_InitStructure); ; //初始化串口
  
	NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; //使能串口2中断
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //先占优先级2级
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级2级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中断通道
	NVIC_Init(&NVIC_InitStructure); //根据NVIC_InitStruct中指定的参数初始化外设NVIC寄存器
 
  USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启中断
   
  USART_Cmd(USART2, ENABLE);                    //使能串口 

 #endif

  RS485_TX_EN=0;			//默认为接收模式
 
}

发送数据

void RS485_Send_Data(u8 *buf,u8 len)
{
	u8 t;
	RS485_TX_EN=1;			//设置为发送模式
  	for(t=0;t<len;t++)		//循环发送数据
	{		   
		while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);	  
		USART_SendData(USART2,buf[t]);
	}	 
 
	while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET);		
	RS485_RX_CNT=0;	  
	RS485_TX_EN=0;				//设置为接收模式	
}

接收数据

void RS485_Receive_Data(u8 *buf,u8 *len)
{
	u8 rxlen=RS485_RX_CNT;
	u8 i=0;
	*len=0;				//默认为0
	delay_ms(10);		//等待10ms,连续超过10ms没有接收到一个数据,则认为接收结束
	if(rxlen==RS485_RX_CNT&&rxlen)//接收到了数据,且接收完成了
	{
		for(i=0;i<rxlen;i++)
		{
			buf[i]=RS485_RX_BUF[i];	
		}		
		*len=RS485_RX_CNT;	//记录本次数据长度
		RS485_RX_CNT=0;		//清零
	}
}

中断函数

 

void USART2_IRQHandler(void)
{
	u8 res;	    
 
 	if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //接收到数据
	{	 
	 			 
		res =USART_ReceiveData(USART2); 	//读取接收到的数据
		if(RS485_RX_CNT<64)
		{
			RS485_RX_BUF[RS485_RX_CNT]=res;		//记录接收到的值
			RS485_RX_CNT++;						//接收数据增加1 
		} 
	}  											 
} 

 主函数

int main(void)
 {	 
	u8 key;
	u8 i=0,t=0;
	u8 cnt=0;
	u8 rs485buf[5]; 
	 
	delay_init();	    	 //延时函数初始化	  
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
	uart_init(115200);	 	//串口初始化为115200
	LED_Init();		  		//初始化与LED连接的硬件接口
	LCD_Init();			   	//初始化LCD 	
	KEY_Init();				//按键初始化		 	 
	RS485_Init(9600);	//初始化RS485
 	POINT_COLOR=RED;//设置字体为红色 
	LCD_ShowString(30,50,200,16,16,"ELITE STM32");
	LCD_ShowString(30,70,200,16,16,"RS485 TEST");	
	LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
	LCD_ShowString(30,110,200,16,16,"2015/1/15");	
	LCD_ShowString(30,130,200,16,16,"KEY0:Send");	//显示提示信息		
 
 	POINT_COLOR=BLUE;//设置字体为蓝色	  
	LCD_ShowString(30,150,200,16,16,"Count:");			//显示当前计数值	
	LCD_ShowString(30,170,200,16,16,"Send Data:");		//提示发送的数据	
	LCD_ShowString(30,210,200,16,16,"Receive Data:");	//提示接收到的数据		
 									  
	while(1)
	{
		key=KEY_Scan(0);
		if(key==KEY0_PRES)//KEY0按下,发送一次数据
		{
			for(i=0;i<5;i++)
			{
				rs485buf[i]=cnt+i;//填充发送缓冲区
				LCD_ShowxNum(30+i*32,190,rs485buf[i],3,16,0X80);	//显示数据
 			}
			RS485_Send_Data(rs485buf,5);//发送5个字节 									   
		}		 
		RS485_Receive_Data(rs485buf,&key);
		if(key)//接收到有数据
		{
			if(key>5)key=5;//最大是5个数据.
 			for(i=0;i<key;i++)LCD_ShowxNum(30+i*32,230,rs485buf[i],3,16,0X80);	//显示数据
 		}
		t++; 
		delay_ms(10);
		if(t==20)
		{
			LED0=!LED0;//提示系统正在运行	
			t=0;
			cnt++;
			LCD_ShowxNum(30+48,150,cnt,3,16,0X80);	//显示数据
		}		   
	} 
}

 

 

 

<think>首先,用户的问题是:“我想解决RS485接收数据超时的问题请问RS485接收数据超时解决方案”。这需要我提供解决方案来解决RS485接收数据超时的问题。从系统级指令中,我需要:-所有行内数学表达式使用$...$格式。-独立公式使用$$...$$格式并单独成段。-LaTeX语法正确。-使用中文回答。-生成相关问题。-在回答中引用的段落末尾自然地添加引用标识,如[^1]。-回答结构清晰,帮助用户逐步解决问题。-参考提供的引用内容。提供的引用:-引用[1]:关于STM32RS485总线通信开发详解,包括架构、原理、硬件设计、代码等。-引用[2]:关于DSP28335RS485FIFO接收功能。-引用[3]:关于设备接线,包括网关、电脑、转换器等。用户的问题是关于RS485接收数据超时,所以我需要基于这些引用提供解决方案。关键点:-接收数据超时可能由多种原因引起,如硬件问题、软件配置、信号干扰等。-我需要参考引用中的内容来支持我的回答。步骤:1.**理解问题**:RS485接收数据超时意味着设备在接收数据时没有在预期时间内接收到完整数据包。2.**常见原因**:-硬件连接问题(如接线错误、信号衰减)。-软件设置问题(如波特率不匹配、超时设置不当)。-环境干扰(如噪声影响信号)。-协议问题(如ModbusRTU中的超时设置)。3.**参考引用**:-引用[1]提到硬件设计、驱动代码和调试,包括ModbusRTU协议。-引用[2]讨论FIFO接收功能,这可以减少CPU干预,提高效率,可能有助于处理超时。-引用[3]描述设备接线,强调正确的物理连接。4.**解决方案框架**:-**步骤1:检查硬件连接**:确保接线正确,使用引用[3]作为参考。-**步骤2:验证软件配置**:检查波特率、数据位、停止位等设置,参考引用[1]的驱动代码部分。-**步骤3:实现超时机制**:在软件中添加超时检测,参考引用[2]的FIFO接收。-**步骤4:处理干扰**:添加错误处理机制,如引用[1]提到的错误处理。-**步骤5:测试和调试**:使用引用[1]的测试方法。5.**结构回答**:-逐步指导用户解决问题。-使用清晰的中文。-在适当的地方添加引用。6.**添加数学表达式**:-可能涉及波特率计算。例如,波特率误差可能导致超时。波特率公式:$\text{波特率}=\frac{\text{比特数}}{\text{时间}}$,但用户问题不直接涉及数学,所以可能不需要。-如果有必要,可以提到波特率匹配:例如,发送端和接收端的波特率必须一致,否则数据接收会出错。-超时时间设置:例如,在ModbusRTU中,字符间超时通常设置为1.5个字符时间。公式:$T_{\text{char}}=\frac{11}{\text{波特率}}$秒(假设10位数据帧:1起始位,8数据位,1停止位)。-使用独立公式:$$T_{\text{char}}=\frac{11}{B}$$其中$B$是波特率。7.**生成相关问题**:-在回答末尾添加相关问题,如系统指令所示。8.**引用标识**:-在回答中自然地引用段落。例如,当提到硬件设计时,添加[^1];当提到FIFO接收时,添加[^2];当提到接线时,添加[^3]。完整回答结构:-**引言**:简要解释问题。-**步骤1:检查硬件连接**。-**步骤2:验证软件配置**。-**步骤3:实现超时机制**。-**步骤4:处理环境干扰**。-**步骤5:测试和调试**。-**总结**。-**相关问题**。确保回答真实可靠:基于引用和一般知识。</think>### RS485接收数据超时问题解决方案 RS485接收数据超时通常是由于硬件连接问题、软件配置错误、信号干扰或协议设置不当导致的。下面我将逐步指导您解决此问题,确保方案真实可靠,并基于工业级应用的最佳实践。解决方案分为硬件检查、软件优化、干扰处理和调试测试四个步骤。每个步骤都参考了相关技术文档,以增强可靠性。 #### 步骤1: 检查硬件连接和元件选型 硬件问题是导致超时的常见原因。首先,确保所有物理连接正确无误: - **接线验证**:RS485采用差分信号传输($V_A - V_B$),必须使用双绞线连接A和B线,并确保终端电阻匹配(通常120Ω)。引用[3]提到网关设备的RS485接口需通过两根线连接USB-485转换器,避免接线反接或松动。检查接线是否遵循:发送端TX+接接收端RX+,TX-接RX-。 - **电源和接地**:为RS485设备提供稳定的24V电源(如引用[3]所示),并确保所有设备共地,以减少地环路干扰。 - **元件选型**:参考引用[1],选用高质量RS485收发器芯片(如MAX485),并检查其驱动能力是否匹配总线负载。超时可能由信号衰减引起,确保线缆长度不超过RS485规范(通常1200米@100kbps)。 如果硬件无误,但问题仍存,进入软件配置优化。 #### 步骤2: 优化软件配置和超时机制 软件设置错误如波特率不匹配或超时参数不当,会导致数据接收失败。参考引用[1]和[2]的驱动代码实现: - **波特率校准**:确保发送端和接收端波特率一致。波特率误差必须小于2%,否则会引起帧错误。计算公式为: $$ \text{误差率} = \left| \frac{B_{\text{发送}} - B_{\text{接收}}}{B_{\text{发送}}} \right| \times 100\% $$ 其中 $ B $ 是波特率(如9600bps)。在初始化代码中,设置UART的波特率寄存器精确匹配。 - **超时参数设置**:在接收中断或轮询代码中添加超时检测。例如,在Modbus RTU协议中(引用[1]),字符间超时时间 $ T_{\text{char}} $ 应设为1.5个字符时间: $$ T_{\text{char}} = \frac{11}{B} \text{ 秒} $$ 这里11表示一个字符帧的位数(1起始位 + 8数据位 + 1停止位 + 1校验位)。在STM32代码中(引用[1]),使用定时器中断实现超时计数: ```c // 示例代码(基于STM32 HAL库) HAL_UART_Receive_IT(&huart, buffer, length); // 启动接收 HAL_TIM_Base_Start_IT(&htim); // 启动定时器,设置超时时间为T_char ``` - **FIFO缓冲区优化**:引用[2]强调使用FIFO(First In First Out)减少CPU干预。在DSP28335平台,配置UART的FIFO深度(如16字节),并在接收函数中处理数据队列,避免因处理延迟导致超时: ```c // DSP28335 FIFO配置示例 UART_EnableFIFO(UART_BASE); // 启用FIFO UART_SetFIFOLevel(UART_BASE, UART_FIFO_RX8); // 设置接收FIFO触发级别 ``` 如果软件配置正确,但超时仍发生,考虑环境干扰。 #### 步骤3: 处理信号干扰和错误机制 RS485在工业环境中易受噪声干扰。引用[1]的“错误处理机制”部分建议: - **噪声抑制**:添加磁珠或TVS二极管保护电路,滤除高频干扰。确保线缆远离电机或高压设备。 - **协议级重试**:在Modbus RTU实现中(引用[1]),加入数据校验(如CRC)和自动重发逻辑。例如,检测到超时后,触发重发机制: ```c if (receive_timeout_flag) { retransmit_data(); // 重发数据 timeout_counter++; // 计数,避免无限循环 } ``` - **差分信号增强**:优化差分电压 $ \Delta V = |V_A - V_B| $,确保其在±1.5V至±5V范围(引用[1])。使用示波器检查信号质量,衰减过大时添加中继器。 #### 步骤4: 系统测试和调试 最后,进行针对性测试验证解决方案。引用[1]和[3]提供测试框架: - **基本测试**:按引用[3]搭建最小系统(网关、USB-485转换器、电脑),使用串口调试工具发送测试数据。监测接收缓冲区,确认超时是否消除。 - **多节点组网测试**:引用[1]建议模拟多设备场景,检查总线冲突。如果超时仅在多节点时出现,优化主从协议(如轮询间隔)。 - **性能监控**:在代码中添加调试输出,记录接收时间戳,分析超时发生点。例如: ```c printf("接收开始时间: %d ms\n", HAL_GetTick()); // 输出时间信息 ``` #### 总结 通过以上步骤,大多数RS485接收数据超时问题可解决:先排查硬件(接线和电源),再调整软件(波特率和超时参数),最后处理干扰和测试验证。实践中,80%的故障源于硬件或配置错误[^1]。确保每个步骤逐项执行,并参考文档进行调试。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值