一、VGA概述
VGA(Video Graphics Array)是IBM在1987年随PS/2机一起推出的一种视频传输标准,具有分辨率高、显示速率快、颜色丰富等优点,在彩色显示器领域得到了广泛的应用。不支持热插拔,不支持音频传输。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-GxZYQU52-1657069753736)(C:\Users\11690\AppData\Roaming\Typora\typora-user-images\1655125145742.png)]
1.VGA接口
VGA接口共有15针,分成3排,每排5个孔,是显卡上应用最为广泛的接口类型,绝大多数显卡都带有此种接口。它传输红、绿、蓝模拟信号以及同步信号(水平和垂直信号),VGA引脚对应接口定义如下:
1.红基色 red (粉红色线)
2.绿基色 green(淡绿色线)
3.蓝基色blue(淡蓝色线)
4.地址码ID Bit(也有部分是RES,或者为ID2显示器标示位2)
5.自测试( 各家定义不同 )(一般为GND)(黑色线)
6.红地(4,6,7,8,11为屏蔽线,连接在一起)
7.绿地
8.蓝地
9.保留( 各家定义不同 )(黄色线)
10.数字地(红色线)
11.地址码(ID0显示器标示位0)
12.地址码(ID1显示器标示位1)(绿色线)
13.行同步(白色线)
14.场同步(棕色线)
15.地址码 ( ID3或显示器标示位3 )(橙色线)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2l9Ron0n-1657069753738)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20220704132336324.png)]
2.色彩原理
由于人眼中的三种视锥细胞分别用来感知光中红色、绿色、蓝色的强度,而所有其他颜色都是按照这三种视锥细胞不同的刺激强度组合形成的,所以结合人眼的生物特性,通过 CIE XYZ 色彩空间的计算和定义,将波长为 700nm 的红色(Red)、波长为 546.1 nm 的绿色(Green)以及波长为 435.8 nm 的蓝色(Blue)作为色光三原色引入色彩体系中。
所以以色光三原色为基础构建的色彩模型就被称为 RGB 色彩模型,同时它属于光的加色模式,因为其他颜色都是由三原色光叠加而形成,当三原色一起叠加的时候,就形成了白色。
设计RGB信号时,既可以R信号、G信号和B信号独⽴的赋值,最后连到端⼝上,也可以直接⽤RGB当做⼀个整体信号,RGB信号在使
⽤时的位宽有三种常见格式,以你的VGA解码芯⽚的配置有关。
- RGB_8,R:G:B = 3:3:2,即RGB332
- RGB_16,R:G:B = 5:6:5,即RGB565
- RGB_24,R:G:B = 8:8:8,即RGB888
3.扫描方式
GA显⽰器扫描⽅式分为逐⾏扫描和隔⾏扫描:逐⾏扫描是扫描从屏幕左上⾓⼀点开始,从左像右逐点扫描,每扫描完⼀⾏,电⼦束回 到屏幕的左边下⼀⾏的起始位置,在这期间,CRT对电⼦束进⾏消隐,每⾏结束时,⽤⾏同步信号进⾏同步;当扫描完所有的⾏,形成⼀ 帧,⽤场同步信号进⾏场同步,并使扫描回到屏幕左上⽅,同时进⾏场消隐,开始下⼀帧。隔⾏扫描是指电⼦束扫描时每隔⼀⾏扫⼀线,完成
⼀屏后在返回来扫描剩下的线,隔⾏扫描的显⽰器闪烁的厉害,会让使⽤者的眼睛疲劳。因此我们⼀般都采⽤逐⾏扫描的⽅式。
扫描原理如下所示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MqK9RvXC-1657069753738)(C:\Users\11690\AppData\Roaming\Typora\typora-user-images\1655125183946.png)]
4.行场信号
⼀开始看这个时序图可能看不懂,它是把⾏场信号绘制在同⼀张图⾥,说明⾏场信号的控制是相似的,只是时间参数不⼀样⽽已。如果展开的话,其实若⼲个HS信号才组合⽽成⼀个VS,如果在⼀副图⽚中,那正确的时序表⽰⽅式应该如下图这样:
SYNC是“信号同步”,Back proch和Left border常常加在⼀起称为“显⽰后沿”,Addressable video为“显⽰区域”,Right porder和Front porch常常加在⼀起称为“显⽰前沿”,⼀个时序其实就是先拉⾼⼀段较短的“信号同步”时间,然后拉低⼀段很长的时间,这就是⼀个回合。同时需要注意,其实也可以完全相反。即先拉低⼀段时间“信号同步”时间,然后拉⾼⼀段很长的时间。
二、显示彩条和字符
生成点阵字模
代码:
参数:
`define vga_640_480
//`define vga_800_600
`ifdef vga_640_480
`define h_right_border 8
`define h_front_porch 8
`define h_sync_time 96
`define h_back_porch 40
`define h_left_border 8
`define h_data_time 640
`define h_total_time 800
`define v_bottom_border 8
`define v_front_porch 2
`define v_sync_time 2
`define v_back_porch 25
`define v_top_border 8
`define v_data_time 480
`define v_total_time 525
`elsif vga_1280_720
`define h_right_border 0
`define h_front_porch 110
`define h_sync_time 40
`define h_back_porch 220
`define h_left_border 0
`define h_data_time 1280
`define h_total_time 1650
`define v_bottom_border 0
`define v_front_porch 5
`define v_sync_time 5
`define v_back_porch 20
`define v_top_border 0
`define v_data_time 720
`define v_total_time 750
`elsif vga_1920_1080
`define h_right_border 0
`define h_front_porch 88
`define h_sync_time 44
`define h_back_porch 148
`define h_left_border 0
`define h_data_time 1920
`define h_total_time 2200
`define v_bottom_border 0
`define v_front_porch 4
`define v_sync_time 5
`define v_back_porch 36
`define v_top_border 0
`define v_data_time 1080
`define v_total_time 1125
`elsif vga_800_600
`define h_right_border 0
`define h_front_porch 40
`define h_sync_time 128
`define h_back_porch 88
`define h_left_border 0
`define h_data_time 800
`define h_total_time 1056
`define v_bottom_border 0
`define v_front_porch 1
`define v_sync_time 4
`define v_back_porch 23
`define v_top_border 0
`define v_data_time 600
`define v_total_time 628
`endif
VGA驱动:
`include "vga_par.v"
module vga_ctrl(
input wire clk ,//VGA时钟25.2MHz
input wire rst_n ,//复位信号
input wire [23:00] data_dis ,//
output reg [10:00] h_addr ,//数据有效显示区域行地址
output reg [10:00] v_addr ,//数据有效显示区域场地址
output reg hsync ,//
output reg vsync ,//
output reg [07:00] vga_r ,//
output reg [07:00] vga_g ,//
output reg [07:00] 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_left_border + `h_front_porch +`h_sync_time,
h_data_sto = `h_left_border + `h_front_porch +`h_sync_time + `h_data_time,
v_sync_sta = 1,
v_sync_sto = `v_sync_time,
v_data_sta = `v_top_border + `v_back_porch +`v_sync_time,
v_data_sto = `v_top_border + `v_back_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;
//
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'd0;
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'd0;
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_dis[23-:08];
vga_g <= data_dis[15-:08];
vga_b <= data_dis[07-:08];
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
//assign sync = 1'b0;
endmodule
顶层文件:
module vga_top(
input wire clk ,
input wire rst_n ,
output wire hsync ,//
output wire vsync ,
output wire [07:00] vga_r ,//
output wire [07:00] vga_g ,//
output wire [07:00] vga_b ,//
output wire vga_blk ,
output wire vga_clk //
);
wire [10:00] h_addr ;
wire [10:00] v_addr ;
wire [23:00] data_dis ;
pll1 pll1_inst (
.areset ( ~rst_n ),
.inclk0 ( clk ),
.c0 ( vga_clk ),
.c1 ( clk1 )
);
data_gen u_data_gen(
.clk (vga_clk ),//VGA时钟25.2MHz
.rst_n (rst_n ),//复位信号
.h_addr (h_addr ),//数据有效显示区域行地址
.v_addr (v_addr ),//数据有效显示区域场地址
.vga_blk (vga_blk ),
.data_dis (data_dis )//
);
vga_ctrl u_vga_ctrl(
.clk (vga_clk ),//VGA时钟25.2MHz
.rst_n (rst_n ),//复位信号
.data_dis (data_dis ),//
.h_addr (h_addr ),//数据有效显示区域行地址
.v_addr (v_addr ),//数据有效显示区域场地址
.hsync (hsync ),//
.vsync (vsync ),//
.vga_r (vga_r ),//
.vga_g (vga_g ),//
.vga_b (vga_b ), //
.vga_blk (vga_blk )
);
endmodule
1.彩条
module data_gen(
input wire clk ,//VGA时钟25.2MHz
input wire rst_n ,//复位信号
input wire [10:00] h_addr ,//数据有效显示区域行地址
input wire [10:00] v_addr ,//数据有效显示区域场地址
input wire vga_blk ,
output reg [23:00] data_dis //
);
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,
v_vld = 480,
pic_w =272,
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;
reg [ 271:0 ] char_line[ 15:0 ]; //272*16
reg [15:00] rom_address;
//彩条
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
data_dis <= WHITE;
end
else begin
case (h_addr)
0 : data_dis <= BLACK ;
80 : data_dis <= RED ;
160 : data_dis <= GREEN ;
240 : data_dis <= BLUE ;
320 : data_dis <= YELLOW ;
400 : data_dis <= SKY_BULE;
480 : data_dis <= PURPLE ;
560 : data_dis <= GRAY ;
default : data_dis <= data_dis;
endcase
end
end
endmodule
2.点阵输出
//初始化显示文字
always@( posedge clk or negedge rst_n ) begin
if ( !rst_n ) begin
char_line[ 0 ] = 272'h00000000000000000000000000000000000000000000000010004000;
char_line[ 1 ] = 272'h00000000000000000000000000000000000000000000000011f84dfe;
char_line[ 2 ] = 272'h00000000000000000000000000000000000000000000000010107020;
char_line[ 3 ] = 272'h18003c000800380018007e0018001800180008003c00180010204440;
char_line[ 4 ] = 272'h240042003800440024004200240024002400380042002400fc4045fc;
char_line[ 5 ] = 272'h40004200080042004200040042004000420008004200400010803d04;
char_line[ 6 ] = 272'h40000200080042004200040042004000420008004200400031fe0124;
char_line[ 7 ] = 272'h5c000400080042004200080042005c004200080002005c0038920d24;
char_line[ 8 ] = 272'h62001800080046004200080042006200420008000400620054927124;
char_line[ 9 ] = 272'h4200040008003a004200100042004200420008000800420054921124;
char_line[ 10 ] = 272'h4200020008000200420010004200420042000800100042009112ff24;
char_line[ 11 ] = 272'h42004200080002004200100042004200420008002000420011221144;
char_line[ 12 ] = 272'h22004200080024002400100024002200240008004200220012223850;
char_line[ 13 ] = 272'h1c003c003e0018001800100018001c0018003e007e001c0014425488;
char_line[ 14 ] = 272'h00000000000000000000000000000000000000000000000010949104;
char_line[ 15 ] = 272'h00000000000000000000000000000000000000000000000011081202;
end
end
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 && 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_dis <= BLACK;
end
else if (pix_x != 11'h7FF && pix_y != 11'h7FF) begin
if(char_line[pix_y][271 - pix_x]== 1'b1)begin
data_dis <= WHITE;
end
else begin
data_dis <= BLUE;
end
end
else begin
data_dis <= data_dis;
end
end
三、实现效果
1.引脚
使用的是EP4CE115F29C7
开发板
2.结果
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NKJCFoJl-1657069753740)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20220704132921527.png)]
修改分辨率为800*600 时钟改为40MHz:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-n7Lr0p2E-1657069753741)(C:\Users\lenovo\AppData\Roaming\Typora\typora-user-images\image-20220704132947111.png)]
图形整体左移
汉字点阵:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qxkt8eql-1657069753741)(C:\Users\lenovo\Desktop\1.jpg)]
四、总结
通过这次作业了解了VGA协议,实现了屏幕显示彩色条纹和字符,学会了不少。
五、参考链接
d
else begin
data_dis <= data_dis;
end
end
# 三、实现效果
## 1.引脚
---
使用的是`EP4CE115F29C7`开发板
## 2.结果
---
[外链图片转存中...(img-NKJCFoJl-1657069753740)]
修改分辨率为800\*600 时钟改为40MHz:
[外链图片转存中...(img-n7Lr0p2E-1657069753741)]
图形整体左移
汉字点阵:
[外链图片转存中...(img-qxkt8eql-1657069753741)]
# 四、总结
---
<font color=#999AAA >通过这次作业了解了VGA协议,实现了屏幕显示彩色条纹和字符,学会了不少。
# 五、参考链接
---
[协议——VGA](https://wenku.baidu.com/view/cea418180a12a21614791711cc7931b765ce7bb7.html)
[FPGA零基础学习:VGA协议驱动设计](https://zhuanlan.zhihu.com/p/359125055)