"); //-->
Verilog 编写的基于VGA的动画图像显示
明德扬科技教育有限公司
官网:www.mdy-edu.com
淘宝:mdy-edu.taobao.com
QQ群:544453837
QQ咨询:158063679
VGA显示动画
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,接口对应孔如下所示:
图1 VGA信号接口对应
像素是产生各种颜色的基本单元。根据物理学中的混色原理,三色发光的亮度比例适当,可呈现白色。适当的调整发光比例可以出现不同的颜色。三基色混色原理示意图如下图所示:
图2 三基色混色原理
颜色 | 黑 | 蓝 | 红 | 紫 | 绿 | 青 | 黄 | 白 |
R | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
G | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |
B | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
表1 三基色颜色编码
上表的RBG一共有8组合,也就是说可以产生8种颜色,但是显示器显示的色彩是非常丰富的,远多于8种颜色。那么,这是如何做到的呢?
对于显示器来说,RGB的三个信号其实是模拟信号,其电平的高低,可以表示颜色的深浅,利用这个原理,就可以产生丰富的色彩。为了控制电压的高低,我们必须用到DA芯片。例如,下图中FPGA产生RGB三种信号,这时RGB都是多位的数字信号。DA芯片根据数字信号的值,产生不同电压的模拟信号rgb。
图3 DA芯片工作原理
模块划分和信号列表如下:
模块划分
顶层模块信号列表
信号名 | 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 程序设计
顶层模块代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | 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计数模块代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 | 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 = 16'b11111_111111_11111 ; parameter RED = 16'b11111_000000_00000 ; parameter GREEN = 16'b00000_111111_00000 ; parameter BLUE = 16'b00000_000000_11111 ; parameter YELLOW = 16'b11111_111111_00000 ; parameter PURPLE = 16'b01111_000000_10000 ; parameter CYAN = 16'b01111_111111_11111 ; parameter PINK = 16'b11111_011111_01111 ; parameter BLACK = 16'b00000_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==1'b0)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==1'b0)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==1'b0)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==1'b0)begin direction <= 1'b0; 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 = 1'b1; end else begin change_flag = 1'b0; end end
always @(posedgeclk or negedgerst_n)begin if(rst_n==1'b0)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==1'b0)begin lcd_rgb<= 8'h0; 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 |
*博客内容为网友个人发布,仅代表博主个人观点,如有侵权请联系工作人员删除。