18_基于FPGA的VGA显示控制
实验原理
VGA标准
VGA(Video Graphics Array)即视频图形阵列,是IBM在1987年随PS/2(PS/2 原是"Personal System 2"的意思,"个人系统2",是IBM公司在1987年推出的一种个人电脑)机推出的。PS/2电脑上使用的键盘鼠标接口就是现在的PS/2接口。因为标准不开放,PS/2电脑在市场中失败了。只有PS/2接口一直沿用到今天)一起推出的使用模拟信号的一种视频传输标准,在当时具有分辨率高、显示速率快、颜色丰富等优点,在彩色显示器领域得到了广泛的应用。这个标准对于现今的个人电脑市场已经十分过时。即使如此,VGA仍然是最多制造商所共同支持的一个标准,个人电脑在加载自己的独特驱动程序之前,都必须支持VGA的标准。例如,微软Windows系列产品的开机画面仍然使用VGA显示模式,这也说明其在显示标准中的重要性和兼容性。
VGA显示模式
VGA最早指的是显示器640X480这种显示模式。VGA技术的应用还主要基于VGA显示卡的计算机、笔记本等设备,而在一些既要求显示彩色高分辨率图像又没有必要使用计算机的设备上,VGA技术的应用却很少见到。本文对嵌入式VGA显示的实现方法进行了研究。基于这种设计方法的嵌入式VGA显示系统,可以在不使用VGA显示卡和计算机的情况下,实现VGA图像的显示和控制。系统具有成本低、结构简单、应用灵活的优点,可广泛应用于超市、车站、飞机场等公共场所的广告宣传和提示信息显示,也可应用于工厂车间生产过程中的操作信息显示,还能以多媒体形式应用于日常生活。
VGA接口
标准的VGA接口一共有15个接口(拔下任何一台VGA液晶或是CRT显示器看看就知道了),真正用到的信号接口不多,就5个。HSYNC是行同步信号,VSYNC是场同步信号,同步信号就是为了让VGA显示器接收部分知道送来的数据是对应哪一行哪一列的哪一个像素点。VGA_R,VGA_G,VGA_B是三原色信号,这三个信号接口的输入都是模拟信号(标准为0—0.7V),所以它们都有相应的地线需要连接。我们使用的大西瓜开发板的VGA_R,VGA_G,VGA_B三个信号线都有三个不同阻值的电阻,并且三原色信号接口输入的只可能是数字信号(0或1),因此驱动液晶屏上显示的颜色最多能达到512种。一般来说,可以在FPGA/CPLD和VGA之间加一个DAC芯片,这样就可能实现65536种或者更多色彩的显示。
VGA接口
VGA接口时序
VGA接口时序如下图所示,场同步信号VSYNC在每帧开始的时候产生一个固定宽度的低脉冲,行同步信号HSYNC在每行开始的时候产生一个固定宽度的低脉冲,数据再某些固定的行和列交汇处有效。
VGA接口时序
实验说明
在实验中,我们使用到开发板的VGA接口,使显示器循环地显示8种颜色。由于在实验中我们使用到了3个IO口,每3个IO口分别控制VGA_R,VGA_G,VGA_B,三原色信号为模拟信号,而开发板出来的信号为数字信号,在我们的开发板的VGA接口上,使用了电阻分压,所以在我们的开发板上,最多可以显示出8种颜色。读者可以自己查看我们开发板的原理图。
硬件原理图
实验代码
顶层原理图设计
显示颜色控制
/********************************版权声明************************************** ** 大西瓜团队 ** **----------------------------文件信息-------------------------- ** 文件名称:color.v ** 创建日期:2012.12.23 ** 功能描述:产生8组不同的coldata数值,该数值为RGB的数值 ** 操作过程:使用者可以自己根据需要修改coldata的数值,显示屏将会显示出不同的颜色。 ** 硬件平台:大西瓜第3代开发板 ** 版权声明:本代码属个人知识产权,本代码仅供交流学习. **---------------------------修改文件的相关信息---------------- ** 修改人: ** 修改日期: ** 修改内容: *******************************************************************************/
module color(clk,rst_n,coldata); input clk; //系统时钟50MHz input rst_n; //低电平复位 output[8:0] coldata; //RGB的数值
reg[24:0] count; reg[2:0] colnum; reg fclk; //分频时钟 reg[8:0] coldata;
//-------------------------------------------------- //进行时钟分频,fclk的频率约为1Hz always@(posedge clk) begin if(count==25'd24500000) begin fclk=~fclk; count<=0; end else count<=count+1; end
//-------------------------------------------------- //产生8组不同的coldata数值 always@(posedge fclk) begin case(colnum) 3'd0:begin coldata<=9'b000_000_011;colnum<=colnum+1;end 3'd1:begin coldata<=9'b000_110_000;colnum<=colnum+1;end 3'd2:begin coldata<=9'b110_000_000;colnum<=colnum+1;end 3'd3:begin coldata<=9'b011_011_001;colnum<=colnum+1;end 3'd4:begin coldata<=9'b100_100_001;colnum<=colnum+1;end 3'd5:begin coldata<=9'b010_011_110;colnum<=colnum+1;end 3'd6:begin coldata<=9'b101_010_100;colnum<=colnum+1;end 3'd7:begin coldata<=9'b011_101_000;colnum<=0;end default:begin coldata<=9'b000_000_001;colnum<=0;end endcase end
endmodule |
VGA控制模块
/********************************版权声明************************************** ** 大西瓜团队 ** **----------------------------文件信息-------------------------- ** 文件名称:VGA.v ** 创建日期:2012.12.23 ** 功能描述:使用者可以在color.v中修改coldata的数值,该模块会根据coldata数值,通过VGA接口在显示屏上显示相应的颜色。 ** 操作过程:将显示屏与开发板的VGA接口接好,把程序烧写进FPGA板中,将会看到8种颜色循环变化。 ** 硬件平台:大西瓜第3代开发板 ** 版权声明:本代码属个人知识产权,本代码仅供交流学习. **---------------------------修改文件的相关信息---------------- ** 修改人: ** 修改日期: ** 修改内容: *******************************************************************************/
module VGA(clk,rst_n,hsync,vsync,vga_r,vga_g,vga_b,coldata);
input clk; //系统时钟50MHz input rst_n; //低电平复位 input[8:0] coldata; //需要显示的色彩,使用者可以自己在color.v中改变数值以获取需要的色彩,该例程实现的是8种色彩的循环变化 output hsync; //行同步信号 output vsync; //场同步信号 output[2:0] vga_r; //红基色信号 output[2:0] vga_g; //绿基色信号 output[2:0] vga_b; //蓝基色信号
reg[2:0] vga_r,vga_g,vga_b; reg[10:0] x_cnt; //行坐标 reg[9:0] y_cnt; //列坐标
//-------------------------------------------------- always @ (posedge clk or negedge rst_n) begin if(!rst_n) x_cnt <= 11'd0; else if(x_cnt == 11'd1039) x_cnt <= 11'd0; else x_cnt <= x_cnt+1'b1; end always @ (posedge clk or negedge rst_n) begin if(!rst_n) y_cnt <= 10'd0; else if(y_cnt == 10'd665) y_cnt <= 10'd0; else if(x_cnt == 11'd1039) y_cnt <= y_cnt+1'b1; end //-------------------------------------------------- wire valid; //有效显示区标志
assign valid = (x_cnt >= 11'd187) && (x_cnt < 11'd987) && (y_cnt >= 10'd31) && (y_cnt < 10'd631);
wire[9:0] xpos,ypos; //有效显示区坐标
assign xpos = x_cnt-11'd187; assign ypos = y_cnt-10'd31;
//-------------------------------------------------- reg hsync_r,vsync_r; //同步信号产生
always @ (posedge clk or negedge rst_n) begin if(!rst_n) hsync_r <= 1'b1; else if(x_cnt == 11'd0) hsync_r <= 1'b0; //产生hsync信号 else if(x_cnt == 11'd120) hsync_r <= 1'b1; end always @ (posedge clk or negedge rst_n) begin if(!rst_n) vsync_r <= 1'b1; else if(y_cnt == 10'd0) vsync_r <= 1'b0; //产生vsync信号 else if(y_cnt == 10'd6) vsync_r <= 1'b1; end assign hsync = hsync_r; assign vsync = vsync_r;
//-------------------------------------------------- wire dis; //显示屏显示范围 assign dis = ( (xpos>=80) && (xpos<=720) ) && ( (ypos>=60) && (ypos<=540) );
//-------------------------------------------------- //分别对RGB的3位数据进行判断 //R,G,B控制液晶屏颜色显示 //最终显示屏显示的颜色是RGB3种颜色的叠加 always@(posedge clk) begin case(coldata[8:6]) //R 3'b000:begin vga_r[2]<=1'bz; vga_r[1]<=1'bz; vga_r[0]<=1'bz;end 3'b001:begin vga_r[2]<=1'bz; vga_r[1]<=1'bz; vga_r[0]<= valid ? dis : 1'b0;end 3'b010:begin vga_r[2]<=1'bz; vga_r[1]<=valid ? dis : 1'b0; vga_r[0]<= 1'bz;end 3'b011:begin vga_r[2]<=1'bz; vga_r[1]<=valid ? dis : 1'b0; vga_r[0]<= valid ? dis : 1'b0;end 3'b100:begin vga_r[2]<=valid ? dis : 1'b0; vga_r[1]<=valid ? dis : 1'b0; vga_r[0]<= 1'bz;end 3'b101:begin vga_r[2]<=valid ? dis : 1'b0; vga_r[1]<=1'bz; vga_r[0]<= valid ? dis : 1'b0;end 3'b110:begin vga_r[2]<=valid ? dis : 1'b0; vga_r[1]<=valid ? dis : 1'b0; vga_r[0]<= 1'bz;end 3'b111:begin vga_r[2]<=valid ? dis : 1'b0; vga_r[1]<=valid ? dis : 1'b0;vga_r[0]<= valid ? dis : 1'b0;end default:begin vga_r[2]<=1'bz; vga_r[1]<=1'bz; vga_r[0]<=1'bz;;end endcase end
always@(posedge clk) begin case(coldata[5:3]) //G 3'b000:begin vga_g[2]<=1'bz; vga_g[1]<=1'bz; vga_g[0]<=1'bz;end 3'b001:begin vga_g[2]<=1'bz; vga_g[1]<=1'bz; vga_g[0]<= valid ? dis : 1'b0;end 3'b010:begin vga_g[2]<=1'bz; vga_g[1]<=valid ? dis : 1'b0; vga_g[0]<= 1'bz;end 3'b011:begin vga_g[2]<=1'bz; vga_g[1]<=valid ? dis : 1'b0; vga_g[0]<= valid ? dis : 1'b0;end 3'b100:begin vga_g[2]<=valid ? dis : 1'b0; vga_g[1]<=valid ? dis : 1'b0; vga_g[0]<= 1'bz;end 3'b101:begin vga_g[2]<=valid ? dis : 1'b0; vga_g[1]<=1'bz; vga_g[0]<= valid ? dis : 1'b0;end 3'b110:begin vga_g[2]<=valid ? dis : 1'b0; vga_g[1]<=valid ? dis : 1'b0; vga_g[0]<= 1'bz;end 3'b111:begin vga_g[2]<=valid ? dis : 1'b0; vga_g[1]<=valid ? dis : 1'b0; vga_g[0]<= valid ? dis : 1'b0;end default:begin vga_g[2]<=1'bz; vga_g[1]<=1'bz; vga_g[0]<=1'bz;;end endcase end
always@(posedge clk) begin case(coldata[2:0]) //B 3'b000:begin vga_b[2]<=1'bz; vga_b[1]<=1'bz; vga_b[0]<=1'bz;end 3'b001:begin vga_b[2]<=1'bz; vga_b[1]<=1'bz; vga_b[0]<= valid ? dis : 1'b0;end 3'b010:begin vga_b[2]<=1'bz; vga_b[1]<=valid ? dis : 1'b0; vga_b[0]<= 1'bz;end 3'b011:begin vga_b[2]<=1'bz; vga_b[1]<=valid ? dis : 1'b0; vga_b[0]<= valid ? dis : 1'b0;end 3'b100:begin vga_b[2]<=valid ? dis : 1'b0; vga_b[1]<=valid ? dis : 1'b0; vga_b[0]<= 1'bz;end 3'b101:begin vga_b[2]<=valid ? dis : 1'b0; vga_b[1]<=1'bz; vga_b[0]<= valid ? dis : 1'b0;end 3'b110:begin vga_b[2]<=valid ? dis : 1'b0; vga_b[1]<=valid ? dis : 1'b0; vga_b[0]<= 1'bz;end 3'b111:begin vga_b[2]<=valid ? dis : 1'b0; vga_b[1]<=valid ? dis : 1'b0; vga_b[0]<= valid ? dis : 1'b0;end default:begin vga_b[2]<=1'bz; vga_b[1]<=1'bz; vga_b[0]<=1'bz;;end endcase end endmodule |
实验操作
实验效果
- 接好VGA接口并把程序烧写进FPGA中
- 观察显示器的变化(在这我们就只提供3种颜色的图片)
大西瓜FPGA-->https://daxiguafpga.taobao.com
配套开发板:https://item.taobao.com/item.htm?spm=a1z10.1-c.w4004-24211932856.3.489d7241aCjspB&id=633897209972
博客资料、代码、图片、文字等属大西瓜FPGA所有,切勿用于商业! 若引用资料、代码、图片、文字等等请注明出处,谢谢!
每日推送不同科技解读,原创深耕解读当下科技,敬请关注微信公众号"科乎"。