实验器材
硬件:
- pc显示屏
- VGA线
- 开发板 (EP4CE6F17C8)
软件:- quartus
- BMP2MIf(位图转换)
- PCtoLCD2002(汉字取模)
4、5 可通过链接获取
VGA(Video Graphics Array)是IBM在1987年随PS/2机⼀起推出的⼀种视频,具有分辨率⾼、显⽰速率快、颜⾊丰富等优点,在彩 ⾊显⽰器领域得到了⼴泛的应⽤。不⽀持热插拔,不⽀持⾳频传输。对于⼀些嵌⼊式VGA显⽰系统,可以在不使⽤VGA显⽰卡和计算机的 情况下,实现VGA图像的显⽰和控制。VGA显⽰器具有成本低、结构简单、应⽤灵活的优点。对于⼀名FPGA⼯程师,尤其是视频图像的 ⽅向的学习者,VGA协议是必须要掌握的。
外部接口
VGA并没有特殊的外部芯⽚,我们需要关注的其实只有5个信号:HS⾏同步信号,VS场同步信号,R红基⾊,G 绿基⾊,B蓝基⾊。
色彩原理
设计RGB信号时,既可以R信号、G信号和B信号独⽴的赋值,最后连到端⼝上,也可以直接⽤RGB当做⼀个整体信号,RGB信号在使 ⽤时的位宽有三种常见格式,以你的VGA解码芯⽚的配置有关。
1.RGB_8,R:G:B = 3: 3:2,即RGB332
2.RGB_16,R:G:B = 5:6:5,即RGB565
3.RGB_24,R:G:B = 8:8:8,即RGB888
扫描方式
VGA显⽰器扫描⽅式分为逐⾏扫描和隔⾏扫描:逐⾏扫描是扫描从屏幕左上⾓⼀点开始,从左像右逐点扫描,每扫描完⼀⾏,电⼦束回 到屏幕的左边下⼀⾏的起始位置,在这期间,CRT对电⼦束进⾏消隐,每⾏结束时,⽤⾏同步信号进⾏同步;当扫描完所有的⾏,形成⼀ 帧,⽤场同步信号进⾏场同步,并使扫描回到屏幕左上⽅,同时进⾏场消隐,开始下⼀帧。隔⾏扫描是指电⼦束扫描时每隔⼀⾏扫⼀线,完成 ⼀屏后在返回来扫描剩下的线,隔⾏扫描的显⽰器闪烁的厉害,会让使⽤者的眼睛疲劳。因此我们⼀般都采⽤逐⾏扫描的⽅式。
任务要求
1)屏幕上显示彩色条纹;
2)显示自定义的汉字字符(姓名-学号);
3)输出一幅彩色图像
查找对应分辨率相关数据
像素时钟频率以640x480p/60hz为例
total pixel=active video+front porch+sync pulse +back porch =800;
total line=active video+front porch+sync pulse +back porc=525,
filed rate=60Hz,
那么:PCLK =80052560 = 25.175MHz;
同步信号 | 引脚 | B | 引脚 | G | 引脚 | R | 引脚 |
---|---|---|---|---|---|---|---|
VGA_HSYNC | C16 | B[0] | C15 | G[0] | B13 | R[0] | B10 |
VGA_VSYNC | D15 | B[1] | B16 | G[1] | A13 | R[1] | A10 |
B[2] | A15 | G[2] | B12 | R[2] | B9 | ||
B[3] | B14 | G[3] | A12 | R[3] | A9 | ||
B[4] | A14 | G[4] | B11 | R[4] | C8 | ||
G[5] | A11 |
`define vga_640_480 //根据需要自行选择
`ifdef vga_640_480
`define H_Right_Border 8
`define H_Front_Proch 8
`define H_Sync_Time 96
`define H_Back_Proch 40
`define H_Left_Border 8
`define H_Data_Time 640
`define H_Total_Time 800
`define V_Bottom_Border 8
`define V_Front_Proch 2
`define V_Sync_Time 2
`define V_Back_Proch 25
`define V_Top_Border 8
`define V_Data_Time 480
`define V_Total_Time 525
`elsif vga_1024_768_75 //75MHz
`define H_Right_Border 0
`define H_Front_Proch 16
`define H_Sync_Time 96
`define H_Back_Proch 176
`define H_Left_Border 0
`define H_Data_Time 1024
`define H_Total_Time 1312
`define V_Bottom_Border 0
`define V_Front_Proch 1
`define V_Sync_Time 3
`define V_Back_Proch 28
`define V_Top_Border 0
`define V_Data_Time 768
`define V_Total_Time 800
`elsif vga_1024_768_60 //60MHz
`define H_Right_Border 0
`define H_Front_Proch 24
`define H_Sync_Time 136
`define H_Back_Proch 160
`define H_Left_Border 0
`define H_Data_Time 1024
`define H_Total_Time 1244
`define V_Bottom_Border 0
`define V_Front_Proch 3
`define V_Sync_Time 6
`define V_Back_Proch 29
`define V_Top_Border 0
`define V_Data_Time 768
`define V_Total_Time 806
/**根据需要自行添加修改**/
`endif
module vga_top (
input clk ,
input rst_n ,
output wire VGA_HSYNC ,
output wire VGA_VSYNC ,
output wire [4:0] VGA_R ,
output wire [5:0] VGA_G ,
output wire [4:0] VGA_B ,
output wire VGA_CLK
);
wire [15:0] data_dis;
wire [10:0] v_addr;
wire [10:0] h_addr;
data_gen data_gen(
.vga_clk (VGA_CLK ),
.rst_n (rst_n ),
.h_addr (h_addr ),
.v_addr (v_addr ),
.data_dis(data_dis)
);
vga_ctrl vga_ctrl(
.clk (clk ),
.rst_n (rst_n ),
.data_dis(data_dis),
.h_addr (h_addr ),
.v_addr (v_addr ),
.vsync (VGA_VSYNC ),
.hsync (VGA_HSYNC ),
.vga_r (VGA_R ),
.vga_g (VGA_G ),
.vga_b (VGA_B ),
.vga_clk (VGA_CLK )
);
endmodule
`include "vga_param.v"
module vga_ctrl(
input clk,
input rst_n,
input [15:0] data_dis,
output reg [10:0] h_addr,//数据有效显示区域行地址
output reg [10:0] v_addr,
output reg hsync,
output reg vsync,
output reg [7:0] vga_r,
output reg [7:0] vga_g,
output reg [7:0] vga_b,
output vga_clk
);
reg [11:0] cnt_h_adder;//行地址计数器
wire add_h_adder;
wire end_h_adder;
reg [11:0] cnt_v_adder;//场地址计数器
wire add_v_adder;
wire end_v_adder;
reg clk_25;
parameter H_SYNC_STA=`H_Sync_Time,
H_SYNC_STO=`H_Total_Time,
H_DATA_STA=`H_Sync_Time+`H_Back_Proch+`H_Left_Border,
H_DATA_STO=`H_Sync_Time+`H_Back_Proch+`H_Left_Border+`H_Data_Time,
V_SYNC_STA =`V_Sync_Time,
V_SYNC_STO =`V_Total_Time,
V_DATA_STA =`V_Sync_Time+`V_Back_Proch+`V_Top_Border,
V_DATA_STO =`V_Sync_Time+`V_Back_Proch+`V_Top_Border+`V_Data_Time;
always@(posedge vga_clk,negedge rst_n)begin
if(!rst_n)
cnt_h_adder<=12'b0;
else if(add_h_adder)
if(end_h_adder)
cnt_h_adder<=12'b0;
else
cnt_h_adder<=cnt_h_adder+12'b1;
else
cnt_h_adder<=cnt_h_adder;
end
assign add_h_adder=1'b1;
assign end_h_adder=add_h_adder&&cnt_h_adder>=`H_Total_Time-1;
always@(posedge vga_clk,negedge rst_n)begin
if(!rst_n)
cnt_v_adder<=12'b0;
else if(add_v_adder)
if(end_v_adder)
cnt_v_adder<=12'b0;
else
cnt_v_adder<=cnt_v_adder+12'b1;
else
cnt_v_adder<=cnt_v_adder;
end
assign add_v_adder=end_h_adder;
assign end_v_adder=add_v_adder&&cnt_v_adder>=`V_Total_Time-1;
//行场同步信号
always@(posedge vga_clk, negedge rst_n)begin
if(!rst_n)
hsync<=1'b1;
else if(cnt_h_adder==H_SYNC_STA-1)
hsync<=1'b0;
else if(cnt_h_adder==H_SYNC_STO-1)
hsync<=1'b1;
else
hsync<=hsync;
end
always@(posedge vga_clk, negedge rst_n)begin
if(!rst_n)
vsync<=1'b1;
else if(cnt_v_adder==V_SYNC_STA-1)
vsync<=1'b0;
else if(cnt_h_adder==V_SYNC_STO-1)
vsync<=1'b1;
else
vsync<=vsync;
end
//数据有效显示区域定义
always@(posedge vga_clk, negedge rst_n)begin
if(!rst_n)
h_addr<=11'd0;
else if(cnt_h_adder>=H_DATA_STO)
h_addr<=11'd0;
else if(cnt_h_adder>=H_DATA_STA)
h_addr<=cnt_h_adder-H_DATA_STA;
else
h_addr<=11'd0;
end
always@(posedge vga_clk, negedge rst_n)begin
if(!rst_n)
v_addr<=11'd0;
else if(cnt_v_adder>=V_DATA_STO)
v_addr<=11'd0;
else if(cnt_v_adder>=V_DATA_STA)
v_addr<=cnt_v_adder-V_DATA_STA;
else
v_addr<=11'd0;
end
always@(posedge vga_clk,negedge rst_n)begin
if(!rst_n)begin
vga_r<=5'b0;
vga_g<=6'b0;
vga_b<=5'b0;
end
else if((cnt_h_adder>=H_DATA_STA-1)&&(cnt_h_adder<=H_DATA_STO-1)&&(cnt_v_adder>=V_DATA_STA-1)&&(cnt_v_adder<=V_DATA_STO-1))begin
vga_r<=data_dis[15:11];
vga_g<=data_dis[10:5];
vga_b<=data_dis[4:0];
end
else begin
vga_r<=5'b0;
vga_g<=6'b0;
vga_b<=5'b0;
end
end
wire c1_sig;
PLL PLL_inst (
.areset ( ~rst_n ),
.inclk0 ( clk ),
.c0 ( vga_clk ),
.c1 ( c1_sig )
);
endmodule
module data_gen(
input vga_clk,
input rst_n,
input [10:0] h_addr,
input [10:0] v_addr,
output reg [15:0] data_dis
);
reg [14:0] address;
wire [15:0] q;
parameter BLACK =15'h0000,
RED =15'hf800,
GREEN =15'h320,
BLUE =15'hf7ff,
YELLOW =15'hffe0,
SKY_BLUE =15'h867d,
PURPLE =15'h939b,
GRAY =15'h8410,
WHITE =15'hffff;
/*
显示彩带块
*/
/*
显示汉字字符块
*/
/*
显示一张图片块
*/
endmodule
data_gen.v 模块
//显示彩带
always@(posedge vga_clk,negedge rst_n)begin
if(!rst_n)
data_dis<=BLACK;
else
case(h_addr)
1 :data_dis<=WHITE ;
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<=BLACK ;
default:data_dis<=data_dis;
endcase
end
效果展示
//显示汉字字符块
parameter
char_line00=320'h001E000000000078000001E000000000000000000000000000000000000000000000000000000000,
char_line01=320'h007E00000F1FF87800001FF800000000000000000000000000000000000000000000000000000000,
char_line02=320'h007800000F1FF87800001FF800000000000000000000000000000000000000000000000000000000,
char_line03=320'h01F81F000FFFF87800FFFFF800000000000000000000000000000000000000000000000000000000,
char_line04=320'h01E01F0003E0787800FFF80000000000000000000000000000000000000000000000000000000000,
char_line05=320'h07E01FC003E0787800FFF8000000001F807FF003E01FE003F01FFF80FC007E007F03FFF80780FFFC,
char_line06=320'h078003C003E0787800F000000000001F807FF003E01FE003F01FFF80FC007E007F03FFF80780FFFC,
char_line07=320'h1FFFFFF0F3E0787800F000000000007FE1FFFC3FE07FF80FFC1FFF83FF03FF81FFC3FFF87F80FFFC,
char_line08=320'h1FFFFFF0F000787800F0000000000079E1E03C3FE078780F3C1E0783CF03E781E3C3C0007F80F03C,
char_line09=320'h1FFFFFF0FC1FF87800FFFFFE000003F9E1E03C3FE0787F3F3F1E1F9FCFCFE787E3F3C0007F80F0FC,
char_line0a=320'h000000F03C1FF87800FFFFFE000003E001E03C03E0781F3C0F001E1F03CF000780F3C000078000F0,
char_line0b=320'h000780F03C1FF87800FFFFFE000003E001E03C03E0781F3C0F001E1F03CF000780F3C000078000F0,
char_line0c=320'h000780003C1E007800F01E00000003E000003C03E0781F3C0F001E1F03CF000780F3C000078000F0,
char_line0d=320'h078780003FFE01F800F01E00000003FFE000FC03E0781F3C0F007E1F03CF7F8780F3FF00078003F0,
char_line0e=320'h0787800003FE01E000F01E00000003FFE000F003E0781F3C0F00781F03CF7F8780F3FF00078003C0,
char_line0f=320'h07FFFFF003FE01E000F01E0003FFF3FFF81FF003E0787F3C0F00781F03CFFFE780F3FFE0078003C0,
char_line10=320'h07FFFFF003FE01E000F01E0003FFF3F8781FC003E0787F3C0F00781F03CFE1E780F3C3E0078003C0,
char_line11=320'h1FFFFFF00FFFF9E000F01E0003FFF3F8781FF003E07FFF3C0F01F81F03CFE1E780F3C3F807800FC0,
char_line12=320'h1E0780000F1FF9E000F01E00000003E07800F003E01FFF3C0F01E01F03CF01E780F0007807800F00,
char_line13=320'h1E078000FF1FF9FF3FFFFFFFE00003E07800FC03E01FFF3C0F01E01F03CF01E780F0007807800F00,
char_line14=320'h00078000FF0079FF3FFFFFFFE00003E078003C03E0001F3C0F01E01F03CF01E780F0007807800F00,
char_line15=320'hFFFFFFFFFF007FFF3FFFFFFFE00003E079E03C03E0001F3C0F01E01F03CF01E780F3C07807800F00,
char_line16=320'hFFFFFFFF0F007F9F00000000000003E079E03C03E0001F3C0F01E01F03CF01E780F3C07807800F00,
char_line17=320'hFFFFFFFF0F007F9FC03C0780000003F879E03C03E01E7F3F3F01E01FCFCFE1E7E3F3C3F807800F00,
char_line18=320'h000780000F007F83C03C07800000007879E03C03E01E780F3C01E003CF03E1E1E3C3C3E007800F00,
char_line19=320'h000780000F007FFFC0FC07E00000007FF9FFFC3FFE1FF80FFC01E003FF03FFE1FFC3FFE07FF80F00,
char_line1a=320'h000780000F007FFFC0F001E00000001FE07FF03FFE07E003F001E000FC007F807F00FF007FF80F00,
char_line1b=320'h000780000F1FFFFFC3F001F80000001FE07FF03FFE07E003F001E000FC007F807F00FF007FF80F00,
char_line1c=320'h000780000F1FE003C3C0007800000000000000000000000000000000000000000000000000000000,
char_line1d=320'h000780000F1FE003CFC0007E00000000000000000000000000000000000000000000000000000000,
char_line1e=320'h00078000000780000F00001E00000000000000000000000000000000000000000000000000000000,
char_line1f=320'h00078000000780000F00001E00000000000000000000000000000000000000000000000000000000;
reg[8:0] char_bit;
always@(posedge vga_clk)
if(h_addr==10'd144)char_bit<=9'd320; //当显示到144像素时准备开始输出图像数据
else if(h_addr>10'd144&&h_addr<10'd464) //左边距屏幕144像素到464像素时 464=144+320(图像宽度)
char_bit<=char_bit-1'b1; //倒着输出图像信息
always@(posedge vga_clk)
if(h_addr>10'd144&&h_addr<10'd464) //X控制图像的横向显示边界:左边距屏幕左边144像素 右边界距屏幕左边界464像素
begin case(v_addr) //Y控制图像的纵向显示边界:从距离屏幕顶部160像素开始显示第一行数据
10'd160:
if(char_line00[char_bit])data_dis<=RED; //如果该行有数据 则颜色为红色
else data_dis<=BLUE; //否则为黑色
10'd162:
if(char_line01[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd163:
if(char_line02[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd164:
if(char_line03[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd165:
if(char_line04[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd166:
if(char_line05[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd167:
if(char_line06[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd168:
if(char_line07[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd169:
if(char_line08[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd170:
if(char_line09[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd171:
if(char_line0a[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd172:
if(char_line0b[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd173:
if(char_line0c[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd174:
if(char_line0d[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd175:
if(char_line0e[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd176:
if(char_line0f[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd177:
if(char_line10[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd178:
if(char_line11[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd179:
if(char_line12[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd180:
if(char_line13[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd181:
if(char_line14[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd182:
if(char_line15[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd183:
if(char_line16[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd184:
if(char_line17[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd185:
if(char_line18[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd186:
if(char_line19[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd187:
if(char_line1a[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd188:
if(char_line1b[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd189:
if(char_line1c[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd190:
if(char_line1d[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd191:
if(char_line1e[char_bit])data_dis<=RED;
else data_dis<=BLUE;
10'd192:
if(char_line1f[char_bit])data_dis<=RED;
else data_dis<=BLUE;
default:data_dis<=BLUE; //默认颜色蓝色
endcase
end
else
data_dis<=BLUE;
调用ROM的ip核。
RGB565 16位宽,所以选择16位宽,100*100像素所以是10000数据。
显示图片
always@(posedge vga_clk, negedge rst_n)begin
if(!rst_n)begin
data_dis=BLUE;
end
else if(add_cnt_address)
data_dis=q;
else
data_dis=BLUE;
end
always@(posedge vga_clk,negedge rst_n)begin
if(!rst_n)
address<=1'b0;
else if(add_cnt_address)
if(end_cnt_address)
address<=1'b0;
else
address<=address+1'b1;
else
address<=address;
end
assign add_cnt_address=h_addr<200&&h_addr>=100&&v_addr<200&&v_addr>=100;
assign end_cnt_address=address==9999;
//例化ROM
ROM ROM_inst (
.address ( address),
.clock ( vga_clk),
.q ( q)
);
链接:https://pan.baidu.com/s/1ZZ8UFZILMjxfgNPAkM7Rgg
提取码:0614