当前位置:网站首页>基于FPGA的VGA协议实现
基于FPGA的VGA协议实现
2022-06-10 13:31:00 【[email protected]】
基于FPGA的VGA协议实现
基于FPGA的VGA协议实现
一、屏幕上显示彩色条纹
1.创建工程
通过python脚本创建好工程文件夹,然后进行代码编写
2.代码编写
我这里使用了vscode来进行代码编写
上图verilog文件定义了会使用的一些变量
在vga_ctrl中则是控制vga显示的逻辑
代码:
`define vga_800_600
`include "vga_param.v"
module vga_ctrl (
input clk ,
input rst_n ,
input [23:0] data_dis ,
output reg [10:0] h_addr , //数据有效显示区域行地址
output reg [10:0] v_addr , //数据有效显示区域场地址
output reg hsync ,
output reg vsync ,
output reg [7:0] vga_r ,
output reg [7:0] vga_g ,
output reg [7:0] vga_b ,
output reg vga_blk , //VGA消隐信号
output reg vga_clk
);
//参数定义
parameter H_SYNC_STA = 1 ,
H_SYNC_STO = `H_Sync_Time ,
H_DATA_STA = `H_Sync_Time + `H_Back_Porch + `H_Left_Border ,
H_DATA_STO = `H_Sync_Time + `H_Back_Porch + `H_Left_Border + `H_Data_Time ,
V_SYNC_STA = 1 ,
V_SYNC_STO = `V_Sync_Time ,
V_DATA_STA = `V_Sync_Time + `V_Back_Porch + `V_Top_Border ,
V_DATA_STO = `V_Sync_Time + `V_Back_Porch + `V_Top_Border + `V_Data_Time;
//信号定义
reg [11:0] cnt_h_addr ; //行地址计数器
wire add_cnt_h_addr ;
wire end_cnt_h_addr ;
reg [11:0] cnt_v_addr ; //场地址计数器
wire add_cnt_v_addr ;
wire end_cnt_v_addr ;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_h_addr <= 1'd0;
end
else if(add_cnt_h_addr)begin
if(end_cnt_h_addr)begin
cnt_h_addr <= 1'd0;
end
else begin
cnt_h_addr <= cnt_h_addr + 1'd1 ;
end
end
end
assign add_cnt_h_addr = 1'd1 ;
assign end_cnt_h_addr = add_cnt_h_addr && cnt_h_addr == `H_Total_Time - 1 ;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
cnt_v_addr <= 1'd0;
end
else if(add_cnt_v_addr)begin
if(end_cnt_v_addr)begin
cnt_v_addr <= 1'd0;
end
else begin
cnt_v_addr <= cnt_v_addr + 1'd1;
end
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 clk or negedge rst_n) begin
if(!rst_n)begin
hsync <= 1'b1;
end
else if(cnt_h_addr == H_SYNC_STA - 1)begin
hsync <= 1'b0;
end
else if(cnt_h_addr == H_SYNC_STO - 1)begin
hsync <= 1'b1;
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
vsync <= 1'b1;
end
else if(cnt_v_addr == V_SYNC_STA - 1)begin
vsync <= 1'b0;
end
else if(cnt_v_addr == V_SYNC_STO - 1)begin
vsync <= 1'b1;
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
vga_clk <= 1'b1;
end
else begin
vga_clk <= ~vga_clk;
end
end
//assign vga_clk = ~clk ;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
h_addr <= 11'b0;
end
else if((cnt_h_addr >= H_DATA_STA - 1) &&(cnt_h_addr <= H_DATA_STO - 1))begin
h_addr <= cnt_h_addr - H_DATA_STA;
end
else begin
h_addr <= 11'd0;
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
v_addr <= 11'b0;
end
else if((cnt_v_addr >= V_DATA_STA - 1) && (cnt_v_addr <= V_DATA_STO - 1))begin
v_addr <= cnt_v_addr - V_DATA_STA;
end
else begin
v_addr <= 11'd0;
end
end
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
vga_r <= 8'd0;
vga_g <= 8'd0;
vga_b <= 8'd0;
vga_blk <= 1'b0;
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_dis[23:16];
vga_g <= data_dis[15:8] ;
vga_b <= data_dis[7:0] ;
vga_blk <= 1'b1 ;
end
else begin
vga_r <= 8'd0;
vga_g <= 8'd0;
vga_b <= 8'd0;
vga_blk <= 1'b0;
end
end
endmodule
data_gen则是vga显示的数据生成文件
代码:
module data_gen (
input clk ,
input rst_n ,
input [10:0] h_addr , //数据有效显示区域行地址
input [10:0] v_addr , //数据有效显示区域场地址
output reg [23:0] data_dis
);
//参数定义
parameter BLACK = 24'h000_000 ,
RED = 24'hFF0_000 ,
GREEN = 24'h00F_F00 ,
BLUE = 24'h000_0FF ,
YELLOW = 24'hFFF_F00 ,
SKY_BULE= 24'h00F_FFF ,
PURPLE = 24'hFF0_0FF ,
GRAY = 24'hC0C_0C0 ,
WHITE = 24'hFFF_FFF ;
always @(posedge clk or negedge rst_n) begin
if(!rst_n)begin
data_dis <= WHITE;
end
else begin
case (h_addr)
0 : data_dis <= BLACK ;
100 : data_dis <= RED ;
200: data_dis <= GREEN ;
300: data_dis <= BLUE ;
400: data_dis <= YELLOW ;
500: data_dis <= SKY_BULE;
600: data_dis <= PURPLE ;
700: data_dis <= GRAY ;
default:data_dis<=data_dis;
endcase
end
end
endmodule
顶层文件:
module vga_top (
input clk ,
input rst_n ,
output wire hsync ,
output wire vsync ,
output wire [7:0] vga_r ,
output wire [7:0] vga_g ,
output wire [7:0] vga_b ,
output wire vga_blk ,
output wire vga_clk
);
wire [23:0] data_dis ;
wire [10:0] h_addr ;
wire [10:0] v_addr ;
data_gen u_data_gen(
.clk (clk ) ,
.rst_n (rst_n ) ,
.h_addr (h_addr ) , //数据有效显示区域行地址
.v_addr (v_addr ) , //数据有效显示区域场地址
.data_dis (data_dis)
);
vga_ctrl u_vga_ctrl(
.clk (clk ) ,
.rst_n (rst_n ) ,
.data_dis (data_dis) ,
.h_addr (h_addr ) , //数据有效显示区域行地址
.v_addr (v_addr ) , //数据有效显示区域场地址
.hsync (hsync ) ,
.vsync (vsync ) ,
.vga_r (vga_r ) ,
.vga_g (vga_g ) ,
.vga_b (vga_b ) ,
.vga_blk (vga_blk ) ,
.vga_clk (vga_clk )
);
endmodule
3.实现效果

二、显示自定义的汉字字符
1.字模提取
下载PCtoLCD取字模
设置字宽字高
输入提取字模的字
选择另存为bmp
打开刚才保存的bmp文件
点击生成字模并保存字模
格式选择c51
这就是需要的字模数据
2.代码
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;
[email protected](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 VGA_CLK = ~CLK_to_DAC; //VGA时钟等于CLK_25取反
assign CLK_to_DAC = CLK_25;
[email protected](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
[email protected](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;
[email protected](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;
[email protected](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 //点阵字模:每一行char_lineXX是显示的一行,共304列
char_line00=256'h0000000000000000000000000000000000000000000000000000000000000000, //第1行
char_line01=256'h0000000000000000000000000000000000000000000000000000000000000000, //第2行
char_line02=256'h0001000000800200000020000000000000000000000000000000000000000000, //第3行
char_line03=256'h0001803000C0030000C070000000000000000000000000000000000000000000, //第4行
char_line04=256'h0C01002000C5030000E060000000000000000000000000000000000000000000, //第5行
char_line05=256'h071220203FFE86000180C0000000000000000000000000000000000000000000, //第6行
char_line06=256'h031FF02000C0D600018181000000000000000000000001E003C00FFC07E001E0, //第7行
char_line07=256'h0318302000C0D7FC018300C000000000000000000000061806200FFC08380618, //第8行
char_line08=256'h0018302000C8AC1803060060000000000000000000000C180C30100010180C18, //第9行
char_line09=256'h001830240FFC2A10031FFFF000000000000000000000081818181000200C0818, //第10行
char_line0a=256'h001FFFFC00002BA0060F003000000000000000000000180018181000200C1800, //第11行
char_line0b=256'h02183020100053000701001000000000000000000000100018081000300C1000, //第12行
char_line0c=256'h7F1830201FFF43000F018380000000000000000000001000300C1000300C1000, //第13行
char_line0d=256'h061830203007C2800B0300E0000000000000000000003000300C1000000C3000, //第14行
char_line0e=256'h061FF0203024C6801B0640700000000000000000000033E0300C13E0001833E0, //第15行
char_line0f=256'h061834206FF8C640130CE018000000000000000000003630300C143000183630, //第16行
char_line10=256'h061836200000CC402310C098000000000000000000003818300C181800303818, //第17行
char_line11=256'h061833200000C8604321FFC0000000000000000000003808300C100800603808, //第18行
char_line12=256'h061833200FF818300303018000000000000000000000300C300C000C00C0300C, //第19行
char_line13=256'h067FF3200C18201C0303018000000000000000000000300C300C000C0180300C, //第20行
char_line14=256'h0600F0200C18C0080304830000000000000000000000300C300C000C0300300C, //第21行
char_line15=256'h0601B0200FF906000308820000000000000000000000300C300C000C0200300C, //第22行
char_line16=256'h062130200C101B000310460000000000000000000000300C1808300C0404300C, //第23行
char_line17=256'h06C330200020191003202C0000000000000000000000180C1818300C0804180C, //第24行
char_line18=256'h0786302004309908030038000000000000000000000018081818201810041808, //第25行
char_line19=256'h070C30200230980C03001800000000000000000000000C180C302018200C0C18, //第26行
char_line1a=256'h061830200320984403007E00000000000000000000000E30062018303FF80E30, //第27行
char_line1b=256'h02203020024F98440300C7800000000000000000000003E003C007C03FF803E0, //第28行
char_line1c=256'h00C3E3E003F31870030301FC0000000000000000000000000000000000000000, //第29行
char_line1d=256'h0100E0E03E000FE0031C00700000000000000000000000000000000000000000, //第30行
char_line1e=256'h0000404030000000026000100000000000000000000000000000000000000000, //第31行
char_line1f=256'h0000000000000000000000000000000000000000000000000000000000000000; //第32行
reg[8:0] char_bit;
[email protected](posedge CLK_to_DAC)
if(X==10'd144)char_bit<=9'd272; //当显示到144像素时准备开始输出图像数据
else if(X>10'd144&&X<10'd416) //左边距屏幕144像素到416像素时 416=144+272(图像宽度)
char_bit<=char_bit-1'b1; //倒着输出图像信息
reg[29:0] vga_rgb; //定义颜色缓存
[email protected](posedge CLK_to_DAC)
if(X>10'd144&&X<10'd416) //X控制图像的横向显示边界:左边距屏幕左边144像素 右边界距屏幕左边界416像素
begin case(Y) //Y控制图像的纵向显示边界:从距离屏幕顶部160像素开始显示第一行数据
10'd160:
if(char_line00[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000; //如果该行有数据 则颜色为红色
else vga_rgb<=30'b0000000000_0000000000_0000000000; //否则为黑色
10'd162:
if(char_line01[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd163:
if(char_line02[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd164:
if(char_line03[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd165:
if(char_line04[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd166:
if(char_line05[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd167:
if(char_line06[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd168:
if(char_line07[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd169:
if(char_line08[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd170:
if(char_line09[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd171:
if(char_line0a[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd172:
if(char_line0b[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd173:
if(char_line0c[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd174:
if(char_line0d[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd175:
if(char_line0e[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd176:
if(char_line0f[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd177:
if(char_line10[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd178:
if(char_line11[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd179:
if(char_line12[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd180:
if(char_line13[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd181:
if(char_line14[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd182:
if(char_line15[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd183:
if(char_line16[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd184:
if(char_line17[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd185:
if(char_line18[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd186:
if(char_line19[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd187:
if(char_line1a[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd188:
if(char_line1b[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd189:
if(char_line1c[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd190:
if(char_line1d[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd191:
if(char_line1e[char_bit])vga_rgb<=30'b1111111111_0000000000_0000000000;
else vga_rgb<=30'b0000000000_0000000000_0000000000;
10'd192:
if(char_line1f[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
3.实现效果

三、输出一幅彩色图像
1.图像转换

选择一张图片用画图打开
重设大小,我的这张图是400*343
另存为bmp
打开位图转换工具,生成mif文件
2.IP核调用

搜索ip核rom
选择后
de2-115的vga是24位,所以bits选择24
大小为400*343
选中mif文件finish
实例化
3.代码
vga驱动
module vga_drive (input wire clk,
input wire rst_n,
input wire [ 23:0 ] rgb_data,
output wire vga_clk,
output reg h_sync,
output reg v_sync,
output reg [ 11:0 ] addr_h,
output reg [ 11:0 ] addr_v,
output wire [ 7:0 ] rgb_r,
output wire [ 7:0 ] rgb_g,
output wire [ 7:0 ] rgb_b
);
// 640 * 480 60HZ
localparam H_FRONT = 16;
localparam H_SYNC = 96;
localparam H_BLACK = 48;
localparam H_ACT = 640;
localparam V_FRONT = 11;
localparam V_SYNC = 2;
localparam V_BLACK = 31;
localparam V_ACT = 480;
localparam H_TOTAL = H_FRONT + H_SYNC + H_BLACK + H_ACT; // 行周期
localparam V_TOTAL = V_FRONT + V_SYNC + V_BLACK + V_ACT; // 列周期
reg [ 11:0 ] cnt_h ; // 行计数器
reg [ 11:0 ] cnt_v ; // 场计数器
reg [ 23:0 ] rgb ; // 对应显示颜色值
// 对应计数器开始、结束、计数信号
wire flag_enable_cnt_h ;
wire flag_clear_cnt_h ;
wire flag_enable_cnt_v ;
wire flag_clear_cnt_v ;
wire flag_add_cnt_v ;
wire valid_area ;
wire clk_25 ;
wire clk_50 ;
//PLL
pll_one pll_one_inst (
.areset ( ~rst_n ),
.inclk0 ( clk ),
.c0 ( clk_50 ), //50M
.c1 ( clk_25 ) //25M
);
//根据不同分配率选择不同频率时钟
assign vga_clk = clk_25;
// 行计数
always @( posedge vga_clk or negedge rst_n ) begin
if ( !rst_n ) begin
cnt_h <= 0;
end
else if ( flag_enable_cnt_h ) begin
if ( flag_clear_cnt_h ) begin
cnt_h <= 0;
end
else begin
cnt_h <= cnt_h + 1;
end
end
else begin
cnt_h <= 0;
end
end
assign flag_enable_cnt_h = 1;
assign flag_clear_cnt_h = cnt_h == H_TOTAL - 1;
// 行同步信号
always @( posedge vga_clk or negedge rst_n ) begin
if ( !rst_n ) begin
h_sync <= 0;
end
else if ( cnt_h == H_SYNC - 1 ) begin // 同步周期时为1
h_sync <= 1;
end
else if ( flag_clear_cnt_h ) begin // 其余为0
h_sync <= 0;
end
else begin
h_sync <= h_sync;
end
end
// 场计数
always @( posedge vga_clk or negedge rst_n ) begin
if ( !rst_n ) begin
cnt_v <= 0;
end
else if ( flag_enable_cnt_v ) begin
if ( flag_clear_cnt_v ) begin
cnt_v <= 0;
end
else if ( flag_add_cnt_v ) begin
cnt_v <= cnt_v + 1;
end
else begin
cnt_v <= cnt_v;
end
end
else begin
cnt_v <= 0;
end
end
assign flag_enable_cnt_v = flag_enable_cnt_h;
assign flag_clear_cnt_v = cnt_v == V_TOTAL - 1;
assign flag_add_cnt_v = flag_clear_cnt_h;
// 场同步信号
always @( posedge vga_clk or negedge rst_n ) begin
if ( !rst_n ) begin
v_sync <= 0;
end
else if ( cnt_v == V_SYNC - 1 ) begin
v_sync <= 1;
end
else if ( flag_clear_cnt_v ) begin
v_sync <= 0;
end
else begin
v_sync <= v_sync;
end
end
// 对应有效区域行地址 1-640
always @( posedge vga_clk or negedge rst_n ) begin
if ( !rst_n ) begin
addr_h <= 0;
end
else if ( valid_area ) begin
addr_h <= cnt_h - H_SYNC - H_BLACK + 1;
end
else begin
addr_h <= 0;
end
end
// 对应有效区域列地址 1-480
always @( posedge vga_clk or negedge rst_n ) begin
if ( !rst_n ) begin
addr_v <= 0;
end
else if ( valid_area ) begin
addr_v <= cnt_v -V_SYNC - V_BLACK + 1;
end
else begin
addr_v <= 0;
end
end
// 有效显示区域
assign valid_area = cnt_h >= H_SYNC + H_BLACK && cnt_h <= H_SYNC + H_BLACK + H_ACT && cnt_v >= V_SYNC + V_BLACK && cnt_v <= V_SYNC + V_BLACK + V_ACT;
// 显示颜色
always @( posedge vga_clk or negedge rst_n ) begin
if ( !rst_n ) begin
rgb <= 24'h0;
end
else if ( valid_area ) begin
rgb <= rgb_data;
end
else begin
rgb <= 24'b0;
end
end
assign rgb_r = rgb[ 23:16 ];
assign rgb_g = rgb[ 15:8 ];
assign rgb_b = rgb[ 7:0 ];
endmodule // vga_dirve
数据转rgb
module data_drive (input wire vga_clk,
input wire rst_n,
input wire [ 11:0 ] addr_h,
input wire [ 11:0 ] addr_v,
output reg [ 23:0 ] rgb_data);
parameter height = 343; // 图片高度
parameter width = 400; // 图片宽度
reg [ 17:0 ] rom_address ; // ROM地址
wire [ 23:0 ] rom_data ; // 图片数据
wire flag_clear_rom_address ; // 地址清零
wire flag_begin_h ; // 图片显示行
wire flag_begin_v ; // 图片显示列
wire flag_enable_out ;
//状态输出
always @( * ) begin
if (flag_enable_out) begin
rgb_data = rom_data;
end
else begin
rgb_data= 0;
end
end
assign flag_begin_h = addr_h > ( ( 640 - width ) / 2 ) && addr_h < ( ( 640 - width ) / 2 ) + width + 1;
assign flag_begin_v = addr_v > ( ( 480 - height )/2 ) && addr_v <( ( 480 - height )/2 ) + height + 1;
assign flag_enable_out = flag_begin_h && flag_begin_v;
//ROM地址计数器
always @( posedge vga_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_out ) 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;
//实例化ROM
rom_2 rom_one_inst (
.address ( rom_address ),
.clock ( vga_clk ),
.q ( rom_data )
);
endmodule // data_drive
顶层文件
module vga_top (input wire clk,
input wire rst_n,
output wire vga_clk,
output wire h_sync,
output wire v_sync,
output wire [ 7:0 ] rgb_r,
output wire [ 7:0 ] rgb_g,
output wire [ 7:0 ] rgb_b
);
reg [ 27:0 ] cnt ;
wire [ 11:0 ] addr_h ;
wire [ 11:0 ] addr_v ;
wire [ 23:0 ] rgb_data ;
//vga模块
vga_drive u_vga_drive(
.clk ( clk ),
.rst_n ( rst_n ),
.rgb_data ( rgb_data ),
.vga_clk ( vga_clk ),
.h_sync ( h_sync ),
.v_sync ( v_sync ),
.rgb_r ( rgb_r ),
.rgb_g ( rgb_g ),
.rgb_b ( rgb_b ),
.addr_h ( addr_h ),
.addr_v ( addr_v )
);
//数据模块
data_drive u_data_drive(
.vga_clk ( vga_clk ),
.rst_n ( rst_n ),
.addr_h ( addr_h ),
.addr_v ( addr_v ),
.rgb_data ( rgb_data )
);
endmodule // vga_top
4.实现效果

四、参考
https://blog.csdn.net/qq_47281915/article/details/125134764?spm=1001.2014.3001.5502
版权声明
本文为[[email protected]]所创,转载请带上原文链接,感谢
https://blog.csdn.net/xyf_fate/article/details/125167171
边栏推荐
- The relocation of Apple's production line shows that 5g industrial interconnection and intelligent manufacturing have limited help for manufacturing in China
- CoordinatorLayout使用浅析
- 【FAQ】运动健康服务REST API接口使用过程中常见问题和解决方法总结
- 解决win10虚拟机和主机不能互相粘贴复制的问题
- 常见的自动化测试框架有哪些?上海软件测试公司安利
- On distributed transaction
- typescript入门笔记(个人用)
- Site investigation system
- 常识,神经元数量,小鼠的脑内神经元大约在7000万个、人类约有860亿个
- WT2003H4-16S 语音芯片按键录音及播放应用解析
猜你喜欢

【Multisim仿真】差分放大电路2

传奇登录器提示连接服务器失败是怎么回事?怎么解决?

On distributed transaction

多云管理平台cmp是什么意思?谁能清楚解释一下

Introduction to assembly language - Summary

Apple邮箱配置QQ邮箱,163邮箱,edu邮箱,gmail邮箱,获取gmail日历

5.8G微波雷达模块使用,5.8G微波雷达模块工作原理和介绍
![[笔记]Windows安全之《三》Shellcode 补充之 Get-InjectedThread脚本搭建环境及其使用](/img/b4/f7838a7e12379190e2bc9b869839f0.png)
[笔记]Windows安全之《三》Shellcode 补充之 Get-InjectedThread脚本搭建环境及其使用

2022大厂高频软件测试面试真题(附答案)

3. web page development tool vs Code
随机推荐
Normal controller structure
解决win10虚拟机和主机不能互相粘贴复制的问题
[Huang ah code] Why is php7 twice as fast as PHP5?
How to locate the hot problem of the game
[笔记]Windows安全之《三》Shellcode 补充之 Get-InjectedThread脚本搭建环境及其使用
工作中记录MySQL中的常用函数
Sohu employees encounter wage subsidy fraud. What is the difference between black property and gray property and how to trace the source?
什么是基因的p值?
Google Earth Engine(GEE)——基于s2影像的实时全球10米土地利用/土地覆盖(LULC)数据集
"Reduce the burden" so that the "pig" can fly higher
From "chemist" to developer, from Oracle to tdengine, two important choices in my life
leetcode-56-合并区间
#yyds干货盘点# 解决剑指offer:跳台阶扩展问题
[deep learning] the credit card fraud anomaly detection based on the deep learning autoencoder is very effective
The shortcomings of the "big model" and the strengths of the "knowledge map"
10 competitive airpods Pro products worth your choice
Can qiniu open an account? Can the security of securities companies be directly opened on the app
组装芯片难保竞争优势,痛定思痛的高通终于开始自研核心架构
CL210OpenStack操作的故障排除--常见核心问题的故障排除
多云管理平台cmp是什么意思?谁能清楚解释一下