VGA显示彩条和图片(FPGA)

一、VGA协议

VGA(Video Graphics Array)视频图形阵列是 IBM 于1987年提出的一个使用模拟信号的电脑显示标准。VGA具有分辨率高、显示速率快、颜色丰富等优点。VGA 接口不但是CRT 显示设备的标准接口,同样也是 LCD 液晶显示设备的标准接口,具有广泛的应用范围。
使用原理:显示器扫描方式分为逐行扫描和隔行扫描:逐行扫描是扫描从屏幕左上角一点开始,从左向右逐点扫描,每扫描完一行,电子束回到屏幕的左边下一行的起始位置,在这期间,每行结束时,用行同步信号进行同步;当扫描完所有的行,形成一帧,用场同步信号进行场同步,并使扫描回到屏幕左上方,开始下一帧。隔行扫描是指电子束扫描时每隔一行扫一线,完成一屏后在返回来扫描剩下的线,隔行扫描的显示器闪烁的厉害,会让使用者的眼睛疲劳。在此我们选择逐行扫描的方式。
 

二、使用设备

设备为DE2-115

TIPS:
具体实现方式请根据开发板来,就比如DE2-115这块板子,需要传输rgb三原色的数据和行场同步信号,也需要传输时钟、和消隐信号,且RBG是888位宽的,其他板子可能不一样,需要更改


三、模块设计

模块分为时钟模块、数据产生模块、和vga控制模块,时钟模块产生所需时钟,但这里并不是根据分辨率自动设置,而是写死在了640*480 @ 60HZ,所以为25M,如果要写其他的,自行更改
数据产生模块是根据vga控制模块传出来的位置来控制所显示的输出,再把所显示的数据输出回传到vga控制模块
vga控制模块就是输出vga协议的一些控制信号

四、代码

若显示彩条,可以直接复制下面代码,把数据生成模块厉的rom实例化和图片输出注释就行,再把彩条输出的输出取消注释

若是显示图片,需要调用rom核,并且需要将图片转成bmp文件,再把bmp转为mif文件,然后在调用rom的时候将图片转为的mif文件设为初始化文件,这样就可以通过地址来读取rom里存储的图片数据,当判断条件成立时,就可以把图片显示到显示屏上了。
top

module vga_top(
    input  wire       clk     ,
	 input  wire       rst_n   ,
	 
	 output wire       hsync   ,
	 output wire       vsync   ,
	 output wire [7:0] vga_r   ,
	 output wire [7:0] vga_g   ,
	 output wire [7:0] vga_b   ,
	 output wire       vga_clk ,
	 output wire       vga_blk
);

wire [23:0] data_dis;
wire [10:0] h_addr;
wire [10:0] v_addr;

vga_ctrl vga_ctrl(
    /*input  wire         */ .clk       (clk     ) ,
	 /*input  wire         */ .rst_n     (rst_n   ) ,
	 /*input  wire [23:0]  */ .data_dis  (data_dis) ,
	 /**/                              
	 /*output reg  [10:0]  */ .h_addr    (h_addr  ) ,
	 /*output reg  [10:0]  */ .v_addr    (v_addr  ) ,
	 /*output reg          */ .hsync     (hsync   ) ,
	 /*output reg          */ .vsync     (vsync   ) ,
	 /*output reg  [7:0]   */ .vga_r     (vga_r   ) ,
	 /*output reg  [7:0]   */ .vga_g     (vga_g   ) ,
	 /*output reg  [7:0]   */ .vga_b     (vga_b   ) ,
	                          .vga_blk   (vga_blk ) ,
	 /*output wire         */ .vga_clk   (vga_clk ) 
);


data_gen data_gen(
    /*input  wire         */ .vga_clk   (vga_clk ) ,
	 /*input  wire         */ .rst_n     (rst_n   ) ,
	 /*input  reg  [10:0]  */ .h_addr    (h_addr  ) ,
	 /*input  reg  [10:0]  */ .v_addr    (v_addr  ) ,
	 /**/                             
	 /*output reg  [23:0]  */ .data_dis  (data_dis) 
);

data_gen

module data_gen(
    input  wire          vga_clk     ,
	 input  wire          rst_n       ,
	 input  wire  [10:0]   h_addr     ,
	 input  wire  [10:0]   v_addr     ,
	 
	 output reg   [23:0]   data_dis   
);
wire [23:00] q_sig;
reg  [399:00] Memery [31:0];
parameter 
          BLACK    = 24'h000000,
          RED      = 24'hFF0000,
          GREEN    = 24'h00FF00,
			 BLUE     = 24'h0000FF,
			 YELLOW   = 24'hFFFF00,
			 SKY_BLUE = 24'h00FFFF,
			 PURPLE   = 24'hFF00FF,
			 GRAY     = 24'hC0C0C0,
			 WHITE    = 24'hFFFFFF;
parameter 
          H_VLD    = 640,
			 V_VLD    = 480,
			 PIC_W    = 400,
			 PIC_H    = 32,
			 X_START  = (H_VLD - PIC_W >> 1) - 1,
			 Y_START  = (V_VLD - PIC_H >> 1) - 1;
reg  [10:00] pix_x,pix_y;		 



always @(posedge vga_clk)begin
          Memery[0]  = 400'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
          Memery[1]  = 400'h000000000000000000000004000000000000000000000000000000000000000000000007000000000004000000000000;
			 Memery[2]  = 400'h000000000000000000000007E00000000007000000180000000000000000000000000007800000000007C000001E0000;
			 Memery[3]  = 400'h000000000000000000000007800000000007C00000180000000000000000080000000007800008000007800000180000;
		    Memery[4]  = 400'h0000000000001C000000000780001C0000078000001800000000000000003E000000000780003E000007800000080000;
          Memery[5]  = 400'h01FFFFFFFFFFFF000FFFFFFFFFFFFF0000078000200C000000FFFFFFFFFFFF8007FFFFFFFFFFFF8000078000380C0000;
          Memery[6]  = 400'h00400003C00000000200000780000000000780007E0C000000000003C00000000000000780000000000780007E060000;
          Memery[7]  = 400'h00000003C00000000000000780000000000780007806000000000003C0000000000000078000C0000007800078060000;
          Memery[8]  = 400'h00000003C0000000000000078001E00000078300F007000000000003C0000000007FFFFFFFFFF00000078780F0030000;
          Memery[9]  = 400'h00000003C0000000003FFFFFFFFFF8001FFFFFC0E003800000000003C000000000180007800000000FFFFFE0E0038000;
          Memery[10] = 400'h00000003C00000000000000780000000000F8001C001C00000000003C00000000000000780000000000F8001C001C000;
          Memery[11] = 400'h00000003C00000000000000780000180000F8003C001E00000000003C000000000000007800003C0000F80038000F000;
			 Memery[12] = 400'h00000003C000000000000007800007E0000F80030000F80000000003C00000003FFFFFFFFFFFFFF0001F800700007800;
			 Memery[13] = 400'h00000003C00000001FFFFFFFFFFFFFF8001F800600007C0000000003C00000000C00000000000000001FC00E00003E00;
		    Memery[14] = 400'h00000003C00000000000000000000000001FF00C00001F8000000003C00000000001000000000000003FBC1800001FC0;
	       Memery[15] = 400'h00000003C00060000000C00000060000003F9E1803800FF800000003C000F0000000FFFFFFFF8000003F9F3003C007C0;
          Memery[16] = 400'h003FFFFFFFFFF8000000FFFFFFFF8000007F8F2003F00300001FFFFFFFFFFC000000E000000F000000778FC003E00000;
          Memery[17] = 400'h000C0003C00000000000E000000F00000077878007C0000000000003C00000000000E000000F000000E7870007800000;
          Memery[18] = 400'h00000003C00000000000E000000F000000E783000700000000000003C00000000000E000000F000000C780000F000000;
          Memery[19] = 400'h00000003C00000000000FFFFFFFF000001C780000E00000000000003C00000000000FFFFFFFF0000018780001E000000;
          Memery[20] = 400'h00000003C00000000000E000000F0000038780001C00000000000003C00000000000E000000F0000030780001C000000;
          Memery[21] = 400'h00000003C00000000000E000000F0000070780003800000000000003C00000000000E000000F000006078000380C0000;
			 Memery[22] = 400'h00000003C00000000000E000000F00000C0780007006000000000003C00000000000E000000F00000807800070030000;
			 Memery[23] = 400'h00000003C00000000000FFFFFFFF000018078000E003800000000003C00000000000FFFFFFFF000010078000E001C000;
		    Memery[24] = 400'h00000003C00000000000E000000F000000078000C001E00000000003C00000000000E000000F0000000780018000F000;
	       Memery[25] = 400'h00000003C00000000000E000000F0000000780018000F00000000003C00000000000E000000F00000007800300007800;
          Memery[26] = 400'h00000003C00001000000E000000F00000007800700007C0000000003C00003800000E000000F00000007800E00007C00;
          Memery[27] = 400'h00000003C00007C00000E000000F00000007801E7FFFFE001FFFFFFFFFFFFFE00000E0001E0F00000007803FFFFF3E00;
          Memery[28] = 400'h0FFFFFFFFFFFFFF00000E0000FFF00000007801FFE003E0004000000000000000000E00001FF00000007800FC0001E00;
          Memery[29] = 400'h00000000000000000000E000007E00000007800E00001C0000000000000000000000E000003C00000007800000001800;	
          Memery[30] = 400'h00000000000000000000E000003800000007800000000000000000000000000000008000002000000004000000000000;
          Memery[31] = 400'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
end  
always @(posedge vga_clk or negedge rst_n)begin
    if(!rst_n)begin
	    pix_x <= 11'd0;
		 pix_y <= 11'd0;
	 end
	 else if((h_addr >= X_START && h_addr < X_START + PIC_W)&&(v_addr >= Y_START && v_addr < Y_START + PIC_W))begin
	    pix_x <= h_addr - X_START;
		 pix_y <= v_addr - Y_START;
	 end      
	 else begin
	    pix_x <= 11'h7FF;
		 pix_y <= 11'h7FF;
	 end
end  
                         		 
always @(posedge vga_clk or negedge rst_n)begin
    if(!rst_n)begin
	    data_dis <= WHITE;
	 end
	 else begin
	    case(h_addr)
		    0  : data_dis <= BLACK   ;
	       80 : data_dis <= RED     ;
			 160: data_dis <= GREEN   ;
			 240: data_dis <= BLUE    ;
			 320: data_dis <= YELLOW  ;
			 400: data_dis <= SKY_BLUE;
			 480: data_dis <= PURPLE  ;
			 560: data_dis <= GRAY    ;
			 default: data_dis <= data_dis;
		 endcase
	 end                       
end
endmodule 

ctrl

`define vga_640_480
`include "vga_param.v"
module vga_ctrl(
 input  wire        clk      ,
 input  wire        rst_n    ,
 input  wire [23:0] data_dis ,
 
 output reg  [10:0] h_addr   ,//数据有效显示区域行地址
 output reg  [10:0] v_addr   ,//数据有效显示区域场地址
 
 output reg         hsync    ,
 output reg         vsync    ,
 
 output reg  [7:0]  vga_r    ,
 output reg  [7:0]  vga_g    ,
 output reg  [7:0]  vga_b    ,
 output reg         vga_blk  ,
 output wire        vga_clk
);

parameter  H_SYNC_STA = 1,
           H_SYNC_STO = `H_Sync_Time,
           H_DATA_STA = `H_Sync_Time + `H_Back_Porch + `H_Left_Border,
			  H_DATA_STO = `H_Sync_Time + `H_Back_Porch + `H_Left_Border + `H_Data_Time;
			  
parameter  V_SYNC_STA = 1,
           V_SYNC_STO = `V_Sync_Time,
           V_DATA_STA = `V_Sync_Time + `V_Back_Porch + `V_Top_Border,
			  V_DATA_STO = `V_Sync_Time + `V_Back_Porch + `V_Top_Border + `V_Data_Time;

 reg   [11:0]   cnt_h_addr;//行地址计数器
 wire           add_h_addr ;
 wire           end_h_addr ;
 
 reg   [11:0]   cnt_v_addr;//列地址计数器
 wire           add_v_addr ;
 wire           end_v_addr ;
 wire           clk_25     ;
 pll	pll_inst (
	.areset ( ~rst_n ),
	.inclk0 ( clk    ),
	.c0 ( clk_25 )
	);

always@(posedge vga_clk or negedge rst_n)begin
    if(!rst_n)begin
        cnt_h_addr <= 12'd0;
	 end
	 else if(add_h_addr)begin
	      if(end_h_addr)begin
			   cnt_h_addr <= 12'd0;
			end
			else begin
			   cnt_h_addr <= cnt_h_addr + 12'd1;
			end
	 end
    else begin
	     cnt_h_addr <= 12'd0;
	 end
end

assign add_h_addr = 1'b1;
assign end_h_addr = add_h_addr && cnt_h_addr >= `H_Total_Time - 1;

always@(posedge vga_clk or negedge rst_n)begin
    if(!rst_n)begin
        cnt_v_addr <= 12'd0;
	 end
	 else if(add_v_addr)begin
	      if(end_v_addr)begin
			   cnt_v_addr <= 12'd0;
			end
			else begin
			   cnt_v_addr <= cnt_v_addr + 12'd1;
			end
	 end
    else begin
	     cnt_v_addr <= cnt_v_addr;
	 end
end

assign add_v_addr = end_h_addr;
assign end_v_addr = add_v_addr && cnt_v_addr >= `V_Total_Time - 1;

always@(posedge vga_clk or negedge rst_n)begin
    if(!rst_n)begin
       hsync <= 1'b1;
	 end
	 else if(cnt_h_addr == H_SYNC_STA- 1)begin
	    hsync <= 1'b0;
	 end
	 else if(cnt_h_addr == H_SYNC_STO - 1)begin
	    hsync <= 1'b1;
	 end
    else begin
	    hsync <= hsync;
	 end
end

always@(posedge vga_clk or negedge rst_n)begin
    if(!rst_n)begin
       vsync <= 1'b1;
	 end
	 else if(cnt_v_addr == V_SYNC_STA - 1)begin
	    vsync <= 1'b0;
	 end
	 else if(cnt_v_addr == V_SYNC_STO - 1)begin
	    vsync <= 1'b1;
	 end
    else begin
	    vsync <= vsync;
	 end
end

assign vga_clk = ~clk_25;

always@(posedge vga_clk or negedge rst_n)begin
    if(!rst_n)begin
       h_addr <= 11'd0;
	 end
	 else if((cnt_h_addr >= H_DATA_STA - 1) && (cnt_h_addr <= H_DATA_STO -1) )begin
	    h_addr <= cnt_h_addr - H_DATA_STA - 1;
	 end
    else begin
	    h_addr <= 11'd0;
	 end
end

always@(posedge vga_clk or negedge rst_n)begin
    if(!rst_n)begin
       v_addr <= 11'd0;
	 end
	 else if((cnt_v_addr >= V_DATA_STA - 1) && (cnt_v_addr <= V_DATA_STO -1)  )begin
	    v_addr <= cnt_v_addr - V_DATA_STA - 1;
	 end
    else begin
	    v_addr <= 11'd0;
	 end
end

always@(posedge vga_clk or negedge rst_n)begin
    if(!rst_n)begin
       vga_r <= 8'b0;
		 vga_g <= 8'b0;
		 vga_b <= 8'b0;
		 vga_blk <= 1'b0;	 
		 end
	 else if((cnt_h_addr >= H_DATA_STA - 1) && (cnt_h_addr <= H_DATA_STO -1) &&
	         (cnt_v_addr >= V_DATA_STA - 1) && (cnt_v_addr <= V_DATA_STO -1) )begin
	    vga_r <= data_dis[23:16];
		 vga_g <= data_dis[15:8];
		 vga_b <= data_dis[7:0];
		 vga_blk <= 1'b1;
	 end
    else begin
	    vga_r <= 8'b0;
		 vga_g <= 8'b0;
		 vga_b <= 8'b0;
		 vga_blk <= 1'b0;
	 end
end

endmodule

 

 

五、总结

毕竟是初学vga协议,还是有很多迷迷糊糊的地方。但结果一段时间的沉淀,之后应该会有所理解。


版权声明:本文为w798214705原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。