分为三个模块:
pll分频模块:用于将系统时钟分频为vga驱动的专用时钟
vga显示数据发送模块:发送想要显示的内容给vga驱动模块
vga驱动模块:按照vga的驱动时序,输出行同步信号,场同步信号,以及有效的565数据
module vga_colorbar(
input sys_clk, //系统时钟
input sys_rst_n, //复位信号
//VGA接口
output vga_hs, //行同步信号
output vga_vs, //场同步信号
output [15:0] vga_rgb //红绿蓝三原色输出
);
//wire define
wire vga_clk_w; //PLL分频得到25Mhz时钟
wire locked_w; //PLL输出稳定信号
wire rst_n_w; //内部复位信号
wire [15:0] pixel_data_w; //像素点数据
wire [ 9:0] pixel_xpos_w; //像素点横坐标
wire [ 9:0] pixel_ypos_w; //像素点纵坐标
//待PLL输出稳定之后,停止复位
assign rst_n_w = sys_rst_n && locked_w;
vga_pll u_vga_pll( //时钟分频模块
.inclk0 (sys_clk),
.areset (~sys_rst_n),
.c0 (vga_clk_w), //VGA时钟 25M
.locked (locked_w)
);
vga_driver u_vga_driver(
.vga_clk (vga_clk_w),
.sys_rst_n (rst_n_w),
.vga_hs (vga_hs),
.vga_vs (vga_vs),
.vga_rgb (vga_rgb),
.pixel_data (pixel_data_w),
.pixel_xpos (pixel_xpos_w),
.pixel_ypos (pixel_ypos_w)
);
vga_display u_vga_display(
.vga_clk (vga_clk_w),
.sys_rst_n (rst_n_w),
.pixel_xpos (pixel_xpos_w),
.pixel_ypos (pixel_ypos_w),
.pixel_data (pixel_data_w)
);
endmodule
module vga_pll (
areset,
inclk0,
c0,
locked);
input areset;
input inclk0;
output c0;
output locked;
module vga_display(
input vga_clk, //VGA驱动时钟
input sys_rst_n, //复位信号
input [ 9:0] pixel_xpos, //由vga驱动模块传来的当前有效数据位坐标信息
input [ 9:0] pixel_ypos,
output reg [15:0] pixel_data //像素点数据,输出给vga驱动模块(565)
);
parameter H_DISP = 10'd640; //分辨率——行
parameter V_DISP = 10'd480; //分辨率——列
localparam WHITE = 16'b11111_111111_11111; //RGB565 白色
localparam BLACK = 16'b00000_000000_00000; //RGB565 黑色
localparam RED = 16'b11111_000000_00000; //RGB565 红色
localparam GREEN = 16'b00000_111111_00000; //RGB565 绿色
localparam BLUE = 16'b00000_000000_11111; //RGB565 蓝色
//根据当前像素点坐标指定当前像素点颜色数据,在屏幕上显示彩条
always @(posedge vga_clk or negedge sys_rst_n) begin
if (!sys_rst_n) //复位时像素点颜色清零
pixel_data <= 16'd0;
else begin
//将显示器按横坐标划分位五条,
//然后判断像素点的横坐标是否依次在这五条内
//如果对应上了就把发送数据设为特定的颜色
if((pixel_xpos >= 0) && (pixel_xpos <= (H_DISP/5)*1))
pixel_data <= WHITE;
else if((pixel_xpos >= (H_DISP/5)*1) && (pixel_xpos < (H_DISP/5)*2))
pixel_data <= BLACK;
else if((pixel_xpos >= (H_DISP/5)*2) && (pixel_xpos < (H_DISP/5)*3))
pixel_data <= RED;
else if((pixel_xpos >= (H_DISP/5)*3) && (pixel_xpos < (H_DISP/5)*4))
pixel_data <= GREEN;
else
pixel_data <= BLUE;
end
end
endmodule
module vga_driver(
input vga_clk, //VGA驱动时钟
input sys_rst_n, //复位信号
//VGA接口
output vga_hs, //行同步信号
output vga_vs, //场同步信号
output [15:0] vga_rgb, //红绿蓝三原色输出
input [15:0] pixel_data, //像素点数据
output [ 9:0] pixel_xpos, //像素点横坐标
output [ 9:0] pixel_ypos //像素点纵坐标
);
//按照vga驱动的表格定义,这里采用的是640x480
parameter H_SYNC = 10'd96; //行同步
parameter H_BACK = 10'd48; //行显示后沿
parameter H_DISP = 10'd640; //行有效数据
parameter H_FRONT = 10'd16; //行显示前沿
parameter H_TOTAL = 10'd800; //行扫描周期
parameter V_SYNC = 10'd2; //场同步
parameter V_BACK = 10'd33; //场显示后沿
parameter V_DISP = 10'd480; //场有效数据
parameter V_FRONT = 10'd10; //场显示前沿
parameter V_TOTAL = 10'd525; //场扫描周期
//reg define
reg [9:0] cnt_h;
reg [9:0] cnt_v;
//wire define
wire vga_en;
wire data_req;
//这五组assign的解释在最下面----------------------------------------------------------
//VGA行场同步信号(两个输出)
assign vga_hs = (cnt_h <= H_SYNC - 1'b1) ? 1'b0 : 1'b1;
assign vga_vs = (cnt_v <= V_SYNC - 1'b1) ? 1'b0 : 1'b1;
//使能RGB565数据输出
assign vga_en = (((cnt_h >= H_SYNC+H_BACK) && (cnt_h < H_SYNC+H_BACK+H_DISP))
&&((cnt_v >= V_SYNC+V_BACK) && (cnt_v < V_SYNC+V_BACK+V_DISP)))
? 1'b1 : 1'b0;
//RGB565数据输出
assign vga_rgb = vga_en ? pixel_data : 16'd0;
//请求像素点颜色数据输入
assign data_req = (((cnt_h >= H_SYNC+H_BACK-1'b1) && (cnt_h < H_SYNC+H_BACK+H_DISP-1'b1))
&& ((cnt_v >= V_SYNC+V_BACK) && (cnt_v < V_SYNC+V_BACK+V_DISP)))
? 1'b1 : 1'b0;
//像素点坐标
assign pixel_xpos = data_req ? (cnt_h - (H_SYNC + H_BACK - 1'b1)) : 10'd0;
assign pixel_ypos = data_req ? (cnt_v - (V_SYNC + V_BACK - 1'b1)) : 10'd0;
//--------------------------------------------------------------------------------------------
//行计数器
always @(posedge vga_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
cnt_h <= 10'd0;
else begin
if(cnt_h < H_TOTAL - 1'b1) //行计数器 小于 行扫描周期 就加1
cnt_h <= cnt_h + 1'b1;
else
cnt_h <= 10'd0; //积满清零
end
end
//场计数器
always @(posedge vga_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
cnt_v <= 10'd0;
else if(cnt_h == H_TOTAL - 1'b1) begin //判断一次行扫描周期是否完成,
if(cnt_v < V_TOTAL - 1'b1) //场计数器 小于 场扫描周期 就加1
cnt_v <= cnt_v + 1'b1;
else
cnt_v <= 10'd0; //积满清零
end
end
endmodule