红外遥控设计验证

前言

        红外遥控是一种无线、非接触控制技术,具有抗干扰能力强,信息传输可靠,功耗低,成本低,易实现等显著优点,被诸多电子设备特别是家用电器广泛采用,并越来越多的应用到计算机和手机系统中。本文首先介绍了红外遥控模块的基本原理,其次详解阐述了红外遥控模块工作原理,最后介绍了红外遥控的重要环节及应用。

正文

一、红外遥控设计验证

        1.项目需求

实验任务:将接收到的遥控数据显示到数码管上,当收到重复码时进行LED闪烁。

        2.技术介绍

        红外遥控编码协议
        NEC协议:采用的是PPM(Pulse Position Modulation,脉冲位置调制)进行编码。当我们按下遥控器的一个按键时,会发送一帧的数据。这一帧数据由引导码、地址码、地址反码、数据码、数据反码以及一位结束位(可忽略)组成。
        RC-5协议:它通过脉冲宽度调制技术,使用曼彻斯特编码的方式传输数据,确保了数据传输的准确性和可靠性。RC-5协议的数据包包括起始位、地址位和命令位,能够识别不同的设备并发出具体的操作指令。工作在38kHz的载波频率上,具有良好的抗干扰能力和误码处理能力,广泛应用于电视、音响等遥控控制系统中。
        RC-6协议:RC-6协议是飞利浦开发的红外遥控协议,相比于RC-5,它在数据传输中引入了更多的功能扩展和改进的编码方式,以提高可靠性和减少误码率。RC-6使用较低的载波频率和复杂的数据包结构,支持更多的操作模式和功能,同时保持了一定的兼容性,广泛应用于各种高端遥控设备中。

        红外线遥控是利用近红外光传送遥控指令的,波长为0.76um~1.5umo。红外发射器件(红外发光管)与红外接收器件(光敏二极管、三极管及光电池)的发光与受光峰值波长一般为0.8um~0.94um,在近红外光波段内,二者的光谱正好重合,能够很好地匹配,可以获得较高的传输效率及较高的可靠性。
红外遥控发射部分由遥控按键、编码与调制电路,红外发光二极管等组成;红外遥控接收部分由光敏二极管、光电放大电路、解调电路等组成;最后将解调的信号输入FPGA内进行解码输出。

        当按下遥控器后遥控器会发送一帧数据,引导码由9ms高脉冲+4.5ms低电平组成,地址码为1个8位二进制数据,可以根据地址码判断是哪个设备发送的该帧数据,地址反码是地址码的按位取反,用于验证地址码,数据码是按键的按键码,8位二进制数(低位数据在前),数据反码校验数据码,一位结束位为560us高脉冲。NEC协议中逻辑1用560us高脉冲+1.69ms低电平表示,逻辑0用560us高脉冲+560us低电平表示,后面还有560us高脉冲的结束位

        接收到的引导码变为9ms低电平+4.5ms高电平,逻辑1/0分别变为560us低电平+1690us高电平/560低电平+560us高电平,重复码变为9ms低电平+2.25ms高电平+560us低电平,接收波形即fpga接收到的数据。

        当按着按键不放时发送的数据码变为重复码,数据帧格式变为重复码:9ms高脉冲+2.25ms低电平+560us结束位,重复码一帧110ms.

        接收的数据与发送数据不同,在发送过程中,高脉冲,与低电平会反转,上图为正确接收到的数据格式。

        这里要在不同码段进行不同计数判断,采样状态机可完美解决该问题,下图为为该系统设计状态机的状态转移图。

        3.顶层架构

        4.端口描述

clk时钟信号(50Mhz)
rst_n复位信号(低电平有效)
ledled输出
inf_in红外接收模块接收到的数据
[2:0] sel位选信号
[7:0] seg段选信号

二、代码验证

接收数据处理模块

module ho_wai(

	input 				clk		,
	input					rst_n		,
	input					inf_in	,
	
	output reg[23:0]	data		,
	output reg			led_en		

);

parameter 	idle		=	5'b00001,//等待
				time9ms	=	5'b00010,//9ms引导
				zhocai	=	5'b00100,//数据码重复码判断
				dataqu	=	5'b01000,//数据码
				chofu		=	5'b10000;//重复码

parameter 	cnt_560usmin = 19'd20_000,
				cnt_560usmax = 19'd35_000,
				cnt_1_69msmin = 19'd80_000,
				cnt_1_69msmax = 19'd90_000,
				cnt_2_25msmin = 19'd100_000,
				cnt_2_25msmax = 19'd125_000,
				cnt_4_5msmin = 19'd175_000,
				cnt_4_5msmax = 19'd275_000,
				cnt_9msmin = 19'd400_000,
				cnt_9msmax = 19'd490_000;
				
reg [4:0]	stater;//状态寄存器
reg 			inf_inda1;//输入信号寄存一排
reg 			inf_inda2;//输入信号寄存一排
wire 			inf_ifall;//输入信号下降沿检测
reg [18:0]	cnt;
wire 			inf_rise;//输入信号上升沿检测
reg 			flag_9ms;//9ms到来标志信号
reg 			flag_4_5ms;//4.5ms到来标志信号
reg [5:0]	cnt_data;//数据计数器
reg 			flag_560us;//560us到来标志信号
reg 			flag_1_69ms;//1.69ms到来标志信号
reg [31:0]	data_reg;
reg 			flag_2_25ms;//2.25ms到来标志信号

always@(posedge clk,negedge rst_n)//状态跳转
begin
	if(rst_n == 0)
			stater <= idle;
	else
		case(stater)
			idle:		if(inf_ifall == 1'b1)//下降沿
							stater <= time9ms;
						else
							stater <= idle;
			time9ms: if((inf_rise == 1'b1)&&(flag_9ms == 1'b1))	//	上升沿并且到9ms
							stater <= zhocai;
						else 
							if((inf_rise == 1'b1)&&(flag_9ms == 1'b0))//上升沿并且不到9ms
								stater <= idle;
							else
								stater <= time9ms;
			zhocai:	if((inf_ifall == 1'b1)&&(flag_2_25ms == 1'b1))//下降沿并且到2.25ms
							stater <= chofu;
						else
							if((inf_ifall == 1'b1)&&(flag_4_5ms == 1'b1))//下降沿并且到4.5ms
								stater <= dataqu;
							else
								if((inf_ifall == 1'b1)&&(flag_4_5ms == 1'b0)&&(flag_2_25ms == 1'b1))
									stater <= idle;
								else
									stater <= zhocai;
			dataqu:	if((inf_rise == 1'b1)&&(flag_560us == 1'b0))
							stater <= idle;
						else
							if((inf_ifall == 1'b1)&&(flag_560us == 1'b0)&&(flag_1_69ms == 1'b0))
								stater <= idle;
							else
								if((inf_rise == 1'b1)&&(cnt_data == 6'd32))
									stater <= idle;
								else
									stater <= dataqu;
			chofu:	if(inf_rise == 1'b1)
							stater <= idle;
						else
							stater <= chofu;
			default : stater <= idle;
		endcase																											
end

always@(posedge clk,negedge rst_n)//数据打拍
begin
	if(rst_n == 0)
		inf_inda1 <= 1'b0;
	else
		inf_inda1 <= inf_in;
end

always@(posedge clk,negedge rst_n)//数据打拍
begin
	if(rst_n == 0)
		inf_inda2 <= 1'b0;
	else
		inf_inda2 <= inf_inda1;
end

assign inf_ifall 	= (inf_inda1 == 1'b0)&&(inf_inda2 == 1'b1);//下降沿检测
assign inf_rise	= (inf_inda1 == 1'b1)&&(inf_inda2 == 1'b0);//上升沿检测

always@(posedge clk,negedge rst_n)//计数器驱动
begin
	if(rst_n == 0)
		cnt <= 19'd0;
	else
		case(stater)
			idle:		cnt <= 19'd0;//计数器清零,方便下次计数
			time9ms: if((inf_rise == 1'b1)&&(flag_9ms == 1'b1))		
							cnt <= 19'd0;//计数器清零,方便下次计数
						else 
							cnt <= cnt + 19'd1;
			zhocai:	if((inf_ifall == 1'b1)&&((flag_2_25ms == 1'b1)||(flag_4_5ms == 1'b1)))
							cnt <= 19'd0;//计数器清零,方便下次计数
						else
							cnt <= cnt + 19'd1;
			dataqu:	if((inf_rise == 1'b1)&&(flag_560us == 1'b1))
							cnt <= 19'd0;//计数器清零,方便下次计数
						else
							if((inf_ifall == 1'b1)&&((flag_560us == 1'b1)||(flag_1_69ms == 1'b1)))
								cnt <= 19'd0;//计数器清零,方便下次计数
							else
								cnt <= cnt + 19'd1;
			chofu:	cnt <= 19'd0;
			default : cnt <= 19'd0;
		endcase
end

always@(posedge clk,negedge rst_n)//flag_9ms到来标准信号使能
begin
	if(rst_n == 0)
		flag_9ms <= 1'b0;
	else
		if((stater == time9ms)&&(cnt >= cnt_9msmin)&&(cnt <= cnt_9msmax))
			flag_9ms <= 1'b1;
		else
			flag_9ms <= 1'b0;
end

always@(posedge clk,negedge rst_n)//flag_4_5ms到来标准信号使能
begin
	if(rst_n == 0)
		flag_4_5ms <= 1'b0;
	else
		if((stater == zhocai)&&(cnt >= cnt_4_5msmin)&&(cnt <= cnt_4_5msmax))
			flag_4_5ms <= 1'b1;
		else
			flag_4_5ms <= 1'b0;
end

always@(posedge clk,negedge rst_n)//flag_560us到来标准信号使能
begin
	if(rst_n == 0)
		flag_560us <= 1'b0;
	else
		if((stater == dataqu)&&(cnt >= cnt_560usmin)&&(cnt <= cnt_560usmax))
			flag_560us <= 1'b1;
		else
			flag_560us <= 1'b0;
end

always@(posedge clk,negedge rst_n)//flag_1_69ms到来标准信号使能
begin
	if(rst_n == 0)
		flag_1_69ms <= 1'b0;
	else
		if((stater == dataqu)&&(cnt >= cnt_1_69msmin)&&(cnt <= cnt_1_69msmax))
			flag_1_69ms <= 1'b1;
		else
			flag_1_69ms <= 1'b0;
end

always@(posedge clk,negedge rst_n)//flag_2_25ms到来标准信号使能
begin
	if(rst_n == 0)
		flag_2_25ms <= 1'b0;
	else
		if((stater == zhocai)&&(cnt >= cnt_2_25msmin)&&(cnt <= cnt_2_25msmax))
			flag_2_25ms <= 1'b1;
		else
			flag_2_25ms <= 1'b0;
end

always@(posedge clk,negedge rst_n)//数据位计数器驱动模块
begin
	if(rst_n == 0)
		cnt_data <= 6'd0;
	else
		if((inf_rise == 1'b1)&&(cnt_data == 6'd32))
			cnt_data <= 6'd0;
		else
			if((inf_ifall == 1'b1)&&(stater == dataqu))//在数据状态下,检测到数据进行自加
				cnt_data <= cnt_data + 1'b1;
			else
				cnt_data <= cnt_data;
end
	
always@(posedge clk,negedge rst_n)//接收数据码暂存
begin
	if(rst_n == 0)
		data_reg <= 32'd0;
	else
		if((stater == dataqu)&&(inf_ifall == 1'b1)&&(flag_560us == 1'b1))
			data_reg[cnt_data] <= 1'b0;
		else
			if((stater == dataqu)&&(inf_ifall == 1'b1)&&(flag_1_69ms == 1'b1))
				data_reg[cnt_data] <= 1'b1;
			else
				data_reg <= data_reg;
end

always@(posedge clk,negedge rst_n)//数据传递
begin
	if(rst_n == 0)
		data <= 24'd0;
	else
		if((cnt_data == 6'd32)&&(~data_reg[23:16] ==	data_reg[31:24])&&(~data_reg[15:8] ==	data_reg[7:0]))//源码反码验证
			data <= {16'b0,data_reg[23:16]};
		else
			data <= data;
end

always@(posedge clk,negedge rst_n)//重复码下led驱动模块
begin
	if(rst_n == 0)
		led_en <= 1'b0;
	else
		if((stater == chofu)&&(~data_reg[23:16] ==	data_reg[31:24]))
			led_en <= 1'b1;
		else
			led_en <= 1'b0;
end

endmodule

呼吸灯模块

module huxi_led(

	input 		clk		,
	input 		rst_n		,
	input			led_en	,
	
	output reg  led				

);
 
parameter cnt_1s_max  = 10'd999;//1s最大计数值
parameter cnt_1ms_max = 10'd999;//1ms最大计数值
parameter cnt_1us_max = 6'd49;//1us最大计数值
reg [9:0]cnt_1s;//1s计数器
reg [9:0]cnt_1ms;//1ms计数器
reg [5:0]cnt_1us;//1us计数器
reg cnt_en;
always @(posedge clk,negedge rst_n)//1us计数原理
begin
	if(rst_n == 0)
		cnt_1us <= 6'd0;
	else 
		if(cnt_1us == cnt_1us_max)//到达最大计数值计数器清零
			cnt_1us <= 6'd0;
		else
			cnt_1us <= cnt_1us + 6'd1;
end
 
always @(posedge clk,negedge rst_n)//1ms计数原理
begin
	if(rst_n == 0)
		cnt_1ms <= 10'd0;
	else //1ms计数器到达最大值时需要等待1us计数器记到最大值时进行清零
		if((cnt_1us == cnt_1us_max)&&(cnt_1ms == cnt_1ms_max))
			cnt_1ms <= 10'd0;//到达最大计数值计数器清零
		else //1us计数器到最大值时进行累加
			if(cnt_1us == cnt_1us_max)
				cnt_1ms <= cnt_1ms + 10'd1;
			else 
				cnt_1ms <= cnt_1ms;
end
always @(posedge clk,negedge rst_n)//1s计数原理
begin
	if(rst_n == 0)
		cnt_1s <= 10'd0;
	else //1s计数器记到最大值且1ms计数器到达最大值,等待1us计数器记到最大值时进行清零
		if((cnt_1s == cnt_1s_max)&&(cnt_1us == cnt_1us_max)&&(cnt_1ms == cnt_1ms_max))
			cnt_1s <= 10'd0;//到达最大计数值计数器清零
		else //1us计数器和1ms计数器到最大值时进行累加
			if((cnt_1us == cnt_1us_max)&&(cnt_1ms == cnt_1ms_max))
				cnt_1s <= cnt_1s + 10'd1;
			else 
				cnt_1s <= cnt_1s;
end
 
always @(posedge clk,negedge rst_n)
begin
	if(rst_n == 0)
		cnt_en <= 1'b0;
	else //完全点亮或完全熄灭后进行状态反转,模拟出呼吸转换
		if((cnt_1s == cnt_1s_max)&&(cnt_1us == cnt_1us_max)&&(cnt_1ms == cnt_1ms_max))
			cnt_en <= ~cnt_en;
		else
			cnt_en <= cnt_en;
end
always @(posedge clk,negedge rst_n)
begin
	if(rst_n == 0)
		led <= 1'b0;
	else //cnt_en 为1时进行呼吸点亮,为0时进行呼吸熄灭
		if(led_en == 1'b1)
			begin
			if(((cnt_en == 1'b0)&&(cnt_1ms <= cnt_1s))||((cnt_en == 1'b1)&&(cnt_1ms > cnt_1s)))
				led <= 1'b1;
			else
				led <= 1'b0;
			end
		else
			led <= 1'b0;
end
	
endmodule 

数码管驱动模块

module seg_driver(
 
	input 				clk		,
	input 				rst_n		,
	input [23:0] 		data_in	,//接收数字时钟信号
	
	output reg [2:0] 	sel		,//位选信号
	output reg [7:0]	seg			//段选信号
);
 
reg [18:0] cnt;//1MS
parameter MAX = 19'd50_000;
//20ns记50000次
//产生1ms的延时
//位选信号1ms变换一次
reg [3:0] temp;
always @(posedge clk,negedge rst_n)
begin
	if(rst_n == 0)
		cnt <= 19'd0;
	else
		if(cnt < MAX - 1)//产生1ms的延时
			cnt <= cnt + 19'd1;
		else
			cnt <= 19'd0;
end 
 
//数码管位选信号控制逻辑
always @(posedge clk,negedge rst_n)
begin
	if(rst_n == 0)
		sel <= 3'd0;
	else
		if(cnt == MAX - 1)//位选信号6位,1ms的延时到变化一次
			if(sel < 5)
				sel <= sel + 3'd1;
			else 
				sel <= 3'd0;
		else 
			sel <= sel;	
end 
always @(*) begin
	if(rst_n == 0)
		temp <= 4'd0;
	else
		case(sel)//位选信号到将数据输出到对应输出位上
			3'd0	:	temp <= data_in[23:20];
			3'd1	:	temp <= data_in[19:16];
			3'd2	:	temp <= data_in[15:12];
			3'd3	:	temp <= data_in[11:8];
			3'd4	:	temp <= data_in[7:4];
			3'd5	:	temp <= data_in[3:0];
			default	:	temp <= 4'd0;
		endcase
end 
always @(*) begin
	if(rst_n == 0)
		seg <= 8'hff;
	else
		case(temp)//段选信号,对应的数码管信号
			4'd0	:	seg <= 8'b1100_0000;//0
			4'd1	:	seg <= 8'b1111_1001;//1
			4'd2	:	seg <= 8'b1010_0100;//2
			4'd3	:	seg <= 8'b1011_0000;//3
			4'd4	:	seg <= 8'b1001_1001;//4
			4'd5	:	seg <= 8'b1001_0010;//5
			4'd6	:	seg <= 8'b1000_0010;//6
			4'd7	:	seg <= 8'b1111_1000;//7
			4'd8	:	seg <= 8'b1000_0000;//8
			4'd9	:	seg <= 8'b1001_0000;//9
			4'd10	:	seg <= 8'b1000_1000;//A
			4'd11	:	seg <= 8'b1000_0011;//b
			4'd12	:	seg <= 8'b1100_0110;//C
			4'd13	:	seg <= 8'b1010_0001;//d
			4'd14	:	seg <= 8'b1000_0110;//E
			4'd15	:	seg <= 8'b1000_1110;//F
			default	:	seg <= 8'hff;
		endcase 
end 
endmodule 

顶层连线

module top_howai(

	input 				clk		,
	input					rst_n		,
	input					inf_in	,

	output  [2:0]	 	sel		,//位选信号
	output  [7:0]		seg		,	//段选信号
	output				led
);

wire 			led_en	;
wire[23:0] 	data		;

ho_wai ho_wai_inst(

	.clk		(clk		),
	.rst_n	(rst_n	),
	.inf_in	(inf_in	),
   
	.data		(data		),
	.led_en	(led_en	)

);

huxi_led huxi_led_inst(

	.clk		(clk		),
	.rst_n	(rst_n	),
	.led_en	(led_en	),
	      
	.led		(led		)

);

seg_driver seg_driver_inst(
 
	.clk		(clk		),
	.rst_n	(rst_n	),
	.data_in	(data 	),//接收数字时钟信号
      
	.sel		(sel		),//位选信号
	.seg		(seg		)//段选信号
);

endmodule

仿真代码

`timescale 1ns/1ps
module top_howai_tb;
	
	reg 			clk	;
	reg 			rst_n	;
	reg			inf_in;
	
	wire [7:0]	seg	;
	wire [2:0]	sel	;
	wire 			led	;
	
defparam 	top_howai_inst.huxi_led_inst.cnt_1s_max = 5;
defparam 	top_howai_inst.huxi_led_inst.cnt_1ms_max  = 5;
defparam 	top_howai_inst.huxi_led_inst.cnt_1us_max  = 2;
	
top_howai top_howai_inst(

	.clk	 	(clk	 	),
	.rst_n	(rst_n	),
	.inf_in	(inf_in	),
         
	.sel		(sel		),//位选信号
	.seg		(seg		),	//段选信号
	.led     (led     ) 
);


initial clk =1;
always #10 clk = ~clk;


initial begin
	rst_n = 0;
	inf_in = 1;
	#20
	rst_n = 1;
	#100
	inf_in = 0;//引导码
	#9000000
	inf_in = 1;
	#4500000
	
	inf_in = 0;//地址码1110_1010
	#560000		
	inf_in = 1;
	#1690000		//逻辑1
	inf_in = 0;
	#560000		
	inf_in = 1;
	#1690000		//逻辑1
	inf_in = 0;
	#560000		
	inf_in = 1;
	#1690000		//逻辑1
	inf_in = 0;
	#560000		
	inf_in = 1;
	#560000		//逻辑0
	inf_in = 0;
	#560000		
	inf_in = 1;
	#1690000		//逻辑1
	inf_in = 0;
	#560000		
	inf_in = 1;
	#560000		//逻辑0
	inf_in = 0;
	#560000		
	inf_in = 1;
	#1690000		//逻辑1	
	inf_in = 0;
	#560000		
	inf_in = 1;
	#560000		//逻辑0

	inf_in = 0;//地址反码(1110_1010---0001_0101)
	#560000		
	inf_in = 1;
	#560000		//逻辑0
	inf_in = 0;
	#560000		
	inf_in = 1;
	#560000		//逻辑0
	inf_in = 0;
	#560000		
	inf_in = 1;
	#560000		//逻辑0
	inf_in = 0;
	#560000		
	inf_in = 1;
	#1690000		//逻辑1
	inf_in = 0;
	#560000		
	inf_in = 1;
	#560000		//逻辑0
	inf_in = 0;
	#560000		
	inf_in = 1;
	#1690000		//逻辑1
	inf_in = 0;
	#560000		
	inf_in = 1;
	#560000		//逻辑0	
	inf_in = 0;
	#560000		
	inf_in = 1;
	#1690000		//逻辑1
	
	inf_in = 0;//数据码
	#560000
	inf_in = 1;
	#560000		//逻辑0
	inf_in = 0;
	#560000
	inf_in = 1;
	#1690000		//逻辑1
	inf_in = 0;
	#560000
	inf_in = 1;
	#560000		//逻辑0
	inf_in = 0;
	#560000
	inf_in = 1;
	#560000		//逻辑0
	inf_in = 0;
	#560000
	inf_in = 1;
	#560000		//逻辑0
	inf_in = 0;
	#560000
	inf_in = 1;
	#1690000		//逻辑1
	inf_in = 0;
	#560000
	inf_in = 1;
	#560000		//逻辑0
	inf_in = 0;
	#560000
	inf_in = 1;
	#560000		//逻辑0
	
	inf_in = 0;//数据反码(0100_0100--1011_1011)
	#560000
	inf_in = 1;
	#1690000		//逻辑1
	inf_in = 0;
	#560000
	inf_in = 1;
	#560000		//逻辑0
	inf_in = 0;
	#560000
	inf_in = 1;
	#1690000		//逻辑1
	inf_in = 0;
	#560000
	inf_in = 1;
	#1690000		//逻辑1
	inf_in = 0;
	#560000
	inf_in = 1;
	#1690000		//逻辑1
	inf_in = 0;
	#560000
	inf_in = 1;
	#560000		//逻辑0
	inf_in = 0;
	#560000
	inf_in = 1;
	#1690000		//逻辑1
	inf_in = 0;
	#560000
	inf_in = 1;
	#1690000		//逻辑1
	
	inf_in = 0;//结束位
	#560000
	
	inf_in = 1;//高电平保持
	#42000000
	
	inf_in = 0;//重复码
	#9000000
	inf_in = 1;
	#2250000
	
	inf_in = 0;//结束位
	#560000
	inf_in = 1;
	#10000
	$stop;
end

endmodule

三、仿真验证

运行仿真,调出中间信号进行观察,如下图,数据码可以完整提取出,为01000100,低位在前,即数据为00100010,对应22即按下遥控器上0按键一次。

当通过引导码判别出接收数据为重复码时,led_en拉高,led以呼吸灯形式闪烁。

观察stater状态按照理论进行跳转,实验成功

参考资料

红外遥控原理

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

张明阳.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值