【嵌入式系统应用开发实验二】---VGA协议实践

1.vga原理

1.1vga概念简述

在这里插入图片描述
(vga接口实物图)

VGA(Video Graphics Array)是一种显示协议,用于控制计算机屏幕的显示。下面是一些常见的VGA控制时序参数及其计算方式。

①行频率(Horizontal Refresh Rate):指每秒钟显示器上水平扫描线的数目。计算方式为行频率 = 垂直频率 × 垂直分辨率。

②场频率(Vertical Refresh Rate):指每秒钟显示器刷新整个屏幕的次数。计算方式为场频率 = 水平频率 ÷ 屏幕上的行数。

③水平同步时钟周期(Horizontal Sync Pulse Width):指水平同步信号在一行像素周期内持续的时间,一般为5-10微秒左右。水平同步信号是一段低电平脉冲信号,它通知显示器在每行像素周期的结束处开始新的扫描。

④垂直同步时钟周期(Vertical Sync Pulse Width):指垂直同步信号在一场行周期内持续的时间,一般为500-700微秒左右。垂直同步信号是一段低电平脉冲信号,它通知显示器在整个屏幕刷新周期的结束处开始新的刷新。

⑤显示前沿(Front Porch):指在一行像素周期的开始处和水平同步信号之间的时间,一般为1-2微秒左右。这段时间用来准备显示像素数据。

⑥显示后沿(Back Porch):指在一行像素周期的结束处和下一行像素数据之间的时间,一般为20-30微秒左右。这段时间用来进行一些复位和调整操作。

在不同的显示模式下,这些参数可能会有所不同,因此在编写VGA控制程序时,需要根据具体的显示模式来设置这些参数。

1.2vga端口结构

在这里插入图片描述
VGA端口通常包含15个针脚,分别为:
在这里插入图片描述
其中,前三个针脚是用来传输RGB三个颜色分量的信号,第四个和第五个针脚是用来传输水平和垂直同步信号的。第六、七、八、九、十一、十三、十五个针脚是接地针脚,用于电路的接地。第十二个和第十四个针脚是用于传输DDC(Display Data Channel)数据的,DDC是一种用于传输显示器相关信息的协议,例如显示器的分辨率、刷新率等信息。
需要注意的是,VGA端口的结构可能会因不同的电脑品牌和型号而有所不同,但一般都包含上述15个针脚。

1.3vga端口扫描原理

在这里插入图片描述

在这里插入图片描述

VGA(Video Graphics Array)端口的扫描原理如下:
首先,计算机通过VGA端口向显示器发送水平同步和垂直同步信号,通知显示器开始扫描并显示屏幕内容。
显示器按照接收到的水平同步信号进行一行像素周期的扫描,同时接收到的垂直同步信号则通知显示器完成一场行周期的扫描,即完成了一次整个屏幕的扫描。
在一行像素周期内,显示器按照RGB颜色分量的信号显示像素点的颜色,每个像素点的颜色由计算机发送的RGB三个颜色分量信号决定。
在每个像素周期的结束处,显示器接收到水平同步信号,开始下一行像素周期的扫描。这样一直循环下去,直到完成整个屏幕的扫描。
需要注意的是,VGA端口的扫描原理可能会因不同的显示器和电脑品牌和型号而有所不同,但整体上的扫描原理基本相同。此外,VGA端口一般采用模拟信号传输,受到干扰的可能性较大,因此在长距离传输时,可能需要进行信号放大和去噪处理。

2.显示姓名学号

2.1 实验环境

1.VGA显示器
2.Cyclone IV E系列 EP4CE115F29C7开发板
3.字模提取网站:https://www.zhetao.com/fontarray.html

2.2字模生成

先输入需要显示的文字,然后点击生成文字点阵
在这里插入图片描述
在生成的代码当中,static const unsigned char bitmap_bytes[]里的内容就是我们所需要的
在这里插入图片描述

2.3具体代码

据此,vga显示姓名和学号的代码如下

module vga_text(
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_B;         //VGA绿色控制线
 wire [7:0] VGA_G;         //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'd56)         //场计数器=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'd56)&&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   192 = (640-256 ) /2
    assign y_dis=Y;       //连线Y   231 = (480- 18) /2
        parameter  //点阵字模:每一行char_lineXX是显示的一行,共272列,256
    char_line00=256'h1000010000000000000000000000000000000000000000000000000000000000,  //第1行
    char_line01=256'h1108008000000000000000000000000000000000000000000000000000000000,  //第2行
    char_line02=256'h11f8008000000000000000000000000000000000000000000000000000000000,  //第3行
    char_line03=256'h10103ffe00000000000000000000000000000000000000000000000000000000,  //第4行
    char_line04=256'h102020000000000018003c003c00180018007e001800180018007e003c003800,  //第5行
    char_line05=256'hfc4023f800000000240042004200240024004200240024002400400042004400,  //第6行
    char_line06=256'h1080201000000000400042004200420042000400420040004200400042004200,  //第7行
    char_line07=256'h31fe20a000000000400002004200420042000400420040004200400042004200,  //第8行
    char_line08=256'h38922040000000005c000400020042004200080042005c004200780002004200,  //第9行
    char_line09=256'h54922ffe00000000620018000400420042000800420062004200440004004600,  //第10行
    char_line0a=256'h5492204200000000420004000800420042001000420042004200020008003a00,  //第11行
    char_line0b=256'h9112204400000000420002001000420042001000420042004200020010000200,  //第12行
    char_line0c=256'h1122204000000000420042002000420042001000420042004200420020000200,  //第13行
    char_line0d=256'h1222404000000000220042004200240024001000240022002400440042002400,  //第14行
    char_line0e=256'h14424040000000001c003c007e0018001800100018001c00180038007e001800,  //第15行
    char_line0f=256'h1094814000000000000000000000000000000000000000000000000000000000,  //第16行
    char_line10=256'h2028FFFE01000000000000000000000000000000000000000000000000000000,  //第17行
    char_line11=256'h2010000001000000000000000000000000000000000000000000000000000000;  //第18行
    reg [7:0] char_bit;
    always@(posedge CLK_to_DAC)
        if(X==10'd192)char_bit<=8'd256;   //当显示到192像素时准备开始输出图像数据
        else if(X>10'd192&&X<10'd448)     //左边距屏幕192像素到448像素时    448=192+256(图像宽度)
            char_bit<=char_bit-1'b1;       //倒着输出图像信息 
        reg[29:0] VGA_Rgb;                //定义颜色缓存
    always@(posedge CLK_to_DAC)    
        if(X>10'd192&&X<10'd448)    //X控制图像的横向显示边界:左边距屏幕左边192像素  右边界距屏幕左边界448像素
            begin case(Y)            //Y控制图像的纵向显示边界:从距离屏幕顶部200像素开始显示第一行数据
                10'd200:
                if(char_line00[char_bit])VGA_Rgb<=30'b1111111111_0000000000_0000000000;  //如果该行有数据 则颜色为红色
                else VGA_Rgb<=30'b0000000000_0000000000_0000000000;                      //否则为黑色
                10'd202:
                if(char_line01[char_bit])VGA_Rgb<=30'b1111111111_0000000000_0000000000;
                else VGA_Rgb<=30'b0000000000_0000000000_0000000000;
                10'd203:
                if(char_line02[char_bit])VGA_Rgb<=30'b1111111111_0000000000_0000000000;
                else VGA_Rgb<=30'b0000000000_0000000000_0000000000;
                10'd204:
                if(char_line03[char_bit])VGA_Rgb<=30'b1111111111_0000000000_0000000000;
                else VGA_Rgb<=30'b0000000000_0000000000_0000000000;
                10'd205:
                if(char_line04[char_bit])VGA_Rgb<=30'b1111111111_0000000000_0000000000;
                else VGA_Rgb<=30'b0000000000_0000000000_0000000000; 
                10'd206:
                if(char_line05[char_bit])VGA_Rgb<=30'b1111111111_0000000000_0000000000;
                else VGA_Rgb<=30'b0000000000_0000000000_0000000000;
                10'd207:
                if(char_line06[char_bit])VGA_Rgb<=30'b1111111111_0000000000_0000000000;
                else VGA_Rgb<=30'b0000000000_0000000000_0000000000; 
                10'd208:
                if(char_line07[char_bit])VGA_Rgb<=30'b1111111111_0000000000_0000000000;
                else VGA_Rgb<=30'b0000000000_0000000000_0000000000;
                10'd209:
                if(char_line08[char_bit])VGA_Rgb<=30'b1111111111_0000000000_0000000000;
                else VGA_Rgb<=30'b0000000000_0000000000_0000000000; 
                10'd210:
                if(char_line09[char_bit])VGA_Rgb<=30'b1111111111_0000000000_0000000000;
                else VGA_Rgb<=30'b0000000000_0000000000_0000000000;
                10'd211:
                if(char_line0a[char_bit])VGA_Rgb<=30'b1111111111_0000000000_0000000000;
                else VGA_Rgb<=30'b0000000000_0000000000_0000000000;
                10'd212:
                if(char_line0b[char_bit])VGA_Rgb<=30'b1111111111_0000000000_0000000000;
                else VGA_Rgb<=30'b0000000000_0000000000_0000000000;
                10'd213:
                if(char_line0c[char_bit])VGA_Rgb<=30'b1111111111_0000000000_0000000000;
                else VGA_Rgb<=30'b0000000000_0000000000_0000000000;
                10'd214:
                if(char_line0d[char_bit])VGA_Rgb<=30'b1111111111_0000000000_0000000000;
                else VGA_Rgb<=30'b0000000000_0000000000_0000000000;
                10'd215:
                if(char_line0e[char_bit])VGA_Rgb<=30'b1111111111_0000000000_0000000000;
                else VGA_Rgb<=30'b0000000000_0000000000_0000000000;
                10'd216:
                if(char_line0f[char_bit])VGA_Rgb<=30'b1111111111_0000000000_0000000000;
                else VGA_Rgb<=30'b0000000000_0000000000_0000000000;
                10'd217:
                if(char_line10[char_bit])VGA_Rgb<=30'b1111111111_0000000000_0000000000;
                else VGA_Rgb<=30'b0000000000_0000000000_0000000000;
                10'd218:
                if(char_line11[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



// {010021081110092001003FF8200820083FF8200820083FF82008200820282010},/*"X",0*/

// {04400440044004404444244424481448145014600440044004400440FFFE0000},/*"Y",1*/

// {00007FFC010001001110091009200100FFFE0100010001000100010001000100},/*"P",2*/

// {00000000000000000000000000007FFE00000000000000000000000000000000},/*"-",0*/

// {00000000000007F008181000300037F0380C300C300C300C181807E000000000},/*"6",0*/

// {0000000000000FE0301838180018006001F00018000C380C30180FE000000000},/*"3",1*/

// {00000000000000800780018001800180018001800180018001800FF800000000},/*"1",2*/

// {0000000000000FE03018300C700C301C382C0FCC001C001838300FC000000000},/*"9",3*/

// {00000000000007E01818381C300C300C300C300C300C38181C1007E000000000},/*"0",4*/

// {0000000000001FFC300820100020004000800180030003000380030000000000},/*"7",5*/

// {00000000000007E01818381C300C300C300C300C300C38181C1007E000000000},/*"0",6*/

// {00000000000007F008181000300037F0380C300C300C300C181807E000000000},/*"6",7*/

// {00000000000007E01818381C300C300C300C300C300C38181C1007E000000000},/*"0",8*/

// {0000000000001FF810001000100017F01818000C000C380C30180FE000000000},/*"5",9*/

// {0000000000000FF03018380C101800180060018006000804300C3FF800000000},/*"2",10*/

// {0000000000001FF810001000100017F01818000C000C380C30180FE000000000},/*"5",11*/

然后进行引脚绑定
在这里插入图片描述
具体绑定代码如下

package require ::quartus::project

set_location_assignment PIN_C13 -to VGA_VS
set_location_assignment PIN_C10 -to VGA_SYNC
set_location_assignment PIN_E12 -to VGA_R[0]
set_location_assignment PIN_E11 -to VGA_R[1]
set_location_assignment PIN_D10 -to VGA_R[2]
set_location_assignment PIN_F12 -to VGA_R[3]
set_location_assignment PIN_G10 -to VGA_R[4]
set_location_assignment PIN_J12 -to VGA_R[5]
set_location_assignment PIN_H8 -to VGA_R[6]
set_location_assignment PIN_H10 -to VGA_R[7]
set_location_assignment PIN_G13 -to VGA_HS
set_location_assignment PIN_G8 -to VGA_G[0]
set_location_assignment PIN_G11 -to VGA_G[1]
set_location_assignment PIN_D12 -to VGA_B[7]
set_location_assignment PIN_D11 -to VGA_B[6]
set_location_assignment PIN_C12 -to VGA_B[5]
set_location_assignment PIN_A11 -to VGA_B[4]
set_location_assignment PIN_B11 -to VGA_B[3]
set_location_assignment PIN_C11 -to VGA_B[2]
set_location_assignment PIN_A10 -to VGA_B[1]
set_location_assignment PIN_B10 -to VGA_B[0]
set_location_assignment PIN_F11 -to VGA_BLANK
set_location_assignment PIN_A12 -to VGA_CLK
set_location_assignment PIN_C9 -to VGA_G[7]
set_location_assignment PIN_F10 -to VGA_G[6]
set_location_assignment PIN_B8 -to VGA_G[5]
set_location_assignment PIN_C8 -to VGA_G[4]
set_location_assignment PIN_H12 -to VGA_G[3]
set_location_assignment PIN_F8 -to VGA_G[2]
set_location_assignment PIN_AG14 -to OSC_50

2.4烧录测试

请添加图片描述
成功显示名字和学号

3.显示彩条

3.1实验环境

1.VGA显示器
2.Cyclone IV E系列 EP4CE115F29C7开发板

3.2VGA时序

分辨率480X640,帧数60Hz
颜色RGB,6‘hffffff,24位,data_disp[23:0]
颜色深度888
屏幕分辨率:2048 ✖ 1080
h_sync[10:0]//行信号2048
v_sync[10:0]//场信号(列)1080
vga_r;[7:0]//三通道,红色
vga_g;[7:0]//三通道,绿色
vga_b;[7:0]//三通道,蓝色
vga_clk //显示器显示时钟

3.3代码

顶层文件代码:

//顶层文件
 module vga_top( 
     input                  clk     ,//时钟信号
     input                  rst_n   ,//复位信号
     
     output  wire           hsync   ,//
     output  wire           vsync   ,// 
     output  wire           sync    ,
     output  wire [7:0]     vga_r   ,//三通道,红色
     output  wire [7:0]     vga_g   ,//三通道,绿色
     output  wire [7:0]     vga_b   ,//三通道,蓝色 
     output  wire           vga_blk ,
     output  wire           vga_clk 
     
   );           
     wire         [10:0]    h_addr  ;//数据有效显示区域行地址
     wire         [10:0]    v_addr  ;//数据有效显示区域场地址  
     wire         [23:0]    data_dis;
 //例化
  data_gen u_data_gen(
     .clk       (clk     ) ,//时钟信号
     .rst_n     (rst_n   ) ,//复位信号
     .h_addr    (h_addr  ) ,//数据有效显示区域行地址
     .v_addr    (v_addr  ) ,//数据有效显示区域场地址
     .data_dis  (data_dis) //需要显示的信号 
  );
 //例化
   vga_ctrl u_vga_ctrl(
     .clk       (clk     ) ,//时钟信号
     .rst_n     (rst_n   ) ,//复位信号
     .data_dis  (data_dis) ,//需要显示的信号
     .h_addr    (h_addr  ) ,//数据有效显示区域行地址
     .v_addr    (v_addr  ) ,//数据有效显示区域场地址
     .hsync     (hsync   ) ,//
     .vsync     (vsync   ) ,//
     .sync      (sync    ) ,
     .vga_r     (vga_r   ) ,//三通道,红色
     .vga_g     (vga_g   ) ,//三通道,绿色
     .vga_b     (vga_b   ) ,//三通道,蓝色
     .vga_blk   (vga_blk ) ,
     .vga_clk   (vga_clk )  //显示器显示时钟         
 );

 endmodule

彩条的格式代码:

//数据生成
 module data_gen(
     input                 clk     ,//时钟信号
     input                 rst_n   ,//复位信号
   
     input       [10:0]    h_addr  ,//数据有效显示区域行地址
     input       [10:0]    v_addr  ,//数据有效显示区域场地址

     output  reg [23:0]    data_dis //需要显示的信号 
 );         
 //参数定义
  parameter  BLACK    = 24'h000000,
             RED      = 24'hFF0000,
             GREEN    = 24'h00FF00,
             BLUE     = 24'h0000FF,
             YELLOW   = 24'hFFFF00,
             SKY_BLUE = 24'h00FFFF,
             PURPLE   = 24'hFF00FF,
             GRAY     = 24'hC0C0C0,
             WHITE    = 24'hFFFFFF;

 //赋值
  always@(posedge clk or negedge rst_n)begin
     if(!rst_n)begin
        data_dis <= BLACK;
     end
     else begin
        case(h_addr)
           0      : data_dis <= BLUE    ;
           80     : data_dis <= RED      ;
           160    : data_dis <= GREEN    ;
           240    : data_dis <= BLUE     ;
           320    : data_dis <= YELLOW   ;
           400    : data_dis <= SKY_BLUE ;
           480    : data_dis <= PURPLE   ;
           560    : data_dis <= GRAY     ;
           default: data_dis <= data_dis ;
        endcase
     end
  end
 
 endmodule

VGA显示输出的代码:

//VGA显示,实训讲解
`define vga_640_480
`include "vga_para.v"
 module vga_ctrl(
     input                 clk     ,//时钟信号
     input                 rst_n   ,//复位信号
     input       [23:0]    data_dis,//需要显示的信号
   
     output  reg [10:0]    h_addr  ,//数据有效显示区域行地址
     output  reg [10:0]    v_addr  ,//数据有效显示区域场地址

     output  reg           hsync   ,//行同步信号
     output  reg           vsync   ,//场同步信号
     output                sync    ,

     output  reg [7:0]     vga_r   ,//三通道,红色
     output  reg [7:0]     vga_g   ,//三通道,绿色
     output  reg [7:0]     vga_b   ,//三通道,蓝色
     output  reg           vga_blk ,//复合空白信号控制信号,VGA消隐信号显示数据时为1电产,其他时候为低电平
     output                vga_clk  //显示器显示时钟         
 );
 //参数定义
     parameter H_SYNC_STA =  1 ;
     parameter H_SYNC_STO =  `H_Sync_Time ;
     parameter H_Data_STA =  `H_Sync_Time + `H_Back_Porch + `H_Left_Border;
     parameter H_Data_STO =  `H_Sync_Time + `H_Back_Porch + `H_Left_Border + `H_Data_Time;   
     parameter V_SYNC_STA =  1 ;
     parameter V_SYNC_STO =  `V_Sync_Time ;
     parameter V_Data_STA =  `V_Sync_Time  + `V_Back_Porch + `V_Top_Border;
     parameter V_Data_STO =  `V_Sync_Time  + `V_Back_Porch + `V_Top_Border + `V_Data_Time;

    //   parameter H_SYNC_STA = `H_Right_Border + `H_Front_Porch;
    //   parameter H_SYNC_STO = `H_Right_Border + `H_Front_Porch + `H_Sync_Time ;
    //   parameter H_Data_STA = `H_Right_Border + `H_Front_Porch + `H_Sync_Time ;
    //   parameter H_Data_STO = `H_Right_Border + `H_Front_Porch + `H_Sync_Time + `H_Data_Time ;
    //   
    //   parameter V_SYNC_STA = `V_Bottom_Border + `V_Front_Porch;
    //   parameter V_SYNC_STO = `V_Bottom_Border + `V_Front_Porch + `V_Sync_Time;
    //   parameter V_Data_STA = `V_Bottom_Border + `V_Front_Porch + `V_Sync_Time ;
    //   parameter V_Data_STO = `V_Bottom_Border + `V_Front_Porch + `V_Sync_Time + `V_Data_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;

  reg          clk_25M   ;

 assign sync = 1'b0;
  //assign vga_blk = ~((cnt_h_addr<(`H_Front_Porch+`H_Sync_Time+`H_Back_Porch))||
  //                   (cnt_v_addr<`V_Front_Porch+`V_Sync_Time+`V_Back_Porch));
 //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
  assign vga_clk = clk_25M;

 //cnt_h_addr
  always@(posedge vga_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)begin
           cnt_h_addr <= 12'd0;
        end
        else begin
           cnt_h_addr = cnt_h_addr + 12'd1;
        end
     end
     else begin
       cnt_h_addr <= 12'd0;
     end
  end
  assign add_h_addr = 1'b1;//开启条件
  assign end_h_addr = add_h_addr && cnt_h_addr >= `H_Total_Time - 1;
 
 //cnt_v_addr
  always@(posedge vga_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)begin
         cnt_v_addr <= 12'd0;
      end
      else begin
         cnt_v_addr = cnt_v_addr + 12'd1;
      end
   end
   else begin
      cnt_v_addr = cnt_v_addr;
   end
  end
  assign add_v_addr = end_h_addr;
  assign end_v_addr = add_v_addr && cnt_v_addr >= `V_Total_Time - 1;

 //行同步信号
  always@(posedge vga_clk or negedge rst_n)begin
     if(!rst_n)begin
        hsync <= 1'b1;
     end
     else if(cnt_h_addr == H_SYNC_STA -1)begin
        hsync <= 1'b0;
     end
     else if(cnt_h_addr == H_SYNC_STO - 1) begin
        hsync <= 1'b1;
     end
     else begin
        hsync <= hsync ;
     end
  end
 
 //场同步信号
  always@(posedge vga_clk or negedge rst_n)begin
     if(!rst_n)begin
        vsync <= 1'b1;
     end
     else if(cnt_v_addr == V_SYNC_STA -1)begin
        vsync <= 1'b0;
     end
     else if(cnt_v_addr == V_SYNC_STO - 1) begin
        vsync <= 1'b1;
     end
     else begin
        vsync <= vsync ;
     end
  end
  

 //数据有效显示区域定义
  always@(posedge vga_clk or negedge rst_n)begin
     if(!rst_n)begin
        h_addr <= 11'd0;
     end
     else if ((cnt_h_addr >= H_Data_STA - 1 )&&(cnt_h_addr <= H_Data_STO -1)) begin
        h_addr <= cnt_h_addr - H_Data_STA -1 ;
     end
     else begin
        h_addr <= 11'd0;
     end
  end

 //场地址有效显示区域定义
    always@(posedge vga_clk or negedge rst_n)begin
     if(!rst_n)begin
        v_addr <= 11'd0;
     end
     else if ((cnt_v_addr >= V_Data_STA - 1 )&& (cnt_v_addr <= V_Data_STO -1)) begin
        v_addr <= cnt_v_addr - V_Data_STA -1 ;
     end
     else begin
        v_addr <= 11'd0;
     end
  end

 //显示数据
  always@(posedge vga_clk or negedge rst_n)begin
     if(!rst_n)begin
        vga_r <= 8'd0;
        vga_b <= 8'd0;
        vga_g <= 8'd0;
        vga_blk <= 1'b0;
     end
     else if((cnt_h_addr >= H_Data_STA - 1 )&&(cnt_h_addr <= H_Data_STO -1)
            && (cnt_v_addr >= V_Data_STA - 1 )&& (cnt_v_addr <= V_Data_STO -1))begin
        vga_r <= data_dis[23:16];//data_dis[23-:8]
        vga_g <= data_dis[15:8] ;//data_dis[15-:8]
        vga_b <= data_dis[7:0]  ;//data_dis[7- :8] 
        vga_blk <= 1'b1;
     end
     else begin
        vga_r <= 8'd0;
        vga_b <= 8'd0;
        vga_g <= 8'd0;
        vga_blk <= 1'b0;
     end
  end
  

 endmodule


3.4仿真

仿真的具体过程见本人博客:https://blog.csdn.net/weixin_52166467/article/details/127827547?spm=1001.2014.3001.5501
本次实验的仿真代码:

`timescale 1ps/1ps
  module vga_top_tb(); 
     reg            clk     ;//时钟信号
     reg            rst_n   ;//复位信号
     
     wire           hsync   ;//
     wire           vsync   ;// 
     wire           sync    ;
     wire   [7:0]   vga_r   ;//三通道,红色
     wire   [7:0]   vga_g   ;//三通道,绿色
     wire   [7:0]   vga_b   ;//三通道,蓝色 
     wire           vga_blk ;//复合空白信号控制信号,VGA消隐信号显示数据时为1电产,其他时候为低电平
     wire           vga_clk ;//显示器显示时钟
  
 //参数定义
  parameter CYCLE = 40;

  always #(CYCLE/2) clk = ~ clk;
 //例化
   vga_top vga_top(
     .clk           (clk     ),//时钟信号
     .rst_n         (rst_n   ),//复位信号

     .hsync         (hsync   ),//
     .vsync         (vsync   ),// 
     .sync          (sync    ) ,
     .vga_r         (vga_r   ),//三通道,红色
     .vga_g         (vga_g   ),//三通道,绿色
     .vga_b         (vga_b   ),//三通道,蓝色 
     .vga_blk       (vga_blk ),//复合空白信号控制信号,VGA消隐信号显示数据时为1电产,其他时候为低电平
     .vga_clk       (vga_clk )//显示器显示时钟
    ); 

 //ASCII 显示颜色字母
    reg  [63:0]   CHAR_CLO;//1位ASCII码需要8bit显示
 //参数定义
    parameter    BLACK    = 24'h000000,
                 RED      = 24'hFF0000,
                 GREEN    = 24'h00FF00,
                 BLUE     = 24'h0000FF,
                 YELLOW   = 24'hFFFF00,
                 SKY_BLUE = 24'h00FFFF,
                 PURPLE   = 24'hFF00FF,
                 GRAY     = 24'hC0C0C0,
                 WHITE    = 24'hFFFFFF;

    always@(*)begin
       case(vga_top.data_dis)
            BLACK    :CHAR_CLO = "BLACK"   ;
            RED      :CHAR_CLO = "RED"     ;
            GREEN    :CHAR_CLO = "GREEN"   ;
            BLUE     :CHAR_CLO = "BLUE"    ;
            YELLOW   :CHAR_CLO = "YELLOW"  ;
            SKY_BLUE :CHAR_CLO = "SKY_BLUE";
            PURPLE   :CHAR_CLO = "PURPLE"  ;
            GRAY     :CHAR_CLO = "GRAY"    ;
            WHITE    :CHAR_CLO = "WHITE"   ; 
            default  :CHAR_CLO = "WHITE"   ;
       endcase
    end
 //初始化
  initial begin
      clk = 1'b1;
      rst_n = 1'b0;
      #(CYCLE * 20 +3);
      rst_n = 1'b1;
      #(CYCLE * 20);
      repeat(2)begin
        @(negedge vsync);
      end
      #1000;
      $stop;

  end

  endmodule

3.5引脚绑定

引脚绑定代码如下,可以手动绑定,也可进行导入

在这里插入代码片package require ::quartus::project

set_location_assignment PIN_C13 -to vsync
set_location_assignment PIN_C10 -to sync 
set_location_assignment PIN_E12 -to vga_r[0]
set_location_assignment PIN_E11 -to vga_r[1]
set_location_assignment PIN_D10 -to vga_r[2]
set_location_assignment PIN_F12 -to vga_r[3]
set_location_assignment PIN_G10 -to vga_r[4]
set_location_assignment PIN_J12 -to vga_r[5]
set_location_assignment PIN_H8 -to  vga_r[6]
set_location_assignment PIN_H10 -to vga_r[7]
set_location_assignment PIN_G13 -to hsync
set_location_assignment PIN_G8 -to  vga_g[0]
set_location_assignment PIN_G11 -to vga_g[1]
set_location_assignment PIN_D12 -to vga_b[7]
set_location_assignment PIN_D11 -to vga_b[6]
set_location_assignment PIN_C12 -to vga_b[5]
set_location_assignment PIN_A11 -to vga_b[4]
set_location_assignment PIN_B11 -to vga_b[3]
set_location_assignment PIN_C11 -to vga_b[2]
set_location_assignment PIN_A10 -to vga_b[1]
set_location_assignment PIN_B10 -to vga_b[0]
set_location_assignment PIN_F11 -to vga_blk
set_location_assignment PIN_A12 -to vga_clk
set_location_assignment PIN_C9 -to vga_g[7]
set_location_assignment PIN_F10 -to vga_g[6]
set_location_assignment PIN_B8 -to vga_g[5]
set_location_assignment PIN_C8 -to vga_g[4]
set_location_assignment PIN_H12 -to vga_g[3]
set_location_assignment PIN_F8 -to vga_g[2]
set_location_assignment PIN_AG14 -to clk

3.6烧录测试

成功的显示输出彩条

在这里插入图片描述

4.显示图片

4.1实验环境

1.VGA显示器
2.Cyclone IV E系列的EP4CE6F17C8
3.BMP2Mif.exe

4.2实验设置

使用BMP2Mif.exe将bmp图片转成hex文件
在这里插入图片描述

查看生成的hex文件
在这里插入图片描述
图片数据太多需要使用ROM来存储数据
在这里插入图片描述
设置位宽度为16位,大小为图片大小16×625 = 10000
在这里插入图片描述
取消勾选
在这里插入图片描述
找到生成的hex文件
在这里插入图片描述
勾选以下选项后直接finsh
在这里插入图片描述

4.3代码

驱动代码:

module vga_dirve (input			wire						clk,            //系统时钟
                  input			wire						rst_n,          //复位
                  input			wire		[ 15:0 ]		rgb_data,       //16位RGB对应值
                  output			wire							vga_clk,    //vga时钟 25M
                  output			reg							h_sync,     //行同步信号
                  output			reg							v_sync,     //场同步信号
                  output			reg		[ 11:0 ]				addr_h, //行地址
                  output			reg		[ 11:0 ]				addr_v,  //列地址
                  output			wire		[ 4:0 ]				rgb_r,  //红基色
                  output			wire		[ 5:0 ]				rgb_g,  //绿基色
                  output			wire		[ 4:0 ]				rgb_b  //蓝基色
);

// 640 * 480 60HZ
localparam	 H_FRONT = 16; // 行同步前沿信号周期长
localparam	 H_SYNC  = 96; // 行同步信号周期长
localparam	 H_BLACK = 48; // 行同步后沿信号周期长
localparam	 H_ACT   = 640; // 行显示周期长
localparam	 V_FRONT = 11; // 场同步前沿信号周期长
localparam	 V_SYNC  = 2; // 场同步信号周期长
localparam	 V_BLACK = 31; // 场同步后沿信号周期长
localparam	 V_ACT   = 480; // 场显示周期长

// 800 * 600 72HZ
// localparam	 H_FRONT = 40; // 行同步前沿信号周期长
// localparam	 H_SYNC  = 120; // 行同步信号周期长
// localparam	 H_BLACK = 88; // 行同步后沿信号周期长
// localparam	 H_ACT   = 800; // 行显示周期长
// localparam	 V_FRONT = 37; // 场同步前沿信号周期长
// localparam	 V_SYNC  = 6; // 场同步信号周期长
// localparam	 V_BLACK = 23; // 场同步后沿信号周期长
// localparam	 V_ACT   = 600; // 场显示周期长


localparam	H_TOTAL = H_FRONT + H_SYNC + H_BLACK + H_ACT; // 行周期
localparam	V_TOTAL = V_FRONT + V_SYNC + V_BLACK + V_ACT; // 列周期

reg			[ 11:0 ]			cnt_h			; // 行计数器
reg			[ 11:0 ]			cnt_v			; // 场计数器
reg			[ 15:0 ]			rgb			; // 对应显示颜色值

// 对应计数器开始、结束、计数信号
wire							flag_enable_cnt_h			;
wire							flag_clear_cnt_h			;
wire							flag_enable_cnt_v			;
wire							flag_clear_cnt_v			;
wire							flag_add_cnt_v  			;
wire							valid_area      			;


// 25M时钟 行周期*场周期*刷新率 = 800 * 525* 60
wire							clk_25			;
// 50M时钟 1040 * 666 * 72
wire							clk_50			;
//PLL
pll	pll_inst (
	.areset ( ~rst_n ),
	.inclk0 ( clk ),
	.c0 ( clk_50 ), //50M
	.c1 ( clk_25 ), //25M
	);
//根据不同分配率选择不同频率时钟
assign vga_clk = clk_25;


// 行计数
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        cnt_h <= 0;
    end
    else if ( flag_enable_cnt_h ) begin
        if ( flag_clear_cnt_h ) begin
            cnt_h <= 0;
        end
        else begin
            cnt_h <= cnt_h + 1;
        end
    end
    else begin
        cnt_h <= 0;
    end
end
assign flag_enable_cnt_h = 1;
assign flag_clear_cnt_h  = cnt_h == H_TOTAL - 1;

// 行同步信号
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        h_sync <= 0;
    end
    else if ( cnt_h == H_SYNC - 1 ) begin // 同步周期时为1
        h_sync <= 1;
    end
        else if ( flag_clear_cnt_h ) begin // 其余为0
        h_sync <= 0;
        end
    else begin
        h_sync <= h_sync;
    end
end

// 场计数
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        cnt_v <= 0;
    end
    else if ( flag_enable_cnt_v ) begin
        if ( flag_clear_cnt_v ) begin
            cnt_v <= 0;
        end
        else if ( flag_add_cnt_v ) begin
            cnt_v <= cnt_v + 1;
        end
        else begin
            cnt_v <= cnt_v;
        end
    end
    else begin
        cnt_v <= 0;
    end
end
assign flag_enable_cnt_v = flag_enable_cnt_h;
assign flag_clear_cnt_v  = cnt_v == V_TOTAL - 1;
assign flag_add_cnt_v    = flag_clear_cnt_h;

// 场同步信号
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        v_sync <= 0;
    end
    else if ( cnt_v == V_SYNC - 1 ) begin
        v_sync <= 1;
    end
        else if ( flag_clear_cnt_v ) begin
        v_sync <= 0;
        end
    else begin
        v_sync <= v_sync;
    end
end

// 对应有效区域行地址 1-640
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        addr_h <= 0;
    end
    else if ( valid_area ) begin
        addr_h <= cnt_h - H_SYNC - H_BLACK + 1;
    end
    else begin
        addr_h <= 0;
    end
end
// 对应有效区域列地址 1-480
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        addr_v <= 0;
    end
    else if ( valid_area ) begin
        addr_v <= cnt_v -V_SYNC - V_BLACK + 1;
    end
    else begin
        addr_v <= 0;
    end
end
// 有效显示区域
assign valid_area = cnt_h >= H_SYNC + H_BLACK && cnt_h <= H_SYNC + H_BLACK + H_ACT && cnt_v >= V_SYNC + V_BLACK && cnt_v <= V_SYNC + V_BLACK + V_ACT;


// 显示颜色
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        rgb <= 16'h0;
    end
    else if ( valid_area ) begin
        rgb <= rgb_data;
    end
    else begin
        rgb <= 16'b0;
    end
end
assign rgb_r = rgb[ 15:11 ];
assign rgb_g = rgb[ 10:5 ];
assign rgb_b = rgb[ 4:0 ];

endmodule // vga_dirve


显示数据代码:

module data_drive (input			wire						vga_clk,
                   input			wire						rst_n,
                   input			wire		[ 11:0 ]		addr_h,
                   input			wire		[ 11:0 ]		addr_v,
                   input			wire		[ 2:0 ]		 key,
                   output			reg		[ 15:0 ]				rgb_data);

localparam	red    = 16'd63488;
localparam	orange = 16'd64384;
localparam	yellow = 16'd65472;
localparam	green  = 16'd1024;
localparam	blue   = 16'd31;
localparam	indigo = 16'd18448;
localparam	purple = 16'd32784;
localparam	white  = 16'd65503;
localparam	black  = 16'd0;
reg [ 383:0 ] char_line[ 64:0 ];

localparam	states_1 = 1; // 彩条
localparam	states_2 = 2; // 字符
localparam	states_3 = 3; // 图片

parameter	height = 78; // 图片高度
parameter	width  = 128; // 图片宽度
reg			[ 1:0 ]			states_current			; // 当前状态
reg			[ 1:0 ]			states_next			    ; // 下个状态
reg			[ 13:0 ]		rom_address				; // ROM地址
wire			[ 15:0 ]		rom_data				; // 图片数据

wire							flag_enable_out1			; // 文字有效区域
wire							flag_enable_out2			; // 图片有效区域
wire							flag_clear_rom_address		; // 地址清零
wire							flag_begin_h			    ; // 图片显示行
wire							flag_begin_v			    ; // 图片显示列

//状态转移
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        states_current <= states_1;
    end
    else begin
        states_current <= states_next;
    end
end

//状态判断
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        states_next <= states_1;
    end
    else if ( key[ 0 ] ) begin
        states_next <= states_1;
    end
        else if ( key[ 1 ] ) begin
        states_next <= states_2;
        end
        else if ( key[ 2 ] ) begin
        states_next <= states_3;
        end
    else begin
        states_next <= states_next;
    end
end

//状态输出
always @( * ) begin
    case ( states_current )
        states_1 : begin
            if ( addr_h == 0 ) begin
                rgb_data = black;
            end
            else if ( addr_h >0 && addr_h <81 ) begin
                rgb_data = red;
            end
            else if ( addr_h >80 && addr_h <161 ) begin
                rgb_data = orange;
            end
            else if ( addr_h >160 && addr_h <241 ) begin
                rgb_data = yellow;
            end
            else if ( addr_h >240 && addr_h <321 ) begin
                rgb_data = green;
            end
            else if ( addr_h >320 && addr_h <401 ) begin
                rgb_data = blue;
            end
            else if ( addr_h >400 && addr_h <481 ) begin
                rgb_data = indigo;
            end
            else if ( addr_h >480 && addr_h <561 ) begin
                rgb_data = purple;
            end
            else if ( addr_h >560 && addr_h <641 ) begin
                rgb_data = white;
            end
            else begin
                rgb_data = black;
            end
            
        end
        states_2 : begin
            if ( flag_enable_out1 ) begin
                rgb_data = char_line[ addr_v-208 ][ 532 - addr_h ]? white:black;
            end
            else begin
                rgb_data = black;
            end
        end
        states_3 : begin
            if ( flag_enable_out2 ) begin
                rgb_data = rom_data;
            end
            else begin
                rgb_data = black;
            end
            
        end
        default: begin
            case ( addr_h )
                0 : rgb_data      = black;
                1 : rgb_data      = red;
                81 : rgb_data     = orange;
                161: rgb_data     = yellow;
                241: rgb_data     = green;
                321: rgb_data     = blue;
                401: rgb_data     = indigo;
                481: rgb_data     = purple;
                561: rgb_data     = white;
                default: rgb_data = rgb_data;
            endcase
        end
    endcase
end

assign flag_enable_out1 = states_current == states_2 && addr_h > 148 && addr_h < 533 && addr_v > 208  && addr_v < 273 ;
assign flag_begin_h     = addr_h > ( ( 640 - width ) / 2 ) && addr_h < ( ( 640 - width ) / 2 ) + width + 1;
assign flag_begin_v     = addr_v > ( ( 480 - height )/2 ) && addr_v <( ( 480 - height )/2 ) + height + 1;
assign flag_enable_out2 = states_current == states_3 && flag_begin_h && flag_begin_v;

//ROM地址计数器
always @( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        rom_address <= 0;
    end
    else if ( flag_clear_rom_address ) begin //计数满清零
        rom_address <= 0;
    end
        else if ( flag_enable_out2 ) begin  //在有效区域内+1
        rom_address <= rom_address + 1;
        end
    else begin  //无效区域保持
        rom_address <= rom_address;
    end
end
assign flag_clear_rom_address = rom_address == height * width - 1;

//初始化显示文字
always@( posedge vga_clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        char_line[ 0 ]  = 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
        char_line[ 1 ]  = 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
        char_line[ 2 ]  = 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
        char_line[ 3 ]  = 384'h000000000000000000000008000000000000000000000000000000000000000000000000000000000000200000800000;
        char_line[ 4 ]  = 384'h0000000001E000000000000E000000000000000000000000000000000002000000000000000000000000380000E00000;
        char_line[ 5 ]  = 384'h0000003000F800000000000780000000000000000000000000000000000F0000001000000000080000003E0000F80000;
        char_line[ 6 ]  = 384'h00000070007C000000000003C0000000000000000000000000000000007F8000000C000000001C0000003E0000FC0000;
        char_line[ 7 ]  = 384'h000000F8007E000000000003C000000000000000000000000000000003FFC000000FFFFFFFFFFE0000003C0000F00000;
        char_line[ 8 ]  = 384'h3FFFFFFC003E000000000003C00300000000000000000000000000003FFFE000000FFFFFFFFFFF0000003C0000F00000;
        char_line[ 9 ]  = 384'h3FFFFFFE003E000000000001C0078000000000000000000000000007FFFF8000000F000000003E0000003C0000F00000;
        char_line[ 10 ] = 384'h1F3E7C00003E0180001FFFFFFFFFC0000000000000000000000000FFFF800000000F000000003C0000003C0000F00000;
        char_line[ 11 ] = 384'h003E7C00001E03C0000FFFFFFFFFE000000000000000000000003FFFC0000000000F000000003C0000003C0000F00000;
        char_line[ 12 ] = 384'h003E7C00001C07E000000600010000000000000000000000001FFFC3C0000000000F000000003C0000003C3000F00600;
        char_line[ 13 ] = 384'h003E7C07FFFFFFF00000038003C00000000000000000000000300003C0000000000F000000003C0000003C7800F00F00;
        char_line[ 14 ] = 384'h003E7C07FFFFFFF8000001C003E00000000000000000000000000003C0000000000F000000003C0007FFFFFDFFFFFF80;
        char_line[ 15 ] = 384'h003E7C03EC006000000001E003C00000000000000000000000000003C0000000000F000000003C0003FFFFFEFFFFFFC0;
        char_line[ 16 ] = 384'h003E7C000F007800000000E007800000000000000000000000000003C0000000000F000000003C0001803C0001F80000;
        char_line[ 17 ] = 384'h003E7C601FC07E00000000E007000000000000000000000000000003C0000000000FFFFFFFFFFC0000007C0001FC0000;
        char_line[ 18 ] = 384'h0F3E7CF01F807E00000000E00E000200000000000000000000000003C0000000000FFFFFFFFFFC0000007C0003F40000;
        char_line[ 19 ] = 384'h0FFFFFF81F00FC00000000E00C000700000000000000000000000003C0000000000E000000003C000000FF8003F60000;
        char_line[ 20 ] = 384'h0FFFFFF81F00F8000000000018000F80000002000000000000000003C0000000000E000000003E000000FDF007F30000;
        char_line[ 21 ] = 384'h0FBE7DF03E00F8000FFFFFFFFFFFFFC0000001800000000000000003C0000000000E0000000030000001FCF80FF38000;
        char_line[ 22 ] = 384'h0FBE7DF03E01F00007FFFFFFFFFFFFE0000000C00000000000000003C0000000000E0000000000000003FC7C0EF1C000;
        char_line[ 23 ] = 384'h0FBE7DF03E01F8000300000000000000000000700000000000000003C0000000000E0000000000000003FC7C1EF1E000;
        char_line[ 24 ] = 384'h0FBE7DF07F83FC0000000000000000000000007C0000000000000003C0000000000E0000000000000007BC3C3CF0F000;
        char_line[ 25 ] = 384'h0FBE7DF07BE3FF0000000000000000000000003E0000000000000003C0000180000E000000000000000F3C1838F07C00;
        char_line[ 26 ] = 384'h0FBE7DF07BF7CFC000030000000700000000001F8000000000000003C00003C0000E000000003000001E3C1870F03F00;
        char_line[ 27 ] = 384'h0FBE7DF0F1F787E00003FFFFFFFF80000000000FC000000000000003C00007E0000E000000007800001C3C00E0F03FC0;
        char_line[ 28 ] = 384'h0FBE7DF0F1FF83E00003FFFFFFFFC00000000007F00000003FFFFFFFFFFFFFF0000E07FFFFFFFC0000383C01C0F01FF8;
        char_line[ 29 ] = 384'h0FBC7DF1E0FF03F00003C0000007000000000003F80000001FFFFFFFFFFFFFF8000E03FFFFFFFE0000703C0300F007E0;
        char_line[ 30 ] = 384'h0FBC7DF1E0FE01F00003C0000007000000000001FC0000000C000003C0000000000E01000000000000E03C0600F00300;
        char_line[ 31 ] = 384'h0FBC7DF3C07C01F00003C0000007000000000000FE00000000000003C0000000001E00000000000001803C2800F00100;
        char_line[ 32 ] = 384'h0FBC7DF3807800E00003C0000007000000000000FE00000000000003C0000000001E00000000000007003C3000F00000;
        char_line[ 33 ] = 384'h0FBC7DF7007000C00003FFFFFFFF0000000000007F00000000000003C0000000001E0000000000000C003C7800F00000;
        char_line[ 34 ] = 384'h0FF87DF700FC00000003FFFFFFFF0000000000003F00000000000003C0000000001E00000000000018003C7E00E00000;
        char_line[ 35 ] = 384'h0FF87FFE01FF00000003C00000070000000000003F00000000000003C0000000001E000000000100000030FC00808000;
        char_line[ 36 ] = 384'h0FF83FFC013F00000003C00000070000000000001F00000000000003C0000000001E000000000380000001F00001C000;
        char_line[ 37 ] = 384'h0FF01FF0003E00000003C00000070000000000001F00000000000003C0000000001C0000000007C0000003FFFFFFE000;
        char_line[ 38 ] = 384'h0FE001F0003E00C00003C00000070000000000000E00000000000003C0000000001CFFFFFFFFFFE0000003FFFFFFF000;
        char_line[ 39 ] = 384'h0FE001F0003E01E00003C00000070000000000000400000000000003C0000000001C7FFFFFFFFFF0000007800003F800;
        char_line[ 40 ] = 384'h0FC001F0003E03F00003FFFFFFFF0000000000000000000000000003C0000000001C20006000000000000F000003E000;
        char_line[ 41 ] = 384'h0F8001FFFFFFFFF80003FFFFFFFF0000000000000000000000000003C0000000003C00007000000000001E000007C000;
        char_line[ 42 ] = 384'h0F8001FFFFFFFFFC0003C02000070000000000000000000000000003C0000000003C0000FC00000000003C00000F8000;
        char_line[ 43 ] = 384'h0FFFFFF7C03E00000003801800060000000000000000000000000003C000000000380000FC00000000007E00001F0000;
        char_line[ 44 ] = 384'h0FFFFFF0003E00000000000E00000000000000000000000000000003C000000000380001F80000000000E780003E0000;
        char_line[ 45 ] = 384'h0F8001F0003E00000000100780000000000000000000000000000003C000000000380001E00000000001C3C0003E0000;
        char_line[ 46 ] = 384'h0F8001F0003E000000001C07C0018000000000000000000000000003C000000000780003C0000000000781F0007C0000;
        char_line[ 47 ] = 384'h0F8001F0003E000000081F03E000E000000000000000000000000003C00000000070000780000000000E00F800F80000;
        char_line[ 48 ] = 384'h0F8001F0003E000000181E01E0007800000000000000000000000003C00000000070000700180000001C007803F00000;
        char_line[ 49 ] = 384'h0F8001F0003E000000181C00E0183E00000000000000000000000003C00000000070000E000C00000070007807E00000;
        char_line[ 50 ] = 384'h0F8001F0003E000000181C00E0181F00000000000000000000000003C000000000E0001C0007000000C000380F800000;
        char_line[ 51 ] = 384'h0F8001F0003E000000381C0060180F80000000000000000000000003C000000000E0003800038000010000381F000000;
        char_line[ 52 ] = 384'h0F8001F0003E000000381C00401807C0000000000000000000000003C000000000C000700001E000000000187E000000;
        char_line[ 53 ] = 384'h0FFFFFF0003E000000701C00001807C0000000000000000000000003C000000001C000600001F00000000010F8000000;
        char_line[ 54 ] = 384'h0FFFFFF0003E000000F01C00001803C0000000000000000000000003C0000000018001C00000F80000000003F0000000;
        char_line[ 55 ] = 384'h0F8001F0003E000003F01C00001803C0000000000000000000000003C00000000380038000007C000000000FC0000000;
        char_line[ 56 ] = 384'h0F8001F0003E000003E01E00003C0180000000000000000000000003C000000003000700FFFFFE000000003F00000000;
        char_line[ 57 ] = 384'h0F8001F0003E000007E01FFFFFFE0000000000000000000000000003C000000006001FFFFFF03E00000001FC00000000;
        char_line[ 58 ] = 384'h0F8001F0003E000003800FFFFFFC0000000000000000000000000003C000000006000FFFE0001E0000000FF000000000;
        char_line[ 59 ] = 384'h0F8001E0003E0000000007FFFFF00000000000000000000000000003C00000000C000FF800001E000000FF8000000000;
        char_line[ 60 ] = 384'h0F000000003C00000000000000000000000000000000000000000003800000000800070000000E00000FF80000000000;
        char_line[ 61 ] = 384'h00000000003800000000000000000000000000000000000000000002000000001800040000000C0001FF000000000000;
        char_line[ 62 ] = 384'h000000000000000000000000000000000000000000000000000000000000000010000000000000000F80000000000000;
        char_line[ 63 ] = 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
        char_line[ 64 ] = 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
    end
end

//实例化ROM
rom	rom_inst (
.address ( rom_address ),
.clock ( vga_clk ),
.q ( rom_data )
);
endmodule // data_drive


顶层代码:

module vga_top (input			wire						clk,
                input			wire						rst_n,
                input			wire		[ 2:0 ]		    key,
                output			wire						vga_clk,
                output			wire						h_sync,
                output			wire						v_sync,
                output			wire		[ 4:0 ]			rgb_r,
                output			wire		[ 5:0 ]			rgb_g,
                output			wire		[ 4:0 ]			rgb_b,
                output			reg		    [ 3:0 ]			led);

reg			[ 27:0 ]			cnt			        ;
wire		[ 11:0 ]		    addr_h              ;
wire		[ 11:0 ]		    addr_v              ;
wire		[ 15:0 ]			rgb_data			;
wire		[ 2:0 ]			    key_flag			;
wire		[ 2:0 ]			    key_value			;

//vga模块
vga_dirve u_vga_dirve(
.clk      ( clk ),
.rst_n    ( rst_n ),
.rgb_data ( rgb_data ),
.vga_clk  ( vga_clk ),
.h_sync   ( h_sync ),
.v_sync   ( v_sync ),
.rgb_r    ( rgb_r ),
.rgb_g    ( rgb_g ),
.rgb_b    ( rgb_b ),
.addr_h   ( addr_h ),
.addr_v   ( addr_v )
);

//数据模块
data_drive u_data_drive(
.vga_clk ( vga_clk ),
.rst_n   ( rst_n ),
.addr_h  ( addr_h ),
.addr_v  ( addr_v ),
.key     ( {key_value[ 2 ] && key_flag[ 2 ], key_value[ 1 ] && key_flag[ 1 ], key_value[ 0 ] && key_flag[ 0 ] } ),
.rgb_data  ( rgb_data )
);


//按键消抖
key_debounce u_key_debounce0(
.clk   ( vga_clk ),
.rst_n ( rst_n ),
.key   ( key[ 0 ] ),
.flag  ( key_flag[ 0 ] ),
.key_value  ( key_value[ 0 ] )
);

key_debounce u_key_debounce1(
.clk   ( vga_clk ),
.rst_n ( rst_n ),
.key   ( key[ 1 ] ),
.flag  ( key_flag[ 1 ] ),
.key_value  ( key_value[ 1 ] )
);

key_debounce u_key_debounce2(
.clk   ( vga_clk ),
.rst_n ( rst_n ),
.key   ( key[ 2 ] ),
.flag  ( key_flag[ 2 ] ),
.key_value  ( key_value[ 2 ] )
);

// led
always @( posedge clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        cnt <= 0;
    end
    else if ( cnt == 50_000_000 - 1 ) begin
        cnt <= 0;
    end
    else begin
        cnt <= cnt + 1;
    end
end
always @( posedge clk or negedge rst_n ) begin
    if ( !rst_n ) begin
        led <= 4'b0000;
    end
    else if ( cnt == 50_000_000 -1 )begin
        led <= ~led;
    end
    else begin
        led <= led;
    end
end
endmodule // vga_top


4.4引脚绑定

引脚绑定代码如下,可以手动绑定,也可进行导入

package require ::quartus::project

set_location_assignment PIN_E1 -to clk
set_location_assignment PIN_E15 -to rst_n
set_location_assignment PIN_C16 -to h_sync
set_location_assignment PIN_D15 -to v_sync


set_location_assignment PIN_A14 -to rgb_b[4]
set_location_assignment PIN_B14 -to rgb_b[3]
set_location_assignment PIN_A15 -to rgb_b[2]
set_location_assignment PIN_B16 -to rgb_b[1]
set_location_assignment PIN_C15 -to rgb_b[0]


set_location_assignment PIN_A11 -to rgb_g[5]
set_location_assignment PIN_B11 -to rgb_g[4]
set_location_assignment PIN_A12 -to rgb_g[3]
set_location_assignment PIN_B12 -to rgb_g[2]
set_location_assignment PIN_A13 -to rgb_g[1]
set_location_assignment PIN_B13 -to rgb_g[0]

set_location_assignment PIN_C8 -to rgb_r[4]
set_location_assignment PIN_A9 -to rgb_r[3]
set_location_assignment PIN_B9 -to rgb_r[2]
set_location_assignment PIN_A10 -to rgb_r[1]
set_location_assignment PIN_B10 -to rgb_r[0]

4.5烧录测试

在这里插入图片描述

5.总结

本次实验主要目的是深入了解VGA协议,理解不同显示模式下的VGA控制时序参数。通过Verilog编程实现VGA显示,并对照VGA协议信号做时序分析,同时观察行、场同步信号中加入一定延时后的现象。在实验中,学习了VGA协议的基本原理,包括行频、场频、水平/垂直同步时钟周期、显示后沿/前沿等概念和计算方式。然后,在Verilog中实现了3种VGA显示:彩色条纹、自定义汉字字符和彩色图像。在实现过程中,我们对比VGA协议信号做了时序分析,确保输出信号的正确性。总的来说,通过本次任务,我们深入学习了VGA协议的原理,掌握了Verilog编程实现VGA显示的方法,同时也了解了VGA信号在延时情况下的表现。这些知识和经验对于后续设计和开发基于VGA的应用有很大的帮助。

6.参考

https://blog.csdn.net/weixin_56102526/article/details/124964347?utm_medium=distribute.pc_relevant.none-task-blog-2defaultbaidujs_baidulandingword~default-8-124964347-blog-125239409.235v30pc_relevant_default_base3&spm=1001.2101.3001.4242.5&utm_relevant_index=11

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值