【四 zedboard】 VGA显示彩条

观看开源骚客第二季并结合自己手上的zedboard板子,实现了VGA彩条显示。
首先打开zedboard的用户手册查看vga相关的接口。zedboard的资料可以到digilent官网下载(https://learn.digilentinc.com/
关于VGA的介绍也可以到官网出看(https://learn.digilentinc.com/Documents/269
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
从上面的端口信息中我们能获取的信息:

1.zedboard板子上的VGA端口号

2.采用的颜色显示的方式是RGB444(这一点与开源骚客中的不同)

3.VGA-HS和VGA-VS分别是行同步信号和场同步信号

注 意 : 行 同 步 信 号 是 一 行 的 开 始 , 场 同 步 信 号 是 一 幅 图 的 开 始 注意: 行同步信号是一行的开始,场同步信号是一幅图的开始
概括来说,行同步信号有效就是电子枪扫描完了一行,然后进行下一行扫描;场同步信号有效,说明整个显示屏已经扫描完,回到第一行进行扫面,一直这样反复的进行,从而实现VGA显示的功能。但是需要注意的是,电子枪在扫描完一行跳到下一行(一行的开始是从左到右)的开始是需要时间的,这就是所谓的消隐,这段时间我们不能对显示器进行显示操作,这也是为什么VGA时序图中有FRONT_PORCH和BACK_PORCH空隙。

在这里插入图片描述
vga对应配置的参数
在这里插入图片描述
现在按照这个参数来编写程序:

在这里插入图片描述

代码

新建一个vga_driver.v文件,这是vga的驱动模块

`timescale 1ns/1ns
module vga_drive(
	//system signals
	input					sclk		,
	input					s_rst_n		,
	//vga		
	output	wire			vga_hsync	,
	output	wire			vga_vsync	,
	output	reg	[11:0]      vga_rgb		

);

//============================================================================
//=================define parameter and internal signals============
//============================================================================
localparam	H_TOTAL_TIME = 800		; //1056
localparam	H_ADDR_TIME	= 640		;//800
localparam	H_SYNC_TIME	= 96		;//128
localparam	H_BACK_PORCH = 48		;//88

localparam	V_TOTAL_TIME = 525		;//628
localparam	V_ADDR_TIME	 = 480		;//600
localparam	V_SYNC_TIME	 = 2		;//4
localparam	V_BACK_PORCH = 33		;//23

reg			[10:0]		cnt_h		;
reg			[ 9:0]		cnt_v		;

//============================================================================
//****************************main code*****************************
//============================================================================
//cnt_h
always@(posedge sclk or negedge s_rst_n) begin
	if(s_rst_n == 1'b0)
		cnt_h <= 'd0;
	else if (cnt_h == H_TOTAL_TIME)
		cnt_h <= 'd0;
	else
		cnt_h <= cnt_h + 1'b1;
end 
//cnt_v
always@(posedge sclk or negedge s_rst_n )begin
	if(s_rst_n == 1'b0)
		cnt_v <= 'd0;
	else if (cnt_v >=V_TOTAL_TIME && cnt_h >= H_TOTAL_TIME)
		cnt_v <= 'd0;
	else if(cnt_h >= H_TOTAL_TIME)
		cnt_v <= cnt_v  + 1'b1;
end 
//vga_rgb
always@(posedge sclk or negedge s_rst_n )begin
	if(s_rst_n == 1'b0 )
		vga_rgb <= 'd0;
	else if (cnt_v >= (V_SYNC_TIME + V_BACK_PORCH) && cnt_v < (V_SYNC_TIME + V_BACK_PORCH + V_ADDR_TIME)) begin
		if(cnt_h >= (H_SYNC_TIME + H_BACK_PORCH -1) && cnt_h < (H_SYNC_TIME + H_BACK_PORCH -1 +200))
			vga_rgb <= 12'h0ff;
		else if(cnt_h >= (H_SYNC_TIME + H_BACK_PORCH -1 + 200) && cnt_h < (H_SYNC_TIME + H_BACK_PORCH -1 +400))
			vga_rgb <= 12'hf0f;
		else if(cnt_h >= (H_SYNC_TIME + H_BACK_PORCH -1+400) && cnt_h < (H_SYNC_TIME + H_BACK_PORCH -1 +600))
			vga_rgb <= 12'hff0;
		else if (cnt_h >= (H_SYNC_TIME + H_BACK_PORCH -1 +600) && cnt_h < (H_SYNC_TIME + H_BACK_PORCH -1 +H_ADDR_TIME))
			vga_rgb <= 12'hfff;
		else
			vga_rgb <= 12'h000;
	end
	else
		vga_rgb <= 12'h000;
end 

assign vga_hsync = (cnt_h < H_SYNC_TIME)? 1'b1:1'b0;
assign vga_vsync = (cnt_v < V_SYNC_TIME)? 1'b1:1'b0;


endmodule

在新建一个文件top.v

`timescale 1ns/1ns 
module top (
	//system signals
	input				sclk		,
	input				s_rst_n		,
	//vga 
	output	wire		vga_hsync	,
	output	wire		vga_vsync	,
	output	wire [11:0]	vga_rgb		
);

//============================================================================
//=================define parameter and internal signals============
//============================================================================
wire        clk_sys40m;



//============================================================================
//****************************main code*****************************
//============================================================================
vga_drive vga_drive_inst(
	//system signals
	.sclk		(clk_sys40m		),
	.s_rst_n	(s_rst_n	),
	//vga		
	.vga_hsync	(vga_hsync	),
	.vga_vsync	(vga_vsync	),
	.vga_rgb	(vga_rgb	)	
);
//时钟分频ip核,在vivado中产生然后在顶层中例化
clk_wiz_0 clk_wiz_0_inst
   (
    // Clock out ports
    .clk_out1   (clk_sys40m),            // output clk_out1
    // Status and control signals
    .reset      (1'b0      ),           // input reset
    .locked     (           ),           // output locked
   // Clock in ports
    .clk_in1    (sclk       )
    );         // input clk_in1
endmodule 

vivado中生成25.175M的时钟

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
选择输出的时钟频率
在这里插入图片描述
然后点击ok就可以了,如果还弹出其他的窗口选着,那就默认即可。这样就可以生成25.175M的时钟了

引脚约束文件

set_property IOSTANDARD LVCMOS33 [get_ports {vga_rgb[11]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_rgb[10]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_rgb[9]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_rgb[8]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_rgb[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_rgb[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_rgb[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_rgb[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_rgb[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_rgb[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_rgb[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {vga_rgb[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports s_rst_n]
set_property IOSTANDARD LVCMOS33 [get_ports sclk]
set_property IOSTANDARD LVCMOS33 [get_ports vga_hsync]
set_property IOSTANDARD LVCMOS33 [get_ports vga_vsync]

set_property PACKAGE_PIN F22 [get_ports s_rst_n]
set_property PACKAGE_PIN Y9 [get_ports sclk]
set_property PACKAGE_PIN AA19 [get_ports vga_hsync]
set_property PACKAGE_PIN Y19 [get_ports vga_vsync]
set_property PACKAGE_PIN V20 [get_ports {vga_rgb[0]}]
set_property PACKAGE_PIN U20 [get_ports {vga_rgb[1]}]
set_property PACKAGE_PIN V19 [get_ports {vga_rgb[2]}]
set_property PACKAGE_PIN V18 [get_ports {vga_rgb[3]}]
set_property PACKAGE_PIN AB22 [get_ports {vga_rgb[4]}]
set_property PACKAGE_PIN AA22 [get_ports {vga_rgb[5]}]
set_property PACKAGE_PIN AB21 [get_ports {vga_rgb[6]}]
set_property PACKAGE_PIN AA21 [get_ports {vga_rgb[7]}]
set_property PACKAGE_PIN Y21 [get_ports {vga_rgb[8]}]
set_property PACKAGE_PIN Y20 [get_ports {vga_rgb[9]}]
set_property PACKAGE_PIN AB20 [get_ports {vga_rgb[10]}]
set_property PACKAGE_PIN AB19 [get_ports {vga_rgb[11]}]

注意:我将复位信号接到了开关SW0,所以下载程序之后,需要将SW0拉高才能显示彩条。

最终的结果
请添加图片描述

如果需要换成其他分辨率,只需要修改参数即可,我要改成这个:
在这里插入图片描述
把时钟分频改为40M
在这里插入图片描述

然后修改参数

`timescale 1ns/1ns
module vga_drive(
	//system signals
	input					sclk		,
	input					s_rst_n		,
	//vga		
	output	wire			vga_hsync	,
	output	wire			vga_vsync	,
	output	reg	[11:0]      vga_rgb		

);

//============================================================================
//=================define parameter and internal signals============
//============================================================================
localparam	H_TOTAL_TIME = 1056	; //1056  800
localparam	H_ADDR_TIME	=  800	;//800   640
localparam	H_SYNC_TIME	= 128	;//128  96
localparam	H_BACK_PORCH = 88	;//88  48

localparam	V_TOTAL_TIME =628 		;//628  525
localparam	V_ADDR_TIME	 =600 		;//600  480
localparam	V_SYNC_TIME	 = 4		;//4  2
localparam	V_BACK_PORCH = 23		;//23  33

reg			[10:0]		cnt_h		;
reg			[ 9:0]		cnt_v		;

//============================================================================
//****************************main code*****************************
//============================================================================
//cnt_h
always@(posedge sclk or negedge s_rst_n) begin
	if(s_rst_n == 1'b0)
		cnt_h <= 'd0;
	else if (cnt_h == H_TOTAL_TIME)
		cnt_h <= 'd0;
	else
		cnt_h <= cnt_h + 1'b1;
end 
//cnt_v
always@(posedge sclk or negedge s_rst_n )begin
	if(s_rst_n == 1'b0)
		cnt_v <= 'd0;
	else if (cnt_v >=V_TOTAL_TIME && cnt_h >= H_TOTAL_TIME)
		cnt_v <= 'd0;
	else if(cnt_h >= H_TOTAL_TIME)
		cnt_v <= cnt_v  + 1'b1;
end 
//vga_rgb
always@(posedge sclk or negedge s_rst_n )begin
	if(s_rst_n == 1'b0 )
		vga_rgb <= 'd0;
	else if (cnt_v >= (V_SYNC_TIME + V_BACK_PORCH) && cnt_v < (V_SYNC_TIME + V_BACK_PORCH + V_ADDR_TIME)) begin
		if(cnt_h >= (H_SYNC_TIME + H_BACK_PORCH -1) && cnt_h < (H_SYNC_TIME + H_BACK_PORCH -1 +200))
			vga_rgb <= 12'h0ff;
		else if(cnt_h >= (H_SYNC_TIME + H_BACK_PORCH -1 + 200) && cnt_h < (H_SYNC_TIME + H_BACK_PORCH -1 +400))
			vga_rgb <= 12'hf0f;
		else if(cnt_h >= (H_SYNC_TIME + H_BACK_PORCH -1+400) && cnt_h < (H_SYNC_TIME + H_BACK_PORCH -1 +600))
			vga_rgb <= 12'hff0;
		else if (cnt_h >= (H_SYNC_TIME + H_BACK_PORCH -1 +600) && cnt_h < (H_SYNC_TIME + H_BACK_PORCH -1 +H_ADDR_TIME))
			vga_rgb <= 12'hfff;
		else
			vga_rgb <= 12'h000;
	end
	else
		vga_rgb <= 12'h000;
end 

assign vga_hsync = (cnt_h < H_SYNC_TIME)? 1'b1:1'b0;
assign vga_vsync = (cnt_v < V_SYNC_TIME)? 1'b1:1'b0;


endmodule

重新生成比特流文件,然后烧入即可
在这里插入图片描述
得到的结果

我主要遇到的问题就是:烧入程序之后,屏幕黑麻麻的一片啥也不显示。
原因:由于马虎大意直接使用系统时钟100m给vga驱动模块,没有把时钟分频信号得到的25.175M给vga驱动模块。
这样的问题,别人总结的原因还有:
1、检查你的时钟是否是对应的分辨率下的有效值。
2、显示屏是否支持这种分辨率。
3、检查 行场时序是否有错
3、检查de信号(即数据有效信号)是否出错
4、管脚约束是否匹配你的板子,电压是否是3.3v

								---晓凡  于桂林202246日书
以下是一个简单的FPGA VGA显示彩条的代码示例: ```verilog module vga_color_bar( input clk, // 像素时钟 input rst_n, // 复位信号 output reg [7:0] r, // 红色分量 output reg [7:0] g, // 绿色分量 output reg [7:0] b, // 蓝色分量 output reg hsync, // 水平同步信号 output reg vsync // 垂直同步信号 ); parameter SCREEN_WIDTH = 640; parameter SCREEN_HEIGHT = 480; parameter H_SYNC_PULSE_WIDTH = 96; parameter H_BACK_PORCH = 48; parameter H_FRONT_PORCH = 16; parameter V_SYNC_PULSE_WIDTH = 2; parameter V_BACK_PORCH = 33; parameter V_FRONT_PORCH = 10; reg [9:0] h_count = 0; reg [8:0] v_count = 0; always @(posedge clk or negedge rst_n) begin if(!rst_n) begin h_count <= 0; v_count <= 0; r <= 8'd0; g <= 8'd0; b <= 8'd0; hsync <= 1'b0; vsync <= 1'b0; end else begin if(h_count == SCREEN_WIDTH + H_SYNC_PULSE_WIDTH + H_BACK_PORCH + H_FRONT_PORCH - 1) begin h_count <= 0; if(v_count == SCREEN_HEIGHT + V_SYNC_PULSE_WIDTH + V_BACK_PORCH + V_FRONT_PORCH - 1) begin v_count <= 0; r <= 8'd0; g <= 8'd0; b <= 8'd0; hsync <= 1'b0; vsync <= 1'b0; end else begin v_count <= v_count + 1; hsync <= 1'b0; vsync <= (v_count >= SCREEN_HEIGHT + V_BACK_PORCH && v_count < SCREEN_HEIGHT + V_BACK_PORCH + V_SYNC_PULSE_WIDTH); end end else begin h_count <= h_count + 1; hsync <= (h_count >= SCREEN_WIDTH + H_BACK_PORCH && h_count < SCREEN_WIDTH + H_BACK_PORCH + H_SYNC_PULSE_WIDTH); if(v_count >= V_BACK_PORCH && v_count < V_BACK_PORCH + SCREEN_HEIGHT) begin r <= h_count[3:0] * 32; g <= h_count[3:0] * 8; b <= h_count[3:0] * 2; end else begin r <= 8'd0; g <= 8'd0; b <= 8'd0; end end end end endmodule ``` 该代码使用Verilog语言实现,使用了同步信号和计数器控制VGA信号的输出,通过改变红、绿、蓝三种颜色的分量实现彩条的渐变效果。注意:该代码只是一个简单的示例,实际使用时需要根据具体的FPGA开发板和显示器的参数进行调整。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值