串口发送+RAM+VGA传图

串口-RAM-VGA系列知识分享:
(0)串口通信实现-串口接收
(1)VGA成像原理与简单实现
(2)VGA显示板级验证
(3)VGA显示-多分辨率输入
(4)串口发送+RAM+VGA传图


前言

本文使用串口发送模块发送数据存储到RAM中,通过RAM读取数据传输图片给TFT显示屏。


提示:以下是本篇文章正文内容,下面案例可供参考

一、结构总体设计

1.UART_RAM_TFT总体设计草图
总体设计草图
2.img_rx_wr(RAM写入逻辑)设计草图
img_rx_wr草图

二、顶层模块

代码如下:

`timescale 1ns / 1ps

module UART_RAM_TFT(
    Clk,
    Reset_n,
    uart_rx,
    VGA_RGB,//TFT数据输出
    VGA_HS, //TFT行同步信号
    VGA_VS, //TFT场同步信号
    VGA_BLK,        //VGA 场消隐信号
    VGA_CLK,
    TFT_BL  //背光
);


    input Clk;
    input Reset_n;
    input uart_rx;
    output [15:0]VGA_RGB;
    output VGA_HS;
    output VGA_VS;
    output VGA_BLK;     //VGA 场消隐信号
    output VGA_CLK; 
    output TFT_BL;

    wire [7:0]rx_data;
    wire rx_done;
    
    wire ram_wren;
    wire [15:0]ram_wraddr;
    wire [15:0]ram_wrdata;
    reg [15:0]ram_rdaddr;
    wire Clk_TFT;
    wire [15:0]ram_rddata;
    
    assign VGA_CLK = Clk_TFT;
    assign TFT_BL = 1;
    
    MMCM MMCM(
        .clk_out1(Clk_TFT),
        .clk_in1(Clk)
    );
    
    uart_byte_rx uart_byte_rx(
        .Clk(Clk),
        .Reset_n(Reset_n),
        .Baud_Set(4),
        .uart_rx(uart_rx),
        .Data(rx_data),
        .Rx_Done(rx_done)  
    ); 
    
    img_rx_wr img_rx_wr(
        .Clk(Clk),
        .Reset_n(Reset_n),
        .rx_data(rx_data),
        .rx_done(rx_done),
        .ram_wren(ram_wren),
        .ram_wraddr(ram_wraddr),
        .ram_wrdata(ram_wrdata)
    );
    
    RAM RAM (
      .clka(Clk),    // input wire clka
      .ena(1),      // input wire ena
      .wea(ram_wren),      // input wire [0 : 0] wea
      .addra(ram_wraddr),  // input wire [15 : 0] addra
      .dina(ram_wrdata),    // input wire [15 : 0] dina
      .clkb(Clk_TFT),    // input wire clkb
      .enb(1),      // input wire enb
      .addrb(ram_rdaddr),  // input wire [15 : 0] addrb
      .doutb(ram_rddata)  // output wire [15 : 0] doutb
    );

    wire Data_Req;
    wire [11:0]hcount,vcount;
    
    wire [15:0]disp_data;
    VGA_CTRL VGA_CTRL(
        .Clk(Clk_TFT),    //系统输入时钟33MHZ
        .Reset_n(Reset_n),
        .Data(disp_data),    //待显示数据
		.Data_Req(Data_Req),
        .hcount(hcount),        //VGA行扫描计数器
        .vcount(vcount),        //VGA场扫描计数器
        .VGA_RGB(VGA_RGB),  //VGA数据输出
        .VGA_HS(VGA_HS),        //VGA行同步信号
        .VGA_VS(VGA_VS),        //VGA场同步信号
        .VGA_BLK(VGA_BLK)      //VGA 场消隐信号
    );
    
    //RAM中存储的图像是256*256的像素矩阵
     wire ram_data_en;
    assign ram_data_en = Data_Req && (hcount <= 255) && (vcount <= 255);
    
    always@(posedge Clk_TFT or negedge Reset_n)
    if(!Reset_n)
        ram_rdaddr <= 0;
    else if(ram_data_en)
        ram_rdaddr <= ram_rdaddr + 1'd1;
    
    wire data_en;
    wire [7:0]R ,G ,B;
    assign R = 8'hFF,G = 8'h00,B = 8'h00;
    wire [15:0]RED; 
    assign RED = {R[7:3],G[7:2],B[7:3]};
    assign data_en = Data_Req && (hcount <= 257) && (vcount <= 255);
    assign disp_data = data_en? ram_rddata:RED;//将多余图像显示红色
    //assign disp_data = ram_data_en? ram_rddata:0;    //将多余数据归0显示黑色
    
endmodule

三、img_rx_wr模块

module img_rx_wr(
    Clk,
    Reset_n,
    rx_data,
    rx_done,
    ram_wren,
    ram_wraddr,
    ram_wrdata
);
    input Clk;
    input Reset_n;
    input [7:0]rx_data;    //串口数据
    input rx_done;         //串口发送停止信号
    output reg ram_wren;   //开始写入信号
    output reg[15:0]ram_wraddr;   //RAM核写入地址
    output [15:0]ram_wrdata;      //写入数据
    
    reg [15:0]rx_data_tmp;
    
    reg [16:0]data_cnt; //统计串口接收的数据个数计数器
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
        data_cnt <= 0;
    else if(rx_done)
        data_cnt <= data_cnt + 1'd1;
 
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
        rx_data_tmp <= 0;
    else if(rx_done)     //串口一次发一个字节,RGB565一次需要2个字节
        rx_data_tmp <= {rx_data_tmp[7:0], rx_data};
 
 
 
//---------------------------------------------------------------
  //17'h0      ...0000
  //17'h1      ...0001
  //17'h2      ...0010
  //根据规律奇数末位为1
//---------------------------------------------------------------       
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
        ram_wren <= 0;
    else if(rx_done && data_cnt[0])    //每两个字节进行一次写入
        ram_wren <= 1'd1;
    else
        ram_wren <= 0;
 
 
        
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
        ram_wraddr <= 0;
    else if(rx_done && data_cnt[0]) 
        ram_wraddr <= data_cnt[16:1];  //data_cnt/2    
        
    assign ram_wrdata = rx_data_tmp;
    
endmodule

四、UART_rx模块

`timescale 1ns/1ns

module uart_byte_rx(
    Clk,
    Reset_n,
    Baud_Set,
    uart_rx,
    Data,
    Rx_Done,  
);

   input Clk;
   input Reset_n;
   input [2:0]Baud_Set;
   input uart_rx;
   output reg[7:0]Data; 
   output reg Rx_Done;
   
   reg [1:0]sync_uart_rx;
   
   always@(posedge Clk)begin
       sync_uart_rx[0] <= #1 uart_rx;
       sync_uart_rx[1] <= #1 sync_uart_rx[0] ;
   end
   
   reg [1:0]uart_rx_r;
   always@(posedge Clk)begin
        uart_rx_r[0] <= #1 sync_uart_rx[1];
        uart_rx_r[1] <= #1 uart_rx_r[0] ;
   end

    wire pedge_uart_rx;
//    assign pedge_uart_rx = ((uart_rx_r[1] == 0) && (uart_rx_r[0] == 1));
    assign pedge_uart_rx = (uart_rx_r == 2'b01);
    wire nedge_uart_rx;
//    assign nedge_uart_rx = ((uart_rx_r[1] == 1) && (uart_rx_r[0] == 0));  
    assign nedge_uart_rx = (uart_rx_r == 2'b10);  
 
    reg [8:0]  Bps_DR;
    always@(*)
        case(Baud_Set)
            0:Bps_DR = 1000000000/9600/16/20 - 2;
            1:Bps_DR = 1000000000/19200/16/20 -2;
            2:Bps_DR = 1000000000/38400/16/20 - 2;
            3:Bps_DR = 1000000000/57600/16/20 - 2;
            4:Bps_DR = 1000000000/115200/16/20 - 2;
            5:Bps_DR = 1000000000/1562500/16/20 - 2;
            default:Bps_DR = 1000000000/9600/16/20 - 1;
        endcase
        
    wire bps_clk_16x;
    assign bps_clk_16x = (div_cnt == Bps_DR / 2);

    reg RX_EN;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
        RX_EN <= #1 0;
    else if(nedge_uart_rx)
        RX_EN <= #1 1;
    else if(Rx_Done || (sta_bit >= 4))
        RX_EN <= #1 0;
        
    reg [8:0]div_cnt;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)    
        div_cnt <= #1 0;
    else if(RX_EN)begin
        if(div_cnt == Bps_DR)
            div_cnt <= #1 0;
        else
            div_cnt <= #1 div_cnt + 1'b1;
    end
    else
        div_cnt <= #1 0;

    reg [7:0]bps_cnt;
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
        bps_cnt <= #1 0;
    else if(RX_EN)begin
        if(bps_clk_16x)begin
            if(bps_cnt == 160)
                bps_cnt <= #1 0;
            else
                bps_cnt <= #1 bps_cnt + 1'b1;
        end
        else
            bps_cnt <= #1 bps_cnt;
     end
     else
        bps_cnt <= #1 0;
       
    //reg width name number/depth
    reg[2:0]r_data[7:0];
    reg [2:0]sta_bit;
    reg [2:0]sto_bit;
    
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) begin
        sta_bit <= #1 0;
        sto_bit <= #1 0;
        r_data[0] <= #1 0;
        r_data[1] <= #1 0;
        r_data[2] <= #1 0;
        r_data[3] <= #1 0;
        r_data[4] <= #1 0;
        r_data[5] <= #1 0;
        r_data[6] <= #1 0;
        r_data[7] <= #1 0;
    end
    else if(bps_clk_16x)begin
        case(bps_cnt)
            0:begin
                sta_bit <= #1 0;
                sto_bit <= #1 0;
                r_data[0] <= #1 0;
                r_data[1] <= #1 0;
                r_data[2] <= #1 0;
                r_data[3] <= #1 0;
                r_data[4] <= #1 0;
                r_data[5] <= #1 0;
                r_data[6] <= #1 0;
                r_data[7] <= #1 0;
            end
            5,6,7,8,9,10,11:sta_bit <= #1 sta_bit + sync_uart_rx[1];
            21,22,23,24,25,26,27: r_data[0] <= #1 r_data[0] + sync_uart_rx[1];
            37,38,39,40,41,42,43: r_data[1] <= #1 r_data[1] + sync_uart_rx[1];
            53,54,55,56,57,58,59: r_data[2] <= #1 r_data[2] + sync_uart_rx[1];
            69,70,71,72,73,74,75: r_data[3] <= #1 r_data[3] + sync_uart_rx[1];
            85,86,87,88,89,90,91: r_data[4] <= #1 r_data[4] + sync_uart_rx[1];
            101,102,103,104,105,106,107: r_data[5] <= #1 r_data[5] + sync_uart_rx[1];
            117,118,119,120,121,122,123: r_data[6] <= #1 r_data[6] + sync_uart_rx[1];
            133,134,135,136,137,138,139: r_data[7] <= #1 r_data[7] + sync_uart_rx[1];
            149,150,151,152,153,154,155: sto_bit <= #1 sto_bit + sync_uart_rx[1];
            default:;
        endcase
    end
        
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
        Data <= #1 0;        
    else if(bps_clk_16x && (bps_cnt == 159))begin
        Data[0] <= #1 (r_data[0] >= 4)?1'b1:1'b0;
        Data[1] <= #1 (r_data[1] >= 4)?1'b1:1'b0;
        Data[2] <= #1 (r_data[2] >= 4)?1'b1:1'b0;
        Data[3] <= #1 (r_data[3] >= 4)?1'b1:1'b0;
        Data[4] <= #1 (r_data[4] >= 4)?1'b1:1'b0;
        Data[5] <= #1 (r_data[5] >= 4)?1'b1:1'b0;
        Data[6] <= #1 (r_data[6] >= 4)?1'b1:1'b0;
        Data[7] <= #1 (r_data[7] >= 4)?1'b1:1'b0;
    end 
    
//    always@(posedge Clk or negedge Reset_n)
//    if(!Reset_n) 
//        Data <= #1 0;        
//    else if(bps_clk_16x && (bps_cnt == 159))begin
//        Data[0] <= #1 r_data[0][2];
//        Data[1] <= #1 r_data[1][2];
//        Data[2] <= #1 r_data[2][2];
//        Data[3] <= #1 r_data[3][2];
//        Data[4] <= #1 r_data[4][2];
//        Data[5] <= #1 r_data[5][2];
//        Data[6] <= #1 r_data[6][2];
//        Data[7] <= #1 r_data[7][2];
//    end 

    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n) 
        Rx_Done <= #1 0;
    else if((div_cnt == Bps_DR/2) && (bps_cnt == 160))
        Rx_Done <= #1 1;
    else
        Rx_Done <= #1 0; 
        
endmodule

五、VGA_CTRL模块

module VGA_CTRL(
    Clk,
    Reset_n,
    Data,
    Data_Req,
    hcount,
    vcount,
    VGA_HS,
    VGA_VS,
    VGA_BLK,
    VGA_RGB
);
    
    input Clk;
    input Reset_n;
    input [15:0]Data;
    output reg Data_Req;
    output reg [11:0]hcount; //当前扫描点的H坐标
    output reg [11:0]vcount; //当前扫描点的V坐标
    output VGA_HS;
    output VGA_VS; 
    output VGA_BLK;
    output reg [15:0]VGA_RGB;//{R[4:0]、G[5:0]、B[4:0]}
    
    `include "vga_parameter.v"
    localparam Hsync_End = `H_Total_Time;
    localparam HS_End = `H_Sync_Time;
    localparam Hdat_Begin = `H_Sync_Time + `H_Back_Porch + `H_Left_Border;
    localparam Hdat_End = `H_Sync_Time + `H_Left_Border + `H_Back_Porch + `H_Data_Time;
    localparam Vsync_End = `V_Total_Time;
    localparam VS_End = `V_Sync_Time;
    localparam Vdat_Begin =  `V_Sync_Time + `V_Back_Porch + `V_Top_Border;
    localparam Vdat_End = `V_Sync_Time + `V_Back_Porch + `V_Top_Border + `V_Data_Time;
    
    reg [11:0]hcnt;//行扫描计数器
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        hcnt <= 0;
    else if(hcnt >= Hsync_End -1)
        hcnt <= 0;
    else
        hcnt <= hcnt + 1'b1;
    
    
    //RAM_IP核输出数据有三拍延迟此处为了对齐数据传输
    
    reg [3:0]VGA_HS_r;
        
    always@(posedge Clk)begin
        VGA_HS_r[0] <= (hcnt < HS_End)?0:1;
        VGA_HS_r[3:1] <= VGA_HS_r[2:0];        
    end
    
    assign VGA_HS = VGA_HS_r[2];

    reg [11:0]vcnt;//场扫描计数器
    always@(posedge Clk or negedge Reset_n)
    if(!Reset_n)
        vcnt <= 0;
    else if(hcnt == Hsync_End -1)begin
        if(vcnt >= Vsync_End -1)
            vcnt <= 0;
        else
            vcnt <= vcnt + 1'd1;
    end
    else
        vcnt <= vcnt;
    
    //RAM_IP核输出数据有三拍延迟此处为了对齐数据传输
    reg [3:0]VGA_VS_r;   
    always@(posedge Clk)begin
        VGA_VS_r[0]  <= (vcnt < VS_End)?0:1;
        VGA_VS_r[3:1] <= VGA_VS_r[2:0];
    end

    assign VGA_VS = VGA_VS_r[2];
            
    //BLK表示的就是输出输出的时间段
//    assign VGA_BLK = ((hcnt >= Hdat_Begin - 1) && (hcnt < Hdat_End - 1) && (vcnt >= Vdat_Begin - 1) && (vcnt < Vdat_End))?1:0;
//    always@(posedge Clk)
//         VGA_BLK <= ((hcnt >= Hdat_Begin - 1) && (hcnt < Hdat_End - 1) && (vcnt >= Vdat_Begin - 1) && (vcnt < Vdat_End))?1:0;   

    always@(posedge Clk)
       Data_Req <= ((hcnt >= Hdat_Begin - 1) && (hcnt < Hdat_End - 1) && (vcnt >= Vdat_Begin) && (vcnt < Vdat_End))?1:0;
    
    //RAM_IP核输出数据有三拍延迟此处为了对齐数据传输
    reg [3:0]VGA_BLK_r;
    always@(posedge Clk)begin
       VGA_BLK_r[0] <= Data_Req;
       VGA_BLK_r[3:1] <= VGA_BLK_r[2:0];
    end
        assign VGA_BLK = VGA_BLK_r[3];
            
//    assign VGA_RGB = VGA_BLK? Data:0;
    always@(posedge Clk)
        VGA_RGB <= Data_Req? Data:0;
        
    always@(posedge Clk)
       hcount <= Data_Req? hcnt - Hdat_Begin:0; 

    always@(posedge Clk)
       vcount <= Data_Req? (vcnt - Vdat_Begin):vcount;          
        
endmodule

六、parameter.v文件

//`define Resolution_480x272 1	//刷新率为60Hz时像素时钟为9MHz
//`define Resolution_640x480 1	//刷新率为60Hz时像素时钟为25.175MHz
`define Resolution_800x480 1	//刷新率为60Hz时像素时钟为33MHz
//`define Resolution_800x600 1	//刷新率为60Hz时像素时钟为40MHz
//`define Resolution_1024x768 1	//刷新率为60Hz时像素时钟为65MHz
//`define Resolution_1280x720 1	//刷新率为60Hz时像素时钟为74.25MHz
//`define Resolution_1920x1080 1	//刷新率为60Hz时像素时钟为148.5MHz

`ifdef Resolution_480x272    
    `define H_Right_Border 0
    `define H_Front_Porch 2
    `define H_Sync_Time 41
    `define H_Back_Porch 2
    `define H_Left_Border 0
    `define H_Data_Time 480
    `define H_Total_Time 525
    `define V_Bottom_Border 0
    `define V_Front_Porch 2
    `define V_Sync_Time 10
    `define V_Back_Porch 2
    `define V_Top_Border 0
    `define V_Data_Time 272
    `define V_Total_Time 286
    
`elsif Resolution_640x480
	`define H_Total_Time  12'd800
	`define H_Right_Border  12'd8
	`define H_Front_Porch  12'd8
	`define H_Sync_Time  12'd96
	`define H_Data_Time 12'd640
	`define H_Back_Porch  12'd40
	`define H_Left_Border  12'd8
	`define V_Total_Time  12'd525
	`define V_Bottom_Border  12'd8
	`define V_Front_Porch  12'd2
	`define V_Sync_Time  12'd2
	`define V_Data_Time 12'd480
	`define V_Back_Porch  12'd25
	`define V_Top_Border  12'd8
	
`elsif Resolution_800x480
	`define H_Total_Time 12'd1056
	`define H_Right_Border 12'd0
	`define H_Front_Porch 12'd40
	`define H_Sync_Time 12'd128
	`define H_Data_Time 12'd800
	`define H_Back_Porch 12'd88
	`define H_Left_Border 12'd0

	`define V_Total_Time 12'd525
	`define V_Bottom_Border 12'd8
	`define V_Front_Porch 12'd2
	`define V_Sync_Time 12'd2
	`define V_Data_Time 12'd480
	`define V_Back_Porch 12'd25
	`define V_Top_Border 12'd8

`elsif Resolution_800x600
	`define H_Total_Time 12'd1056
	`define H_Right_Border 12'd0
	`define H_Front_Porch 12'd40
	`define H_Sync_Time 12'd128
	`define H_Data_Time 12'd800
	`define H_Back_Porch 12'd88
	`define H_Left_Border 12'd0

	`define V_Total_Time 12'd628
	`define V_Bottom_Border 12'd0
	`define V_Front_Porch 12'd1
	`define V_Sync_Time 12'd4
	`define V_Data_Time 12'd600
	`define V_Back_Porch 12'd23
	`define V_Top_Border 12'd0

`elsif Resolution_1024x768
	`define H_Total_Time 12'd1344
	`define H_Right_Border 12'd0
	`define H_Front_Porch 12'd24
	`define H_Sync_Time 12'd136
	`define H_Data_Time 12'd1024
	`define H_Back_Porch 12'd160
	`define H_Left_Border 12'd0

	`define V_Total_Time 12'd806
	`define V_Bottom_Border 12'd0
	`define V_Front_Porch 12'd3
	`define V_Sync_Time 12'd6
	`define V_Data_Time 12'd768
	`define V_Back_Porch 12'd29
	`define V_Top_Border 12'd0

`elsif Resolution_1280x720
	`define H_Total_Time 12'd1650
	`define H_Right_Border 12'd0
	`define H_Front_Porch 12'd110
	`define H_Sync_Time 12'd40
	`define H_Data_Time 12'd1280
	`define H_Back_Porch 12'd220
	`define H_Left_Border 12'd0

	`define V_Total_Time 12'd750
	`define V_Bottom_Border 12'd0
	`define V_Front_Porch 12'd5
	`define V_Sync_Time 12'd5
	`define V_Data_Time 12'd720
	`define V_Back_Porch 12'd20
	`define V_Top_Border 12'd0
		
`elsif Resolution_1920x1080
	`define H_Total_Time 12'd2200
	`define H_Right_Border 12'd0
	`define H_Front_Porch 12'd88
	`define H_Sync_Time 12'd44
	`define H_Data_Time 12'd1920
	`define H_Back_Porch 12'd148
	`define H_Left_Border 12'd0

	`define V_Total_Time 12'd1125
	`define V_Bottom_Border 12'd0
	`define V_Front_Porch 12'd4
	`define V_Sync_Time 12'd5
	`define V_Data_Time 12'd1080
	`define V_Back_Porch 12'd36
	`define V_Top_Border 12'd0	
	
`endif

七、clk_IP和RAM_IP配置

具体IP配置根据所需选择,可参考我之前文章,自行根据所需配置。

八、仿真文件展示

`timescale 1ns / 1ps

module UART_RAM_TFT_tb(

    );
    
    reg Clk;
    reg Reset_n;
    reg uart_rx;
    wire [15:0]VGA_RGB;
    wire VGA_HS;
    wire VGA_VS;
    wire VGA_BLK;     //VGA 场消隐信号
    wire VGA_CLK; 
    wire TFT_BL;
        
    UART_RAM_TFT UART_RAM_TFT(
        Clk,
        Reset_n,
        uart_rx,
        VGA_RGB,//TFT数据输出
        VGA_HS, //TFT行同步信号
        VGA_VS, //TFT场同步信号
        VGA_BLK,        //VGA 场消隐信号
        VGA_CLK,
        TFT_BL  //背光
    );
    
    initial Clk = 1;
    always#10 Clk = ~Clk;
    
    initial begin
        Reset_n = 0;
        #201;
        Reset_n = 1;
        #2000;
        #2000000;
        $stop;
    end    
    
endmodule

九、上板演示

在这里插入图片描述
串口传图展示:

在这里插入图片描述
【附件:】链接:https://pan.baidu.com/s/1wWgnTeCfzlFzGWUCQe7ANg?pwd=mnz3
提取码:mnz3

  • 3
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

C.V-Pupil

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

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

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

打赏作者

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

抵扣说明:

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

余额充值