一、VGA概述
1.1 简述
- **VGA(Video Graphics Array)**视频图形阵列是IBM于1987年提出的一个使用模拟信号的电脑显示标准。VGA接口即电脑采用VGA标准输出数据的专用接口。VGA接口共有15针,分成3排,每排5个孔,显卡上应用最为广泛的接口类型,绝大多数显卡都带有此种接口。它传输红、绿、蓝模拟信号以及同步信号(水平和垂直信号)。
- 大多数计算机与外部显示设备之间都是通过模拟VGA接口连接,计算机内部以数字方式生成的显示图像信息,被显卡中的数字/模拟转换器转变为R、G、B三原色信号和行、场同步信号,信号通过电缆传输到显示设备中。对于模拟显示设备,如模拟CRT显示器,信号被直接送到相应的处理电路,驱动控制显像管生成图像。而对于LCD、DLP等数字显示设备,显示设备中需配置相应的A/D(模拟/数字)转换器,将模拟信号转变为数字信号。在经过D/A和A/D两次转换后,不可避免地造成了一些图像细节的损失。VGA接口应用于CRT显示器无可厚非,但用于连接液晶之类的显示设备,则转换过程的图像损失会使显示效果略微下降。
而且可以从接口处来判断显卡是独显还是集成显卡,VGA接口竖置的说明是集成显卡,VGA接口横置说明是独立显卡(一般的台式主机都可以用此方法来查看)。
1.2 管脚定义
- 管脚定义
管脚 | 定义 |
---|---|
1 | 红基色 red |
2 | 绿基色 green |
3 | 蓝基色 blue |
4 | 地址码 ID Bit |
5 | 自测试 ( 各家定义不同 ) |
6 | 红地 |
7 | 绿地 |
8 | 蓝地 |
9 | 保留 ( 各家定义不同 ) |
10 | 数字地 |
11 | 地址码 |
12 | 地址码 |
13 | 行同步 |
14 | 场同步 |
15 | 地址码 ( 各家定义不同) |
大家要是想了解更多的内容,比如原理等,可点击下方连接去百度百科查看:
百度百科-VGA
1.3 行、场时序及分辨率
- VGA时序标准
- 行同步时序:(行时序的各种信号,可对照下面的表格里的显示参数)
- 场同步时序
- VGA的不同分辨率显示参数
- 将行同步时序图与场同步时序图结合起来就构成了 VGA 时序图:
红色区域表示在一个完整的行扫描周期中,Video 图像信息只在此区域有效,黄色区域表示在一个完整的场扫描周期中,Video 图像信息只在此区域有效,两者相交的橙色区域,就是 VGA 图像的最终显示区域。
其他可详见此博主的博客(点击跳转)
二、VGA显示文字
笔主整篇文章中使用的板子都是 EP4CE115F29C7,使用其他板子问题不大,但引脚绑定不太一样,可自行对应板子查找更改。
- 引脚
2.1 点阵汉字生成
- VGA显示文字主要要用到点阵汉字,笔主这里用的是朋友推荐的一个网站,好用,感觉比PCtoLCD2002 好用。指路网站:单片机-LCD-LED-OLED中文点阵生成软件
- 生成
- 在下面的字符里,使用中间那一栏,如图
- 将那些字节复制粘贴到你的txt文件里(自己建一个就行)
- 然后进行整理(笔主这里的学号名字是已经整理好的)
- 用替换将原理点阵里的
, 0x
替换为(没错就是空白,不要输入空格,就是什么都不填),然后再把前面两列的0x删掉就可以了,最后一个字节那里打上;
就OK了。
2.2 工程建立
- 笔主这里用的软件是Quartus 18.1
- 自己新建一个工程(网上步骤很多,笔主之前的文章好像也写过),目录结构如下:
名称 | 作用 |
---|---|
doc | 一些说明文档、仿真、上板结果等 |
ip | 知识产权 |
prj | 工程文件 |
rtl | 源文件(.v) |
tb | 仿真文件 |
- rtl 源文件里主要有:
名称 | 作用 |
---|---|
vga_top | 顶层文件:主要是模块例化 |
vga_param | 参数定义:对各种不同的分辨率的显示参数定义 |
data_gen | 数据读取模块 |
vga_ctrl | VGA驱动、控制模块 |
- tb里还有一个仿真测试文件 vga_tb
2.3 引入ip核-实现特定时钟频率+不同分辨率显示
- 为了正确在 640*480 的分辨率下显示,需要一个25MHz的时钟,我们需要引入 PLL ip核
- 搜索PLL,如图:
- 将文件存到 ip 里,笔主这里已经添加过了
- 直接next
- next
- 一路next到如下界面,设置为25MHz
- 为了显示不同分辨率,笔主这里另一个分辨率为 800*600,需要一个40MHz的时钟,我们这里再加一个时钟 c1
- 然后next到最后界面,选中生成例化模块,这里自己编写代码的时候运用比较方便
- 改变分辨率步骤
①更改vga_param 里的 define 后面的名称,比如
define vga_640_480 改为 define vga_800_600 (“ ` ”被省略了,博客里显示不出来)
②vga_top里定义了时钟频率
③改变一下1、2 处就行,比如 vga_25 改为 vga_40
其他分辨率更改都是类似。
2.3 代码实现
- vga_param
- 笔主因为老师要求不同分辨率,所以只定义两种,其他可自行添加(根据前面的那个分辨率显示参数表格)
`define vga_640_480//这里在你使用不同分辨率的时候要改变
//笔主因为老师要求不同分辨率,所以定义两种,其他可自行添加(根据前面的那个分辨率显示参数表格)
`ifdef vga_640_480
//执行操作A
`define H_Right_Border 8
`define H_Front_Porch 8
`define H_Sync_Time 96
`define H_Back_Porch 40
`define H_Left_Border 8
`define H_Data_Time 640
`define H_Total_Time 800
`define V_Bottom_Border 8
`define V_Front_Porch 2
`define V_Sync_Time 2
`define V_Back_Porch 25
`define V_Top_Border 8
`define V_Data_Time 480
`define V_Total_Time 525
`elsif vga_800_600
//执行操作B
`define H_Right_Border 0
`define H_Front_Border 40
`define H_Sync_Time 128
`define H_Back_Porch 88
`define H_Left_Border 0
`define H_Data_Time 800
`define H_Total_Time 1056
`define V_Bottom_Border 0
`define V_Front_Porch 1
`define V_Sync_Time 4
`define V_Back_Porch 23
`define V_Top_Border 0
`define V_Data_Time 600
`define V_Total_Time 628
`endif
- vga_ctrl
`include "vga_param.v"
module vga_ctrl (
input wire clk , //vga clk 640*480 25.2MHz
input wire rst_n , //复位信号
input wire [23:0] data_disp , //
output reg [10:0] h_addr , //数据有效显示区域行地址
output reg [10:0] v_addr , //数据有效显示区域场地址
output reg vsync , //
output reg hsync , //
output reg [07:0] vga_r , //RGB三色
output reg [07:0] vga_g , //
output reg [07:0] vga_b , //
output reg vga_blk , //VGA 消隐信号
output wire vga_clk //
);
//参数定义
parameter H_SYNC_STA = 1 ,//行同步开始信号
H_SYNC_STO = `H_Sync_Time ,//行同步停止
H_Data_STA = `H_Sync_Time + `H_Back_Porch + `H_Left_Border,//行数据开始
H_Data_STO = `H_Sync_Time + `H_Back_Porch + `H_Left_Border + `H_Data_Time ,//行数据开始
V_SYNC_STA = 1 ,
V_SYNC_STO = `V_Sync_Time ,
V_Data_STA = `V_Sync_Time + `V_Back_Porch + `V_Top_Border,
V_Data_STO = `V_Sync_Time + `V_Back_Porch + `V_Top_Border + `V_Data_Time;
reg [11:00] cnt_h_addr ; //行地址计数器
wire add_h_addr ;
wire end_h_addr ;
reg [11:00] cnt_v_addr ; //场地址计数器
wire add_v_addr ;
wire end_v_addr ;
//行地址计数器
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_h_addr <= 12'd0;
end
else if (add_h_addr) begin
if (end_h_addr) begin
cnt_h_addr <= 12'd0;
end
else begin
cnt_h_addr <= cnt_h_addr + 12'd1;
end
end
else begin
cnt_h_addr <= cnt_h_addr;
end
end
assign add_h_addr = 1'b1;
assign end_h_addr = add_h_addr && cnt_h_addr >= `H_Total_Time - 1;
//场地址计数器
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_v_addr <= 12'd0;
end
else if (add_v_addr) begin
if (end_v_addr) 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 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 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
assign vga_clk = ~clk;
//数据有效显示区域定义
//行
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
h_addr <= 11'd0;
end
else if ((cnt_h_addr >= H_Data_STA) && (cnt_h_addr <= H_Data_STO)) begin
h_addr <= cnt_h_addr - H_Data_STA;
end
else begin
h_addr <= 11'd0;
end
end
//场
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
v_addr <= 11'd0;
end
else if ((cnt_v_addr >= V_Data_STA) && (cnt_v_addr <= V_Data_STO)) begin
v_addr <= cnt_v_addr - V_Data_STA;
end
else begin
v_addr <= 11'd0;
end
end
//显示数据
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
vga_r <= 8'd0;
vga_g <= 8'd0;
vga_b <= 8'd0;
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_disp[23:16];//data_dis[23-:8]
vga_g = data_disp[15:08];//data_dis[15-:8]
vga_b = data_disp[07:00];//data_dis[07-:8]
vga_blk <= 1'b1;
end
else begin
vga_r <= 8'd0;
vga_g <= 8'd0;
vga_b <= 8'd0;
vga_blk <= 1'b0;
end
end
endmodule
- data_gen
module data_gen (
input wire clk , //vga clk 640*480 25.2MHz
input wire rst_n , //复位信号
input wire [10:0] h_addr , //数据有效显示区域行地址
input wire [10:0] v_addr , //数据有效显示区域场地址
output reg [23:0] data_disp //数据
);
reg [ 223:0 ] char_line[ 15:0 ];//16*14个字符=224,224*16的字符存储区
//参数定义
parameter
BLACK = 24'h000000,
RED = 24'hFF0000,
GREEN = 24'h00FF00,
BLUE = 24'h0000FF,
YELLOW = 24'hFFFF00,
SKY_BULE= 24'h00FFFF,
PURPLE = 24'hFF00FF,
GRAY = 24'hC0C0C0,
WHITE = 24'hFFFFFF;
parameter
H_VLD = 640,
// H_VLD = 800,
V_VLD = 480,
// V_VLD = 600,
PIC_W = 224,
PIC_H = 16,
X_START = (H_VLD - PIC_W >> 1)-1,//正中间
Y_START = (V_VLD - PIC_H >> 1)- 1;
reg [10:00] pix_x,pix_y;//字符显示坐标
//显示区域
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
pix_x <= 11'd0;
pix_y <= 11'd0;
end
else if ((h_addr >= X_START - 1 && h_addr < X_START + PIC_W)
&& (v_addr >= Y_START && v_addr < Y_START + PIC_H)) begin
pix_x <= h_addr - X_START;
pix_y <= v_addr - Y_START;
end
else begin
pix_x = 11'h7FF;
pix_y = 11'h7FF;
end
end
//显示颜色
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
data_disp <= WHITE;
end
else if (pix_x != 11'h7FF && pix_y != 11'h7FF) begin
if (char_line[pix_y][223 - pix_x] == 1'b1) begin
data_disp <= PURPLE ;
end
else begin
data_disp <= WHITE ;
end
end
else
data_disp <= BLACK;
end
//初始化显示文字
always@( posedge clk or negedge rst_n ) begin
if ( !rst_n ) begin//将前面得到的点阵放在这里~
char_line[ 0 ] = 224'h01001000000000000000000000000000000000000000000000000000;
char_line[ 1 ] = 224'h010008fe000000000000000000000000000000000000000000000000;
char_line[ 2 ] = 224'h02807f10000000000000000000000000000000000000000000000000;
char_line[ 3 ] = 224'h0440222018003c000800380018007e001800180018003c003c003c00;
char_line[ 4 ] = 224'h0820147c240042003800440024004200240024002400420042004200;
char_line[ 5 ] = 224'h10107f44400042000800420042000400420040004200420042004200;
char_line[ 6 ] = 224'h2fe84454400002000800420042000400420040004200420042004200;
char_line[ 7 ] = 224'hc10648545c000400080042004200080042005c004200020002002400;
char_line[ 8 ] = 224'h01005254620018000800460042000800420062004200040004001800;
char_line[ 9 ] = 224'h3ff844544200040008003a0042001000420042004200080008002400;
char_line[ 10 ] = 224'h01004854420002000800020042001000420042004200100010004200;
char_line[ 11 ] = 224'h11105154420042000800020042001000420042004200200020004200;
char_line[ 12 ] = 224'h11084228220042000800240024001000240022002400420042004200;
char_line[ 13 ] = 224'h210444241c003c003e0018001800100018001c0018007e007e003c00;
char_line[ 14 ] = 224'h45048842000000000000000000000000000000000000000000000000;
char_line[ 15 ] = 224'h02003082000000000000000000000000000000000000000000000000;
end
end
endmodule
- vga_top
module vga_top (
input wire clk ,
input wire rst_n ,
output wire vsync , //
output wire hsync , //
output wire [07:00] vga_r , //RGB三色
output wire [07:00] vga_g , //
output wire [07:00] vga_b , //
output wire vga_blk , //
output wire vga_clk //
);
wire [23:00] data_disp;
wire vga_25;
wire vga_40;//60MHz
wire locked;
wire [10:00] h_addr;
wire [10:00] v_addr;
wire reset;
assign reset = rst_n & locked;
// pll u_pll (
// .areset ( !rst_n ),
// .inclk0 ( clk ),
// .c0 ( vga_25 )
// );
pll_25 pll_25_inst (
.areset ( ~rst_n ),
.inclk0 ( clk ),
.c0 ( vga_25 ),
.c1 ( vga_40 ),
.locked (locked)
);
data_gen u_data_gen(
.clk (vga_25 ), //vga clk 640*480 25.2MHz
.rst_n (reset ), //复位信号
.h_addr (h_addr ), //数据有效显示区域行地址
.v_addr (v_addr ), //数据有效显示区域场地址
.data_disp (data_disp) //
);
vga_ctrl u_vga_ctrl(
.clk (vga_25 ), //vga clk 640*480 25.2MHz
.rst_n (reset ), //复位信号
.data_disp (data_disp), //
.h_addr (h_addr ), //数据有效显示区域行地址
.v_addr (v_addr ), //数据有效显示区域场地址
.vsync (vsync ), //
.hsync (hsync ), //
.vga_r (vga_r ), //RGB三色
.vga_g (vga_g ), //
.vga_b (vga_b ), //
.vga_blk (vga_blk ), //
.vga_clk (vga_clk ) //
);
endmodule
- vga_tb
module vga_top (
input wire clk ,
input wire rst_n ,
output wire vsync , //
output wire hsync , //
output wire [07:00] vga_r , //RGB三色
output wire [07:00] vga_g , //
output wire [07:00] vga_b , //
output wire vga_blk , //
output wire vga_clk //
);
wire [23:00] data_disp;
wire vga_25;//25MHz
wire vga_40;//40MHz
wire locked;
wire [10:00] h_addr;
wire [10:00] v_addr;
wire reset;
assign reset = rst_n & locked;
pll_25 pll_25_inst (
.areset ( ~rst_n ),
.inclk0 ( clk ),
.c0 ( vga_25 ),
.c1 ( vga_40 ),
.locked (locked)
);
data_gen u_data_gen(
.clk (vga_25 ), //vga clk 640*480 25.2MHz
.rst_n (reset ), //复位信号
.h_addr (h_addr ), //数据有效显示区域行地址
.v_addr (v_addr ), //数据有效显示区域场地址
.data_disp (data_disp) //
);
vga_ctrl u_vga_ctrl(
.clk (vga_25 ), //vga clk 640*480 25.2MHz
.rst_n (reset ), //复位信号
.data_disp (data_disp), //
.h_addr (h_addr ), //数据有效显示区域行地址
.v_addr (v_addr ), //数据有效显示区域场地址
.vsync (vsync ), //
.hsync (hsync ), //
.vga_r (vga_r ), //RGB三色
.vga_g (vga_g ), //
.vga_b (vga_b ), //
.vga_blk (vga_blk ), //
.vga_clk (vga_clk ) //
);
endmodule
2.4 上板验证
- 640*480分辨率显示下:显示在正中间
- 800*600分辨率显示下:可见因为分辨率的改变而数据读取模块的行场未改变,位置向左上偏移了一些,是正常的。
三、VGA显示彩条
这里彩条很简单,均匀显示,没有考虑每个彩条所显示的区域。
3.1 代码实现
- data_gen
module data_gen (
input wire clk , //vga clk 640*480 25.2MHz
input wire rst_n , //复位信号
input wire [10:0] h_addr , //数据有效显示区域行地址
input wire [10:0] v_addr , //数据有效显示区域场地址
output reg [23:0] data_disp //
);
//参数定义
parameter
BLACK = 24'h000000,
RED = 24'hFF0000,
GREEN = 24'h00FF00,
BLUE = 24'h0000FF,
YELLOW = 24'hFFFF00,
SKY_BULE= 24'h00FFFF,
PURPLE = 24'hFF00FF,
GRAY = 24'hC0C0C0,
WHITE = 24'hFFFFFF;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
data_disp <= WHITE;
end
else begin//彩条
case (h_addr)
0 : data_disp <= BLACK ;
80 : data_disp <= RED ;
160 : data_disp <= GREEN ;
240 : data_disp <= BLUE ;
320 : data_disp <= YELLOW ;
400 : data_disp <= SKY_BULE ;
480 : data_disp <= PURPLE ;
560 : data_disp <= GRAY ;
default: data_disp <= data_disp ;
endcase
end
end
endmodule
- 其他 .v 文件与前文一致。
3.2 上板验证
- 640*480分辨率显示下:显示在正中间
- 800*600分辨率显示下:彩条变得不均匀,但符合预期。
四、VGA显示图片
4.1 24位位图
- 在前面的学习中了解到图像的格式有多种,例如JPEG,BMP,PNG,JPG等,图像的位数也有单色、16色、256色、4096色、16位真彩色、24位真彩色、32位真彩色在这里插入图片描述这几种。
VGA的驱动程序显示的格式为RGB565,我们先找到一张需要显示的彩色图片,经过处理,将该图片转化为ROM可以存储的格式,然后VGA驱动程序从ROM中读取数据,输出到VGA显示屏显示。尽量 选一张小的图片,因为ROM存储空间有限。 - 可以用电脑自带的 画图 软件,将一张图片转为 bmp 格式
- 使用BMP2Mif软件将 bmp 格式图片转换为 Mif 文件。
- 转换后的.mif文件:
4.2 引入ROM ip核
- 新建Quartus工程,产生ROM IP核,将生成的mif文件保存在ROM中
- 搜索ROM,双击选择ROM:1-PORT
- 选择存储的位置,一般为了方便管理就存储在ip中
- 更改设置,word大小设置要大于图片大小(52x52x24 < 65536),然后next
- 取消勾选q,然后next
- 如果是16位位图,就加载HEX文件,然后next
- 这里因为我们转换的是24位位图,所以在ROM里要引入 .mif 文件。(16位位图不用管)
- 勾选上输出 inst,方便例化,然后finish
- 这里同时要调用前面的pll ip核生成一个25mHz的时钟。
4.3 代码实现
- 在data_gen.v文件里,从ROM取出图片数据。
module data_gen (
input wire clk , //vga clk 640*480 25.2MHz
input wire rst_n , //复位信号
input wire [10:0] h_addr , //数据有效显示区域行地址
input wire [10:0] v_addr , //数据有效显示区域场地址
output reg [23:0] data_disp //
);
reg [ 13:0 ] rom_address ; // ROM地址
wire [ 23:0 ] rom_data ; // 图片数据
wire flag_enable_out2 ; // 图片有效区域
wire flag_clear_rom_address ; // 地址清零
wire flag_begin_h ; // 图片显示行
wire flag_begin_v ; // 图片显示列
parameter height = 52; // 图片高度
parameter width = 52; // 图片宽度
reg [ 223:0 ] char_line[ 15:0 ];//16*14个字符=224,224*16的字符存储区
//参数定义
parameter
BLACK = 24'h000000,
RED = 24'hFF0000,
GREEN = 24'h00FF00,
BLUE = 24'h0000FF,
YELLOW = 24'hFFFF00,
SKY_BULE= 24'h00FFFF,
PURPLE = 24'hFF00FF,
GRAY = 24'hC0C0C0,
WHITE = 24'hFFFFFF;
always @( posedge clk or negedge rst_n) begin
if(!rst_n)begin
data_disp = BLACK;
end
else if ( flag_enable_out2 ) begin
data_disp = rom_data;
end
else begin
data_disp = BLACK;
end
end
//ROM地址计数器
always @( posedge 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;
assign flag_begin_h = h_addr > ( ( 640 - width ) / 2 ) && h_addr < ( ( 640 - width ) / 2 ) + width + 1;
assign flag_begin_v = v_addr > ( ( 480 - height )/2 ) && v_addr <( ( 480 - height )/2 ) + height + 1;
assign flag_enable_out2 = flag_begin_h && flag_begin_v;
//实例化ROM
rom rom_inst (
.address ( rom_address ),
.clock ( clk ),
.q ( rom_data )
);
endmodule
- 其他 .v 文件与前文一致。
4.4 上板验证
- 640*480分辨率显示下:显示在正中间
- 800*600分辨率显示下:图片向上偏移,符合预期。
文章来源:https://www.toymoban.com/news/detail-431814.html
tb文件
- vga_tb
`timescale 1ns/1ps
`define clk_period 20 //时钟周期参数定义
module vga_tb ();
//激励信号
reg clk ;
reg rst_n ;
//观测信号
wire vsync ;
wire hsync ;
wire [07:0] vga_r ;
wire [07:0] vga_g ;
wire [07:0] vga_b ;
wire vga_blk ;
wire vga_clk ;
//ASCII 显示颜色字符
reg [63:00] CHAR_CLO ;
parameter
BLACK = 24'h000000,
RED = 24'hFF0000,
GREEN = 24'h00FF00,
BLUE = 24'h0000FF,
YELLOW = 24'hFFFF00,
SKY_BULE= 24'h00FFFF,
PURPLE = 24'hFF00FF,
GRAY = 24'hC0C0C0,
WHITE = 24'hFFFFFF;
always @(*) begin
case(u_vga_top.data_disp)
BLACK : CHAR_CLO = "BLACK ";
RED : CHAR_CLO = "RED ";
GREEN : CHAR_CLO = "GREEN ";
BLUE : CHAR_CLO = "BLUE ";
YELLOW : CHAR_CLO = "YELLOW ";
SKY_BULE : CHAR_CLO = "SKY_BULE";
PURPLE : CHAR_CLO = "PURPLE ";
GRAY : CHAR_CLO = "GRAY ";
WHITE : CHAR_CLO = "WHITE ";
// default : CHAR_CLO = "WHITE ";
default : CHAR_CLO = CHAR_CLO;
// default : WHITE = "WHITE ";
endcase
end
//模块例化
vga_top u_vga_top(
.clk (clk ),
.rst_n (rst_n ),
.vsync (vsync ),
.hsync (hsync ),
.vga_r (vga_r ),
.vga_g (vga_g ),
.vga_b (vga_b ),
.vga_blk (vga_blk),
.vga_clk (vga_clk)
);
//系统初始化
//时钟生成
initial clk = 1'b0;
always #(`clk_period / 2 ) clk = ~clk;
//其他激励
initial begin
// clk = 1'b1;
rst_n = 1'b0;
#(`clk_period * 20 + 3)
rst_n = 1'b1; //产生复位
#(`clk_period * 20);
repeat(2)begin
@(negedge vsync);
end
#(`clk_period * 20000)
$stop;
end
endmodule
可自行验证文章来源地址https://www.toymoban.com/news/detail-431814.html
小小的总结
- VGA显示,难点在于显示驱动模块,行场同步时序的代码编写,可以先写计数器和大模块,一些内部信号与标志信号可以逐步完善;其次就是数据显示中显示区域代码的编写。
- VGA显示,显示彩条部分还可以改进,可以定义不同彩条的显示区域。显示文字主要就是显示位置的确定与汉字点阵的生成,汉字点阵还是费了一些功夫,最开始实在没找到一个比较合适的转换工具和方法,后来在朋友的帮助指点下终于可以了。显示图片一定要注意24位位图的话在ROM里面引入的是 .mif 文件,16位位图的话就引入hex文件。
- 代码或哪一部分有问题欢迎留言指正。
参考文献
- 百度百科-VGA
- VGA显示原理、时序标准及相关参数
- 【FPGA实验】基于DE2-115平台的VGA显示
到了这里,关于【FPGA】VGA显示文字、彩条、图片——基于DE2-115的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!