欢迎使用CSDN-markdown编辑器

来源:互联网 发布:短暂的婚姻 知乎 编辑:程序博客网 时间:2024/06/06 01:45
                        **FPGA学习之VGA显示图片** 这周刚刚调完用FPGA自带的ROM来存储图片,并且用VGA在显示器上显示,下面上详细的操作步骤。

一、从整体上认识我们要做什么

从图中可以看到,我们需要控制的信号有VGA_CLK,VGA_SYNC_N,
VGA_BLANK_N,VGA_R,VGA_G,VGA_B等。相应的信号定义见以下代码。

        //system signals        input wire          s_clk       ,        input wire          s_rst_n     ,        //VGA signals        output wire         vga_clk     ,        output wire  [7:0]  vga_R       ,        output wire  [7:0]  vga_G       ,        output wire  [7:0]  vga_B       ,        output wire         vga_sync_n  ,        output wire         vga_black_n ,        output reg          vga_vs      ,        output reg          vga_hs

二、定义的信号解释
s_clk : 输入时钟,频率为25M
s_rst_n : 系统复位,低电平复位
vga_clk : VGA时钟,频率为25M
vga_R、vga_G、vga_B :图片的红、绿、蓝三个分量
vga_sync_n、vga_black_n:DAC的控制信号
vga_vs、vga_hs:vga行信号、场信号
三、VGA控制时序
这里写图片描述
这里写图片描述
我们要实现的分辨率是640*480,需要用到的VGA时钟就是25MHz(具体的计算方法网上可以找到),根据VGA时序的具体要求,我们能得到以下参数(这些代码中的数字表示要经过多少个时钟周期):

//=========场信号parameter h_total           = 12'd800 - 12'd1   ;parameter h_sync            = 12'd96            ;//同步信号parameter h_back_proch      = 12'd48            ;//显示后沿parameter h_front_proch     = 12'd16            ;//显示前沿parameter h_display         = 12'd640           ;//显示区域//=========行信号parameter v_total           = 12'd525 - 12'd1   ;parameter v_sync            = 12'd2             ;//同步信号parameter v_back_proch      = 12'd33            ;//显示后沿parameter v_front_proch     = 12'd10            ;//显示前沿parameter v_display         = 12'd480           ;//显示区域  

下面是行信号与场信号的产生:

//=============================================//行信号always @ ( posedge s_clk or negedge s_rst_n )begin    if ( !s_rst_n )        vga_hs <= 1'b0 ;    else if ( xcnt >= h_sync )        vga_hs <= 1'b1 ;    else        vga_hs <= 1'b0 ;end//==============================================//场信号always @ ( posedge s_clk or negedge s_rst_n )begin    if ( !s_rst_n )        vga_vs <= 1'b0 ;     else if ( ycnt >= v_sync )        vga_vs <= 1'b1 ;    else        vga_vs <= 1'b0 ;end//=============================================

接下来,行像素计数和场信号像素计数:

//=============================================//行信号计数always @ ( posedge s_clk or negedge s_rst_n )begin    if ( !s_rst_n )        xcnt <= 12'd0 ;    else if ( xcnt == h_total )        xcnt <= 12'd0 ;    else        xcnt <= xcnt + 1'b1 ;end//==============================================//场信号计数always @ ( posedge s_clk or negedge s_rst_n )begin    if ( !s_rst_n )        ycnt <= 12'd0 ;    else if ( xcnt == h_total )        ycnt <= ycnt + 1'b1 ;    else if ( ycnt == v_total )        ycnt <= 12'd0 ;end

确定显示器的显示区域(和定义的参数数据一起看):

//=============================================//显示有效区域always @ ( posedge s_clk or negedge s_rst_n )begin    if ( !s_rst_n )        display_en <= 1'b0 ;    else if ( ( xcnt >= h_sync + h_back_proch ) && ( xcnt <= h_sync + h_back_proch + h_display )               && ( ycnt >= v_sync + v_back_proch ) && ( ycnt <= v_sync + v_back_proch + v_display) )        display_en <= 1'b1 ;    else        display_en <= 1'b0 ;end

由于在工程中调用了ROM,所以,把ROM例化:

//=============================================//ROM例化wire    [23:0]          q           ;reg     [15:0]          addr        ;my_rom      u_my_rom(    .address    (   addr    )   ,    .clock      (   s_clk   )   ,    .q          (   q       )) ;            

重头戏来了,图片显示坐标的确定,我参考的是网上一些计算公式来确定ROM的地址信息:

//图像区域显示reg             picture     ;reg     [11:0]  y_cnt       ; always @ ( posedge s_clk or negedge s_rst_n )begin    if ( !s_rst_n )        picture <= 1'b0 ;    else if ( xcnt >= 12'd201 && ycnt >= 12'd200 && xcnt <= 12'd468 && ycnt <= 12'd349 )        picture <= 1'b1 ;    else        picture <= 1'b0 ;end

addr <= ( ycnt - 16’d200 ) * 16’d267 + ( xcnt - 16’d200 );
这句代码中的数字解释一下,括号中的200指的是显示图片的原点,及ROM地址为0,267指的是图像的宽度,这样计算,就能得到相应的ROM地址,也就能得到像素的值。

//ROM数据读取always @ ( posedge s_clk or negedge s_rst_n )begin    if ( !s_rst_n )        addr <= 16'd0 ;    else if ( picture )        addr <= ( ycnt - 16'd200 ) * 16'd267 + ( xcnt - 16'd200 );    else         addr <= 16'd0 ;end

DAC控制信号代码(为什么信号这么赋值,请参考数据手册):

assign vga_sync_n  = 1'b0 ;assign vga_black_n = display_en ;

四、mif文件的生成
用画图软件将需要显示的图片从JPG另存为BMP,然后用下面这个软件,根据自己想要的格式,一键转换成mif文件:
这里写图片描述
将mif文件添加到ROM中,接下来就可以愉快的用VGA来显示图片了!
五、结束语
第一次写博客,可能没有很好地组织语言,各位看官若是有什么问题,欢迎发送邮件到otherfiles@163.com讨论!谢谢!

原创粉丝点击