1 功能概述

顯示器的像素按照從左到右,從上到下的順序進行刷新。從上到下刷新完一遍稱為一幀,屏幕刷新頻率就是說屏幕一秒鐘能夠刷新多少幀,當達到一定的幀數,我們的肉眼也就分辨不出來了,這樣我們就看到我們的電腦屏幕,我們在操作的時候是連續的了。運用這些科學原理完成在VGA介面的顯示屏上動畫功能,是相關技術人員必備的技能之一。

動畫的概念不同於一般意義上的動畫片,它集合了繪畫、漫畫、電影、數字媒體、攝影、等眾多藝術門類於一身的綜合藝術。可以理解為使用繪畫的手法,創造生命運動的藝術。較規範的定義是採用逐幀拍攝對象並連續播放而形成運動的影像技術。通過把人物的表情、動作、變化等分解後畫成許多動作瞬間的畫幅,再連續形成一系列畫面,給視覺造成連續變化的圖畫。它自19世紀上半葉誕生至今, 經過了一個多世紀發展,已經有了較為完善的理論體系和產業體系,電腦科技的高速進步更是使傳統動畫產業突飛猛進,目前已被廣泛應用到商業中。

與幻燈和圖片不同的是,計算機動畫基本原理與電影、電視一樣,都是視覺暫留原理。即在前一幅畫還沒有消失前播放下一幅畫,給人造成一種流暢的視覺變化效果。本案例即採用FPGA在VGA介面顯示屏上,運用verilog語言在明德揚至簡開發板二代實現動畫顯示效果。

本項目功能要求如下:

(1)該VGA介面輸出的圖像解析度為下列表格中第一種640*480,即幀長為800*525。

(2)VGA顯示要求:複位後,屏幕中央顯示直徑為10的藍色圓點;按下按鍵0,圓點圖像逐漸變大,直至直徑變為400;再按一下按鍵0,圓點逐漸變小,直到直徑為10。此過程要有明顯的動畫效果。

2 設計思路

VGA顯示中,FPGA需要產生5個信號:R、G、B三基色信號,行同步信號HS和場同步信號VS,介面對應孔如下所示:

像素是產生各種顏色的基本單元。根據物理學中的混色原理,三色發光的亮度比例適當,可呈現白色。適當的調整發光比例可以出現不同的顏色。三基色混色原理示意圖如下圖所示:

上表的RBG一共有8組合,也就是說可以產生8種顏色,但是顯示器顯示的色彩是非常豐富的,遠多於8種顏色。那麼,這是如何做到的呢?

對於顯示器來說,RGB的三個信號其實是模擬信號,其電平的高低,可以表示顏色的深淺,利用這個原理,就可以產生豐富的色彩。為了控制電壓的高低,我們必須用到DA晶元。例如,下圖中FPGA產生RGB三種信號,這時RGB都是多位的數字信號。DA晶元根據數字信號的值,產生不同電壓的模擬信號rgb。

模塊劃分和信號列表如下:

頂層模塊信號列表

信號名 I/O 位寬 說明
clk I 1 系統工作時鐘50MHz。
rst_n I 1 系統複位信號,低電平有效。
key_en I 1 按鍵信號
lcd_hs O 1 行同步信號。
lcd_vs O 1 場/幀同步信號。
lcd_rgb O 16 RBG三基色信號。

PLL分頻模塊信號列表

信號名 I/O 位寬 說明
inclk0 I 1 輸入工作時鐘50MHz。
c0 O 1 輸出時鐘25MHz。

VGA介面計數模塊信號列表

信號名 I/O 位寬 說明
clk I 1 系統工作時鐘25MHz。
rst_n I 1 系統複位信號,低電平有效。
key_en I 1 按鍵信號,按下高電平。
hys O 1 行同步信號。
vys O 1 場/幀同步信號。
lcd_rgb O 16 RBG三基色信號。

3 程序設計

頂層模塊代碼

module vga_exec1(
clk ,
rst_n ,
lcd_hs ,
lcd_vs ,
lcd_rgb ,
key_en
);

parameter PICTURE_W = 16;

input clk ;
input rst_n ;
input key_en ;
output lcd_hs ;
output lcd_vs ;
output [PICTURE_W:0] lcd_rgb ;

wire clk_0 ;

parameter ROW_W = 10;

wire lcd_hs ;
wire lcd_vs ;
wire [PICTURE_W-1:0] lcd_rgb ;

vga_pll module_1(
.inclk0 (clk ),
.c0 (clk_0 )
);

vga_driver module_6(
.clk (clk_0 ),
.rst_n (rst_n ),
.hys (lcd_hs ),
.vys (lcd_vs ),
.lcd_rgb (lcd_rgb),
.key_en (key_en)
);
endmodule

VGA計數模塊代碼

module vga_driver(
clk ,
rst_n ,
key_en ,
hys ,
vys ,
lcd_rgb
);

parameter PICTURE_W = 16 ;
parameter ROW_W = 10 ;

parameter X0_INIT = 273 ;
parameter X1_INIT = 373 ;
parameter Y0_INIT = 202 ;
parameter Y1_INIT = 282 ;
parameter X_GAP = 5 ;
parameter Y_GAP = 4 ;
parameter CNT_TIME = 625 ;

parameter TIME_1S = 25000000 ;
parameter TIME_20MS = 500000 ;
parameter X_CENT = 323 ;
parameter Y_CENT = 242 ;
parameter X_PRE_CENT = X_CENT + 141 ;
parameter Y_PRE_CENT = Y_CENT + 32 ;

parameter WHITE = 16b11111_111111_11111 ;
parameter RED = 16b11111_000000_00000 ;
parameter GREEN = 16b00000_111111_00000 ;
parameter BLUE = 16b00000_000000_11111 ;
parameter YELLOW = 16b11111_111111_00000 ;
parameter PURPLE = 16b01111_000000_10000 ;
parameter CYAN = 16b01111_111111_11111 ;
parameter PINK = 16b11111_011111_01111 ;
parameter BLACK = 16b00000_000000_00000 ;

input clk ;
input rst_n ;
input key_en ;

output hys ;
output vys ;

output [PICTURE_W-1:0] lcd_rgb ;
reg [PICTURE_W-1:0] lcd_rgb ;

reg [ROW_W-1:0] h_cnt ;
reg [ROW_W-1:0] v_cnt ;
reg hys ;
reg vys ;
reg valid_area ;
reg key_flag ;
reg[19:0] shake_cnt ;
reg flag ;

reg[ 9:0] cnt_time ;
reg change_flag ;
reg[19:0] range ;
reg[19:0] distance ;
reg direction ;

always @(posedgeclk or negedgerst_n)begin
if(!rst_n)begin
h_cnt<= 0;
end
else if(add_h_cnt)begin
if(end_h_cnt)
h_cnt<= 0;
else
h_cnt<= h_cnt + 1;
end
end
assign add_h_cnt = 1;
assign end_h_cnt = add_h_cnt&&h_cnt== 800-1;

always @(posedgeclk or negedgerst_n)begin
if(!rst_n)begin
v_cnt<= 0;
end
else if(add_v_cnt)begin
if(end_v_cnt)
v_cnt<= 0;
else
v_cnt<= v_cnt + 1;
end
end
assign add_v_cnt = end_h_cnt;
assign end_v_cnt = add_v_cnt&&v_cnt== 525-1;

always@(posedgeclk or negedgerst_n)begin
if(!rst_n)begin
hys<= 0;
end
else if(add_h_cnt&&h_cnt==96 - 1)begin
hys<= 1;
end
else if(end_h_cnt)begin
hys<= 0;
end
end

always@(posedgeclk or negedgerst_n)begin
if(!rst_n)begin
vys<= 0;
end
else if(add_v_cnt&&v_cnt== 2 - 1)begin
vys<= 1;
end
else if(end_v_cnt)begin
vys<= 0;
end
end

always @(*)begin
valid_area = h_cnt>=141 &&h_cnt<=786 &&v_cnt>=32 &&v_cnt<=515;
end

always @(posedgeclk or negedgerst_n)begin
if(rst_n==1b0)begin
shake_cnt<= 0;
end
else if(add_shake_cnt)begin
if(end_shake_cnt)
shake_cnt<= 0;
else
shake_cnt<= shake_cnt + 1;
end
else begin
shake_cnt<= 0;
end
end
assign add_shake_cnt = key_en&& flag==0;
assign end_shake_cnt = add_shake_cnt&&shake_cnt==TIME_20MS-1;

always @(posedgeclk or negedgerst_n)begin
if(rst_n==1b0)begin
flag <= 0;
end
else if(end_shake_cnt)begin
flag <= 1;
end
else if(key_en==0)begin
flag <= 0;
end
end

always @(posedgeclk or negedgerst_n)begin
if(!rst_n)begin
cnt_time<= 0;
end
else if(add_cnt_time)begin
if(end_cnt_time)
cnt_time<= 0;
else
cnt_time<= cnt_time + 1;
end
end
assign add_cnt_time = key_flag&&add_h_cnt&&h_cnt==0 &&v_cnt==0;
assign end_cnt_time = add_cnt_time&&cnt_time== CNT_TIME -1;

always @(posedgeclk or negedgerst_n)begin
if(rst_n==1b0)begin
key_flag<= 0;
end
else if(end_shake_cnt)begin
key_flag<= 1;
end
else if(end_cnt_time)
key_flag<= 0;
end

always @(posedgeclk or negedgerst_n)begin
if(rst_n==1b0)begin
direction <= 1b0;
end
else if(cnt_time==0 &&end_shake_cnt) begin
direction <= ~direction;
end
end

always @(*)begin
if(h_cnt==0 &&v_cnt==0 &&cnt_time!=0) begin
change_flag = 1b1;
end
else begin
change_flag = 1b0;
end
end

always @(posedgeclk or negedgerst_n)begin
if(rst_n==1b0)begin
range <= 25 ;
end
else if(h_cnt==0 &&v_cnt==0 &&change_flag) begin
if(direction)
range <= range + 64;
else
range <= range - 64;
end
end

always @(*)begin
distance = ((h_cnt - X_PRE_CENT) * (h_cnt - X_PRE_CENT)) +
((v_cnt - Y_PRE_CENT) * (v_cnt - Y_PRE_CENT));
end

always @(posedgeclk or negedgerst_n)begin
if(rst_n==1b0)begin
lcd_rgb<= 8h0;
end
else if(valid_area)begin
if(distance < range)begin
lcd_rgb<= BLUE;
end
else begin
lcd_rgb<= WHITE;
end
end
else begin
lcd_rgb<= 0;
end
end
endmodule

推薦閱讀:

相關文章