一、VGA概述
1.1 簡(jiǎn)述
- **VGA(Video Graphics Array)**視頻圖形陣列是IBM于1987年提出的一個(gè)使用模擬信號(hào)的電腦顯示標(biāo)準(zhǔn)。VGA接口即電腦采用VGA標(biāo)準(zhǔn)輸出數(shù)據(jù)的專用接口。VGA接口共有15針,分成3排,每排5個(gè)孔,顯卡上應(yīng)用最為廣泛的接口類型,絕大多數(shù)顯卡都帶有此種接口。它傳輸紅、綠、藍(lán)模擬信號(hào)以及同步信號(hào)(水平和垂直信號(hào))。
- 大多數(shù)計(jì)算機(jī)與外部顯示設(shè)備之間都是通過(guò)模擬VGA接口連接,計(jì)算機(jī)內(nèi)部以數(shù)字方式生成的顯示圖像信息,被顯卡中的數(shù)字/模擬轉(zhuǎn)換器轉(zhuǎn)變?yōu)镽、G、B三原色信號(hào)和行、場(chǎng)同步信號(hào),信號(hào)通過(guò)電纜傳輸?shù)斤@示設(shè)備中。對(duì)于模擬顯示設(shè)備,如模擬CRT顯示器,信號(hào)被直接送到相應(yīng)的處理電路,驅(qū)動(dòng)控制顯像管生成圖像。而對(duì)于LCD、DLP等數(shù)字顯示設(shè)備,顯示設(shè)備中需配置相應(yīng)的A/D(模擬/數(shù)字)轉(zhuǎn)換器,將模擬信號(hào)轉(zhuǎn)變?yōu)閿?shù)字信號(hào)。在經(jīng)過(guò)D/A和A/D兩次轉(zhuǎn)換后,不可避免地造成了一些圖像細(xì)節(jié)的損失。VGA接口應(yīng)用于CRT顯示器無(wú)可厚非,但用于連接液晶之類的顯示設(shè)備,則轉(zhuǎn)換過(guò)程的圖像損失會(huì)使顯示效果略微下降。
而且可以從接口處來(lái)判斷顯卡是獨(dú)顯還是集成顯卡,VGA接口豎置的說(shuō)明是集成顯卡,VGA接口橫置說(shuō)明是獨(dú)立顯卡(一般的臺(tái)式主機(jī)都可以用此方法來(lái)查看)。
1.2 管腳定義
- 管腳定義
管腳 | 定義 |
---|---|
1 | 紅基色 red |
2 | 綠基色 green |
3 | 藍(lán)基色 blue |
4 | 地址碼 ID Bit |
5 | 自測(cè)試 ( 各家定義不同 ) |
6 | 紅地 |
7 | 綠地 |
8 | 藍(lán)地 |
9 | 保留 ( 各家定義不同 ) |
10 | 數(shù)字地 |
11 | 地址碼 |
12 | 地址碼 |
13 | 行同步 |
14 | 場(chǎng)同步 |
15 | 地址碼 ( 各家定義不同) |
大家要是想了解更多的內(nèi)容,比如原理等,可點(diǎn)擊下方連接去百度百科查看:
百度百科-VGA
1.3 行、場(chǎng)時(shí)序及分辨率
- VGA時(shí)序標(biāo)準(zhǔn)
- 行同步時(shí)序:(行時(shí)序的各種信號(hào),可對(duì)照下面的表格里的顯示參數(shù))
- 場(chǎng)同步時(shí)序
- VGA的不同分辨率顯示參數(shù)
- 將行同步時(shí)序圖與場(chǎng)同步時(shí)序圖結(jié)合起來(lái)就構(gòu)成了 VGA 時(shí)序圖:
紅色區(qū)域表示在一個(gè)完整的行掃描周期中,Video 圖像信息只在此區(qū)域有效,黃色區(qū)域表示在一個(gè)完整的場(chǎng)掃描周期中,Video 圖像信息只在此區(qū)域有效,兩者相交的橙色區(qū)域,就是 VGA 圖像的最終顯示區(qū)域。
其他可詳見此博主的博客(點(diǎn)擊跳轉(zhuǎn))
二、VGA顯示文字
筆主整篇文章中使用的板子都是 EP4CE115F29C7,使用其他板子問(wèn)題不大,但引腳綁定不太一樣,可自行對(duì)應(yīng)板子查找更改。
- 引腳
2.1 點(diǎn)陣漢字生成
- VGA顯示文字主要要用到點(diǎn)陣漢字,筆主這里用的是朋友推薦的一個(gè)網(wǎng)站,好用,感覺比PCtoLCD2002 好用。指路網(wǎng)站:?jiǎn)纹瑱C(jī)-LCD-LED-OLED中文點(diǎn)陣生成軟件
- 生成
- 在下面的字符里,使用中間那一欄,如圖
- 將那些字節(jié)復(fù)制粘貼到你的txt文件里(自己建一個(gè)就行)
- 然后進(jìn)行整理(筆主這里的學(xué)號(hào)名字是已經(jīng)整理好的)
- 用替換將原理點(diǎn)陣?yán)锏?
, 0x
替換為(沒(méi)錯(cuò)就是空白,不要輸入空格,就是什么都不填),然后再把前面兩列的0x刪掉就可以了,最后一個(gè)字節(jié)那里打上;
就OK了。
2.2 工程建立
- 筆主這里用的軟件是Quartus 18.1
- 自己新建一個(gè)工程(網(wǎng)上步驟很多,筆主之前的文章好像也寫過(guò)),目錄結(jié)構(gòu)如下:
名稱 | 作用 |
---|---|
doc | 一些說(shuō)明文檔、仿真、上板結(jié)果等 |
ip | 知識(shí)產(chǎn)權(quán) |
prj | 工程文件 |
rtl | 源文件(.v) |
tb | 仿真文件 |
- rtl 源文件里主要有:
名稱 | 作用 |
---|---|
vga_top | 頂層文件:主要是模塊例化 |
vga_param | 參數(shù)定義:對(duì)各種不同的分辨率的顯示參數(shù)定義 |
data_gen | 數(shù)據(jù)讀取模塊 |
vga_ctrl | VGA驅(qū)動(dòng)、控制模塊 |
- tb里還有一個(gè)仿真測(cè)試文件 vga_tb
2.3 引入ip核-實(shí)現(xiàn)特定時(shí)鐘頻率+不同分辨率顯示
- 為了正確在 640*480 的分辨率下顯示,需要一個(gè)25MHz的時(shí)鐘,我們需要引入 PLL ip核
- 搜索PLL,如圖:
- 將文件存到 ip 里,筆主這里已經(jīng)添加過(guò)了
- 直接next
- next
- 一路next到如下界面,設(shè)置為25MHz
- 為了顯示不同分辨率,筆主這里另一個(gè)分辨率為 800*600,需要一個(gè)40MHz的時(shí)鐘,我們這里再加一個(gè)時(shí)鐘 c1
- 然后next到最后界面,選中生成例化模塊,這里自己編寫代碼的時(shí)候運(yùn)用比較方便
- 改變分辨率步驟
①更改vga_param 里的 define 后面的名稱,比如
define vga_640_480 改為 define vga_800_600 (“ ` ”被省略了,博客里顯示不出來(lái))
②vga_top里定義了時(shí)鐘頻率
③改變一下1、2 處就行,比如 vga_25 改為 vga_40
其他分辨率更改都是類似。
2.3 代碼實(shí)現(xiàn)
- vga_param
- 筆主因?yàn)槔蠋熞蟛煌直媛剩灾欢x兩種,其他可自行添加(根據(jù)前面的那個(gè)分辨率顯示參數(shù)表格)
`define vga_640_480//這里在你使用不同分辨率的時(shí)候要改變
//筆主因?yàn)槔蠋熞蟛煌直媛剩远x兩種,其他可自行添加(根據(jù)前面的那個(gè)分辨率顯示參數(shù)表格)
`ifdef vga_640_480
//執(zhí)行操作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
//執(zhí)行操作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 , //復(fù)位信號(hào)
input wire [23:0] data_disp , //
output reg [10:0] h_addr , //數(shù)據(jù)有效顯示區(qū)域行地址
output reg [10:0] v_addr , //數(shù)據(jù)有效顯示區(qū)域場(chǎng)地址
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 消隱信號(hào)
output wire vga_clk //
);
//參數(shù)定義
parameter H_SYNC_STA = 1 ,//行同步開始信號(hào)
H_SYNC_STO = `H_Sync_Time ,//行同步停止
H_Data_STA = `H_Sync_Time + `H_Back_Porch + `H_Left_Border,//行數(shù)據(jù)開始
H_Data_STO = `H_Sync_Time + `H_Back_Porch + `H_Left_Border + `H_Data_Time ,//行數(shù)據(jù)開始
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 ; //行地址計(jì)數(shù)器
wire add_h_addr ;
wire end_h_addr ;
reg [11:00] cnt_v_addr ; //場(chǎng)地址計(jì)數(shù)器
wire add_v_addr ;
wire end_v_addr ;
//行地址計(jì)數(shù)器
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;
//場(chǎng)地址計(jì)數(shù)器
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;
//行場(chǎng)同步信號(hào)
//行同步信號(hào)
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
//場(chǎng)同步信號(hào)
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;
//數(shù)據(jù)有效顯示區(qū)域定義
//行
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
//場(chǎng)
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
//顯示數(shù)據(jù)
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 , //復(fù)位信號(hào)
input wire [10:0] h_addr , //數(shù)據(jù)有效顯示區(qū)域行地址
input wire [10:0] v_addr , //數(shù)據(jù)有效顯示區(qū)域場(chǎng)地址
output reg [23:0] data_disp //數(shù)據(jù)
);
reg [ 223:0 ] char_line[ 15:0 ];//16*14個(gè)字符=224,224*16的字符存儲(chǔ)區(qū)
//參數(shù)定義
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;//字符顯示坐標(biāo)
//顯示區(qū)域
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//將前面得到的點(diǎn)陣放在這里~
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 ), //復(fù)位信號(hào)
.h_addr (h_addr ), //數(shù)據(jù)有效顯示區(qū)域行地址
.v_addr (v_addr ), //數(shù)據(jù)有效顯示區(qū)域場(chǎng)地址
.data_disp (data_disp) //
);
vga_ctrl u_vga_ctrl(
.clk (vga_25 ), //vga clk 640*480 25.2MHz
.rst_n (reset ), //復(fù)位信號(hào)
.data_disp (data_disp), //
.h_addr (h_addr ), //數(shù)據(jù)有效顯示區(qū)域行地址
.v_addr (v_addr ), //數(shù)據(jù)有效顯示區(qū)域場(chǎng)地址
.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 ), //復(fù)位信號(hào)
.h_addr (h_addr ), //數(shù)據(jù)有效顯示區(qū)域行地址
.v_addr (v_addr ), //數(shù)據(jù)有效顯示區(qū)域場(chǎng)地址
.data_disp (data_disp) //
);
vga_ctrl u_vga_ctrl(
.clk (vga_25 ), //vga clk 640*480 25.2MHz
.rst_n (reset ), //復(fù)位信號(hào)
.data_disp (data_disp), //
.h_addr (h_addr ), //數(shù)據(jù)有效顯示區(qū)域行地址
.v_addr (v_addr ), //數(shù)據(jù)有效顯示區(qū)域場(chǎng)地址
.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 上板驗(yàn)證
- 640*480分辨率顯示下:顯示在正中間
- 800*600分辨率顯示下:可見因?yàn)榉直媛实母淖兌鴶?shù)據(jù)讀取模塊的行場(chǎng)未改變,位置向左上偏移了一些,是正常的。
三、VGA顯示彩條
這里彩條很簡(jiǎn)單,均勻顯示,沒(méi)有考慮每個(gè)彩條所顯示的區(qū)域。
3.1 代碼實(shí)現(xiàn)
- data_gen
module data_gen (
input wire clk , //vga clk 640*480 25.2MHz
input wire rst_n , //復(fù)位信號(hào)
input wire [10:0] h_addr , //數(shù)據(jù)有效顯示區(qū)域行地址
input wire [10:0] v_addr , //數(shù)據(jù)有效顯示區(qū)域場(chǎng)地址
output reg [23:0] data_disp //
);
//參數(shù)定義
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 上板驗(yàn)證
- 640*480分辨率顯示下:顯示在正中間
- 800*600分辨率顯示下:彩條變得不均勻,但符合預(yù)期。
四、VGA顯示圖片
4.1 24位位圖
- 在前面的學(xué)習(xí)中了解到圖像的格式有多種,例如JPEG,BMP,PNG,JPG等,圖像的位數(shù)也有單色、16色、256色、4096色、16位真彩色、24位真彩色、32位真彩色在這里插入圖片描述這幾種。
VGA的驅(qū)動(dòng)程序顯示的格式為RGB565,我們先找到一張需要顯示的彩色圖片,經(jīng)過(guò)處理,將該圖片轉(zhuǎn)化為ROM可以存儲(chǔ)的格式,然后VGA驅(qū)動(dòng)程序從ROM中讀取數(shù)據(jù),輸出到VGA顯示屏顯示。盡量 選一張小的圖片,因?yàn)镽OM存儲(chǔ)空間有限。 - 可以用電腦自帶的 畫圖 軟件,將一張圖片轉(zhuǎn)為 bmp 格式
- 使用BMP2Mif軟件將 bmp 格式圖片轉(zhuǎn)換為 Mif 文件。
- 轉(zhuǎn)換后的.mif文件:
4.2 引入ROM ip核
- 新建Quartus工程,產(chǎn)生ROM IP核,將生成的mif文件保存在ROM中
- 搜索ROM,雙擊選擇ROM:1-PORT
- 選擇存儲(chǔ)的位置,一般為了方便管理就存儲(chǔ)在ip中
- 更改設(shè)置,word大小設(shè)置要大于圖片大小(52x52x24 < 65536),然后next
- 取消勾選q,然后next
- 如果是16位位圖,就加載HEX文件,然后next
- 這里因?yàn)槲覀冝D(zhuǎn)換的是24位位圖,所以在ROM里要引入 .mif 文件。(16位位圖不用管)
- 勾選上輸出 inst,方便例化,然后finish
- 這里同時(shí)要調(diào)用前面的pll ip核生成一個(gè)25mHz的時(shí)鐘。
4.3 代碼實(shí)現(xiàn)
- 在data_gen.v文件里,從ROM取出圖片數(shù)據(jù)。
module data_gen (
input wire clk , //vga clk 640*480 25.2MHz
input wire rst_n , //復(fù)位信號(hào)
input wire [10:0] h_addr , //數(shù)據(jù)有效顯示區(qū)域行地址
input wire [10:0] v_addr , //數(shù)據(jù)有效顯示區(qū)域場(chǎng)地址
output reg [23:0] data_disp //
);
reg [ 13:0 ] rom_address ; // ROM地址
wire [ 23:0 ] rom_data ; // 圖片數(shù)據(jù)
wire flag_enable_out2 ; // 圖片有效區(qū)域
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個(gè)字符=224,224*16的字符存儲(chǔ)區(qū)
//參數(shù)定義
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地址計(jì)數(shù)器
always @( posedge clk or negedge rst_n ) begin
if ( !rst_n ) begin
rom_address <= 0;
end
else if ( flag_clear_rom_address ) begin //計(jì)數(shù)滿清零
rom_address <= 0;
end
else if ( flag_enable_out2 ) begin //在有效區(qū)域內(nèi)+1
rom_address <= rom_address + 1;
end
else begin //無(wú)效區(qū)域保持
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;
//實(shí)例化ROM
rom rom_inst (
.address ( rom_address ),
.clock ( clk ),
.q ( rom_data )
);
endmodule
- 其他 .v 文件與前文一致。
4.4 上板驗(yàn)證
- 640*480分辨率顯示下:顯示在正中間
- 800*600分辨率顯示下:圖片向上偏移,符合預(yù)期。
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-431814.html
tb文件
- vga_tb
`timescale 1ns/1ps
`define clk_period 20 //時(shí)鐘周期參數(shù)定義
module vga_tb ();
//激勵(lì)信號(hào)
reg clk ;
reg rst_n ;
//觀測(cè)信號(hào)
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)
);
//系統(tǒng)初始化
//時(shí)鐘生成
initial clk = 1'b0;
always #(`clk_period / 2 ) clk = ~clk;
//其他激勵(lì)
initial begin
// clk = 1'b1;
rst_n = 1'b0;
#(`clk_period * 20 + 3)
rst_n = 1'b1; //產(chǎn)生復(fù)位
#(`clk_period * 20);
repeat(2)begin
@(negedge vsync);
end
#(`clk_period * 20000)
$stop;
end
endmodule
可自行驗(yàn)證文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-431814.html
小小的總結(jié)
- VGA顯示,難點(diǎn)在于顯示驅(qū)動(dòng)模塊,行場(chǎng)同步時(shí)序的代碼編寫,可以先寫計(jì)數(shù)器和大模塊,一些內(nèi)部信號(hào)與標(biāo)志信號(hào)可以逐步完善;其次就是數(shù)據(jù)顯示中顯示區(qū)域代碼的編寫。
- VGA顯示,顯示彩條部分還可以改進(jìn),可以定義不同彩條的顯示區(qū)域。顯示文字主要就是顯示位置的確定與漢字點(diǎn)陣的生成,漢字點(diǎn)陣還是費(fèi)了一些功夫,最開始實(shí)在沒(méi)找到一個(gè)比較合適的轉(zhuǎn)換工具和方法,后來(lái)在朋友的幫助指點(diǎn)下終于可以了。顯示圖片一定要注意24位位圖的話在ROM里面引入的是 .mif 文件,16位位圖的話就引入hex文件。
- 代碼或哪一部分有問(wèn)題歡迎留言指正。
參考文獻(xiàn)
- 百度百科-VGA
- VGA顯示原理、時(shí)序標(biāo)準(zhǔn)及相關(guān)參數(shù)
- 【FPGA實(shí)驗(yàn)】基于DE2-115平臺(tái)的VGA顯示
到了這里,關(guān)于【FPGA】VGA顯示文字、彩條、圖片——基于DE2-115的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!