文章目录
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