DE2-115的VGA显示(字符,彩条,图片)

一、TCL文件

这里给出DE2-115开发板的tcl文件

在这里插入图片描述
加入后选中文件然后Run
在这里插入图片描述

package require ::quartus::project

set_location_assignment PIN_G13 -to VGA_HS
set_location_assignment PIN_G13 -to VGA_HS
set_location_assignment PIN_C13 -to VGA_VS
set_location_assignment PIN_D12 -to VGA_B[7]
set_location_assignment PIN_D11 -to VGA_B[6]
set_location_assignment PIN_C12 -to VGA_B[5]
set_location_assignment PIN_A11 -to VGA_B[4]
set_location_assignment PIN_B11 -to VGA_B[3]
set_location_assignment PIN_C11 -to VGA_B[2]
set_location_assignment PIN_A10 -to VGA_B[1]
set_location_assignment PIN_B10 -to VGA_B[0]
set_location_assignment PIN_F11 -to VGA_BLANK
set_location_assignment PIN_A12 -to VGA_CLK
set_location_assignment PIN_C9 -to VGA_G[7]
set_location_assignment PIN_F10 -to VGA_G[6]
set_location_assignment PIN_B8 -to VGA_G[5]
set_location_assignment PIN_C8 -to VGA_G[4]
set_location_assignment PIN_H12 -to VGA_G[3]
set_location_assignment PIN_F8 -to VGA_G[2]
set_location_assignment PIN_G11 -to VGA_G[1]
set_location_assignment PIN_G8 -to VGA_G[0]
set_location_assignment PIN_H10 -to VGA_R[7]
set_location_assignment PIN_H8 -to VGA_R[6]
set_location_assignment PIN_J12 -to VGA_R[5]
set_location_assignment PIN_G10 -to VGA_R[4]
set_location_assignment PIN_F12 -to VGA_R[3]
set_location_assignment PIN_D10 -to VGA_R[2]
set_location_assignment PIN_E11 -to VGA_R[1]
set_location_assignment PIN_E12 -to VGA_R[0]
set_location_assignment PIN_C10 -to VGA_SYNC


二、VGA显示彩色条纹

代码实现

分辨率选择文件

`define 	vga_640_480

`ifdef	vga_640_480
	`define	H_Right_Border 8
	`define	H_Front_Porch  8
	`define	H_Sync_Time    96
	`define	H_Back_Porch	40
	`define	H_Left_Border	8
	`define	H_Data_Time		640
	`define	H_Total_Time	800
	`define	V_Bottom_Border	8
	`define	V_Front_Porch	2
	`define	V_Sync_Time		2
	`define	V_Back_Porch	25
	`define	V_Top_Border	8
	`define	V_Data_Time		480
	`define	V_Total_Time	525

`elsif	vga_1920_1080
	`define	H_Right_Border 0
	`define	H_Front_Porch  88
	`define	H_Sync_Time    44
	`define	H_Back_Porch	148
	`define	H_Left_Border	0
	`define	H_Data_Time		1920
	`define	H_Total_Time	2200
	`define	V_Bottom_Borde	0
	`define	V_Front_Porch	4
	`define	V_Sync_Time		5
	`define	V_Back_Porch	36
	`define	v_Top_Border	2
	`define	v_Data_Time		1080
	`define	v_Total_Time	1125

	
`endif

驱动

//`define 	vga_1920_1080L
`include "vga_para.v"

module vga_drive(

	input						clk			, //640*480--25.2M
	input						rst_n			,
	input	 		[15:0]	data_display,
	
	output reg	[11:0] 	h_addr		,//数据有效显示区域行地址
	output reg	[11:0]	v_addr		,//数据有效显示区域场地址
	
	output reg				vsync			,
	output reg				hsync			,
	output reg 	[4:0]		vga_r			,
	output reg 	[5:0]		vga_g			,
	output reg 	[4:0]		vga_b			,
	output reg				vga_blk		,//消隐信号
	output					vga_clk		,
	output 					sync			
	
);

wire				clk_25M;	
wire				locked;

pll25	pll_inst (
	.areset 		( ~rst_n ),
	.inclk0     ( clk ),
	.c0 		   ( clk_25M ),
	);
	


assign	vga_clk = clk_25M;

assign	sync = hsync && vsync;

parameter	H_SYNC_STA = 1;
parameter   H_SYNC_STO = `H_Sync_Time;
parameter   H_Data_STA = `H_Right_Border + `H_Front_Porch + `H_Sync_Time;
parameter   H_Data_STO = `H_Right_Border + `H_Front_Porch + `H_Sync_Time + `H_Data_Time;

parameter   V_SYNC_STA = 1;
parameter   V_SYNC_STO = `V_Sync_Time;
parameter   V_Data_STA = `V_Bottom_Border + `V_Front_Porch + `V_Sync_Time;
parameter   V_Data_STO = `V_Bottom_Border + `V_Front_Porch + `V_Sync_Time + `V_Data_Time;


wire				add_h_addr		;
wire				end_h_addr		;


reg	[11:0]	cnt_v_addr;//行地址寄存器
wire				add_cnt_v_addr	;
wire				end_cnt_v_addr	;

reg	[11:0]	cnt_h_addr		;//场地址寄存器
wire				add_cnt_h_addr ;
wire				end_cnt_h_addr ;

always@(posedge	vga_clk or negedge	rst_n)begin
	if(!rst_n)begin
		cnt_h_addr <= 12'd0;
	end
	else if(add_cnt_h_addr)begin
		if(end_cnt_h_addr)
			cnt_h_addr <= 12'd0;
		else
			cnt_h_addr <= cnt_h_addr + 12'd1;
	end
	else begin
		cnt_h_addr <= 12'd0;
	end
		
	
end
assign	add_cnt_h_addr = 1'b1;
assign	end_cnt_h_addr = add_cnt_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_cnt_v_addr)begin
		if(end_cnt_v_addr)
			cnt_v_addr <= 12'd0;
		else
			cnt_v_addr <= cnt_v_addr + 12'd1;
	end
	else begin
		cnt_v_addr <= cnt_v_addr;
	end
		
	
end
assign	add_cnt_v_addr = end_cnt_h_addr;
assign	end_cnt_v_addr = add_cnt_v_addr && cnt_v_addr >= `V_Total_Time - 1; 


//行场同步信号
always@(posedge	vga_clk or negedge	rst_n)begin
	if(!rst_n)
		hsync <= 1'b1;
	else if(cnt_h_addr == H_SYNC_STA -1)
		hsync <= 1'b0;
	else if(cnt_h_addr == H_SYNC_STO-1)
		hsync <= 1'b1;
	else
		hsync <= hsync;
end

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



//有效显示区域
always@(posedge vga_clk or negedge rst_n)begin
	if(!rst_n)
		h_addr <= 12'b0;
	else	if(cnt_h_addr >= H_Data_STA && cnt_h_addr <= H_Data_STO)begin
		h_addr <= cnt_h_addr - H_Data_STA ;
		vga_blk <= 1'b1;
	end
   else begin
		h_addr <= 12'b0;
		vga_blk <= 1'b0;
	end
	
end
always@(posedge vga_clk or negedge rst_n)begin
	if(!rst_n)
		v_addr <= 12'b0;
	else	if(cnt_v_addr >= V_Data_STA  && cnt_v_addr <= V_Data_STO)begin
		v_addr <= cnt_v_addr - V_Data_STA;
	end
   else begin
		v_addr <= 12'b0;
	end
	
end


//数据显示
always@(posedge vga_clk or negedge rst_n)begin
	if(!rst_n)begin
		vga_r <= 5'h0;
		vga_g <= 6'h0;
		vga_b <= 5'h0;
	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_display[15:11];	//data_display[23-:8]
		vga_g <= data_display[10:5];	//data_display[15-:8]
		vga_b <= data_display[4:0];	//data_display[7-:8]
	end
	else begin
		vga_r <= 5'h0;
		vga_g <= 6'h0;
		vga_b <= 5'h0;
	end
		
end


endmodule


显示彩条

module data_gen(	
	input								clk			, //640*480--25.2M
	input								rst_n			,
	input 				[11:0] 	h_addr		,//数据有效显示区域行地址
	input 				[11:0]	v_addr		,//数据有效显示区域场地output	
	
	output	reg 		[15:0]	data_display
);

localparam	red    = 16'd63488;
localparam	orange = 16'd64384;
localparam	yellow = 16'd65472;
localparam	green  = 16'd1024;
localparam	blue   = 16'd31;
localparam	indigo = 16'd18448;
localparam	purple = 16'd32784;
localparam	white  = 16'd65503;
localparam	black  = 16'd0;

parameter	height = 78; // 图片高度
parameter	width  = 122; // 图片宽度

 reg [127:0] char_line [15:0];
 reg [11:0]	pix,piy;
 
reg			[ 13:0 ]		rom_address				; // ROM地址
wire			[ 15:0 ]		rom_data				; // 图片数据
wire							flag_begin_h			    ; // 图片显示行
wire							flag_begin_v			    ; // 图片显示列

always@(posedge	clk or negedge rst_n)begin
	if(!rst_n)
		data_display <= white;
	else	
		case(h_addr)
			0:		data_display <= black  	;
			80:	data_display <= red    	;
			160:	data_display <= green  	;
			240:	data_display <= blue	 	;
			320:	data_display <= yellow 	;
			400:	data_display <= orange;
			480:	data_display <= purple  ;
			560:	data_display <= indigo		;			
			default: data_display <= data_display;
		endcase
end

parameter	H_LED = 640,V_LED = 480, PIC_W = 128 ,PIC_H = 16;
parameter	x_start = (H_LED - PIC_W >> 1) -1;
parameter	y_start = (V_LED - PIC_H >> 1) -1;



always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		pix <= 12'd0;
		piy <= 12'd0;
	end
	else if((h_addr >= x_start && h_addr < x_start + PIC_W)&&
			 (v_addr >= y_start && v_addr < y_start + PIC_H))begin
		pix <= h_addr - x_start;
		piy <= v_addr - y_start;
   end
	else begin
		pix <= 12'h7ff;
		piy <= 12'h7ff;
	end

end

// always@(posedge clk or negedge	rst_n)begin
// 	if(!rst_n)begin
// 		data_display <= white;
// 	end
// 	else if(pix != 12'h7ff &&piy != 12'h7ff)begin
// 		if(char_line[piy][128-pix])begin
// 			data_display <= white;
// 		end
// 		else
// 			data_display <= black;
// 	end

// end

endmodule

顶层文件

module	top(
input						clk,
input						rst_n,
	
 output	 				vsync,	
 output 					hsync,		
 output  	[4:0]		vga_r,		
 output  	[5:0]		vga_g,		
 output  	[4:0]		vga_b,		
 output					vga_clk,
 output					vga_blk,
 output					sync
);





wire	[11:0]   h_addr;
wire	[11:0]   v_addr;
wire	[15:0]	data_display;



vga_drive  inst_vga_drive(
.clk				(clk), //640*480--25.2M
.rst_n			(rst_n),
.data_display	(data_display),

.h_addr			(h_addr),//数据有效显示区域行地址
.v_addr			(v_addr),//数据有效显示区域场地址

.vsync			(vsync),
.hsync			(hsync),
.vga_r			(vga_r),
.vga_g			(vga_g),
.vga_b			(vga_b),
.vga_blk			(vga_blk),
.vga_clk     	(vga_clk),
.sync				(sync)
	
);

data_gen		inst_data_gen(	
.clk				(vga_clk), //640*480--25.2M
.rst_n			(rst_n),
.h_addr			(h_addr),//数据有效显示区域行地址
.v_addr			(v_addr),//数据有效显示区域场地output	

.data_disp	(data_display)
);





endmodule


三、VGA显示字符

代码实现

module VGA_colorbar_test(
    OSC_50,     //原CLK2_50时钟信号
    VGA_CLK,    //VGA自时钟
    VGA_HS,     //行同步信号
    VGA_VS,     //场同步信号
    VGA_BLANK,  //复合空白信号控制信号  当BLANK为低电平时模拟视频输出消隐电平,此时从R9~R0,G9~G0,B9~B0输入的所有数据被忽略
    VGA_SYNC,   //符合同步控制信号      行时序和场时序都要产生同步脉冲
    VGA_R,      //VGA绿色
    VGA_B,      //VGA蓝色
    VGA_G);     //VGA绿色
 input OSC_50;     //外部时钟信号CLK2_50
 output VGA_CLK,VGA_HS,VGA_VS,VGA_BLANK,VGA_SYNC;
 output [7:0] VGA_R,VGA_B,VGA_G;
 parameter H_FRONT = 16;     //行同步前沿信号周期长
 parameter H_SYNC = 96;      //行同步信号周期长
 parameter H_BACK = 48;      //行同步后沿信号周期长
 parameter H_ACT = 640;      //行显示周期长
 parameter H_BLANK = H_FRONT+H_SYNC+H_BACK;        //行空白信号总周期长
 parameter H_TOTAL = H_FRONT+H_SYNC+H_BACK+H_ACT;  //行总周期长耗时
 parameter V_FRONT = 11;     //场同步前沿信号周期长
 parameter V_SYNC = 2;       //场同步信号周期长
 parameter V_BACK = 31;      //场同步后沿信号周期长
 parameter V_ACT = 480;      //场显示周期长
 parameter V_BLANK = V_FRONT+V_SYNC+V_BACK;        //场空白信号总周期长
 parameter V_TOTAL = V_FRONT+V_SYNC+V_BACK+V_ACT;  //场总周期长耗时
 reg [10:0] H_Cont;        //行周期计数器
 reg [10:0] V_Cont;        //场周期计数器
 wire [7:0] VGA_R;         //VGA红色控制线
 wire [7:0] VGA_G;         //VGA绿色控制线
 wire [7:0] VGA_B;         //VGA蓝色控制线
 reg VGA_HS;
 reg VGA_VS;
 reg [10:0] X;             //当前行第几个像素点
 reg [10:0] Y;             //当前场第几行
 reg CLK_25;
 always@(posedge OSC_50)begin 
      CLK_25=~CLK_25;         //时钟
 end 

 assign VGA_SYNC = 1'b0;   //同步信号低电平
 assign VGA_BLANK = ~((H_Cont<H_BLANK)||(V_Cont<V_BLANK));  //当行计数器小于行空白总长或场计数器小于场空白总长时,空白信号低电平

 assign CLK_to_DAC = CLK_25;
assign VGA_CLK = ~CLK_to_DAC;  //VGA时钟等于CLK_25取反

 always@(posedge CLK_to_DAC)begin
        if(H_Cont<H_TOTAL)           //如果行计数器小于行总时长
            H_Cont<=H_Cont+1'b1;      //行计数器+1
        else H_Cont<=0;              //否则行计数器清零
        if(H_Cont==H_FRONT-1)        //如果行计数器等于行前沿空白时间-1
            VGA_HS<=1'b0;             //行同步信号置0
        if(H_Cont==H_FRONT+H_SYNC-1) //如果行计数器等于行前沿+行同步-1
            VGA_HS<=1'b1;             //行同步信号置1
        if(H_Cont>=H_BLANK)          //如果行计数器大于等于行空白总时长
            X<=H_Cont-H_BLANK;        //X等于行计数器-行空白总时长   (X为当前行第几个像素点)
        else X<=0;                   //否则X为0
end

 always@(posedge VGA_HS)begin
        if(V_Cont<V_TOTAL)           //如果场计数器小于行总时长
            V_Cont<=V_Cont+1'b1;      //场计数器+1
        else V_Cont<=0;              //否则场计数器清零
        if(V_Cont==V_FRONT-1)       //如果场计数器等于场前沿空白时间-1
            VGA_VS<=1'b0;             //场同步信号置0
        if(V_Cont==V_FRONT+V_SYNC-1) //如果场计数器等于行前沿+场同步-1
            VGA_VS<=1'b1;             //场同步信号置1
        if(V_Cont>=V_BLANK)          //如果场计数器大于等于场空白总时长
            Y<=V_Cont-V_BLANK;        //Y等于场计数器-场空白总时长    (Y为当前场第几行)  
        else Y<=0;                   //否则Y为0
end

 reg valid_yr;

 always@(posedge CLK_to_DAC)begin
    if(V_Cont == 10'd32)         //场计数器=32时
        valid_yr<=1'b1;           //行输入激活
    else if(V_Cont==10'd512)     //场计数器=512时
        valid_yr<=1'b0;           //行输入冻结
 end

 wire valid_y=valid_yr;       //连线   
 reg valid_r;     

 always@(posedge CLK_to_DAC)begin
    if((H_Cont == 10'd32)&&valid_y)     //行计数器=32时
        valid_r<=1'b1;                   //像素输入激活
    else if((H_Cont==10'd512)&&valid_y) //行计数器=512时 
        valid_r<=1'b0;                   //像素输入冻结
 end

 wire valid = valid_r;               //连线
 assign x_dis=X;       //连线X
 assign y_dis=Y;       //连线Y
 // reg[7:0] char_bit;
 // always@(posedge CLK_to_DAC)
 //     if(X==10'd144)char_bit<=9'd240;   //当显示到144像素时准备开始输出图像数据
 //     else if(X>10'd144&&X<10'd384)     //左边距屏幕144像素到416像素时    416=144+272(图像宽度)
 //         char_bit<=char_bit-1'b1;       //倒着输出图像信息
         
 reg[29:0] vga_rgb;                //定义颜色缓存
 always@(posedge CLK_to_DAC) begin
     if(X>=0&&X<200)begin    //X控制图像的横向显示边界:左边距屏幕左边144像素  右边界距屏幕左边界416像素
         vga_rgb<=30'hffffffffff;   //白色
     end
     else if(X>=200&&X<400)begin
         vga_rgb<=30'hf00ff65f1f;   
     end
     else if(X>=400&&X<600)begin
         vga_rgb<=30'h9563486251; 
     end
     else begin
         vga_rgb<=30'h5864928654; 
     end
 end
 assign VGA_R=vga_rgb[23:16];
 assign VGA_G=vga_rgb[15:8];
 assign VGA_B=vga_rgb[7:0];
endmodule



汉字点阵生成

PCtoLCD2002完美版,可以到网上找一下,我是在正点原子官网工具包中找到的,多找几个资料包一般都有。
在这里插入图片描述
注意,这里如果直接生成输入后生成的字模不是连续的,无法显示在一行中,即每一个字符都是从左上角开始显示,会乱正确步骤为

  • 输入想要的字符

  • 另存为图片
    在这里插入图片描述

  • 打开图片
    在这里插入图片描述

  • 点击齿轮,调整显示的点阵行数据个数(匹配代码中的高度),前后缀
    在这里插入图片描述

代码

module VGA_test(
OSC_50,     //原CLK2_50时钟信号
VGA_CLK,    //VGA自时钟
VGA_HS,     //行同步信号
VGA_VS,     //场同步信号
VGA_BLANK,  //复合空白信号控制信号  当BLANK为低电平时模拟视频输出消隐电平,此时从R9~R0,G9~G0,B9~B0输入的所有数据被忽略
VGA_SYNC,   //符合同步控制信号      行时序和场时序都要产生同步脉冲
VGA_R,      //VGA绿色
VGA_B,      //VGA蓝色
VGA_G);     //VGA绿色
 input OSC_50;     //外部时钟信号CLK2_50
 output VGA_CLK,VGA_HS,VGA_VS,VGA_BLANK,VGA_SYNC;
 output [7:0] VGA_R,VGA_B,VGA_G;
 parameter H_FRONT = 16;     //行同步前沿信号周期长
 parameter H_SYNC = 96;      //行同步信号周期长
 parameter H_BACK = 48;      //行同步后沿信号周期长
 parameter H_ACT = 640;      //行显示周期长
 parameter H_BLANK = H_FRONT+H_SYNC+H_BACK;        //行空白信号总周期长
 parameter H_TOTAL = H_FRONT+H_SYNC+H_BACK+H_ACT;  //行总周期长耗时
 parameter V_FRONT = 11;     //场同步前沿信号周期长
 parameter V_SYNC = 2;       //场同步信号周期长
 parameter V_BACK = 31;      //场同步后沿信号周期长
 parameter V_ACT = 480;      //场显示周期长
 parameter V_BLANK = V_FRONT+V_SYNC+V_BACK;        //场空白信号总周期长
 parameter V_TOTAL = V_FRONT+V_SYNC+V_BACK+V_ACT;  //场总周期长耗时
 reg [10:0] H_Cont;        //行周期计数器
 reg [10:0] V_Cont;        //场周期计数器
 wire [7:0] VGA_R;         //VGA红色控制线
 wire [7:0] VGA_G;         //VGA绿色控制线
 wire [7:0] VGA_B;         //VGA蓝色控制线
 reg VGA_HS;
 reg VGA_VS;
 reg [10:0] X;             //当前行第几个像素点
 reg [10:0] Y;             //当前场第几行
 reg CLK_25;
 always@(posedge OSC_50)
    begin 
      CLK_25=~CLK_25;         //时钟
    end 
    assign VGA_SYNC = 1'b0;   //同步信号低电平
    assign VGA_BLANK = ~((H_Cont<H_BLANK)||(V_Cont<V_BLANK));  //当行计数器小于行空白总长或场计数器小于场空白总长时,空白信号低电平
    assign CLK_to_DAC = CLK_25;
	assign VGA_CLK = ~CLK_to_DAC;  //VGA时钟等于CLK_25取反
    
 always@(posedge CLK_to_DAC)
    begin
        if(H_Cont<H_TOTAL)           //如果行计数器小于行总时长
            H_Cont<=H_Cont+1'b1;      //行计数器+1
        else H_Cont<=0;              //否则行计数器清零
        if(H_Cont==H_FRONT-1)        //如果行计数器等于行前沿空白时间-1
            VGA_HS<=1'b0;             //行同步信号置0
        if(H_Cont==H_FRONT+H_SYNC-1) //如果行计数器等于行前沿+行同步-1
            VGA_HS<=1'b1;             //行同步信号置1
        if(H_Cont>=H_BLANK)          //如果行计数器大于等于行空白总时长
            X<=H_Cont-H_BLANK;        //X等于行计数器-行空白总时长   (X为当前行第几个像素点)
        else X<=0;                   //否则X为0
    end
 always@(posedge VGA_HS)
    begin
        if(V_Cont<V_TOTAL)           //如果场计数器小于行总时长
            V_Cont<=V_Cont+1'b1;      //场计数器+1
        else V_Cont<=0;              //否则场计数器清零
        if(V_Cont==V_FRONT-1)       //如果场计数器等于场前沿空白时间-1
            VGA_VS<=1'b0;             //场同步信号置0
        if(V_Cont==V_FRONT+V_SYNC-1) //如果场计数器等于行前沿+场同步-1
            VGA_VS<=1'b1;             //场同步信号置1
        if(V_Cont>=V_BLANK)          //如果场计数器大于等于场空白总时长
            Y<=V_Cont-V_BLANK;        //Y等于场计数器-场空白总时长    (Y为当前场第几行)  
        else Y<=0;                   //否则Y为0
    end
    reg valid_yr;
 always@(posedge CLK_to_DAC)
    if(V_Cont == 10'd32)         //场计数器=32时
        valid_yr<=1'b1;           //行输入激活
    else if(V_Cont==10'd512)     //场计数器=512时
        valid_yr<=1'b0;           //行输入冻结
    wire valid_y=valid_yr;       //连线   
    reg valid_r;            
 always@(posedge CLK_to_DAC)   
    if((H_Cont == 10'd32)&&valid_y)     //行计数器=32时
        valid_r<=1'b1;                   //像素输入激活
    else if((H_Cont==10'd512)&&valid_y) //行计数器=512时 
        valid_r<=1'b0;                   //像素输入冻结
    wire valid = valid_r;               //连线
    wire[10:0] x_dis;     //像素显示控制信号
    wire[10:0] y_dis;     //行显示控制信号
    assign x_dis=X;       //连线X
    assign y_dis=Y;       //连线Y
        parameter
    //16*3 + 8*12 =144
    char_line00=240'h020008102028000000000000000000000000,
    char_line01=240'h04001D102024000000000000000000000000,
    char_line02=240'h0800F0902020000000000000000000000000,
    char_line03=240'h7FFC109027FE183C3C08187E181818180818,
    char_line04=240'h400410102420244242382442242424243824,
    char_line05=240'h4004FD10FC20404242084204424042400840,
    char_line06=240'h47C410902424400242084204424042400840,
    char_line07=240'h4444389027A45C0402084208425C425C085C,
    char_line08=240'h4444341024A4621804084208426242620862,
    char_line09=240'h4444501E24A8420408084210424242420842,
    char_line0a=240'h444453F024A8420210084210424242420842,
    char_line0b=240'h47C490103C90424220084210424242420842,
    char_line0c=240'h44441010E692224242082410242224220822,
    char_line0d=240'h40041010492A1C3C7E3E1810181C181C3E1C,
    char_line0e=240'h401410100846000000000000000000000000,
    char_line0f=240'h400810101082000000000000000000000000;

    reg[7:0] char_bit;
    always@(posedge CLK_to_DAC)
        if(X==10'd180)char_bit<=9'd240;   //当显示到144像素时准备开始输出图像数据
        else if(X>10'd180&&X<10'd420)     //左边距屏幕144像素到416像素时    416=144+272(图像宽度)
            char_bit<=char_bit-1'b1;       //倒着输出图像信息
            
    reg[29:0] vga_rgb;                //定义颜色缓存
    always@(posedge CLK_to_DAC) 
        if(X>10'd180&&X<10'd420)    //X控制图像的横向显示边界:左边距屏幕左边144像素  右边界距屏幕左边界416像素
            begin case(Y)            //Y控制图像的纵向显示边界:从距离屏幕顶部160像素开始显示第一行数据
                10'd200:
                if(char_line00[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;  //如果该行有数据 则颜色为红色
                else vga_rgb<=30'b0000000000_0000000000_0000000000;                      //否则为黑色
                10'd201:
                if(char_line01[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd202:
                if(char_line02[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd203:
                if(char_line03[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd204:
                if(char_line04[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000; 
                10'd205:
                if(char_line05[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd206:
                if(char_line06[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000; 
                10'd207:
                if(char_line07[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd208:
                if(char_line08[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000; 
                10'd209:
                if(char_line09[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd210:
                if(char_line0a[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd211:
                if(char_line0b[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd212:
                if(char_line0c[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd213:
                if(char_line0d[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd214:
                if(char_line0e[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                10'd215:
                if(char_line0f[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
                else vga_rgb<=30'b0000000000_0000000000_0000000000;
                default:vga_rgb<=30'h0000000000;   //默认颜色黑色
            endcase 
        end
    else vga_rgb<=30'h000000000;             //否则黑色
    assign VGA_R=vga_rgb[23:16];
    assign VGA_G=vga_rgb[15:8];
    assign VGA_B=vga_rgb[7:0];
endmodule



四、VGA显示图片

配置IP核PLL

我们板子上所固有的时钟是50M的,但VGA协议所使用的是25M的,所以我们要调用IP核——PLL来实现时钟分频
1.找到PLL核,点击ALTPLL
在这里插入图片描述
2.自定义保存路径,点击OK

在这里插入图片描述
点击三个小点,最好在output_files目录下新建文件夹ipcore,然后设置相应的文件名
在这里插入图片描述

3.基础时钟设置为50M
在这里插入图片描述
4.取消输出使能

在这里插入图片描述

5.一直保持默认,下一步,直到出现配置C0,选择二分频得到25MHz时钟
在这里插入图片描述
6、例化一个模板便于使用

在这里插入图片描述
可以直接复制后使用,但注意不要添加到工程目录中
在这里插入图片描述

配置ip核ROM

首先我们要有一张图片,最好小一点,转换为mif格式,这也是正点原子的工具
在这里插入图片描述
在转换后的文件中我们可以看到具体的宽度一集深度,不要超过最大深度
在这里插入图片描述

在这里插入图片描述
取消勾选
在这里插入图片描述
添加刚刚转化的mif文件,路径不要设置的太深,不要有中文
在这里插入图片描述

同样也例化一个模板
在这里插入图片描述

代码实现

分辨率选择文件

`define 	vga_640_480

`ifdef	vga_640_480
	`define	H_Right_Border 8
	`define	H_Front_Porch  8
	`define	H_Sync_Time    96
	`define	H_Back_Porch	40
	`define	H_Left_Border	8
	`define	H_Data_Time		640
	`define	H_Total_Time	800
	`define	V_Bottom_Border	8
	`define	V_Front_Porch	2
	`define	V_Sync_Time		2
	`define	V_Back_Porch	25
	`define	V_Top_Border	8
	`define	V_Data_Time		480
	`define	V_Total_Time	525

`elsif	vga_1920_1080
	`define	H_Right_Border 0
	`define	H_Front_Porch  88
	`define	H_Sync_Time    44
	`define	H_Back_Porch	148
	`define	H_Left_Border	0
	`define	H_Data_Time		1920
	`define	H_Total_Time	2200
	`define	V_Bottom_Borde	0
	`define	V_Front_Porch	4
	`define	V_Sync_Time		5
	`define	V_Back_Porch	36
	`define	v_Top_Border	2
	`define	v_Data_Time		1080
	`define	v_Total_Time	1125

	
`endif

驱动

//`define 	vga_1920_1080L
`include "vga_para.v"

module vga_drive(

	input						clk			, //640*480--25.2M
	input						rst_n			,
	input	 		[15:0]	data_display,
	
	output reg	[11:0] 	h_addr		,//数据有效显示区域行地址
	output reg	[11:0]	v_addr		,//数据有效显示区域场地址
	
	output reg				vsync			,
	output reg				hsync			,
	output reg 	[4:0]		vga_r			,
	output reg 	[5:0]		vga_g			,
	output reg 	[4:0]		vga_b			,
	output reg				vga_blk		,//消隐信号
	output					vga_clk		,
	output 					sync			
	
);

wire				clk_25M;	
wire				locked;

pll25	pll_inst (
	.areset 		( ~rst_n ),
	.inclk0     ( clk ),
	.c0 		   ( clk_25M ),
	);
	


assign	vga_clk = clk_25M;

assign	sync = hsync && vsync;

parameter	H_SYNC_STA = 1;
parameter   H_SYNC_STO = `H_Sync_Time;
parameter   H_Data_STA = `H_Right_Border + `H_Front_Porch + `H_Sync_Time;
parameter   H_Data_STO = `H_Right_Border + `H_Front_Porch + `H_Sync_Time + `H_Data_Time;

parameter   V_SYNC_STA = 1;
parameter   V_SYNC_STO = `V_Sync_Time;
parameter   V_Data_STA = `V_Bottom_Border + `V_Front_Porch + `V_Sync_Time;
parameter   V_Data_STO = `V_Bottom_Border + `V_Front_Porch + `V_Sync_Time + `V_Data_Time;


wire				add_h_addr		;
wire				end_h_addr		;


reg	[11:0]	cnt_v_addr;//行地址寄存器
wire				add_cnt_v_addr	;
wire				end_cnt_v_addr	;

reg	[11:0]	cnt_h_addr		;//场地址寄存器
wire				add_cnt_h_addr ;
wire				end_cnt_h_addr ;

always@(posedge	vga_clk or negedge	rst_n)begin
	if(!rst_n)begin
		cnt_h_addr <= 12'd0;
	end
	else if(add_cnt_h_addr)begin
		if(end_cnt_h_addr)
			cnt_h_addr <= 12'd0;
		else
			cnt_h_addr <= cnt_h_addr + 12'd1;
	end
	else begin
		cnt_h_addr <= 12'd0;
	end
		
	
end
assign	add_cnt_h_addr = 1'b1;
assign	end_cnt_h_addr = add_cnt_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_cnt_v_addr)begin
		if(end_cnt_v_addr)
			cnt_v_addr <= 12'd0;
		else
			cnt_v_addr <= cnt_v_addr + 12'd1;
	end
	else begin
		cnt_v_addr <= cnt_v_addr;
	end
		
	
end
assign	add_cnt_v_addr = end_cnt_h_addr;
assign	end_cnt_v_addr = add_cnt_v_addr && cnt_v_addr >= `V_Total_Time - 1; 


//行场同步信号
always@(posedge	vga_clk or negedge	rst_n)begin
	if(!rst_n)
		hsync <= 1'b1;
	else if(cnt_h_addr == H_SYNC_STA -1)
		hsync <= 1'b0;
	else if(cnt_h_addr == H_SYNC_STO-1)
		hsync <= 1'b1;
	else
		hsync <= hsync;
end

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



//有效显示区域
always@(posedge vga_clk or negedge rst_n)begin
	if(!rst_n)
		h_addr <= 12'b0;
	else	if(cnt_h_addr >= H_Data_STA && cnt_h_addr <= H_Data_STO)begin
		h_addr <= cnt_h_addr - H_Data_STA ;
		vga_blk <= 1'b1;
	end
   else begin
		h_addr <= 12'b0;
		vga_blk <= 1'b0;
	end
	
end
always@(posedge vga_clk or negedge rst_n)begin
	if(!rst_n)
		v_addr <= 12'b0;
	else	if(cnt_v_addr >= V_Data_STA  && cnt_v_addr <= V_Data_STO)begin
		v_addr <= cnt_v_addr - V_Data_STA;
	end
   else begin
		v_addr <= 12'b0;
	end
	
end


//数据显示
always@(posedge vga_clk or negedge rst_n)begin
	if(!rst_n)begin
		vga_r <= 5'h0;
		vga_g <= 6'h0;
		vga_b <= 5'h0;
	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_display[15:11];	//data_display[23-:8]
		vga_g <= data_display[10:5];	//data_display[15-:8]
		vga_b <= data_display[4:0];	//data_display[7-:8]
	end
	else begin
		vga_r <= 5'h0;
		vga_g <= 6'h0;
		vga_b <= 5'h0;
	end
		
end


endmodule


读取rom中数据

module data_gen (
    input   wire              clk         , //vga clk 640*480 25.2MHz
    input   wire              rst_n       , //复位信号

    input   wire   [10:0]     h_addr      , //数据有效显示区域行地址
    input   wire   [10:0]     v_addr      , //数据有效显示区域场地址

    output  reg    [15:0]     data_disp     //

);

    
    reg			[ 13:0 ]		rom_address				; // ROM地址
    wire		[ 15:0 ]		rom_data				; // 图片数据

    wire						flag_enable_out2			; // 图片有效区域
    wire						flag_clear_rom_address		; // 地址清零
    wire						flag_begin_h			    ; // 图片显示行
    wire						flag_begin_v			    ; // 图片显示列
    
    parameter	height = 46; // 图片高度
    parameter	width  = 62; // 图片宽度

    reg [ 223:0 ] char_line[ 15:0 ];//16*14个字符=224,224*16的字符存储区
//参数定义
    parameter
        BLACK   = 24'h000000,
        RED     = 24'hFF0000,
        GREEN   = 24'h00FF00,
        BLUE    = 24'h0000FF,
        YELLOW  = 24'hFFFF00,
        SKY_BULE= 24'h00FFFF,
        PURPLE  = 24'hFF00FF,
        GRAY    = 24'hC0C0C0,
        WHITE   = 24'hFFFFFF; 

    always @( posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        data_disp = BLACK;
    end
    else if ( flag_enable_out2 ) begin
        data_disp = rom_data;
    end
    else begin
        data_disp = BLACK;
    end
    end

    //ROM地址计数器
    always @( posedge clk or negedge rst_n ) begin
        if ( !rst_n ) begin
            rom_address <= 0;
        end
        else if ( flag_clear_rom_address ) begin //计数满清零
            rom_address <= 0;
        end
            else if ( flag_enable_out2 ) begin  //在有效区域内+1
            rom_address <= rom_address + 1;
            end
        else begin  //无效区域保持
            rom_address <= rom_address;
        end
    end
    assign flag_clear_rom_address = rom_address == height * width - 1;
    assign flag_begin_h     = h_addr > ( ( 640 - width ) / 2 ) && h_addr < ( ( 640 - width ) / 2 ) + width + 1;
    assign flag_begin_v     = v_addr > ( ( 480 - height )/2 ) && v_addr <( ( 480 - height )/2 ) + height + 1;
    assign flag_enable_out2 = flag_begin_h && flag_begin_v;

    //实例化ROM
    pic_rom	rom_inst (
    .address    ( rom_address   ),
    .clock      ( clk           ),
    .q          ( rom_data      )
    );
endmodule

顶层文件

module	top(
input						clk,
input						rst_n,
	
 output	 				vsync,	
 output 					hsync,		
 output  	[4:0]		vga_r,		
 output  	[5:0]		vga_g,		
 output  	[4:0]		vga_b,		
 output					vga_clk,
 output					vga_blk,
 output					sync
);





wire	[11:0]   h_addr;
wire	[11:0]   v_addr;
wire	[15:0]	data_display;



vga_drive  inst_vga_drive(
.clk				(clk), //640*480--25.2M
.rst_n			(rst_n),
.data_display	(data_display),

.h_addr			(h_addr),//数据有效显示区域行地址
.v_addr			(v_addr),//数据有效显示区域场地址

.vsync			(vsync),
.hsync			(hsync),
.vga_r			(vga_r),
.vga_g			(vga_g),
.vga_b			(vga_b),
.vga_blk			(vga_blk),
.vga_clk     	(vga_clk),
.sync				(sync)
	
);

data_gen		inst_data_gen(	
.clk				(vga_clk), //640*480--25.2M
.rst_n			(rst_n),
.h_addr			(h_addr),//数据有效显示区域行地址
.v_addr			(v_addr),//数据有效显示区域场地output	

.data_disp	(data_display)
);





endmodule


五、加入干扰

当下面代码中图片长宽和图片像素的长宽不匹配的时候就会出现干扰

vga


module data_gen (
    input   wire              clk         , //vga clk 640*480 25.2MHz
    input   wire              rst_n       , //复位信号

    input   wire   [10:0]     h_addr      , //数据有效显示区域行地址
    input   wire   [10:0]     v_addr      , //数据有效显示区域场地址

    output  reg    [15:0]     data_disp     //

);

    
    reg			[ 13:0 ]		rom_address				; // ROM地址
    wire		[ 15:0 ]		rom_data				; // 图片数据

    wire						flag_enable_out2			; // 图片有效区域
    wire						flag_clear_rom_address		; // 地址清零
    wire						flag_begin_h			    ; // 图片显示行
    wire						flag_begin_v			    ; // 图片显示列
    
    parameter	height = 400; // 图片高度
    parameter	width  = 600; // 图片宽度

    reg [ 223:0 ] char_line[ 15:0 ];//16*14个字符=224,224*16的字符存储区
//参数定义
    parameter
        BLACK   = 24'h000000,
        RED     = 24'hFF0000,
        GREEN   = 24'h00FF00,
        BLUE    = 24'h0000FF,
        YELLOW  = 24'hFFFF00,
        SKY_BULE= 24'h00FFFF,
        PURPLE  = 24'hFF00FF,
        GRAY    = 24'hC0C0C0,
        WHITE   = 24'hFFFFFF; 

    always @( posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        data_disp = BLACK;
    end
    else if ( flag_enable_out2 ) begin
        data_disp = rom_data;
    end
    else begin
        data_disp = BLACK;
    end
    end

    //ROM地址计数器
    always @( posedge clk or negedge rst_n ) begin
        if ( !rst_n ) begin
            rom_address <= 0;
        end
        else if ( flag_clear_rom_address ) begin //计数满清零
            rom_address <= 0;
        end
            else if ( flag_enable_out2 ) begin  //在有效区域内+1
            rom_address <= rom_address + 1;
            end
        else begin  //无效区域保持
            rom_address <= rom_address;
        end
    end
    assign flag_clear_rom_address = rom_address == height * width - 1;
    assign flag_begin_h     = h_addr > ( ( 640 - width ) / 2 ) && h_addr < ( ( 640 - width ) / 2 ) + width + 1;
    assign flag_begin_v     = v_addr > ( ( 480 - height )/2 ) && v_addr <( ( 480 - height )/2 ) + height + 1;
    assign flag_enable_out2 = flag_begin_h && flag_begin_v;

    //实例化ROM
    pic_rom	rom_inst (
    .address    ( rom_address   ),
    .clock      ( clk           ),
    .q          ( rom_data      )
    );
endmodule


代码

六、效果展示

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

  • 23
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值