FPGA学习笔记:verilog基础代码与modelsim仿真(六)——vga显示模块

VGA显示

目标:实现屏幕红、橙、黄、绿、青、蓝、紫、黑、白、灰条形显示

1. 模块框图与波形图

在这里插入图片描述

vga_colorbar是实现目标功能的总体模块框图,为了实现对应的输出,我们使用三个具体功能模块实现功能。

(1) clk_gen——使用pll锁相环实现时钟分频
(2)vga_ctrl——图像控制与输出模块
(3)vga_pic——图像数据生成模块

将三个模块布局布线,最终组成vga_colorbar模块,如下图:

在这里插入图片描述
首先讨论clk_gen模块。由图,sys_clk与sys_rst_n是系统时钟与复位按钮
clk_gen是我们自定义的输出频率为15MHZ时钟的pll锁相环;
areset为复位按键,由于其为高电平有效,故对sys_rst_n取反输入。
clk_out是15MHZ时钟;
locked为标志信号,正常输出高电平,当复位信号有效时,输出低电平;

在讨论接下来的两个模块之前,我们先明确显示屏是如何显示我们需要的图像,这对后面的模块设计至关重要



首先明确VGA显示屏是如何扫描得到有效图像:


VGA扫描原理
如上图所示,直观来看vga显示屏从左到右,从上到下逐个像素点进行扫描;
那么控制行扫描的信号成为行同步信号——hync;
控制列扫描信号成为场同步信号——vsync;


接着,我们进一步来看行同步信号hysnc与场同步信号vsync的详细数据:

在这里插入图片描述


行/场同步信号从波形的角度看可分为六部分,分别为同步、后沿、左边框、有效图像、右边框、前沿部分;表中的时钟部分代表着clk_gen的输出时钟频率,也是vga_ctrl、vga_pic的输入时钟频率,本文中我们使用25MHZ时钟频率。


有效图像部分

图中红色与黄色相交的部分即为有效图像部分


至此,我们可以开始绘制各个模块的波形图进而编写代码。

2. 子模块波形图与代码实现

(1).vga_ctrl模块波形图

vga_ctrl模块

在这里插入图片描述
绿色为输入数据,红色为输出数据,黄色为中间变量;

cnt_h与cnt_v分别为行同步计数与场同步计数,即图像的坐标,由上表可知,当cnt_h技术到144-83范围且cnt_v在计数到35-514范围时,vga在有效图像的显示范围内。
pix_x与pix_y分别为有效图像显示的坐标变量;
rgb_valid为有效图像标志信号;


(2).vga_ctrl模块代码实现

RTL代码:

 module vga_ctrl

 (
     
    input   wire         vga_clk     ,
    input   wire         sys_rst_n   ,
    input   wire[15:0]   pix_data     ,
    
    output  wire         hsync       ,
    output  wire         vsync       ,
    output  wire  [9:0]  pix_y       ,
    output  wire  [9:0]  pix_x       ,
    output  wire [15:0]  vga_rgb      
     
 
     
     
 );
     parameter  H_SYNC   = 10'd96  ,
                H_BACK    = 10'd40 ,
                H_LEFT    = 10'd8  ,
                H_VALID   = 10'd640,
                H_RIGHT   = 10'd8  ,
                H_FRONT   = 10'd8  ,
                H_TOTAL   = 10'd800 ;
                
    parameter   V_TOTAL   = 10'd525 ,
                V_SYNC    = 10'd2   ,
                V_BACK    = 10'd25  ,
                V_TOP    = 10'd8   ,
                V_VALID   = 10'd480 ,
                V_RIGHT   = 10'd8   ,
                V_FRONT   = 10'd2   ;
       
       
 
 
reg    [9:0]   cnt_h   ;
reg    [9:0]   cnt_v   ;
wire           rgb_valid ;
wire           pix_data_req ;
 
 always@(posedge vga_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_h <= 10'd0;
    else    if(cnt_h == H_TOTAL  - 10'd1)
        cnt_h <= 10'd0 ;
    else
        cnt_h <= 10'd1 + cnt_h ;
        
 always@(posedge vga_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_v <= 10'd0;
    else    if(cnt_v == V_TOTAL - 10'd1 && cnt_h == H_TOTAL  - 10'd1)
        cnt_v <= 10'd0 ;
    else    if(cnt_h == H_TOTAL -1'b1)
        cnt_v <= 10'd1 + cnt_v ;  
    else
        cnt_v <= cnt_v ;
        
        
        
        
assign rgb_valid = ((cnt_h >= H_SYNC + H_BACK + H_LEFT)
                      && (cnt_h < H_SYNC + H_BACK+  H_LEFT + H_VALID)
                      && (cnt_v >= V_SYNC + V_BACK + V_TOP)
                      && (cnt_v < V_SYNC + V_BACK+  V_TOP + V_VALID))
                      ? 1'b1 : 1'b0 ;
                      
                     
assign pix_data_req = ((cnt_h >= H_SYNC + H_BACK + H_LEFT -1'b1)
                      && (cnt_h < H_SYNC + H_BACK+  H_LEFT + H_VALID - 1'b1)
                      && (cnt_v >= V_SYNC + V_BACK + V_TOP)
                      && (cnt_v < V_SYNC + V_BACK+  V_TOP + V_VALID))
                      ? 1'b1 : 1'b0 ;
                      

assign pix_x = (pix_data_req == 1'b1) ? (cnt_h - (H_SYNC + H_BACK +H_LEFT - 1'b1)) :10'h3ff ;
assign pix_y = (pix_data_req == 1'b1) ? (cnt_v - (V_SYNC + V_BACK +V_TOP)) :10'h3ff ;



assign hsync = (cnt_h <= H_SYNC - 10'd1) ? 1'b1 : 1'b0 ;
assign vsync = (cnt_v <= V_SYNC - 10'd1) ? 1'b1 : 1'b0 ;


assign vga_rgb = (rgb_valid == 1'b1) ? pix_data : 16'h0000 ;





 
 endmodule
 

仿真代码:

  `timescale 1ns/1ns
  module tb_vga_ctrl();
  
  reg           sys_clk     ;
  reg           sys_rst_n   ;
  wire  [15:0]  pix_data    ;

wire            vga_clk     ;
wire            locked      ;
wire            rst_n       ;

wire    [9:0]   pix_x       ;
wire    [9:0]   pix_y       ;
wire            hsync       ;
wire            vsync       ;
wire    [15:0]  vga_rgb     ;
 
  initial
     begin
         sys_clk = 1'b1;
         sys_rst_n <= 1'b0;
         #20
         sys_rst_n <= 1'b1;
     end
  
 always #10 sys_clk = ~sys_clk; //clk frequency
 
 assign rst_n = (sys_rst_n && locked) ;
    
 
clk_gen	    clk_gen_inst (
	.areset ( ~sys_rst_n ),
	.inclk0 ( sys_clk ),
	.c0     ( vga_clk ),
	.locked ( locked )
	);

 
vga_ctrl  vga_ctrl_inst
 (

         .sys_rst_n(rst_n)   ,
         .vga_clk   (vga_clk )  ,
         .pix_data  (pix_data)   ,
        
         .hsync     (hsync)  ,
         .vsync     (vsync  )  ,
         .pix_y     (pix_y )  ,
         .pix_x     (pix_x )  ,
         .vga_rgb   (vga_rgb)   
         
    
            
         
 );
 
vga_pic     vga_pic_inst
(
    .vga_clk    (vga_clk ) ,
    .sys_rst_n  (rst_n) ,
    .pix_x      (pix_x ) ,
    .pix_y      (pix_y  ) ,
         
    .pix_data   (pix_data) 
  
  
);
     
 endmodule
(3).vga_pic模块波形

vga_pic模块波形
在这里插入图片描述

(3).vga_pic代码实现

RTL代码:

module vga_pic(
    input   wire            vga_clk     ,
    input   wire            sys_rst_n   ,
    input   wire    [9:0]   pix_x       ,
    input   wire    [9:0]   pix_y       ,
    
    output  reg     [15:0]  pix_data    
  
  
);

 parameter   H_VALID = 10'd640,
             V_VALID = 10'd480;
    
parameter   RED         = 16'hF800  ,
            ORANGE      = 16'hfc00  ,
            YELLOW      = 16'hffe0  ,
            GREEN       = 16'h07e0  ,
            CYAN        = 16'h07ff  ,
            BLUE        = 16'h00ff  ,
            PURPLE      = 16'hf81f  ,
            BLACK       = 16'h0000  ,
            WHITE       = 16'hffff  ,
            GRAY        = 16'hd69a  ;
 
always@(posedge vga_clk  or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        pix_data <= BLACK ;
    else    if(pix_x >= 10'd0 && pix_x < ((H_VALID / 10) * 1 ))
        pix_data <= RED   ;
    else    if((pix_x >= (H_VALID / 10) * 1)  && pix_x < ((H_VALID / 10) * 2 ))
        pix_data <= ORANGE  ;
    else    if((pix_x >= (H_VALID / 10) * 2 ) && pix_x < ((H_VALID / 10) * 3 ))
        pix_data <= YELLOW   ;
    else    if((pix_x >= (H_VALID / 10) * 3 ) && pix_x < ((H_VALID / 10) * 4 ))
        pix_data <= GREEN   ;
    else    if((pix_x >= (H_VALID / 10) * 4 ) && pix_x < ((H_VALID / 10) * 5 ))
        pix_data <= CYAN   ;
    else    if((pix_x >= (H_VALID / 10) * 5 ) && pix_x < ((H_VALID / 10) * 6 ))
        pix_data <= BLUE    ;
    else    if((pix_x >= (H_VALID / 10) * 6 ) && pix_x < ((H_VALID / 10) * 7 ))
        pix_data <= PURPLE   ;
    else    if((pix_x >= (H_VALID / 10) * 7 )&& pix_x < ((H_VALID / 10) * 8 ))
        pix_data <= BLACK   ;
    else    if((pix_x >= (H_VALID / 10) * 8 ) && pix_x < ((H_VALID / 10) * 9 ))
        pix_data <= WHITE   ;
    else    if((pix_x >= (H_VALID / 10) * 9 ) && pix_x < H_VALID )
        pix_data <= GRAY   ;
    else
        pix_data <= BLACK   ;
      
 
 
 
 
endmodule

3.顶层模块vga_colorbar代码实现

RTL代码:

module vga_colorbar(    
    input   wire        sys_clk     ,
    input   wire        sys_rst_n   ,
    
    output  wire        hsync       ,
    output  wire        vsync       ,
    output  wire [15:0]  vga_rgb      

);

wire    vga_clk     ;
wire    locked      ;
wire    rst_n       ;

wire    [9:0]   pix_x   ;
wire    [9:0]   pix_y   ;
wire    [15:0]  pix_data ;

assign  rst_n = (sys_rst_n && locked);

clk_gen	clk_gen_inst (
	.areset ( ~sys_rst_n ),
	.inclk0 ( sys_clk ),
	.c0     ( vga_clk ),
	.locked ( locked )
	);

 
vga_ctrl  vga_ctrl_inst
 (

    .sys_rst_n(rst_n)   ,
    .vga_clk   (vga_clk )  ,
    .pix_data  (pix_data)   ,
    
    .hsync     (hsync)  ,
    .vsync     (vsync  )  ,
    .pix_y     (pix_y )  ,
    .pix_x     (pix_x )  ,
    .vga_rgb   (vga_rgb)   
         
    
            
         
 );
 
vga_pic     vga_pic_inst
(
    .vga_clk    (vga_clk ) ,
    .sys_rst_n  (rst_n) ,
    .pix_x      (pix_x ) ,
    .pix_y      (pix_y  ) ,
         
    .pix_data   (pix_data) 
  
  
);
 
 
endmodule


顶层模块仿真代码:

 `timescale 1ns/1ns
module tb_vga_colorbar();    
      reg       sys_clk     ;
      reg       sys_rst_n   ;
                           
      wire        hsync     ;
      wire        vsync     ;
      wire [15:0]  vga_rgb  ; 

initial
    begin
         sys_clk = 1'b1;
         sys_rst_n <= 1'b0;
         #20
         sys_rst_n <= 1'b1;
    end
     
always #10 sys_clk = ~sys_clk; //clk frequency

vga_colorbar   vga_colorbar_inst
(
   .sys_clk   (sys_clk ) ,
   .sys_rst_n (sys_rst_n ) ,
               
   .hsync     (hsync  ) ,
   .vsync     (vsync  ) ,
   .vga_rgb   (vga_rgb )

);




endmodule 
  • 1
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
好的,以下是一个万年历的FPGA课程设计的Verilog代码仿真: ``` module calendar( input clk, // 时钟信号 input reset, // 复位信号 output reg [3:0] year, // 年份 output reg [3:0] month, // 月份 output reg [4:0] day, // 日 output reg [2:0] week // 星期 ); // 闰年判断 wire leap_year = ((year % 4 == 0) && (year % 100 != 0)) || (year % 400 == 0); // 每月天数 reg [6:0] days_in_month; always @(*) begin case (month) 4, 6, 9, 11: days_in_month = 30; 2: days_in_month = leap_year ? 29 : 28; default: days_in_month = 31; endcase end // 日历计算 reg [5:0] day_count; reg [2:0] day_of_week; always @(posedge clk or posedge reset) begin if (reset) begin year <= 0; month <= 1; day <= 1; week <= 0; day_count <= 0; day_of_week <= 0; end else begin if (day_count == 0) begin day_count <= 1; day_of_week <= (day_of_week == 6) ? 0 : day_of_week + 1; if (day == days_in_month) begin day <= 1; if (month == 12) begin month <= 1; year <= year + 1; end else begin month <= month + 1; end end else begin day <= day + 1; end end else begin day_count <= day_count + 1; end week <= (day_count + day_of_week) % 7; end end endmodule ``` 在上面的代码中,我们使用了一个状态机来计算每一天的日期和星期。在每个时钟上升沿,我们检查当前是否需要更新日历,以及更新哪些日期和星期。我们还使用一个闰年标志来计算每个月的天数。最后,我们将日历输出到四个输出端口。 以下是一个简单的仿真测试,它显示了日历的输出。在仿真中,我们提供了一个时钟信号和一个复位信号,以便在仿真开始时将日历复位为1月1日。 ``` module calendar_tb; reg clk; reg reset; wire [3:0] year; wire [3:0] month; wire [4:0] day; wire [2:0] week; calendar dut( .clk(clk), .reset(reset), .year(year), .month(month), .day(day), .week(week) ); initial begin clk = 0; reset = 1; #10 reset = 0; end always #5 clk = ~clk; initial begin $monitor("%d/%d/%d %d", year, month, day, week); #100 $finish; end endmodule ``` 在上面的仿真测试中,我们使用了一个monitor语句来跟踪日历的输出,并在仿真完成时结束仿真。我们还提供了一个时钟和复位信号以启动仿真。 希望这个代码仿真对您有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

保温杯配红牛

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值