vivado中HDMI的显示彩条,图片,灰度值,二值化。

       #1


高清多媒体接口High Definition Multimedia Interface,HDMI )是一种全数字视频声音发送接口,可以发送未压缩音频视频信号。HDMI可用于机顶盒DVD播放机个人计算机、电视、游戏主机、综合扩大机、数字音响与电视机等设备。HDMI可以同时发送音频和视频信号,由于音频和视频信号采用同一条线材,大大简化系统线路的安装难度。

        HDMI是日常生活中常用的视频输入输出接口协议,可以同时传输视频和音频,且速率高,有四种接口,但是比较常用的是Type-A接口,长下面这个样子。

  然后是时序标准,可以看到,采用的是1920 x 1080的分辨率,60Hz的刷新率

        可以看到其中行的像素点总共是2200个,其中有效显示图像的像素点是1920个,行同步信号是44个像素点,后沿是148个像素点,前沿是88个像素点,这样在HDMI里面一行就有1920+44+148+88=2200个像素点.

HDMI编码接口可以用开发工具中现成的IP,我们只需要把RGB的数据输出到IP中就可以了,先简单的显示一下彩条,最基础的图像测试。

        宽在这里面叫做场,可以看到一共有1125个像素点,其中有1080个像素点是有效显示图像的,场同步信号是5个像素点,后沿是36个,前沿是4个,加起来就是1125+36+4+5=1125.

因为左右和上下边框都是0,这里就可以不用管他们。

这样我们就可以定义参数:

parameter   H_SYNC  = 12'd44    ,
            H_BACK  = 12'd148   ,
            H_VALD  = 12'd1920  ,
            H_FRONT = 12'd88    ,
            H_TOTAL = 12'd2200  ;

parameter   V_SYNC  = 12'd5     ,
            V_BACK  = 12'd36    ,
            V_VALD  = 12'd1080  , 
            V_FRONT = 12'd4     ,
            V_TOTAL = 12'd1125  ;

         首先显示一个彩条,这是最简单的测试了,如果想实现竖的彩条,那就在行上面做文章,我们可以分成三等分,每640个像素点换个颜色,比如三原色,红蓝绿,这个很简单,用一个always块便可以实现。

always @(posedge pclk)
    if((pix_x >= 192) && (pix_x <=832))
        pix_data<=RED;
    else if((pix_x > 832) && (pix_x <=1472))
        pix_data<=GREEN;
    else if((pix_x > 1472) && (pix_x <=2112))
        pix_data<=BLUE;
    else
        pix_data<=24'hff; 

         然后显示图像原图,我们需要准备一张喜欢的图片,但是要注意这个图片的大小,因为板子的资源是有限的,要注意好板子可以存多大的图片,这里用的是200*200的大小,我们用MATLAB把图片生成一个coe文件,这样就可以把图片放到我们的rom中。

这里用的一个简单的单端口rom,因为我们只需要读出数据就可以了。

输出位宽24位,因为RGB888,红蓝绿每个占8位.

 然后这里我们选中本地生成的coe文件。

     然后是行扫描和场扫描的计数器,每个时钟来临让像素点动一次,扫描完一行换下一行。

always @(posedge pclk)
    if(!rst_n)
        cnt_h <= 'd0;
    else if(cnt_h == H_TOTAL - 1)
        cnt_h <= 'd0;
    else 
        cnt_h <= cnt_h + 1;
        
always @(posedge pclk)
    if(!rst_n)
        cnt_v <= 'd0;
    else if(cnt_v == V_TOTAL - 1 && cnt_h == H_TOTAL - 1)
        cnt_v <= 'd0;
    else if(cnt_h == H_TOTAL - 1)
        cnt_v <= cnt_v + 1;

  然后涉及到一个显示区域的问题,因为显示器的标格式有前沿后沿,左边框右边框等,所以我们可以单独设置一个DE信号,只有当显示器需要显示内容时才显示,其他时候给一个默认值即可,这个操作可以用一个三目运算符完成。

assign de = (cnt_h >= H_SYNC + H_BACK && cnt_h < H_SYNC + H_BACK + H_VALD
             && cnt_v >= V_SYNC + V_BACK && cnt_v < V_SYNC + V_BACK + V_VALD) ? 1: 0;
assign rgb = (de)? rgb_data : 24'hffffff;

然后是图片模块

这里可以直接调用官方的IP核,找到romIP和进行配置,因为我们只需要读数据就可以了

这里的数据位宽选择24位,因为是RGB888,所以一个像素点有24个数据,然后深度选择65536,因为我的图片格式是256x256=65536

这里的rom数据源我们就选择转换出来的coe文件,记得要对上深度和位宽,不然会报错的。

然后就可以简单的写一个模块,输入坐标数据,然后按顺序读出数据就好,没有什么问题。

module vga_pic(
    input   wire                pclk    ,
    input   wire                rst_n   ,
    input   wire    [11:0]      pic_x   ,
    input   wire    [11:0]      pic_y   ,
    output  wire    [23:0]      rgb_data  
    );    
assign  rgb_data =  data_out    ;
blk_mem_gen_0 your_instance_name (
  .clka(pclk),  
  .addra({pic_y[7:0] ,pic_x[7:0]}),
  .douta(data_out)                             

这里的时钟是用的官方的IP核,因为视频显示的时钟是很快的,开发板默认的50M时钟是肯定来不及的,所以我们需要更快的时钟才能完成数据的输入输出。

这里下面的时钟源输入50MHz,然后输出两个148.5的时钟还有742.5的时钟,这个148.5的时钟

这里的148.5的时钟是因为这样的,我们可以计算一下

        这就是为什么时钟需要用148.5MHz的,然后还有一个742.5MHz的时钟,因为HMDI有一个TMDS模块,会进行一个8转10bit的操作,所以我们需要在一个工作时钟周期内串行传10个数据。

        你也可能会说那为什么时钟是742.5的,不应该是1485MHz吗,为什么只有一半,是因为他是双沿输出,一个时钟周期可以输出两个数据,所以时钟只需要一般就可以了,所以是742.5。

        因为我们是要进行三种图片处理的展示,一种原图,一种灰度,一种原图,所以可以单独写一个控制模块,这个模块的主要作用是将显示的区域隔开,我们可以界定一个区域显示一种效果。

`timescale 1ns / 1ps


module pic_ctrl(
input                       pclk            ,
input                       rst_n           ,
input  wire     [11:0]      pic_x           ,
input  wire     [11:0]      pic_y           ,
input           [23:0]      rgb_data_src    ,//原图数据
input           [23:0]      rgb_data_gray   ,//灰度数据
input           [23:0]      rgb_data_binary ,//二值化数据
input                       rgb_de_src      ,//使能信号
input                       rgb_de_gray     ,//使能信号
input                       rgb_de_binary   ,//使能信号
output reg [23:0]           rgb_data_aim        //最终输出视频信号
    );   
parameter block1=256;
parameter block2=512;
parameter block3=768;    
parameter SIZE=256;
always @(posedge pclk)
    if(!rst_n)
        rgb_data_aim<=0;
    else if(pic_x > 0 && pic_x <=256 && pic_y >= 0 && pic_y < 256)//使能信号
        rgb_data_aim<=rgb_data_src;//原图数据
    else if(pic_x > 256 && pic_x <=512 && pic_y >= 0 && pic_y < 256)//使能信号
        rgb_data_aim<=rgb_data_gray;//灰度数据
    else if(pic_x > 512 && pic_x <=768 && pic_y >= 0 && pic_y < 256)//使能信号
        rgb_data_aim<=rgb_data_binary;//二值化数据  
    else
        rgb_data_aim<=24'h00ffff;     
        
//assign  rgb_data = (pic_x > image_x && pic_x <=image_x + SIZE && pic_y >= image_y && pic_y < image_y + SIZE) ? data_out : 24'h0;        
              
endmodule

这里的原图数据已经接入了,然后还差灰度和二值化的数据,所以接下来就是数据处理的模块。

灰度处理

这里是直接用的算法,网上有很多的算法,可以自己挑选一个喜欢的。

先进行一个取值,取出我们的RGB数据

wire [7:0] red;    
wire [7:0] blue;    
wire [7:0] green;    
 
assign blue  =rgb_data[7:0]; 
assign green =rgb_data[15:8]; 
assign red=rgb_data[23:16]; 

然后进行一个乘法处理,然后相加,最后移位来代替一个除法

always @(posedge pclk) begin
    if(!rst_n) begin
        red_r   <= 0;
        green_r <= 0;
        blue_r  <= 0;
    end else begin
        red_r   <= red * 8'd77;
        green_r <= green * 8'd150;
        blue_r  <= blue * 8'd29;
    end
end
// 第二级加法寄存器
reg [15:0] gray_r1;

always @(posedge pclk) begin
    if(!rst_n)
        gray_r1 <= 0;
    else
        gray_r1 <= red_r + green_r + blue_r;
end
// 第三级移位寄存器
reg [7:0] gray_r2;

always @(posedge pclk) begin
    if(!rst_n)
        gray_r2 <= 0;
    else
        gray_r2 <= gray_r1>>8;
end

最后将这个gray_r2复制三遍,拼在一起组成一个24为的数据即可。

assign rgb_gray={gray_r2,gray_r2,gray_r2};//gray_r2,gray_r2,

灰度到这里就处理结束了

二值化处理

二值化这个就太简单了,刚刚不是完成了图片的灰度化处理吗,直接判断这个数值的大小,我们可以界定一个界限,当这个值超过一定数时就给黑色,当小于等于时就给白色。

assign rgb_data = (rgb_gary>127)?24'hffffff:24'h0;

然后是顶层模块



module TOP(
    input   wire            sys_clk     ,
    input   wire            sys_rst_n   ,
    output  wire            hdmi_clk_p  ,
    output  wire            hdmi_clk_n  ,
    output  wire            hdmi_red_p  ,
    output  wire            hdmi_red_n  ,
    output  wire            hdmi_green_p,
    output  wire            hdmi_green_n,
    output  wire            hdmi_blue_p ,
    output  wire            hdmi_blue_n ,
    output  wire            HDMI_EN
    );
assign  HDMI_EN = 1;
wire    [11:0]   pic_x   ;
wire    [11:0]   pic_y   ;
wire            de;
wire            vga_clk;
wire            locked;
wire            rst;
wire    [23:0]  rgb_data;  
wire    [23:0]  rgb_gray;
wire    [23:0]  rgb_binary;
wire    [23:0]  rgb;
wire    [23:0]  rgb_data_aim;
wire            vsync;
wire            hsync; 
wire            vga_clk_5x;
wire            fps_flag;    
assign  rst = locked & sys_rst_n;

hdmi_ctrl hdmi_ctrl_inst(
    .sys_clk     (vga_clk     ),
    .sys_clk_5x  (vga_clk_5x  ),
    .sys_rst_n   (rst   ),
    .de          (de   ),
    .hsync       (hsync       ),
    .vsync       (vsync       ),
    .rgb_blue    (rgb[7:0]),   //输入的8bitrgb数据
    .rgb_green   (rgb[15:8]),  //输入的8bitrgb数据
    .rgb_red     (rgb[23:16]), //输入的8bitrgb数据
    .hdmi_clk_p  (hdmi_clk_p  ),
    .hdmi_clk_n  (hdmi_clk_n  ),
    .hdmi_red_p  (hdmi_red_p  ),
    .hdmi_red_n  (hdmi_red_n  ),
    .hdmi_green_p(hdmi_green_p),
    .hdmi_green_n(hdmi_green_n),
    .hdmi_blue_p (hdmi_blue_p ),
    .hdmi_blue_n (hdmi_blue_n )
    );
vga_ctrl vga_ctrl_u1(
    .pclk    (vga_clk    ),
    .rst_n   (rst   ),
    .rgb_data(rgb_data_aim),//rgb_data,最终输入视频信号
    .pic_x   (pic_x   ),
    .pic_y   (pic_y   ),    
    .hsync   (hsync   ),
    .vsync   (vsync   ),
    .de      (de      ),
    .fps_flag(fps_flag),
    .rgb     (rgb     )//输出rgb数据
    );
总图输出   
pic_ctrl pic_ctrl(
.   pclk           ( vga_clk            ) ,
.   rst_n          ( rst           ) ,
.   pic_x          ( pic_x           ) ,
.   pic_y          ( pic_y           ) ,
.   rgb_data_src   ( rgb_data       ) ,//原图数据
.   rgb_data_gray  ( rgb_gray       ) ,//灰度数据
.   rgb_data_binary( rgb_binary     ) ,//二值化数据
.   rgb_de_src     ( rgb_de_src      ) ,//使能信号,悬空未使用
.   rgb_de_gray    ( rgb_de_gray     ) ,//使能信号,悬空未使用
.   rgb_de_binary  ( rgb_de_binary   ) ,//使能信号,悬空未使用
.   rgb_data_aim   ( rgb_data_aim    )     //最终输出视频信号
    );
    
///二值化处理  ///   
binaryimage binary(
. pclk         (vga_clk       ) ,//pclk时钟 
. rst_n        (rst      ) ,      //复位    
. rgb_gray     (rgb_gray   ) ,//输入灰度化数据
. rgb_binary   (rgb_binary )//输出二值化
    ); 
    
///灰度化处理  ///  
rgbgray rgb1(
. pclk      ( vga_clk      )  ,//pclk时钟 
. rst_n     ( rst     )  ,      //复位    
. iValid    ( de    )  ,//输入有效信号,这里悬空,没使用
. rgb_data  ( rgb_data  )  ,//ram输入的rgb数据
. oValid    ( oValid    )   ,//输出有效信号,这里悬空,没使用
. rgb_gray  ( rgb_gray  )   ///输入的24位灰度数据
    );
    
 //原图数据输出   /
vga_pic vga_pic_u1(
    .pclk    (vga_clk    ),//pclk时钟
    .rst_n   (rst   ),      //复位
    .pic_x   (pic_x   ),    //像素x
    .pic_y   (pic_y   ),    //像素y
    .fps_flag(fps_flag),    //帧结束信号
    .rgb_data(rgb_data)     //原图数据 256*256       
    );
    
clk_wiz_0 clk_wiz_0_inst
   (
    // Clock out ports
    .clk_out1(vga_clk),     // output clk_out1
    // Status and control signals
    .clk_out2(vga_clk_5x),
    .resetn(sys_rst_n), // input resetn
    .locked(locked),       // output locked
   // Clock in ports
    .clk_in1(sys_clk)); 
endmodule

结束。

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值