利用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 VGA显示基本原理图
2、VGA信号时序
普通的VGA显示器,其引出线共含5个信号:G,R,B三基色信号;HS:行同步信号;VS:场同步信号。
对于5个信号的时序驱动,以及VGA显示器,要严格遵循“VGA工业标准”,即640*480*60Hz模式。通常我们用的显示器都满足工业标准,因此设计VGA控制器是要参考显示器的技术规格。图2为VGA行扫描、场扫描的时序图。
图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;
另外读者可以在颜色控制模块修改参数来进行条纹间隔大小修改,也可以产生方格等,这些有读者自己完成。
用户377235 2015-5-18 21:00
谢谢博主,找了好久,终于在你这儿找到了想要的~