原创 【博客大赛】利用FPGA控制VGA接口来使显示器显示彩条纹(里面包括调试中的查错检查方法)

2013-12-7 11:31 4839 13 14 分类: FPGA/CPLD

利用FPGA控制VGA接口来使显示器显示彩条纹

最近一直在调关于通过VGA接口来控制显示器的程序,今天终于调试出结果来了,赶紧上来与大家分享一下。

1、VGA显示原理

常见的彩色显示器一般由阴极射线管(CRT)构成,彩色由GRB(Green Red Blue)基色组成。显示采用逐行扫描的方式解决,阴极射线*发出电子束打在涂有荧光粉的荧光屏上,产生GRB基色,合成一个彩色像素。扫描从屏幕的左上方开始,从左到右,从上到下,逐行扫描,每扫完一行,电子束回到屏幕的左边下一行的起始位置,在这期间,CRT对电子束进行消隐,每行结束时,用行同步信号进行行同步;扫描完所有行,用场同步信号进行场同步,并使扫描回到屏幕的左上方,同时进行场消隐,并预备进行下一次的扫描。VGA显示原理图如图1所示。

在本文中,FPGA 通过串联电阻直接驱动 5 个 VGA 信号。每个颜色信号串一个电阻,每位的颜色信号分别是 VGA_RED,VGA_GREEN,VGA_BLUE。每个电阻与终端的 75 欧电缆电阻相结合,确保颜色信号保持在VGA规定的0V~0.7V之间。VGA_HSYNC 和VGA_VSYNC 信号使用 LVTTL 或 LVCMOS3I/O 标驱动电平。通过VGA_RED,VGA_GREEN,VGA_BLUE 置高或低来产生 8 种颜色。实际应用中,VGA_RED,VGA_GREEN 和 VGA_BLUE 可以接到 DAC 的输出,每个 DAC 用 8 bit 或更多的比特控制,3 条色彩控制线根据DAC 输出的电压大小配合实现更多种颜色的显示。VGA 显示的原理是利用水平扫描信号和竖直信号实现二维平面的像素扫描显示,以 640×480 像素的扫描显示示意图为例,当水平扫描信号 VGA_HSYNC 信号为高时,VGA 显示器从左向右依次扫描当前行的 640 个像素点。每扫描完一行,VGA_HSYNC 信号电平拉低,水平扫描位置回到最左端。

1.jpg

图1 VGA显示基本原理图

2、VGA信号时序

普通的VGA显示器,其引出线共含5个信号:G,R,B三基色信号;HS:行同步信号;VS:场同步信号。

    对于5个信号的时序驱动,以及VGA显示器,要严格遵循“VGA工业标准”,即640*480*60Hz模式。通常我们用的显示器都满足工业标准,因此设计VGA控制器是要参考显示器的技术规格。图2为VGA行扫描、场扫描的时序图。

2.jpg

图2 VGA行扫描、场扫描时序

 

由于本文采用的是640*480且刷新频率为60Hz显示模式,即显示器每秒扫描60场,而VGA在实际工作时并不是每行扫描640个点,每场扫描480行,而是每行800个点,每场525行,这是因为有行消隐和场消隐的存在的缘故,其中行消隐后沿为Tb+Tc=40+8=48个时钟周期,行消隐前沿为Te+Tf=8+8=16个时钟周期,场消隐后沿为Tb+Tc=25+8=33个时钟周期,行消隐前沿为Te+Tf=8+2个时钟周期,“消隐”的意思是指使显示器信号消失不见,所以在这段时间内不能有R,G,B信号输入,否则屏幕不会显示(本人就是在这儿出现了错误,下面会提到),用于有效显示的区域是640*480,所以才有了本段开头的模式。这样点像素的频率为:800*525*60=25.175MHz。由于采用的FPGA开发板为50MHz的系统时钟,所以需要对其进行2分频,然后按时序要求输出行、场同步信号即可。

但是在实际操作中我按照行、场信号时序要求输出了结果,也仍然还是不能调试通过,整个屏依然是无视频信号输入。于是我用signal tap Ⅱ进行实时观测,发现行时序信号(HS_OUT),与场时序信号输出(VS_OUT)与驱动时序要求完全一致,但是结果却无法显示。后来我就找到参考书按照参考书给出的程序代码一行一行的敲进去,最后却可以显示,通过使用signal tap Ⅱ实时观测信号输出,发现除了RGB信号外,其余的完全一样,那么问题肯定就出在R、G、B信号上,通过对比发现,我在所有的时刻均将R/G/B信号输出高电平,目的是想让整个屏都显示白色,因为我认为既然在固定的640*480这个区域内给予信号输入屏幕都会有显示,那么对于整个像素周期均给予输入,那么肯定也会有显示啊。但是事实上我是错的,原因就在于上一段中提到的行、场消隐的原因。即在消隐阶段不能有视频信号输入,也就是说在这一段内R/G/B必须均为低电平,只有在行数据有效区、长数据有效区的两个Td(即640*480的区域)同时满足的区域内才能给予视频信号输入,即R/G/B才能有输入,而我恰好违反了这个原则,在弄清原因之后,我修改了代码,结果可以屏幕顺利显示出我所要的结果。颜色显示组合为:

R

G

B

Resulting color

0

0

0

Black(黑色)

0

0

1

Blue(蓝色)

0

1

0

Green(绿色)

0

1

1

Cyan(靛色)

1

0

0

Red(红色)

1

0

1

Magenta(紫色)

1

1

0

Yellow(黄色)

1

1

1

White(白色)

具体代码与结果如下:

library ieee;

use ieee.std_logic_1164.all;

use ieee.std_logic_unsigned.all;

-- here we use the 640*480@60Hz screen_display mode,but there are --horizion_blacking(48back+16front),

--vertical_blacking(33+10) and syn_time(96h,2v) time so the time counter is

-- horizon_cnt=800(96+48+640+16),vertical_cnt=525(2+33+480+10),and --clk=60*800*525=25MHz(25174800Hz)

entity VGA_control is

      port(

             clk50: in std_logic;

             R: out std_logic;

             G: out std_logic;

             B: out std_logic;

             hs_out: out std_logic;

             vs_out: out std_logic

      );

end entity;

 

architecture control of VGA_control is

signal h_cnt,v_cnt: integer range 0 to 799;

signal clk : std_logic;

 

begin

clk_devide: process(clk50)       --according to VGA standard and the --analysis before,the frequency of clk should be 25MHz

      begin

             if(rising_edge(clk50)) then

                    clk<=not clk;

             end if;

      end process;

      process(clk)

      begin    

             if (rising_edge(clk)) then

                    if h_cnt=799 then

                           h_cnt<=0;

                    else

                           h_cnt<=h_cnt+1;

                    end if;

             end if;   

      end process;

      process(clk,h_cnt)

             begin

             if(clk'event and clk='1') then

                    if((h_cnt>=0) and (h_cnt<96)) then

                           hs_out<='0';

                    end if;

                    if(h_cnt>=96) and (h_cnt<=799) then

                           hs_out<='1';

                    end if;

             end if;

      end process;

      process(clk,h_cnt)

             begin

             if (rising_edge(clk)) then    --由于要先进行行扫描,在进行列扫描所--以,必须行计数器满800后列计数器才能加1

                    if(h_cnt=799) then

                           if v_cnt=524 then

                                  v_cnt<=0;

                           else

                                  v_cnt<=v_cnt+1;

                           end if;

                    end if;

             end if;   

      end process;

      process(clk,v_cnt)

      begin

      if(rising_edge(clk))then—产生

             if(v_cnt>=0) and (v_cnt<2) then

                    vs_out<='0';

             end if;

             if(v_cnt>=2) and (v_cnt<525) then

                    vs_out<='1';

             end if;

      end if;

      end process;

      process(clk)

      begin

             if(rising_edge(clk)) then       --竖条纹颜色输出

                    if (h_cnt<=223) and (h_cnt>=143) and (v_cnt<=514) and (v_cnt>=34)then

                           R<='0';  

                           G<='0';

                           B<='1';

                    elsif (h_cnt<=303) and (h_cnt>=223) and (v_cnt<=514) and (v_cnt>=34)then

                           R<='0';

                           G<='1';

                           B<='0';

                    elsif (h_cnt<=383) and (h_cnt>=303) and (v_cnt<=514) and (v_cnt>=34)then

                           R<='0';

                           G<='1';

                           B<='1';

                    elsif (h_cnt<=463) and (h_cnt>=383) and (v_cnt<=514) and (v_cnt>=34)then

                           R<='1';

                           G<='0';

                           B<='0';

                    elsif (h_cnt<=543) and (h_cnt>=463) and (v_cnt<=514) and (v_cnt>=34)then

                           R<='1';

                           G<='0';

                           B<='1';

                    elsif (h_cnt<=623) and (h_cnt>=543) and (v_cnt<=514) and (v_cnt>=34)then

                           R<='1';

                           G<='1';

                           B<='0';

                    elsif (h_cnt<=703) and (h_cnt>=623) and (v_cnt<=514) and (v_cnt>=34)then

                           R<='1';

                           G<='1';

                           B<='1'; 

                    elsif (h_cnt<=783) and (h_cnt>=703) and (v_cnt<=514) and (v_cnt>=34)then

                           R<='0';

                           G<='0';

                           B<='0';

                    else

                           R<='0';

                           G<='0';

                           B<='0';

                    end if;

             end if;

      end process;

end architecture;

另外读者可以在颜色控制模块修改参数来进行条纹间隔大小修改,也可以产生方格等,这些有读者自己完成。

文章评论1条评论)

登录后参与讨论

用户377235 2015-5-18 21:00

谢谢博主,找了好久,终于在你这儿找到了想要的~

相关推荐阅读
1053683568_507245520 2014-03-20 11:19
cadence16.6 软件绘制PCB板
   最近一直在学习cadence的使用,现在就对近来学习做个总结,虽然还没有达到熟练的程度,但是也希望可以给后来者做个借鉴吧。         本人的方向是硬件方向,马上面临着找工作的压力。...
1053683568_507245520 2014-01-03 21:02
【博客大赛】自己定制DPRAM的读写操作
DPRAM的读写操作 下面是本人写的DPRAM的读写操作,自己定制DPRAM,不用altera FPGA 内部自带的IP core,选择的存储器块类型是M9K(对于不同类型的存储器块,当同时对...
1053683568_507245520 2013-12-15 20:51
【博客大赛】我的EDN
我的EDN 每次进入EDN网站,看到大家在踊跃的分享自己的学习经历,经验,以及聊生活谈梦想,都会激发我的热情,激发我对生活的热爱,对未来的幻想,对自己的思索。当我懒惰时,我会进来看看,看看特权...
1053683568_507245520 2013-12-06 11:45
【博客大赛】利用VHDL产生奇分频器
利用VHDL产生占空比为50%的奇倍数分频电路 一般的介绍VHDL语言的书在对分频器进行举例描述的时候,都是举得偶数倍分频的例子,因为那相对来说比较简单(只需要设置一个中间信号变量,然后在分频...
1053683568_507245520 2013-12-06 11:45
【博客大赛】VHDL进程语句的并行执行分析
相信许多人在学习VHDL时,都会对进程如何执行的,以及进程之间的并行执行产生疑问,本文将以下面一个具体的例子来分析单个进程的执行,与进程之间的并行执行。 library ieee; use...
我要评论
1
13
关闭 站长推荐上一条 /2 下一条