基于FPGA的VGA协议实现

一、VGA

1.简介
VGA(Video Graphics Array)视频图形阵列是IBM于1987年提出的一个使用模拟信号的电脑显示标准。VGA接口即电脑采用VGA标准输出数据的专用接口。VGA接口共有15针,分成3排,每排5个孔,显卡上应用最为广泛的接口类型,绝大多数显卡都带有此种接口。它传输红、绿、蓝模拟信号以及同步信号(水平和垂直信号)。

VGA接口是一种D型接口,上面共有15针孔,分成三排,每排五个。 其中,除了2根NC(Not Connect)信号、3根显示数据总线和5个GND信号,比较重要的是3根RGB彩色分量信号和2根扫描同步信号HSYNC和VSYNC针。VGA接口中彩色分量采用RS343电平标准。RS343电平标准的峰值电压为1V。VGA接口是显卡上应用最为广泛的接口类型,多数的显卡都带有此种接口。有些不带VGA接口而带有DVI(Digital Visual Interface数字视频接口)接口的显卡,也可以通过一个简单的转接头将DVI接口转成VGA接口,通常没有VGA接口的显卡会附赠这样的转接头。
在这里插入图片描述

2.管脚定义
大多数计算机与外部显示设备之间都是通过模拟VGA接口连接,计算机内部以数字方式生成的显示图像信息,被显卡中的数字/模拟转换器转变为R、G、B三原色信号和行、场同步信号,信号通过电缆传输到显示设备中。对于模拟显示设备,如模拟CRT显示器,信号被直接送到相应的处理电路,驱动控制显像管生成图像。而对于LCD、DLP等数字显示设备,显示设备中需配置相应的A/D(模拟/数字)转换器,将模拟信号转变为数字信号。在经过D/A和A/D两次转换后,不可避免地造成了一些图像细节的损失。VGA接口应用于CRT显示器无可厚非,但用于连接液晶之类的显示设备,则转换过程的图像损失会使显示效果略微下降。
而且可以从接口处来判断显卡是独显还是集成显卡,VGA接口竖置的说明是集成显卡,VGA接口横置说明是独立显卡(一般的台式主机都可以用此方法来查看)。
在这里插入图片描述
在这里插入图片描述

3.VGA显示原理
VGA通过引脚的模拟电压(0V-0.714V)显示红绿蓝三种颜色,不同的电压值对应不同的颜色。
VGA驱动显示器用的是扫描的方式,一般是逐行扫描。
逐行扫描是扫描从屏幕左上角一点开始,从左像右逐点扫描,每扫描完一行,电子束回到屏幕的左边下一行的起始位置,在这期间,CRT对电子束进行消隐,每行结束时,用行同步信号进行同步;
当扫描完所有的行,形成一帧后,用场同步信号进行场同步,并使扫描回到屏幕左上方,同时进行场消隐,开始下一帧。
FPGA芯片驱动VGA显示,需要先产生模拟信号,这就要借助数模转换器D/A,利用D/A产生模拟信号,输出至VGA的RED、GREEN、BLUE基色数据线。另一种方法是利用电阻网络分流模拟D/A实现的。

4.VGA通信协议
vga通信时序图
在这里插入图片描述
VS:帧时序
帧时序的四个部分别是:同步脉冲(Sync o)、显示后沿(Back porch p)、显示时序段(Display interval q)和显示前沿(Front porchr)。其中同步脉冲(Sync o)、显示后沿(Back porch p)和显示前沿(Front porch r)是消隐区,RGB信号无效,屏幕不显示数据。显示时序段(Display interval q)是有效数据区。
在这里插入图片描述

HS:行时序
行时序的四个部分分别是:同步脉冲(Sync a)、显示后沿(Back porch b)、显示时序(Display interval c)和显示前沿(Front porchd)。其中同步脉冲(Sync a)、显示后沿(Back porch b)和显示前沿(Front porch d)是消隐区,RGB信号无效,屏幕不显示数据。显示时序段(Display interval c)是有效数据区。
在这里插入图片描述

二、VGA显示彩色条纹

1.相关代码
25M的时钟:

module clk_25M_get(
  input   wire          clk           , //VGA时
  input   wire          rst_n         , //复位
  output  reg         clk_25M         
);

always @(posedge clk or negedge rst_n) begin
     if (!rst_n) begin
         clk_25M <= 1'b0     ; 
     end 
     else  begin
         clk_25M <=  ~clk_25M;
     end 
end
endmodule


屏幕信息定义

`define vga_640_480

`ifdef vga_640_480
    `define H_Right_Border   8
    `define H_Front_Porch    8
    `define H_Sync_Time      96
    `define H_Back_Porch     40
    `define H_Left_Border    8
    `define H_Data_Time      640
    `define H_Total_Time     800

    `define V_Bottom_Border   8
    `define V_Front_Porch    2
    `define V_Sync_Time      2
    `define V_Back_Porch     25
    `define V_Top_Border     8
    `define V_Data_Time      480
    `define V_Total_Time     525


`elsif vga_1920_1080
    `define H_Right_Border    0
    `define H_Front_Porch    88
    `define H_Sync_Time      44
    `define H_Back_Porch     148
    `define H_Left_Border    0
    `define H_Data_Time      1920
    `define H_Total_Time     2200

    `define V_Bottom_Border   0
    `define V_Front_Porch    4
    `define V_Sync_Time      5
    `define V_Back_Porch     36
    `define V_Top_Border     0
    `define V_Data_Time      1080
    `define V_Total_Time     1125    



`elsif vga_800_480
    `define H_Right_Border   0
    `define H_Front_Porch    40
    `define H_Sync_Time      128
    `define H_Back_Porch     88
    `define H_Left_Border    0
    `define H_Data_Time      800
    `define H_Total_Time     1056

    `define V_Bottom_Border  8
    `define V_Front_Porch    2
    `define V_Sync_Time      2
    `define V_Back_Porch     25
    `define V_Top_Border     8
    `define V_Data_Time      480
    `define V_Total_Time     525


`elsif vga_800_600
    `define H_Right_Border   0
    `define H_Front_Porch    40
    `define H_Sync_Time      128
    `define H_Back_Porch     88
    `define H_Left_Border    0
    `define H_Data_Time      800
    `define H_Total_Time     1056

    `define V_Bottom_Border  0
    `define V_Front_Porch    1
    `define V_Sync_Time      4
    `define V_Back_Porch     23
    `define V_Top_Border     0
    `define V_Data_Time      600
    `define V_Total_Time     628


`elsif vga_1024_600
    `define H_Right_Border   0
    `define H_Front_Porch    24
    `define H_Sync_Time      136
    `define H_Back_Porch     160
    `define H_Left_Border    0
    `define H_Data_Time      1024
    `define H_Total_Time     1344

    `define V_Bottom_Border  0
    `define V_Front_Porch    1
    `define V_Sync_Time      4
    `define V_Back_Porch     23
    `define V_Top_Border     0
    `define V_Data_Time      600
    `define V_Total_Time     628


`elsif vga_1024_768
    `define H_Right_Border   0
    `define H_Front_Porch    24
    `define H_Sync_Time      136
    `define H_Back_Porch     160
    `define H_Left_Border    0
    `define H_Data_Time      1024
    `define H_Total_Time     1344

    `define V_Bottom_Border  0
    `define V_Front_Porch    3
    `define V_Sync_Time      6
    `define V_Back_Porch     29
    `define V_Top_Border     0
    `define V_Data_Time      768
    `define V_Total_Time     806


`elsif vga_1280_720
    `define H_Right_Border   0
    `define H_Front_Porch    110
    `define H_Sync_Time      40
    `define H_Back_Porch     220
    `define H_Left_Border    0
    `define H_Data_Time      1280
    `define H_Total_Time     1650

    `define V_Bottom_Border  0
    `define V_Front_Porch    5
    `define V_Sync_Time      5
    `define V_Back_Porch     20
    `define V_Top_Border     0
    `define V_Data_Time      720
    `define V_Total_Time     750

`else



`endif


vga_ctrl.v


`include "vga_param.v"
// `define vga_640_480
// `define vga_1920_1080



/**
 *
 * VGA控制模块
*/
module vga_ctrl(
    input   wire            clk         ,
    input   wire            rst_n       ,
    input   wire [23:0]     data_display,   // 要显示的数据

    output  reg [10:0]      h_addr      ,   // 行地址--数据有效显示区域行地址
    output  reg [10:0]      v_addr      ,   // 场地址--数据有效显示区域场地址
    
    output  reg             hsync       ,
    output  reg             vsync       ,
    output  reg [7:0]       vga_r       ,    // R
    output  reg [7:0]       vga_g       ,    // G
    output  reg [7:0]       vga_b       ,    // B
    // output  wire            vga_sync_n  ,
    output  reg             vga_black   ,
    output  wire            vga_clk          // 时钟
);

    
    parameter           H_SYNC_START = 1;                        // 行同步开始
    parameter           H_SYNC_STOP  = `H_Sync_Time;         // 行同步结束
    parameter           H_DATA_START = `H_Sync_Time + `H_Back_Porch + `H_Left_Border; 
    parameter           H_DATA_STOP  = `H_Sync_Time + `H_Back_Porch + `H_Left_Border + `H_Data_Time;
    
    parameter           V_SYNC_START = 1;                        // 场同步开始
    parameter           V_SYNC_STOP  = `V_Sync_Time;         // 场同步结束
    parameter           V_DATA_START = `V_Sync_Time + `V_Back_Porch + `V_Top_Border; 
    parameter           V_DATA_STOP  = `V_Sync_Time + `V_Back_Porch + `V_Top_Border + `V_Data_Time;


    // parameter           V_BLANK      = `V_Total_Time;        //场空白信号总周期长
    // parameter           H_BLANK      = `H_Total_Time;        //场空白信号总周期长



    reg     [11:0]      cnt_h_addr;   // 行地址计数器
    wire                add_h_addr;
    wire                end_h_addr;

    reg     [11:0]      cnt_v_addr;   // 场地址计数器
    wire                add_v_addr;
    wire                end_v_addr;



// 行地址计数
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            cnt_h_addr <= 12'd0;
        end

        else if (add_h_addr) begin
            if (end_h_addr)
                cnt_h_addr <= 12'd0;
            else
                cnt_h_addr <= cnt_h_addr + 1'b1;
        end

        else begin
            cnt_h_addr <= 12'd0;
        end
    end
    assign add_h_addr = 1'b1;
    assign end_h_addr = ((cnt_h_addr>=`H_Total_Time-1) && add_h_addr);


// 场地址计数
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            cnt_v_addr <= 12'd0;
        end

        else if (add_v_addr) begin
            if (end_v_addr)
                cnt_v_addr <= 12'd0;
            else
                cnt_v_addr <= cnt_v_addr + 1'b1;
        end

        else begin
            cnt_v_addr <= cnt_v_addr;
        end
    end
    assign add_v_addr = end_h_addr;
    assign end_v_addr = ((cnt_v_addr>=`V_Total_Time-1) && add_v_addr);


    // always @(posedge clk or negedge rst_n) begin
    //     if (!rst_n) begin
    //     end
    //
    //     else if (add_v_addr) begin
    //     end
    //
    //     else begin
    //     end
    // end


    // assign vga_sync_n = 1'b0; //符合同步控制信号      行时序和场时序都要产生同步脉冲
    //assign vga_black  = ~((cnt_h_addr < H_BLANK) || (cnt_v_addr < V_BLANK));  //当行计数器小于行空白总长或场计数器小于场空白总长时,空白信号低电平


// 行同步信号  低有效
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            hsync <= 1'b1;
        end
    
        else if (cnt_h_addr == H_SYNC_START - 1) begin  // 行同步开始
            hsync <= 1'b0;
        end

        else if (cnt_h_addr == H_SYNC_STOP - 1) begin   // 行同步结束
            hsync <= 1'b1;
        end
    
        else begin
            hsync <= hsync;
        end
    end


// 场同步信号  低有效
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            vsync <= 1'b1;
        end
    
        else if (cnt_v_addr == V_SYNC_START - 1) begin
            vsync <= 1'b0;
        end

        else if (cnt_v_addr == V_SYNC_STOP - 1) begin
            vsync <= 1'b1;
        end
    
        else begin
            vsync <= vsync;
        end
    end



    assign vga_clk = clk;


// 数据有效显示区域定义
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            h_addr <= 11'd0;
        end
    
        else if ((cnt_h_addr >= (H_DATA_START - 1)) && (cnt_h_addr <= H_DATA_STOP)) begin
            h_addr <= cnt_h_addr - H_DATA_START - 1;  // 总的 减去 前面的多余部分
        end
    
        else begin
            h_addr <= 11'd0;
        end
    end


// 数据有效显示区域定义
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            v_addr <= 11'd0;
        end
    
        else if ((cnt_v_addr >= (V_DATA_START - 1)) && (cnt_v_addr <= V_DATA_STOP)) begin
            v_addr <= cnt_v_addr - V_DATA_START - 1;
        end
    
        else begin
            v_addr <= 11'd0;
        end
    end


// 显示数据
    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            vga_r <= 8'd0;
            vga_g <= 8'd0;
            vga_b <= 8'd0;
        end
    
        // 在显示数据范围内
        else if (  ((cnt_h_addr >= (H_DATA_START - 1)) && (cnt_h_addr <= H_DATA_STOP)) && 
                    ((cnt_v_addr >= (V_DATA_START - 1)) && (cnt_v_addr <= V_DATA_STOP))  ) begin
            vga_r <= data_display[23:16];
            vga_g <= data_display[15:8];
            vga_b <= data_display[7:0];
            vga_black <= 1'b1;
        end
    
        else begin
            vga_r <= 8'd0;
            vga_g <= 8'd0; 
            vga_b <= 8'd0;
            vga_black <= 1'b0;
        end
    end
endmodule


vga_generate.v

module data_generate(
    input   wire            clk         ,
    input   wire            rst_n       ,

    input   wire [10:0]     h_addr      ,   // 行地址--数据有效显示区域行地址
    input   wire [10:0]     v_addr      ,   // 场地址--数据有效显示区域场地址

    output  reg [23:0]      data_display   // 要显示的数据
);


    parameter 
        BLACK    = 24'h000000,
        RED      = 24'hFF0000,
        GREEN    = 24'h00FF00,
        BLUE     = 24'h0000FF,
        YELLOW   = 24'hFFFF00,
        CYANRAY  = 24'h00FFFF,
        PURPLE   = 24'hFF00FF,
        GRAY     = 24'hC0C0C0,
        WHITE    = 24'hFFFFFF;





    always @(posedge clk or negedge rst_n) begin
        if (!rst_n) begin
            data_display <= WHITE;
        end

        else begin
            case (h_addr)
                0:          data_display <= BLACK  ;
                80:         data_display <= RED    ;
                160:        data_display <= GREEN  ;
                240:        data_display <= BLUE   ;
                320:        data_display <= YELLOW ;
                400:        data_display <= CYANRAY;
                480:        data_display <= PURPLE ;
                560:        data_display <= GRAY   ;
                default:    data_display <= data_display;
            endcase
        end
    end
endmodule


顶层文件vga_top.v

/**
 *
 * 顶层文件
*/

module vga_top(
    input   wire        clk,
    input   wire        rst_n,

    output  wire             hsync       ,
    output  wire             vsync       ,
    output  wire [7:0]       vga_r       ,
    output  wire [7:0]       vga_g       ,
    output  wire [7:0]       vga_b       ,
    // output  wire             vga_sync_n  ,
    output  wire             vga_black   ,
    output  wire             vga_clk      
);

    wire [23:0]     data_display;   // 要显示的数据

    wire [10:0]     h_addr      ;   // 行地址--数据有效显示区域行地
    wire [10:0]     v_addr      ;   // 场地址--数据有效显示区域场地

    
    wire    clk_25M;

     clk_25M_get u_clk_25M_get(
         .clk           (clk    ), //VGA时
         .rst_n         (rst_n  ), //复位
         .clk_25M       (clk_25M)  
     );



     data_generate u_data_generate(
         /*input   wire        */    .clk            (clk_25M      ),
         /*input   wire        */    .rst_n          (rst_n        ),

         /*input   wire [10:0] */    .h_addr         (h_addr       ),   // 行地址--数据有效显示区域行地址
         /*input   wire [10:0] */    .v_addr         (v_addr       ),   // 场地址--数据有效显示区域场地址

         /*output  wire [23:0] */    .data_display   (data_display )    // 要显示的数据
     );![请添加图片描述](https://img-blog.csdnimg.cn/1660334f7ecd4160b71c835ce6129c95.png)


    // 显示字符
//    data_gen_char u_data_gen_char(
//        /*input   wire        */    .clk            (clk_25M      ),
//        /*input   wire        */    .rst_n          (rst_n        ),

//        /*input   wire [10:0] */    .h_addr         (h_addr       ),   // 行地址--数据有效显示区域行地址
//        /*input   wire [10:0] */    .v_addr         (v_addr       ),   // 场地址--数据有效显示区域场地址

//        /*output  wire [23:0] */    .data_display   (data_display )    // 要显示的数据
    );



    vga_ctrl u_vga_ctrl(
        /*input   wire       */     .clk            (clk_25M     ),
        /*input   wire       */     .rst_n          (rst_n       ),
        /*input   wire [23:0]*/     .data_display   (data_display),   // 要显示的数据
        
        /*output  wire [10:0]*/     .h_addr         (h_addr      ),   // 行地址--数据有效显示区域行地址
        /*output  wire [10:0]*/     .v_addr         (v_addr      ),   // 场地址--数据有效显示区域场地址
        
        /*output  reg        */     .hsync          (hsync       ),
        /*output  reg        */     .vsync          (vsync       ),
        /*output  reg [7:0]  */     .vga_r          (vga_r       ),    // R
        /*output  reg [7:0]  */     .vga_g          (vga_g       ),    // G
        /*output  reg [7:0]  */     .vga_b          (vga_b       ),    // B
                                    // .vga_sync_n     (vga_sync_n  ),
                                    .vga_black      (vga_black   ),
        /*output  wire       */     .vga_clk        (vga_clk     )  // 时钟
    );

endmodule


2.实验效果
在这里插入图片描述

三、VGA字符显示

1.通过汉字点阵获取16进制字符
字模选项:
在这里插入图片描述
2.主要代码

module vga(
OSC_50,     //原CLK2_50时钟信号
VGA_CLK,    //VGA自时钟
VGA_HS,     //行同步信号
VGA_VS,     //场同步信号
VGA_BLANK,  //复合空白信号控制信号  当BLANK为低电平时模拟视频输出消隐电平,此时从R9~R0,G9~G0,B9~B0输入的所有数据被忽略
VGA_SYNC,   //符合同步控制信号      行时序和场时序都要产生同步脉冲
VGA_R,      //VGA绿色
VGA_B,      //VGA蓝色
VGA_G);     //VGA绿色
 input OSC_50;     //外部时钟信号CLK2_50
 output VGA_CLK,VGA_HS,VGA_VS,VGA_BLANK,VGA_SYNC;
 output [7:0] VGA_R,VGA_B,VGA_G;
 parameter H_FRONT = 16;     //行同步前沿信号周期长
 parameter H_SYNC = 96;      //行同步信号周期长
 parameter H_BACK = 48;      //行同步后沿信号周期长
 parameter H_ACT = 640;      //行显示周期长
 parameter H_BLANK = H_FRONT+H_SYNC+H_BACK;        //行空白信号总周期长
 parameter H_TOTAL = H_FRONT+H_SYNC+H_BACK+H_ACT;  //行总周期长耗时
 parameter V_FRONT = 11;     //场同步前沿信号周期长
 parameter V_SYNC = 2;       //场同步信号周期长
 parameter V_BACK = 31;      //场同步后沿信号周期长
 parameter V_ACT = 480;      //场显示周期长
 parameter V_BLANK = V_FRONT+V_SYNC+V_BACK;        //场空白信号总周期长
 parameter V_TOTAL = V_FRONT+V_SYNC+V_BACK+V_ACT;  //场总周期长耗时
 reg [10:0] H_Cont;        //行周期计数器
 reg [10:0] V_Cont;        //场周期计数器
 wire [7:0] VGA_R;         //VGA红色控制线
 wire [7:0] VGA_G;         //VGA绿色控制线
 wire [7:0] VGA_B;         //VGA蓝色控制线
 reg VGA_HS;
 reg VGA_VS;
 reg [10:0] X;             //当前行第几个像素点
 reg [10:0] Y;             //当前场第几行
 reg CLK_25;
 always@(posedge OSC_50)
    begin 
      CLK_25=~CLK_25;         //时钟
    end 
    assign VGA_SYNC = 1'b0;   //同步信号低电平
    assign VGA_BLANK = ~((H_Cont<H_BLANK)||(V_Cont<V_BLANK));  //当行计数器小于行空白总长或场计数器小于场空白总长时,空白信号低电平
    assign VGA_CLK = ~CLK_to_DAC;  //VGA时钟等于CLK_25取反
    assign CLK_to_DAC = CLK_25;
 always@(posedge CLK_to_DAC)
    begin
        if(H_Cont<H_TOTAL)           //如果行计数器小于行总时长
            H_Cont<=H_Cont+1'b1;      //行计数器+1
        else H_Cont<=0;              //否则行计数器清零
        if(H_Cont==H_FRONT-1)        //如果行计数器等于行前沿空白时间-1
            VGA_HS<=1'b0;             //行同步信号置0
        if(H_Cont==H_FRONT+H_SYNC-1) //如果行计数器等于行前沿+行同步-1
            VGA_HS<=1'b1;             //行同步信号置1
        if(H_Cont>=H_BLANK)          //如果行计数器大于等于行空白总时长
            X<=H_Cont-H_BLANK;        //X等于行计数器-行空白总时长   (X为当前行第几个像素点)
        else X<=0;                   //否则X为0
    end
 always@(posedge VGA_HS)
    begin
        if(V_Cont<V_TOTAL)           //如果场计数器小于行总时长
            V_Cont<=V_Cont+1'b1;      //场计数器+1
        else V_Cont<=0;              //否则场计数器清零
        if(V_Cont==V_FRONT-1)       //如果场计数器等于场前沿空白时间-1
            VGA_VS<=1'b0;             //场同步信号置0
        if(V_Cont==V_FRONT+V_SYNC-1) //如果场计数器等于行前沿+场同步-1
            VGA_VS<=1'b1;             //场同步信号置1
        if(V_Cont>=V_BLANK)          //如果场计数器大于等于场空白总时长
            Y<=V_Cont-V_BLANK;        //Y等于场计数器-场空白总时长    (Y为当前场第几行)  
        else Y<=0;                   //否则Y为0
    end
    reg valid_yr;
 always@(posedge CLK_to_DAC)
    if(V_Cont == 10'd32)         //场计数器=32时
        valid_yr<=1'b1;           //行输入激活
    else if(V_Cont==10'd512)     //场计数器=512时
        valid_yr<=1'b0;           //行输入冻结
    wire valid_y=valid_yr;       //连线   
    reg valid_r;            
 always@(posedge CLK_to_DAC)   
    if((H_Cont == 10'd32)&&valid_y)     //行计数器=32时
        valid_r<=1'b1;                   //像素输入激活
    else if((H_Cont==10'd512)&&valid_y) //行计数器=512时 
        valid_r<=1'b0;                   //像素输入冻结
    wire valid = valid_r;               //连线
    wire[10:0] x_dis;     //像素显示控制信号
    wire[10:0] y_dis;     //行显示控制信号
    assign x_dis=X;       //连线X
    assign y_dis=Y;       //连线Y
        parameter

    char_line00=240'h00200000000000000000000000000000000000000000000000000000000000000000,
    char_line01=240'h002000003FF800000000000000000000000000000000000000000000000000000000,
    char_line02=240'h7820FFFE210800000000000000000000000000000000000000000000000000000000,
    char_line03=240'h482004002108000007F00FE000800FE00FE007E01FFC07E00FE007E000800FE007E0,
    char_line04=240'h482004003FF800000818301807803018301818183008181830181818078030181818,
    char_line05=240'h4820040021080000100038180180300C300C381C2010381C300C381C01803818381C,
    char_line06=240'h4BFE07F021080000300000180180700C700C300C0020300C700C300C01800018300C,
    char_line07=240'h482004103FF87FFE37F000600180301C301C300C0040300C301C300C01800060300C,
    char_line08=240'h4820041001000000380C01F00180382C382C300C0080300C382C300C018001F0300C,
    char_line09=240'h4820081001000000300C001801800FCC0FCC300C0180300C0FCC300C01800018300C,
    char_line0a=240'h782008103FF80000300C000C0180001C001C300C0300300C001C300C0180000C300C,
    char_line0b=240'h4820101001000000300C380C018000180018381803003818001838180180380C3818,
    char_line0c=240'h0020101001000000181830180180383038301C1003801C1038301C10018030181C10,
    char_line0d=240'h002020100100000007E00FE00FF80FC00FC007E0030007E00FC007E00FF80FE007E0,
    char_line0e=240'h002040A0FFFE00000000000000000000000000000000000000000000000000000000,
    char_line0f=240'h00208040000000000000000000000000000000000000000000000000000000000000;

    reg[7:0] char_bit;
    always@(posedge CLK_to_DAC)
        if(X==10'd180)char_bit<=9'd240;   //当显示到144像素时准备开始输出图像数据
        else if(X>10'd180&&X<10'd420)     //左边距屏幕144像素到416像素时    416=144+272(图像宽度)
            char_bit<=char_bit-1'b1;       //倒着输出图像信息
            
    reg[29:0] vga_rgb;                //定义颜色缓存
    always@(posedge CLK_to_DAC) 
        if(X>10'd180&&X<10'd420)    //X控制图像的横向显示边界:左边距屏幕左边144像素  右边界距屏幕左边界416像素
            begin case(Y)            //Y控制图像的纵向显示边界:从距离屏幕顶部160像素开始显示第一行数据
                10'd200:
                if(char_line00[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;  //如果该行有数据 则颜色为红色
                else vga_rgb<=30'b0000000000_0000000000_0000000000;                      //否则为黑色
                10'd201:
                if(char_line01[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd202:
                if(char_line02[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd203:
                if(char_line03[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd204:
                if(char_line04[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000; 
                10'd205:
                if(char_line05[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd206:
                if(char_line06[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000; 
                10'd207:
                if(char_line07[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd208:
                if(char_line08[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000; 
                10'd209:
                if(char_line09[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd210:
                if(char_line0a[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd211:
                if(char_line0b[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd212:
                if(char_line0c[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd213:
                if(char_line0d[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd214:
                if(char_line0e[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd215:
                if(char_line0f[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                default:vga_rgb<=30'h0000000000;   //默认颜色黑色
            endcase 
        end
    else vga_rgb<=30'h000000000;             //否则黑色
    assign VGA_R=vga_rgb[23:16];
    assign VGA_G=vga_rgb[15:8];
    assign VGA_B=vga_rgb[7:0];
endmodule




3.实验结果

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值