原创 [博客大赛]【FPGA】基于DE2-70的VGA控制显示

2014-4-21 16:45 4119 20 21 分类: FPGA/CPLD 文集: FPGA
一、概述
   本文将讲述基于FPGA的VGA显示控制原理,并在Altera的DE2-70 FPGA开发板上实现以下效果:利用VGA控制,使液晶显示器显示一幅七彩色条图像(红、黄、蓝、白、洋红、、绿),并且彩图可在拨码开关iSW1的控制下实现不同移动模式。可实现的模式有:(1)彩色图在显示屏内任意移动,撞到显示器边缘时弹回;(2)彩色图沿着显示器的边沿逆时针移动;(3)彩色图沿着显示器的边沿顺时针移动。
1.jpg
图1、七色彩条图像
 
二、VGA显示原理与时序控制图
    VGA显示器采用光栅扫描方式,即轰击荧光屏的电子束在CRT显示器上从左到右、从上到下做有规律的移动,其水平移动受水平同步信号HSYNC控制,垂直移动受垂直同步信号VSYNC控制。扫描方式一般分为逐行扫描和隔行扫描,这里采用逐行扫描。完成一行扫描的时间称为水平扫描时间,其倒数称为行频率,完成一帧(整屏)扫描的时间称为垂直扫描时间,其倒数称为场频,又称刷新率。
    VGA工业标准要求的时钟频率如下:
    时钟频率(Clock frequency) 25.175MHz(像素输出的频率)
    行频(Line frequency) 31469Hz
    场频(Field frequency) 59.94Hz
VGA控制时序如下,图2、图3分别是行时序图、场时序图:
vga行扫描.jpg
图2、VGA的行扫描时序图
vga场扫描.jpg
图3、VGA的场扫描时序图
 
具体的,VGA时序要求如下:
时序图.jpg
图4、VGA的时序要求
 
三、基于Altera DE2-70的VGA显示控制框图
    DE2-70的系统时钟为50MHz,而VGA控制时钟频率为25.175MHz,故调用锁相环模块PLL来进行时钟分频,输入50MHz,输出25MHz。当然,也可以用Verilog HDL设计一个计数器,用于时钟分频,得到25MHz的VGA控制时钟。大致的VGA显示控制框图如图5、6所示:
结构框图1.jpg
图5、VGA显示ROM图像的控制结构框图
结构框图2.jpg
图6、VGA显示彩色条纹的控制结构框图
 
 四、Verilog HDL源代码:
/*
Module name : vga 
Function : 基于DE2-70,产生126*126大小的七竖条彩色图(红、黄、蓝、白、洋红、青、绿),每条竖条纹为18*126
     并在按键iSW1控制下,图像可在显示屏上按不同方向移动(任意方向、沿显示屏边沿顺时针、沿显示屏边沿逆时针)
Create date : 2014/4/12
Student : 张小龙
Version : Quartus ii 9.1 & DE2-70
*/
module vga(iclk_50,irst,ovga_clock,ovga_hs,ovga_vs,ovga_blank,ovga_sync,
           ovga_r,ovga_g,ovga_b,ovga_r0,ovga_g0,ovga_b0,iSW1);
parameter  H_TA=96;
parameter  H_TB=40;
parameter  H_TC=8;
parameter  H_TD=640;
parameter  H_TE=8;
parameter  H_TF=8;
parameter  H_BLANK  =H_TA+H_TB+H_TC;
parameter  H_TOTAL  =H_TA+H_TB+H_TC+H_TD+H_TE+H_TF;
parameter  LENGTH=126,WIDTH=126;
parameter  V_TA=2;
parameter  V_TB=25;
parameter  V_TC=8;
parameter  V_TD=480;
parameter  V_TE=8;
parameter  V_TF=2;
parameter  V_BLANK=V_TA+V_TB+V_TC;
parameter  V_TOTAL=V_TA+V_TB+V_TC+V_TD+V_TE+V_TF;
(*chip_pin="AD15"*)input iclk_50;       
(*chip_pin="AA23"*)input irst;
(*chip_pin="D24"*)output ovga_clock;
(*chip_pin="C15"*)output ovga_blank;
(*chip_pin="B15"*)output ovga_sync;
(*chip_pin="J19"*)output reg ovga_hs;
(*chip_pin="H19"*)output reg ovga_vs;
(*chip_pin="G20,E20,F20,H20,G21,H21,D22,E22"*)output reg[7:0] ovga_r;
(*chip_pin="D19,C19,A19,B19,B18,C18,B17,A17"*)output reg[7:0] ovga_b;
(*chip_pin="A14,B14,B13,C13,A12,B12,C12,A11"*)output reg[7:0] ovga_g;
 
/*R、G、B分别用8-bit表示,而DE2-70的DAC为10-bit
  故RGB剩余的两位均为0  */
  
(*chip_pin="E23,D23"*)output [1:0] ovga_r0;
(*chip_pin="C16,B16"*)output [1:0] ovga_b0;
(*chip_pin="B11,A10"*)output [1:0] ovga_g0;
 
(*chip_pin="AB26"*) input iSW1; //按键1,用于改变移动方向  
integer flag=0; //标志位,0-任意方向移动,1-逆时针方向移动,2-顺时针方向移动
reg iclk;              
reg[10:0] h_cont,v_cont;
reg[9:0] xpos,ypos;
reg[1:0] ij;
/*************************************************************/
always@(posedge iclk_50)
 begin iclk<=~iclk; end //分频,产生25MHz时钟
   assign ovga_sync    =1'b1;
   assign ovga_blank   =~((h_cont
   assign ovga_clock   =~iclk;
   assign ovga_r0=2'h0; //RGB信号剩余不用的位,全部置0
   assign ovga_g0=2'h0;
   assign ovga_b0=2'h0;
 always@(posedge iclk or posedge irst)   //列扫描    
begin if(irst)
       begin  h_cont<=0; ovga_hs<=1;end //Reset
   else begin
       if(h_cont
       if(h_cont<=H_TA-1) ovga_hs<=1'b0; else ovga_hs<=1'b1;    //前沿
       end
end 
always@(posedge ovga_hs or posedge irst)   //行扫描
begin if(irst)
    begin v_cont<=0; ovga_vs<=1; end //Reset
else begin
    if(v_cont
    if(v_cont<=V_TA-1) ovga_vs<=1'b0; else ovga_vs<=1'b1;       //前沿
    end
end
always @(posedge iclk or posedge irst)
begin if(irst) begin ovga_r<=8'h0; ovga_g<=8'h0;                //Reset
ovga_b<=8'h0; end
else begin
if(h_cont<(xpos+H_BLANK+18)&&h_cont>=(xpos+H_BLANK)&&
  v_cont<(ypos+V_BLANK+WIDTH)&&v_cont>=(ypos+V_BLANK))      //有效显示区域内赋值显示
begin
ovga_r<=8'b11111111;
ovga_g<=8'h0; ovga_b<=8'h0;                 //RGB分量赋值,产生红色
end
else if(h_cont<(xpos+H_BLANK+36)&&h_cont>=(xpos+H_BLANK+18)
  &&v_cont<(ypos+V_BLANK+WIDTH)&&v_cont>=(ypos+V_BLANK))    //有效显示区域内赋值显示
begin
ovga_r<=8'b11111111;
ovga_g<=8'b11111111; ovga_b<=8'h0;         //RGB分量赋值,产生黄色
end
else if(h_cont<(xpos+H_BLANK+54)&&h_cont>=(xpos+H_BLANK+36)&&
  v_cont<(ypos+V_BLANK+WIDTH)&&v_cont>=(ypos+V_BLANK))      //有效显示区域内赋值显示
begin
ovga_r<=8'h0;
ovga_g<=8'h0; ovga_b<=8'b11111111;               //RGB分量赋值,产生蓝色
end
else if(h_cont<(xpos+H_BLANK+72)&&h_cont>=(xpos+H_BLANK+54)&&   
  v_cont<(ypos+V_BLANK+WIDTH)&&v_cont>=(ypos+V_BLANK))      //有效显示区域内赋值显示
begin
ovga_r<=8'b11111111;
ovga_g<=8'b11111111; ovga_b<=8'b11111111;         //RGB分量赋值,产生白色    
end
else if(h_cont<(xpos+H_BLANK+90)&&h_cont>=(xpos+H_BLANK+72)&&
  v_cont<(ypos+V_BLANK+WIDTH)&&v_cont>=(ypos+V_BLANK))      //有效显示区域内赋值显示
begin
ovga_r<=8'b11111111;
ovga_g<=8'h0; ovga_b<=8'b11111111;       //RGB分量赋值,产生洋红色       
end
else if(h_cont<(xpos+H_BLANK+108)&&h_cont>=(xpos+H_BLANK+90)&&
  v_cont<(ypos+V_BLANK+WIDTH)&&v_cont>=(ypos+V_BLANK))      //有效显示区域内赋值显示
begin
ovga_r<=8'h0;
ovga_g<=8'b11111111; ovga_b<=8'b11111111;         //RGB分量赋值,产生青色      
end
else if(h_cont<(xpos+H_BLANK+LENGTH)&&h_cont>=(xpos+H_BLANK+108)&&
  v_cont<(ypos+V_BLANK+WIDTH)&&v_cont>=(ypos+V_BLANK))      //有效显示区域内赋值显示
begin
ovga_r<=8'h0;
ovga_g<=8'b11111111; ovga_b<=8'h0;                //RGB分量赋值,产生绿色
end
else begin ovga_r<=8'h0; ovga_g<=8'h0;           //有效显示区域外为背景色(黑色)
ovga_b<=8'h0; end
end
end
//*********************************************************
//按键控制图像移动方向模式的标志位
//flag=0,图像任意方向移动;
//flag=1,图像沿着显示器边沿顺时针移动;
//flag=2,图像沿着显示器边沿逆时针移动
//*********************************************************
always @(posedge iSW1)                                        
  begin
flag<=flag+1;
if(flag==2)
flag<=0;
  end
//*********************************************************      
always@(negedge ovga_vs)
begin 
if(flag==1) //彩图沿着显示器边沿顺时针移动
  begin
if(ij==2'b00) begin   
xpos<=xpos+1;
ypos<=0;
if(xpos+LENGTH==640) ij<=2'b10; end
else if(ij==2'b01) begin
xpos<=0;
ypos<=ypos-1;
if(ypos==0) ij<=2'b00;end
else if(ij==2'b10)begin
xpos<=640-LENGTH;
ypos<=ypos+1;
if(ypos+WIDTH==480) ij<=2'b11;end
else if(ij==2'b11)begin 
xpos<=xpos-1;
ypos<=480-WIDTH;
if(xpos==0) ij<=2'b01; end
  end
 
else if(flag==2) //彩图沿着显示器边沿逆时针移动
  begin
if(ij==2'b00) begin   
xpos<=0;
ypos<=ypos+1;
if(ypos+WIDTH==480) ij<=2'b01; end
else if(ij==2'b01) begin
ypos<=480-WIDTH;
xpos<=xpos+1;
if(xpos+LENGTH==640) ij<=2'b11;end
else if(ij==2'b10)begin
ypos<=0;
xpos<=xpos-1;
if(xpos==0) ij<=2'b00;end
else if(ij==2'b11)begin 
xpos<=640-LENGTH;
ypos<=ypos-1;
if(ypos==0) ij<=2'b10; end
  end
 
else if(flag==0) //彩图在显示器上任意方向移动
  begin
if(ij==2'b00) begin   
xpos<=xpos+1;
ypos<=ypos+1;
if(ypos+WIDTH==480) ij<=2'b01;
else if(xpos+LENGTH==640) ij<=2'b10;end
else if(ij==2'b01) begin
ypos<=ypos-1;
xpos<=xpos+1;
if(ypos==0) ij<=2'b00;
else if(xpos+LENGTH==640) ij<=2'b11;end
else if(ij==2'b10)begin
ypos<=ypos+1;
xpos<=xpos-1;
if(ypos+WIDTH==480) ij<=2'b11;
else if(xpos==0) ij<=2'b00;end
else if(ij==2'b11)begin 
xpos<=xpos-1;
ypos<=ypos-1;
if(xpos==0) ij<=2'b01;
if(ypos==0) ij<=2'b10; end
  end
end
//********************************************************
endmodule
 
)>
)>
 
)||(v_cont
 
 

文章评论1条评论)

登录后参与讨论

用户658643 2014-4-21 08:51

欢迎新伙伴!
相关推荐阅读
460114537_680770963 2014-06-09 18:25
【Protel】Altium Designer 10的初作PCB板——AVR mega16单片机系统版
       经过好久的挣扎,自学Altium Designer 10,终于画出了自己的第一块PCB——基于AVR mega16单片机的小系统开发板,不知道焊接好元器件后能否正常工作~~~~(&g...
460114537_680770963 2014-05-16 13:04
【关于工作】初次面试“血泪史“
公司:广东XXXXXX          岗位:硬件工程师       笔试 :半小时的笔试+填信息表      1、 一个C语言程序: include<stdio.h> v...
460114537_680770963 2014-05-12 22:08
【Protel】Altium Designer 10学习笔记(一)
1、PCB,Printed Circuit Board印制电路板/印刷电路板,准确定以为:以绝缘敷铜板为基板,经过印刷、蚀刻、钻孔及后处理等工序,将电路中元器件的连接关系用一组导线图形和孔位制作在...
460114537_680770963 2014-05-11 23:10
【protel】ATmega16单片机开发系统——基于Altium Designer 10
        最近,在自学Altium Designer 10(原Protel),想在大三下学期把PCB学会。上图和PDF附件一张,欢迎各位指教,感激不尽。  以下是我画的原理图,基于Atmel...
460114537_680770963 2014-04-29 12:17
联发科处理器能走多远?
功能机时代,联发科(MTK)是山寨手机的代名词,其廉价的手机芯片+操作界面解决方案成为了杂牌、低价手机的首选,一度“臭名昭彰”;而随着Android智能平台的崛起,联发科如今已经成为增长最快的科技公司...
EE直播间
更多
我要评论
1
20
关闭 站长推荐上一条 /7 下一条