赞
踩
HDMI 是新一代的多媒体接口标准,英文全称是 High-Definition Multimedia Interface,即高清多媒体接口。
它能够同时传输视频和音频,简化了设备的接口和连线;同时提供了更高的数据传输带宽,可以传输无压缩的数字音频及高分辨率视频信号。HDMI 1.0 版本于 2002 年发布,最高数据传输速度为 5Gbps;而2017 年发布的 HDMI 2.1 标准的理论带宽可达 48Gbps。
在 HDMI 接口出现之前,被广泛应用的是 VGA 接口。VGA 的全称是 Video Graphics Array,即视频图形阵列,是一个使用模拟信号进行视频传输的标准。VGA 接口采用 15 针插针式结构,里面传输模拟信号颜色分量、同步等信号,是很多老显卡、笔记本和投影仪所使用的接口。由于 VGA 接口传输的是模拟信号,其信号容易受到干扰,因此 VGA 在高分辨率下字体容易虚,信号线长的话,图像有拖尾现象。VGA接口由下图所示:
协议包含的信号:HS行同步信号,VS场同步信号,RGB三种颜色信号一共5种信号。
RGB分为RGB888,RGB565和RGB332三种不同长度的颜色信号,RGB888表示红绿蓝三个信号各占8个比特,RGB565则红绿蓝分别占5,6,5个比特。
这里以 RGB888 格式为例,介绍不同的颜色分量。在图 23.1.3 中,一个像素点占用 3 个字节,其中bit23~bit16 是 RED 通道,bit15~bit8 是 GREEN 通道,bit7~bit0 是 BLUE 通道。所以红色对应的值就是24’hFF0000
,
蓝色对应的值就是 24’h0000FF
,
绿色对应的值为 24’h00FF00
。
通过调节 R、G、B 的比例可以产生其它的颜色,比如 24’hFFFF00
就是黄色,24’h000000
就是黑色,24’hFFFFFF
就是白色。大家可以打开电脑的“画图”工具,在里面使用调色板即可获取到想要的颜色对应的数值,如图 所示:
VGA协议扫描屏幕的顺序是从左到右,从上到下,从左上到右下。
根据VGA协议的定义,VGA的行同步信号HSYNC,在每一行开始时产生一个高电平脉冲,场同步信号在每一帧开始时产生一个高电平脉冲。
行同步(横轴),场同步(纵轴),以及它们会产生的脉冲信号:
VGA协议各种信号的参数来源,根据数据手册(640x480,60HZ和75HZ):
data_drive.v
module data_drive (input wire vga_clk, input wire rst_n, input wire [ 11:0 ] addr_h, input wire [ 11:0 ] addr_v, input wire [ 2:0 ] key, output reg [ 23:0 ] rgb_data); localparam orange = 24'd16750899; // 11111100_11111111_00001000 localparam yellow = 24'd16776960; // 11111111_11111111_10000000 localparam green = 24'd65280; // 00111111_11111111_00000000 localparam blue = 24'd255; // 00000001_11111111_00000000 localparam indigo = 24'd10027161; // 01111100_10000000_00000000 localparam purple = 24'd16738047; // 00001111_11111111_00000000 localparam white = 24'd16777215; // 11111111_11111111_11111111 localparam black = 24'd0; // 00000000_00000000_00000000 localparam red = 24'd16711936; // 11111111_11111111_11110000 // 分辨率为 640*480 时行时序各个参数定义 parameter C_H_SYNC_PULSE = 96 , C_H_BACK_PORCH = 48 , C_H_ACTIVE_TIME = 640 , C_H_FRONT_PORCH = 16 , C_H_LINE_PERIOD = 800 ; // 分辨率为 640*480 时场时序各个参数定义 parameter C_V_SYNC_PULSE = 2 , C_V_BACK_PORCH = 33 , C_V_ACTIVE_TIME = 480 , C_V_FRONT_PORCH = 10 , C_V_FRAME_PERIOD = 525 ; // reg [11:0] x; reg [11:0] y; reg turn_flag_x; reg turn_flag_y; //方块的长和宽 parameter LENGTH1 = 200; parameter WIDTH1 = 200; reg frame_flag; //帧结束标志 //帧结束标志 always @(posedge vga_clk or negedge rst_n) begin if (!rst_n) begin frame_flag <= 1'b0; end else if ((addr_h == 23) && (addr_v == 23)) begin frame_flag <= 1'b1; end else begin frame_flag <= 1'b0; end end //变量y always @(posedge vga_clk or negedge rst_n) begin if (!rst_n) begin y <= 'd0; end else if ((turn_flag_y == 1'b0 && frame_flag == 1'b1 && (y == 480 - WIDTH1 - 1)) || (turn_flag_y == 1'b1 && frame_flag == 1'b1 && (y == 'd0)))begin y <= y; end else if (turn_flag_y == 1'b0 && frame_flag == 1'b1) begin y <= y + 1'b1; end else if (turn_flag_y == 1'b1 && frame_flag == 1'b1) begin y <= y - 1'b1; end end //位置变量y翻转标志 always @(posedge vga_clk or negedge rst_n) begin if (!rst_n) begin turn_flag_y <= 1'b0; end else if ((y == 480 - WIDTH1 - 1) && frame_flag == 1'b1 && turn_flag_y == 1'b0) begin turn_flag_y <= 1'b1; end else if (y == 'd0 && frame_flag == 1'b1 && turn_flag_y == 1'b1) begin turn_flag_y <= 1'b0; end end //变量x always @(posedge vga_clk or negedge rst_n) begin if (!rst_n) begin x <= 'd0; end else if((turn_flag_x == 1'b0 && frame_flag == 1'b1 && x == (640 - LENGTH1 - 1'b1)) || (turn_flag_x == 1'b1 && frame_flag == 1'b1 && x == 'd0)) begin x <= x; end else if (turn_flag_x == 1'b0 && frame_flag == 1'b1) begin x <= x + 1'b1; end else if (turn_flag_x == 1'b1 && frame_flag == 1'b1) begin x <= x - 1'b1; end end //位置变量x翻转标志 always @(posedge vga_clk or negedge rst_n) begin if (!rst_n) begin turn_flag_x <= 1'b0; end else if (turn_flag_x == 1'b0 && frame_flag == 1'b1 && x == 640 - LENGTH1 - 1'b1) begin turn_flag_x <= 1'b1; end else if (turn_flag_x == 1'b1 && frame_flag == 1'b1 && x == 'd0) begin turn_flag_x <= 1'b0; end end // reg [ 447:0 ] char_line[ 64:0 ]; localparam states_1 = 1; // 彩条 localparam states_2 = 2; // 字符 localparam states_3 = 3; // 图片 parameter height = 52; // 图片高度 parameter width = 52; // 图片宽度 reg [ 1:0 ] states_current ; // 当前状态 reg [ 1:0 ] states_next ; // 下个状态 reg [ 17:0 ] rom_address ; // ROM地址 wire [ 23:0 ] rom_data ; // 图片数据 wire flag_enable_out1 ; // 文字有效区域 wire flag_enable_out2 ; // 图片有效区域 wire flag_clear_rom_address ; // 地址清零 wire flag_begin_h ; // 图片显示行 wire flag_begin_v ; // 图片显示列 //状态转移 always @( posedge vga_clk or negedge rst_n ) begin if ( !rst_n ) begin states_current <= states_1; end else begin states_current <= states_next; end end //状态判断 always @( posedge vga_clk or negedge rst_n ) begin if ( !rst_n ) begin states_next <= states_1; end else if ( key[ 0 ] ) begin states_next <= states_1; end else if ( key[ 1 ] ) begin states_next <= states_2; end else if ( key[ 2 ] ) begin states_next <= states_3; end else begin states_next <= states_next; end end //状态输出 always @( * ) begin case ( states_current ) states_1 : begin if ( addr_h == 0 ) begin rgb_data = black; end else if(addr_h >= C_H_SYNC_PULSE + C_H_BACK_PORCH + x && addr_h < C_H_SYNC_PULSE + C_H_BACK_PORCH + x + LENGTH1 && addr_v >= C_V_SYNC_PULSE + C_V_BACK_PORCH + y && addr_v < C_V_SYNC_PULSE + C_V_BACK_PORCH + y + WIDTH1) rgb_data = white; else if ( addr_h >0 && addr_h <81 ) begin rgb_data = red; end else if ( addr_h >80 && addr_h <161 ) begin rgb_data = orange; end else if ( addr_h >160 && addr_h <241 ) begin rgb_data = yellow; end else if ( addr_h >240 && addr_h <321 ) begin rgb_data = green; end else if ( addr_h >320 && addr_h <401 ) begin rgb_data = blue; end else if ( addr_h >400 && addr_h <481 ) begin rgb_data = indigo; end else if ( addr_h >480 && addr_h <561 ) begin rgb_data = purple; end else if ( addr_h >560 && addr_h <641 ) begin rgb_data = white; end else begin rgb_data = black; end end states_2 : begin if ( flag_enable_out1 ) begin rgb_data = char_line[ addr_v-208 ][ 532 - addr_h ]? white:black; end else begin rgb_data = black; end end states_3 : begin if ( flag_enable_out2 ) begin rgb_data = rom_data; end else begin rgb_data = black; end end default: begin case ( addr_h ) 0 : rgb_data = black; 1 : rgb_data = red; 81 : rgb_data = orange; 161: rgb_data = yellow; 241: rgb_data = green; 321: rgb_data = blue; 401: rgb_data = indigo; 481: rgb_data = purple; 561: rgb_data = white; default: rgb_data = rgb_data; endcase end endcase end assign flag_enable_out1 = states_current == states_2 && addr_h > 80 && addr_h < 80+448+1 && addr_v > 208 && addr_v < 273 ; 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_out2 = states_current == states_3 && 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 || key[ 2 ] ) begin //计数满清零 rom_address <= 0; end else if ( flag_enable_out2 ) 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; //初始化显示文字 always@( posedge vga_clk or negedge rst_n ) begin if ( !rst_n ) begin char_line[0]=240'h00000000000000000000000000000000; char_line[1]=240'h00000000000000000000000000000000; char_line[2]=240'h00000000000000000000000001C00000; char_line[3]=240'h000000000000000000000FFF81FC0000; char_line[4]=240'h38F9F1C79FDE1C7871F1C0FBBFFE0000; char_line[5]=240'h31DBB3CEC1BB18ECF3B3C2FB1FFE0000; char_line[6]=240'h709B37CCC3B338CDF137C7DF1FF80000; char_line[7]=240'h7C3871CCE333BECE7071C3DF0FFC0000; char_line[8]=240'hEE7861CCE733F7CE70F1C1DB0FFC0000; char_line[9]=240'hCE18E1CCE633E7CE7031C1DBBFFE0000; char_line[10]=240'hCF99C1CEC63B67EC7331C3FB9FFE0000; char_line[11]=240'hEFFBF1CFCE3F77FC73F1C77F0FF80000; char_line[12]=240'h7CF3F1C78E1E3E7871E1CE180FF80000; char_line[13]=240'h0000000000000000000000180FF80000; char_line[14]=240'h00000000000000000000001804100000; char_line[15]=240'h00000000000000000000000000000000; end end //实例化ROM ROM1 ROM1_inst ( .address ( rom_address ), .clock ( vga_clk ), .q ( rom_data ) ); endmodule // data_drive
key_debounce.v
module key_debounce( input wire clk, input wire rst_n, input wire key, output reg flag,// 0抖动, 1抖动结束 output reg key_value//key抖动结束后的值 ); parameter MAX_NUM = 20'd1_000_000; reg [19:0] delay_cnt;//1_000_000 reg key_reg;//key上一次的值 always @(posedge clk or negedge rst_n) begin if(!rst_n) begin key_reg <= 1; delay_cnt <= 0; end else begin key_reg <= key; //当key为1 key 为0 表示按下抖动,开始计时 if(key_reg != key ) begin delay_cnt <= MAX_NUM ; end else begin if(delay_cnt > 0) delay_cnt <= delay_cnt -1; else delay_cnt <= 0; end end end //当计时完成,获取key的值 always @(posedge clk or negedge rst_n) begin if(!rst_n) begin flag <= 0; key_value <= 1; end else begin // 计时完成 处于稳定状态,进行赋值 if(delay_cnt == 1) begin flag <= 1; key_value <= key; end else begin flag <= 0; key_value <= key_value; end end end endmodule
top.v
module top( input wire clk, input wire rst_n, input wire [ 2:0 ] key, 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, output reg [ 3:0 ] led); reg [ 27:0 ] cnt ; wire [ 11:0 ] addr_h ; wire [ 11:0 ] addr_v ; wire [ 23:0 ] rgb_data ; wire [ 2:0 ] key_flag ; wire [ 2:0 ] key_value ; //vga模块 vga_dirve u_vga_dirve( .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 ), .key ( {key_value[ 2 ] && key_flag[ 2 ], key_value[ 1 ] && key_flag[ 1 ], key_value[ 0 ] && key_flag[ 0 ] } ), .rgb_data ( rgb_data ) ); //按键消抖 key_debounce u_key_debounce0( .clk ( vga_clk ), .rst_n ( rst_n ), .key ( key[ 0 ] ), .flag ( key_flag[ 0 ] ), .key_value ( key_value[ 0 ] ) ); key_debounce u_key_debounce1( .clk ( vga_clk ), .rst_n ( rst_n ), .key ( key[ 1 ] ), .flag ( key_flag[ 1 ] ), .key_value ( key_value[ 1 ] ) ); key_debounce u_key_debounce2( .clk ( vga_clk ), .rst_n ( rst_n ), .key ( key[ 2 ] ), .flag ( key_flag[ 2 ] ), .key_value ( key_value[ 2 ] ) ); // led always @( posedge clk or negedge rst_n ) begin if ( !rst_n ) begin cnt <= 0; end else if ( cnt == 50_000_000 - 1 ) begin cnt <= 0; end else begin cnt <= cnt + 1; end end always @( posedge clk or negedge rst_n ) begin if ( !rst_n ) begin led <= 4'b0000; end else if ( cnt == 50_000_000 -1 )begin led <= ~led; end else begin led <= led; end end endmodule // vga_top
vga_dirve.v
module vga_dirve (input wire clk, //系统时钟 input wire rst_n, //复位 input wire [ 23:0 ] rgb_data, //16位RGB对应值 output wire vga_clk, //vga时钟 25M 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; // 场显示周期长 // 800 * 600 72HZ // localparam H_FRONT = 40; // 行同步前沿信号周期长 // localparam H_SYNC = 120; // 行同步信号周期长 // localparam H_BLACK = 88; // 行同步后沿信号周期长 // localparam H_ACT = 800; // 行显示周期长 // localparam V_FRONT = 37; // 场同步前沿信号周期长 // localparam V_SYNC = 6; // 场同步信号周期长 // localparam V_BLACK = 23; // 场同步后沿信号周期长 // localparam V_ACT = 600; // 场显示周期长 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 ; // 25M时钟 行周期*场周期*刷新率 = 800 * 525* 60 wire clk_25 ; // 50M时钟 1040 * 666 * 72 wire clk_50 ; // pll pll_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
Tools -> IP Catalog
点击next
一直next到这里
然后点finish就可以了
还要添加一个ROM核用于展示大一点的图片的内容
用电脑自带的画图软件可以点击“重新调整大小”修改图片的大小,还可以保存为24位位图格式
用这个软件可以把位图输出成mif格式或者hex格式,下载链接在下面,网上也可以搜到下载链接
链接:https://pan.baidu.com/s/1E3v6Au58HmBqQC0xouC2cQ?pwd=1234
提取码:1234
我这个图片的大小是52*52,选择比图片大的大小,所以选的24 4096 如图所示
选择生成的.hex文件
勾选好点finish就可以了
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。