信号线 | 定义 |
---|---|
HS | 行同步信号(3.3V 电平) |
VS | 场同步信号(3.3V 电平) |
R | 红基色 (0~0.714V 模拟信号) |
G | 绿基色 (0~0.714V 模拟信号) |
B | 蓝基色 (0~0.714V 模拟信号) |
每扫描完一行,重新开始下一行;每扫描完一场,重新开始下一场;直到像素点扫描完成。
VGA接口:R,G,B三通道,直接赋给数字信号,RGB,最多产生8种色彩。
通过构建电阻网络进行连接,即通过电阻网络分流模拟DAC控制电压大小来控制R,G,B的输入电压。
//----------------------------------------------------------------------------------------
// Modified by: 正点原子
// Modified date: 2018/1/30 11:12:36
// Version: V1.1
// Descriptions: vga驱动
//
//----------------------------------------------------------------------------------------
//****************************************************************************************//
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 //像素点纵坐标
);
//parameter define
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;
//*****************************************************
//** main code
//*****************************************************
//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)
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)
cnt_v <= cnt_v + 1'b1;
else
cnt_v <= 10'd0;
end
end
endmodule
常见VGA显示刷新率时序
//****************************************************************************************//
module vga_display(
input vga_clk, //VGA驱动时钟
input sys_rst_n, //复位信号
input [ 9:0] pixel_xpos, //像素点横坐标
input [ 9:0] pixel_ypos, //像素点纵坐标
output reg [15:0] pixel_data //像素点数据,
);
//parameter define
parameter H_DISP = 10'd640; //分辨率——行
parameter V_DISP = 10'd480; //分辨率——列
localparam WIDTH = 10'd160; //字符区域宽度
localparam HEIGHT = 10'd22; //字符区域高度
localparam SIDE_W = 10'd40; //边框宽度
localparam BLACK = 16'b00000_000000_00000; //RGB565 黑色
//localparam PINK = 16'b11010_010111_10101; //RGB565 粉色
//localparam RED = 16'b11111_000000_00000; //RGB565 红色
//localparam GREEN = 16'b00000_111111_00000; //RGB565 绿色
//reg define
reg [159:0] char[22:0]; //字符数组
reg [ 9:0] block_x; //字符左上角横坐标
reg [ 9:0] block_y; //字符左上角纵坐标
reg [21:0] div_cnt; //时钟分频计数器
reg h_direct; //字符水平移动方向,1:右移,0:左移
reg v_direct; //字符竖直移动方向,1:向下,0:向上
reg [16:0] color[10:0]; //颜色数组
reg [ 9:0] flag;
//wire define
wire [ 9:0] x_cnt;
wire [ 9:0] y_cnt;
wire move_en; //方块移动使能信号,频率为100hz
//*****************************************************
//** main code
//*****************************************************
assign move_en = (div_cnt == 22'd300000 - 1'b1) ? 1'b1 : 1'b0;
assign x_cnt = pixel_xpos - block_x; //像素点相对于字符区域起始点水平坐标
assign y_cnt = pixel_ypos - block_y; //像素点相对于字符区域起始点竖直坐标
//给字符数组赋值,显示汉字“I LOVE YOU”,汉字大小为32*32
always @(posedge vga_clk) begin
char[0] <= 160'h3FFC00007E0003C07C1E7FFC00007E3E03C0FC3E;
char[1] <= 160'h03C0000018000C30180C180C000038080C303008;
char[2] <= 160'h03C0000018001818180818040000180818183008;
char[3] <= 160'h03C0000018001008180818020000181010083008;
char[4] <= 160'h03C000001800300C1808180200000C10300C3008;
char[5] <= 160'h03C000001800300C0C10180000000C10300C3008;
char[6] <= 160'h03C00000180060040C10180000000C2060043008;
char[7] <= 160'h03C00000180060060C1018100000062060063008;
char[8] <= 160'h03C00000180060060C1018100000062060063008;
char[9] <= 160'h03C00000180060060C2018300000034060063008;
char[10] <= 160'h03C000001800600606201FF00000034060063008;
char[11] <= 160'h03C0000018006006062018300000038060063008;
char[12] <= 160'h03C0000018006006062018100000018060063008;
char[13] <= 160'h03C0000018006006064018100000018060063008;
char[14] <= 160'h03C0000018006006034018000000018060063008;
char[15] <= 160'h03C0000018002006034018000000018020063008;
char[16] <= 160'h03C000001800300C0340180000000180300C3008;
char[17] <= 160'h03C000001802300C0380180200000180300C3008;
char[18] <= 160'h03C0000018021008018018020000018010083008;
char[19] <= 160'h03C0000018041818018018040000018018181810;
char[20] <= 160'h03C00000180C0C300100180C000001800C301C20;
char[20] <= 160'h3FFC00007FFC03C001007FFC000007E003C007C0;
end
always @(posedge vga_clk) begin
color[0] <= 16'b11010_010111_10101; //RGB565 粉色
color[1] <= 16'b11111_000000_00000; //RGB565 红色
color[2] <= 16'b00000_111111_00000; //RGB565 绿色
color[3] <= 16'b00000_000000_11111; //RGB565 蓝色
color[4] <= 16'b11111_111111_11111; //RGB565 白色
color[5] <= 16'b00000_011111_01111; //RGB565 深青色
color[6] <= 16'b01111_000000_01111; //RGB565 紫色
color[7] <= 16'b00000_111111_11111; //RGB565 青色
color[8] <= 16'b11111_111111_00000; //RGB565 黄色
color[9] <= 16'b00000_000000_01111; //RGB565 深蓝色
end
//通过对vga驱动时钟计数,实现时钟分频
always @(posedge vga_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
div_cnt <= 22'd0;
else begin
if(div_cnt < 22'd300000 - 1'b1)
div_cnt <= div_cnt + 1'b1;
else
div_cnt <= 22'd0; //计数达10ms后清零
end
end
//当方块移动到边界时,改变移动方向
always @(posedge vga_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
h_direct <= 1'b1; //方块初始水平向右移动
v_direct <= 1'b1; //方块初始竖直向下移动
flag <= 10'd0;
end
else begin
if(block_x == SIDE_W - 1'b1) //到达左边界时,水平向右
h_direct <= 1'b1;
else //到达右边界时,水平向左
if(block_x == H_DISP - SIDE_W - WIDTH)
h_direct <= 1'b0;
else
h_direct <= h_direct;
if(block_y == SIDE_W - 1'b1) //到达上边界时,竖直向下
v_direct <= 1'b1;
else //到达下边界时,竖直向上
if(block_y == V_DISP - SIDE_W - HEIGHT)
v_direct <= 1'b0;
else
v_direct <= v_direct;
if((block_x == SIDE_W - 1'b1)||(block_x == H_DISP - SIDE_W - WIDTH)
||(block_y == SIDE_W - 1'b1)||(block_y == V_DISP - SIDE_W - HEIGHT))
flag <= flag + 1'b1;
else
flag <= flag;
if (flag > 10'd9)
flag <= 1'b0;
else if(flag < 1'b0)
flag <= 10'd9;
end
end
//根据方块移动方向,改变其纵横坐标
always @(posedge vga_clk or negedge sys_rst_n) begin
if (!sys_rst_n) begin
block_x <= 22'd100; //字符初始位置横坐标
block_y <= 22'd100; //字符初始位置纵坐标
end
else if(move_en) begin
if(h_direct)
block_x <= block_x + 1'b1; //字符向右移动
else
block_x <= block_x - 1'b1; //字符向左移动
if(v_direct)
block_y <= block_y + 1'b1; //字符向下移动
else
block_y <= block_y - 1'b1; //字符向上移动
end
else begin
block_x <= block_x;
block_y <= block_y;
end
end
//给不同的区域绘制不同的颜色
always @(posedge vga_clk or negedge sys_rst_n) begin
if (!sys_rst_n)
pixel_data <= BLACK;
else begin
if((pixel_xpos < SIDE_W) || (pixel_xpos >= H_DISP - SIDE_W)
|| (pixel_ypos < SIDE_W) || (pixel_ypos >= V_DISP - SIDE_W))
pixel_data <= color[ flag - 1'b1]; //绘制边框颜色
else
if((pixel_xpos >= block_x) && (pixel_xpos < block_x + WIDTH)
&& (pixel_ypos >= block_y) && (pixel_ypos < block_y + HEIGHT)) begin
if(char[y_cnt][10'd159 - x_cnt])
pixel_data <= color[ flag ]; //绘制字符颜色
else
pixel_data <= BLACK; //绘制字符区域背景为黑色
end
else
pixel_data <= BLACK; //绘制屏幕背景为黑色
end
end
endmodule