FPGA——用VGA时序显示图像(3)(代码)

FPGA——用VGA时序显示图像原理详解(1)_居安士的博客-CSDN博客_vga时序

FPGA——用VGA时序显示图像原理详解(2)_居安士的博客-CSDN博客_vga显示时序

关于VGA时序的原理可以看上面2篇(建议先看),这一篇接(2)写VGA的代码实现


首先关于VGA时序,我们一共需要控制的信号线有5条:行同步+场同步+红+绿+蓝

input clk,
input rst,
output       hs   ,//行同步信号
output       vs   ,//场同步信号
output       de   ,//有效数据
output [7:0] rgb_r,//red
output [7:0] rgb_g,//green
output [7:0] rgb_b //blue

我们需要控制何时把hs和vs拉高,拉低,就需要根据数据手册上,不同图像的像素来设置前肩,后肩,同步信号,数据有效信号(如何查看数据手册已经在前面解析过)这里建议大家使用条件编译的方法来练习,这样可以方便我们后续图像像素变化时进行修改

//640x480 25.175Mhz 按照数据手册修改参数
`ifdef  VIDEO_640_480
parameter H_ACTIVE = 16'd640; //行有效
parameter H_FP = 16'd16;      //行前肩
parameter H_SYNC = 16'd96;    //行同步
parameter H_BP = 16'd48;      //行后肩
parameter V_ACTIVE = 16'd480; //场有效
parameter V_FP  = 16'd10;     //场前肩
parameter V_SYNC  = 16'd2;    //场同步
parameter V_BP  = 16'd33;     //场后肩
parameter HS_POL = 1'b0;      //
parameter VS_POL = 1'b0;      //
`endif

设置好了这些参数之后,我们需要设置2个计数器,分别是行计数器和场计数器,当一行计数完成之后,场计数器+1

//行计数器进行计数
always@(posedge clk)begin
	if(rst)begin
		h_cnt<=12'd0;
	end
	else if(h_cnt==H_total-1)begin
		h_cnt<=12'd0;
	end
	else begin
		h_cnt<=h_cnt+12'd1;
	end
end

//场计数器进行计数
always@(posedge clk)begin
	if(rst)begin
		v_cnt<=12'd0;
	end
	else if(h_cnt==H_total-1)begin//行同步信号拉高一次,v_cnt+1
		if(v_cnt==V_total-1)begin
			v_cnt<=12'd0;
		end
		else begin
			v_cnt<=v_cnt+12'd1;
		end
	end
	else begin
		v_cnt<=v_cnt;
	end
end

接下来我们就可以根据计数器,输出行同步信号和场同步信号

 这里,计数是从前肩开始,所以当行计数器=前肩,行同步信号拉高,计数器=前肩+行同步,行同步信号拉低

//产生行同步信号
always@(posedge clk)begin
	if(reset)begin
		hs_reg<=1'd0;
	end
	else if(h_cnt==H_FP-1)begin
		hs_reg<=1'd1;
	end
	else if(h_cnt==H_FP+H_SYNC-1)begin
		hs_reg<=1'd0;
	end
	else begin
		hs_reg<=hs_reg;
	end
end

场同步信号类似,需要注意的是,每一个场计数器里面都有行总个数个周期(eg: v_cnt=V_HP到v_cnt=V_HP+1时里面其实有640个clk,在哪个clk拉高呢?),但是我们的场计数器只能在一个确定的时刻拉高,所以这里还需&&上一个特定的时刻

//产生场同步信号
always@(posedge clk or posedge rst)
begin
 if(rst == 1'b1)
  vs_reg <= 1'd0;
 else if((v_cnt == V_FP - 1) && (h_cnt == H_FP - 1))//场同步信号开始,&&(h_cnt == H_FP - 1)目的是在多个时钟周期里面选择一个时钟拉高场同步
  vs_reg <= 1'd1;//HS_POL=1
 else if((v_cnt == V_FP + V_SYNC - 1) && (h_cnt == H_FP - 1))//场同步信号结束
  vs_reg <= 1'd0;  
 else
  vs_reg <= vs_reg;
end

数据有效的指示信号de,是在行有效&&场有效时输出

行有效是在当行计数器=前肩+行同步+后肩,行同步信号拉高,计数器=前肩+行同步+后肩+数据个数,行同步信号拉低

场有效信号与场同步信号相似,也需要&&上一个特定的时刻

//产生行有效信号
always@(posedge clk or posedge rst)
begin
 if(rst == 1'b1)
  h_active <= 1'b0;
 else if(h_cnt == H_FP + H_SYNC + H_BP - 1)//行有效开始
  h_active <= 1'b1;
 else if(h_cnt == H_TOTAL - 1)//行有效结束
  h_active <= 1'b0;
 else
  h_active <= h_active;
end

//产生场有效信号
always@(posedge clk or posedge rst)
begin
 if(rst == 1'b1)
  v_active <= 1'd0;
 else if((v_cnt == V_FP + V_SYNC + V_BP - 1) && (h_cnt == H_FP - 1))//场有效开始
  v_active <= 1'b1;
 else if((v_cnt == V_TOTAL - 1) && (h_cnt == H_FP - 1)) //场有效结束
  v_active <= 1'b0;   
 else
  v_active <= v_active;
end

接下来需要实现RGB分量的输出,这里实现彩条数据的输出,只需要给RGB某个颜色的值,就可以实现某个颜色的输出。

reg[7:0] rgb_r_reg;              //红
reg[7:0] rgb_g_reg;              //绿
reg[7:0] rgb_b_reg;              //蓝

always@(posedge clk)begin
	if(rst)begin
		rgb_r_reg<=8'd0;
    rgb_g_reg<=8'd0;
    rgb_b_reg<=8'd0;
	end
	else begin
		rgb_r_reg<=8'd0;
    rgb_g_reg<=8'd0;
    rgb_b_reg<=8'hff;
	end
end

assign rgb_r = rgb_r_reg;
assign rgb_g = rgb_g_reg;
assign rgb_b = rgb_b_reg;

仿真一下:

可以看出RGB分量输出没问题, 貌似也是一幅图一幅图地输出了,我们放大看一下计数情况

首先看行同步信号输出情况,可以看出行计数器一共计数800,是对的,行前肩结束之后,行同步信号拉高了,之后持续了行同步时间,没有问题

 

 再看看场同步信号,确实是一幅图传输完毕后输出一次

 de信号也是符合的

 完整代码如下:

module VGA(
input clk,
input rst,
output       hs   ,//行同步信号
output       vs   ,//场同步信号
output       de   ,//有效数据
output [7:0] rgb_r,//red
output [7:0] rgb_g,//green
output [7:0] rgb_b //blue
    );
    
 	//640x480 25.175Mhz 按照数据手册修改参数
//`ifdef  VIDEO_640_480
parameter H_ACTIVE = 16'd640; //行有效
parameter H_FP = 16'd16;      //行前肩
parameter H_SYNC = 16'd96;    //行同步
parameter H_BP = 16'd48;      //行后肩
parameter V_ACTIVE = 16'd480; //场有效
parameter V_FP  = 16'd10;     //场前肩
parameter V_SYNC  = 16'd2;    //场同步
parameter V_BP  = 16'd33;     //场后肩
parameter HS_POL = 1'b0;      //
parameter VS_POL = 1'b0;      //
//`endif
   
parameter H_total=H_ACTIVE+H_FP+H_SYNC+H_BP;//行总时间
parameter V_total=V_ACTIVE+V_SYNC+V_FP+V_BP;//场总时间
   
reg hs_reg;//行同步信号寄存
reg vs_reg;//场同步信号寄存
//定义行场计数器
reg [11:0]h_cnt;
reg [11:0]v_cnt;

reg[7:0] rgb_r_reg;              //红
reg[7:0] rgb_g_reg;              //绿
reg[7:0] rgb_b_reg;              //蓝

always@(posedge clk)begin
	if(rst)begin
		rgb_r_reg<=8'd0;
    rgb_g_reg<=8'd0;
    rgb_b_reg<=8'd0;
	end
	else begin
		rgb_r_reg<=8'd0;
    rgb_g_reg<=8'd0;
    rgb_b_reg<=8'hff;
	end
end

assign rgb_r = rgb_r_reg;
assign rgb_g = rgb_g_reg;
assign rgb_b = rgb_b_reg;


reg h_active;                    //行有效
reg v_active;                    //场有效
wire video_active;               //数据有效
assign video_active = h_active & v_active;//数据有效=行有效且列有效
assign de=video_active;

//行计数器进行计数
always@(posedge clk)begin
	if(rst)begin
		h_cnt<=12'd0;
	end
	else if(h_cnt==H_total-1)begin
		h_cnt<=12'd0;
	end
	else begin
		h_cnt<=h_cnt+12'd1;
	end
end

//场计数器进行计数
always@(posedge clk)begin
	if(rst)begin
		v_cnt<=12'd0;
	end
	else if(h_cnt==H_total-1)begin//行同步信号拉高一次,v_cnt+1
		if(v_cnt==V_total-1)begin
			v_cnt<=12'd0;
		end
		else begin
			v_cnt<=v_cnt+12'd1;
		end
	end
	else begin
		v_cnt<=v_cnt;
	end
end


//产生行同步信号
always@(posedge clk)begin
	if(rst)begin
		hs_reg<=1'd0;
	end
	else if(h_cnt==H_FP-1)begin
		hs_reg<=1'd1;
	end
	else if(h_cnt==H_FP+H_SYNC-1)begin
		hs_reg<=1'd0;
	end
	else begin
		hs_reg<=hs_reg;
	end
end


//产生场同步信号
always@(posedge clk or posedge rst)
begin
 if(rst == 1'b1)
  vs_reg <= 1'd0;
 else if((v_cnt == V_FP - 1) && (h_cnt == H_FP - 1))//场同步信号开始,&&(h_cnt == H_FP - 1)目的是在多个时钟周期里面选择一个时钟拉高场同步
  vs_reg <= 1'd1;
 else if((v_cnt == V_FP + V_SYNC - 1) && (h_cnt == H_FP - 1))//场同步信号结束
  vs_reg <= 1'd0;  
 else
  vs_reg <= vs_reg;
end

//产生行有效信号
always@(posedge clk or posedge rst)
begin
 if(rst == 1'b1)
  h_active <= 1'b0;
 else if(h_cnt == H_FP + H_SYNC + H_BP - 1)//行有效开始
  h_active <= 1'b1;
 else if(h_cnt == H_total - 1)//行有效结束
  h_active <= 1'b0;
 else
  h_active <= h_active;
end

//产生场有效信号
always@(posedge clk or posedge rst)
begin
 if(rst == 1'b1)
  v_active <= 1'd0;
 else if((v_cnt == V_FP + V_SYNC + V_BP - 1) && (h_cnt == H_FP - 1))//场有效开始
  v_active <= 1'b1;
 else if((v_cnt == V_total - 1) && (h_cnt == H_FP - 1)) //场有效结束
  v_active <= 1'b0;   
 else
  v_active <= v_active;
end
   
   
   
endmodule

  • 4
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
FPGA中使用VGA时序显示图像的仿真过程可以通过以下步骤实现: 1. 首先,需要使用时钟生成模块(PLL)来生成VGA工作所需的时钟信号。这个时钟信号将用于控制图像的扫描和刷新。 2. 接下来,使用图像生成模块(VGA_P)来确定每个有效图像区域的像素点。这个模块将根据控制模块传入的坐标信号,生成待显示图像的色彩信息。 3. 图像控制模块(VGA_C)负责生成行场同步信号,并确定有效图像区域的位置和零点坐标。这个模块还需要接收RGB信息和行场同步信号。 4. 最后,将生成的图像信号通过VGA端口输出,连接到VGA显示器上进行显示。 通过以上步骤,可以在FPGA中使用VGA时序显示图像的仿真。这样,你就可以在仿真环境中验证图像显示效果,并进行必要的调试和优化。 #### 引用[.reference_title] - *1* [FPGA学习——VGA显示](https://blog.csdn.net/weixin_56102526/article/details/124964347)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* *3* [FPGA——VGA显示协议](https://blog.csdn.net/a17377547725/article/details/129729079)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值