• 基于FPGA的VGA显示彩条、字符、图片


    目录

    一、VGA介绍

    (一) VGA协议

    (二) VGA端口介绍

    (三) 色彩原理

    (四)VGA显示原理

    VGA通信协议:

     VGA时序解析

     时钟分频

    二、实现

    ​1.彩条显示

    2.字符显示

    3.图片显示

    三、代码

     1.vga驱动模块

     2.显示数据生成模块

     3.按键消抖模块

     4.顶层模块

    四、效果

    RTL视图

    顶层​编辑

     vga_drive​编辑

     data_drive

     视频

    ​五 、参考

    一、VGA介绍

    (一) VGA协议

    什么是VGA?VGA不是用来显示的那块屏幕,而是用来传输信号的接口。VGA全称是Video Graphics Array,即视频图形阵列,是模拟信号的一种视频传输标准。不⽀持热插拔,不⽀持⾳频传输。对于⼀些嵌⼊式VGA显示系统,可以在不使⽤VGA显卡和计算机的 情况下,实现VGA图像的显示和控制。VGA显示器具有成本低、结构简单、应⽤灵活的优点。

    (二) VGA端口介绍

    VGA端口是视频输出端口,端口一共包含15个管脚,如下图

     VGA接口是一种D型接口,上面共有15针孔,分成三排,每排五个。 其中,除了2根NC(Not Connect)信号、3根显示数据总线和5个GND信号,比较重要的是3根RGB彩色分量信号和2根扫描同步信号HSYNC和VSYNC针。VGA接口中彩色分量采用RS343电平标准。RS343电平标准的峰值电压为1V。VGA接口是显卡上应用最为广泛的接口类型,多数的显卡都带有此种接口。有些不带VGA接口而带有DVI(Digital Visual Interface数字视频接口)接口的显卡,也可以通过一个简单的转接头将DVI接口转成VGA接口,通常没有VGA接口的显卡会附赠这样的转接头。

    在通常使用的连接方法里面,15个管脚里面的5个是最重要的,他们包括3个基本红、绿、蓝三条基本色彩和水平与垂直两条控制线。

     大多数计算机与外部显示设备之间都是通过模拟VGA接口连接,计算机内部以数字方式生成的显示图像信息,被显卡中的数字/模拟转换器转变为R、G、B三原色信号和行、场同步信号,信号通过电缆传输到显示设备中。对于模拟显示设备,如模拟CRT显示器,信号被直接送到相应的处理电路,驱动控制显像管生成图像。而对于LCD、DLP等数字显示设备,显示设备中需配置相应的A/D(模拟/数字)转换器,将模拟信号转变为数字信号。在经过D/A和A/D两次转换后,不可避免地造成了一些图像细节的损失。VGA接口应用于CRT显示器无可厚非,但用于连接液晶之类的显示设备,则转换过程的图像损失会使显示效果略微下降。
    而且可以从接口处来判断显卡是独显还是集成显卡,VGA接口竖置的说明是集成显卡,VGA接口横置说明是独立显卡(一般的台式主机都可以用此方法来查看)。


    (三) 色彩原理

    三基⾊是指通过其他颜⾊的混合⽆法得到的“基本 ⾊”由于⼈的⾁眼有感知红、绿、蓝三种不同颜⾊的锥体细胞,因此⾊彩空间通常可以由三种基本⾊来表达

    设计RGB信号时,既可以R信号、G信号和B信号独⽴的赋值,最后连到端⼝上,也可以直接⽤RGB当做⼀个整体信号,RGB信号在使⽤时的位宽有三种常见格式,以你的VGA解码芯⽚的配置有关。

    1. RGB_8,R:G:B = 3:3:2,即RGB332
    2. RGB_16,R:G:B = 5:6:5,即RGB565
    3. RGB_24,R:G:B = 8:8:8,即RGB888

    依次对应8、16、24位位宽,位宽越高,图像越清晰

     (四)VGA显示原理

    VGA通过引脚的模拟电压(0V-0.714V)显示红绿蓝三种颜色,不同的电压值对应不同的颜色。
    VGA驱动显示器用的是扫描的方式,一般是逐行扫描。
    逐行扫描是扫描从屏幕左上角一点开始,从左像右逐点扫描,每扫描完一行,电子束回到屏幕的左边下一行的起始位置,在这期间,CRT对电子束进行消隐,每行结束时,用行同步信号进行同步;
    当扫描完所有的行,形成一帧后,用场同步信号进行场同步,并使扫描回到屏幕左上方,同时进行场消隐,开始下一帧。
    FPGA芯片驱动VGA显示,需要先产生模拟信号,这就要借助数模转换器D/A,利用D/A产生模拟信号,输出至VGA的RED、GREEN、BLUE基色数据线。另一种方法是利用电阻网络分流模拟D/A实现的。
    具体颜色对应的电压值:

     利用电阻网络分流模拟D/A:

    参考:https://blog.csdn.net/qq_40147893/article/details/108342484

    VGA通信协议:

    VS:帧时序

    帧时序的四个部分别是:同步脉冲(Sync o)、显示后沿(Back porch p)、显示时序段(Display interval q)和显示前沿(Front porchr)。其中同步脉冲(Sync o)、显示后沿(Back porch p)和显示前沿(Front porch r)是消隐区,RGB信号无效,屏幕不显示数据。显示时序段(Display interval q)是有效数据区。

    HS:行时序 

    行时序的四个部分分别是:同步脉冲(Sync a)、显示后沿(Back porch b)、显示时序(Display interval c)和显示前沿(Front porchd)。其中同步脉冲(Sync a)、显示后沿(Back porch b)和显示前沿(Front porch d)是消隐区,RGB信号无效,屏幕不显示数据。显示时序段(Display interval c)是有效数据区。

     VGA时序解析

    不同分辨率对应参数

     时钟分频

    举例:分别使用640×480 60HZ和800×600 72HZ,对应时钟分别为25M和50M,需要使用PLL进行分频 时钟频率 = 行帧长 × 列帧长 * 刷新率,640 ×480 60HZ对应时钟频率= 800 ×525 × 60 = 25.2M,1040x666x72=49.9M

    二、实现

    IP核里面找到ALTPLL

    基础时钟选择50M

     取消勾选输出使能

     c0默认输出50M即可,c1分频到25M,如需其他时钟频率可以自己进行设置

     勾选如下选项后finish 

     1.彩条显示

    根据当前行地址判断需要显示的颜色即可。

    2.字符显示

    在子模提取工具里面输入需要显示的字符并设置字符大小为64*64,点阵大小为64*64

     然后点击文件-另存为,把图片保存为BMP图片

     再点击文件-打开,把保存的BMP图片打开得到整体的字符

     再点击选项按如下参数设置

    最后点击生成字符并保存字符为文本文件

     最后得到字符如下

     把得到的字符在verilog里面使用即可

     注意:char_line[0]这一行全赋值为0,也就是说增加了第一行0,其余不变

    之所以要转变成BMP图片格式,是因为否则生成的都是单个字模,位数会不统一,为了位数长度统一,代码中384=64*6,也就是一个字符宽度64,因为显示6个字符,因此位宽384

     3.图片显示

    原图:

     使用工具BMP2MifV1.0把图片转为HEX文件

    在转换图片之前需要先修改图片的格式,使用电脑自带的画图软件打开此图片

    点击重新调整大小

    点击文件-另存为 

     注意:保存类型一定要选择为24位位图(*.bmp;*.dib),否则加载不成功

    然后开始转换  

     选择输出图像格式RGB565   文件类型Hex

     转换完成得到dongman.hex,内容如图

    由于图片数据太多需要使用ROM来存储数据

     设置位宽度为16位,大小为图片大小128×78 = 9984

     取消勾选下列选项

    找到刚才生成的dongman.hex文件 

    勾选以下选项后直接finsh即可

    数据的读取和使用参考后面的代码部分

    三、代码

    基于EP4CE6F17C8型号芯片

     1.vga驱动模块

    1. module vga_dirve (input wire clk, //系统时钟
    2. input wire rst_n, //复位
    3. input wire [ 15:0 ] rgb_data, //16位RGB对应值
    4. output wire vga_clk, //vga时钟 25M
    5. output reg h_sync, //行同步信号
    6. output reg v_sync, //场同步信号
    7. output reg [ 11:0 ] addr_h, //行地址
    8. output reg [ 11:0 ] addr_v, //列地址
    9. output wire [ 4:0 ] rgb_r, //红基色
    10. output wire [ 5:0 ] rgb_g, //绿基色
    11. output wire [ 4:0 ] rgb_b //蓝基色
    12. );
    13. // 640 * 480 60HZ
    14. localparam H_FRONT = 16; // 行同步前沿信号周期长
    15. localparam H_SYNC = 96; // 行同步信号周期长
    16. localparam H_BLACK = 48; // 行同步后沿信号周期长
    17. localparam H_ACT = 640; // 行显示周期长
    18. localparam V_FRONT = 11; // 场同步前沿信号周期长
    19. localparam V_SYNC = 2; // 场同步信号周期长
    20. localparam V_BLACK = 31; // 场同步后沿信号周期长
    21. localparam V_ACT = 480; // 场显示周期长
    22. // 800 * 600 72HZ
    23. // localparam H_FRONT = 40; // 行同步前沿信号周期长
    24. // localparam H_SYNC = 120; // 行同步信号周期长
    25. // localparam H_BLACK = 88; // 行同步后沿信号周期长
    26. // localparam H_ACT = 800; // 行显示周期长
    27. // localparam V_FRONT = 37; // 场同步前沿信号周期长
    28. // localparam V_SYNC = 6; // 场同步信号周期长
    29. // localparam V_BLACK = 23; // 场同步后沿信号周期长
    30. // localparam V_ACT = 600; // 场显示周期长
    31. localparam H_TOTAL = H_FRONT + H_SYNC + H_BLACK + H_ACT; // 行周期
    32. localparam V_TOTAL = V_FRONT + V_SYNC + V_BLACK + V_ACT; // 列周期
    33. reg [ 11:0 ] cnt_h ; // 行计数器
    34. reg [ 11:0 ] cnt_v ; // 场计数器
    35. reg [ 15:0 ] rgb ; // 对应显示颜色值
    36. // 对应计数器开始、结束、计数信号
    37. wire flag_enable_cnt_h ;
    38. wire flag_clear_cnt_h ;
    39. wire flag_enable_cnt_v ;
    40. wire flag_clear_cnt_v ;
    41. wire flag_add_cnt_v ;
    42. wire valid_area ;
    43. // 25M时钟 行周期*场周期*刷新率 = 800 * 525* 60
    44. wire clk_25 ;
    45. // 50M时钟 1040 * 666 * 72
    46. wire clk_50 ;
    47. //PLL
    48. pll pll_inst (
    49. .areset ( ~rst_n ),
    50. .inclk0 ( clk ),
    51. .c0 ( clk_50 ), //50M
    52. .c1 ( clk_25 ), //25M
    53. );
    54. //根据不同分配率选择不同频率时钟
    55. assign vga_clk = clk_25;
    56. // 行计数
    57. always @( posedge vga_clk or negedge rst_n ) begin
    58. if ( !rst_n ) begin
    59. cnt_h <= 0;
    60. end
    61. else if ( flag_enable_cnt_h ) begin
    62. if ( flag_clear_cnt_h ) begin
    63. cnt_h <= 0;
    64. end
    65. else begin
    66. cnt_h <= cnt_h + 1;
    67. end
    68. end
    69. else begin
    70. cnt_h <= 0;
    71. end
    72. end
    73. assign flag_enable_cnt_h = 1;
    74. assign flag_clear_cnt_h = cnt_h == H_TOTAL - 1;
    75. // 行同步信号
    76. always @( posedge vga_clk or negedge rst_n ) begin
    77. if ( !rst_n ) begin
    78. h_sync <= 0;
    79. end
    80. else if ( cnt_h == H_SYNC - 1 ) begin // 同步周期时为1
    81. h_sync <= 1;
    82. end
    83. else if ( flag_clear_cnt_h ) begin // 其余为0
    84. h_sync <= 0;
    85. end
    86. else begin
    87. h_sync <= h_sync;
    88. end
    89. end
    90. // 场计数
    91. always @( posedge vga_clk or negedge rst_n ) begin
    92. if ( !rst_n ) begin
    93. cnt_v <= 0;
    94. end
    95. else if ( flag_enable_cnt_v ) begin
    96. if ( flag_clear_cnt_v ) begin
    97. cnt_v <= 0;
    98. end
    99. else if ( flag_add_cnt_v ) begin
    100. cnt_v <= cnt_v + 1;
    101. end
    102. else begin
    103. cnt_v <= cnt_v;
    104. end
    105. end
    106. else begin
    107. cnt_v <= 0;
    108. end
    109. end
    110. assign flag_enable_cnt_v = flag_enable_cnt_h;
    111. assign flag_clear_cnt_v = cnt_v == V_TOTAL - 1;
    112. assign flag_add_cnt_v = flag_clear_cnt_h;
    113. // 场同步信号
    114. always @( posedge vga_clk or negedge rst_n ) begin
    115. if ( !rst_n ) begin
    116. v_sync <= 0;
    117. end
    118. else if ( cnt_v == V_SYNC - 1 ) begin
    119. v_sync <= 1;
    120. end
    121. else if ( flag_clear_cnt_v ) begin
    122. v_sync <= 0;
    123. end
    124. else begin
    125. v_sync <= v_sync;
    126. end
    127. end
    128. // 对应有效区域行地址 1-640
    129. always @( posedge vga_clk or negedge rst_n ) begin
    130. if ( !rst_n ) begin
    131. addr_h <= 0;
    132. end
    133. else if ( valid_area ) begin
    134. addr_h <= cnt_h - H_SYNC - H_BLACK + 1;
    135. end
    136. else begin
    137. addr_h <= 0;
    138. end
    139. end
    140. // 对应有效区域列地址 1-480
    141. always @( posedge vga_clk or negedge rst_n ) begin
    142. if ( !rst_n ) begin
    143. addr_v <= 0;
    144. end
    145. else if ( valid_area ) begin
    146. addr_v <= cnt_v -V_SYNC - V_BLACK + 1;
    147. end
    148. else begin
    149. addr_v <= 0;
    150. end
    151. end
    152. // 有效显示区域
    153. 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;
    154. // 显示颜色
    155. always @( posedge vga_clk or negedge rst_n ) begin
    156. if ( !rst_n ) begin
    157. rgb <= 16'h0;
    158. end
    159. else if ( valid_area ) begin
    160. rgb <= rgb_data;
    161. end
    162. else begin
    163. rgb <= 16'b0;
    164. end
    165. end
    166. assign rgb_r = rgb[ 15:11 ];
    167. assign rgb_g = rgb[ 10:5 ];
    168. assign rgb_b = rgb[ 4:0 ];
    169. endmodule // vga_dirve

     2.显示数据生成模块

    1. module data_drive (input wire vga_clk,
    2. input wire rst_n,
    3. input wire [ 11:0 ] addr_h,
    4. input wire [ 11:0 ] addr_v,
    5. input wire [ 2:0 ] key,
    6. output reg [ 15:0 ] rgb_data);
    7. localparam red = 16'd63488;
    8. localparam orange = 16'd64384;
    9. localparam yellow = 16'd65472;
    10. localparam green = 16'd1024;
    11. localparam blue = 16'd31;
    12. localparam indigo = 16'd18448;
    13. localparam purple = 16'd32784;
    14. localparam white = 16'd65503;
    15. localparam black = 16'd0;
    16. reg [ 383:0 ] char_line[ 64:0 ];
    17. localparam states_1 = 1; // 彩条
    18. localparam states_2 = 2; // 字符
    19. localparam states_3 = 3; // 图片
    20. parameter height = 78; // 图片高度
    21. parameter width = 128; // 图片宽度
    22. reg [ 1:0 ] states_current ; // 当前状态
    23. reg [ 1:0 ] states_next ; // 下个状态
    24. reg [ 13:0 ] rom_address ; // ROM地址
    25. wire [ 15:0 ] rom_data ; // 图片数据
    26. wire flag_enable_out1 ; // 文字有效区域
    27. wire flag_enable_out2 ; // 图片有效区域
    28. wire flag_clear_rom_address ; // 地址清零
    29. wire flag_begin_h ; // 图片显示行
    30. wire flag_begin_v ; // 图片显示列
    31. //状态转移
    32. always @( posedge vga_clk or negedge rst_n ) begin
    33. if ( !rst_n ) begin
    34. states_current <= states_1;
    35. end
    36. else begin
    37. states_current <= states_next;
    38. end
    39. end
    40. //状态判断
    41. always @( posedge vga_clk or negedge rst_n ) begin
    42. if ( !rst_n ) begin
    43. states_next <= states_1;
    44. end
    45. else if ( key[ 0 ] ) begin
    46. states_next <= states_1;
    47. end
    48. else if ( key[ 1 ] ) begin
    49. states_next <= states_2;
    50. end
    51. else if ( key[ 2 ] ) begin
    52. states_next <= states_3;
    53. end
    54. else begin
    55. states_next <= states_next;
    56. end
    57. end
    58. //状态输出
    59. always @( * ) begin
    60. case ( states_current )
    61. states_1 : begin
    62. if ( addr_h == 0 ) begin
    63. rgb_data = black;
    64. end
    65. else if ( addr_h >0 && addr_h <81 ) begin
    66. rgb_data = red;
    67. end
    68. else if ( addr_h >80 && addr_h <161 ) begin
    69. rgb_data = orange;
    70. end
    71. else if ( addr_h >160 && addr_h <241 ) begin
    72. rgb_data = yellow;
    73. end
    74. else if ( addr_h >240 && addr_h <321 ) begin
    75. rgb_data = green;
    76. end
    77. else if ( addr_h >320 && addr_h <401 ) begin
    78. rgb_data = blue;
    79. end
    80. else if ( addr_h >400 && addr_h <481 ) begin
    81. rgb_data = indigo;
    82. end
    83. else if ( addr_h >480 && addr_h <561 ) begin
    84. rgb_data = purple;
    85. end
    86. else if ( addr_h >560 && addr_h <641 ) begin
    87. rgb_data = white;
    88. end
    89. else begin
    90. rgb_data = black;
    91. end
    92. end
    93. states_2 : begin
    94. if ( flag_enable_out1 ) begin
    95. rgb_data = char_line[ addr_v-208 ][ 532 - addr_h ]? white:black;
    96. end
    97. else begin
    98. rgb_data = black;
    99. end
    100. end
    101. states_3 : begin
    102. if ( flag_enable_out2 ) begin
    103. rgb_data = rom_data;
    104. end
    105. else begin
    106. rgb_data = black;
    107. end
    108. end
    109. default: begin
    110. case ( addr_h )
    111. 0 : rgb_data = black;
    112. 1 : rgb_data = red;
    113. 81 : rgb_data = orange;
    114. 161: rgb_data = yellow;
    115. 241: rgb_data = green;
    116. 321: rgb_data = blue;
    117. 401: rgb_data = indigo;
    118. 481: rgb_data = purple;
    119. 561: rgb_data = white;
    120. default: rgb_data = rgb_data;
    121. endcase
    122. end
    123. endcase
    124. end
    125. assign flag_enable_out1 = states_current == states_2 && addr_h > 148 && addr_h < 533 && addr_v > 208 && addr_v < 273 ;
    126. assign flag_begin_h = addr_h > ( ( 640 - width ) / 2 ) && addr_h < ( ( 640 - width ) / 2 ) + width + 1;
    127. assign flag_begin_v = addr_v > ( ( 480 - height )/2 ) && addr_v <( ( 480 - height )/2 ) + height + 1;
    128. assign flag_enable_out2 = states_current == states_3 && flag_begin_h && flag_begin_v;
    129. //ROM地址计数器
    130. always @( posedge vga_clk or negedge rst_n ) begin
    131. if ( !rst_n ) begin
    132. rom_address <= 0;
    133. end
    134. else if ( flag_clear_rom_address ) begin //计数满清零
    135. rom_address <= 0;
    136. end
    137. else if ( flag_enable_out2 ) begin //在有效区域内+1
    138. rom_address <= rom_address + 1;
    139. end
    140. else begin //无效区域保持
    141. rom_address <= rom_address;
    142. end
    143. end
    144. assign flag_clear_rom_address = rom_address == height * width - 1;
    145. //初始化显示文字
    146. always@( posedge vga_clk or negedge rst_n ) begin
    147. if ( !rst_n ) begin
    148. char_line[ 0 ] = 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
    149. char_line[ 1 ] = 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
    150. char_line[ 2 ] = 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
    151. char_line[ 3 ] = 384'h000000000000000000000002000000000000000000000000000000300000000000000000000000000000000000000000;
    152. char_line[ 4 ] = 384'h0000000000000000000000078000000000000800000004000000001E0000000000000000000100000000200000800000;
    153. char_line[ 5 ] = 384'h000000000000000000000007C000000000000E00000003000000000F80000000000180000003800000003C0000E00000;
    154. char_line[ 6 ] = 384'h000000000000000000000007E000000000000F80000003C000000007C00000000001FFFFFFFFE00000003F0000F80000;
    155. char_line[ 7 ] = 384'h00000000000000000000000F8000000000000F00000003C000000003E00000000001FFFFFFFFE00000003E0000F00000;
    156. char_line[ 8 ] = 384'h00000000000000000000000FC000000000000E000000038000000003E00000000001E0000003C00000003C0000E00000;
    157. char_line[ 9 ] = 384'h00000000000008000000001F4000000000000E000000038000600001E00000000001E0000003C00000003C0000E00000;
    158. char_line[ 10 ] = 384'h0000000000001C000000001E6000000000000E000000038000600000C00002000001E0000003C00000003C0000E00000;
    159. char_line[ 11 ] = 384'h0000000000003E000000003E3000000000000E003000038000600000C00007000001E0000003C00000003C0000E00000;
    160. char_line[ 12 ] = 384'h01FFFFFFFFFFFF000000003C3800000000000E0078300380007FFFFFFFFFFF800001E0000003C00000003C0000E00000;
    161. char_line[ 13 ] = 384'h00FFFFFFFFFFFF8000000078180000000FFFFFFFFC3C0380007FFFFFFFFFFFC00001FFFFFFFFC00000003C0000E00000;
    162. char_line[ 14 ] = 384'h0060000000000000000000F80C00000007FFFFFFFE3E038000E0000000000FE00001FFFFFFFFC00000803C0000E00000;
    163. char_line[ 15 ] = 384'h0000000000000000000000F00E00000000000E00003E038000E0018000000F800001E0000003C00000E03C0000E00000;
    164. char_line[ 16 ] = 384'h0000000000000000000001E00700000000000E00003C038001E001C000001E000001E0000003C00000F83C0000E00400;
    165. char_line[ 17 ] = 384'h0000000000000000000003E00380000000000E00003C038003E001F000001C000001E0000003C00000F03C0C00E00700;
    166. char_line[ 18 ] = 384'h0000000000000000000003C003C0000000000E00003C038003E003F8000030000001E0000003C00000F03C0FFFFFFF80;
    167. char_line[ 19 ] = 384'h00000000000000000000078001E0000000000E00003C038007C007E0000060000001E0000003C00000F03C0FFFFFFF80;
    168. char_line[ 20 ] = 384'h000000000000000000000F0000F0000000000E00403C0380078007C0003040000001FFFFFFFFC00000F03C0E00E00F00;
    169. char_line[ 21 ] = 384'h000000000000000000001E000078000000400E00603C038000000FFFFFF800000001FFFFFFFFC00000F03C0E00E00F00;
    170. char_line[ 22 ] = 384'h000000000000000000003E02003E0000007FFFFFF03C038000000FFFFFFC00000001E0000003C00000F03C0E00E00F00;
    171. char_line[ 23 ] = 384'h000000000000000000007C03801F0000007FFFFFF83C038000001F00007E00000001E0000003800000F03C0E00E00F00;
    172. char_line[ 24 ] = 384'h00000000000000000000F803E01FC00000700E00F03C038000003C8000F000000001C0000002030000F03C0E00E00F00;
    173. char_line[ 25 ] = 384'h00000000000000000001E003E007E00000700E00E03C0380000078C001E00000000000000000078000F03C0E00E00F00;
    174. char_line[ 26 ] = 384'h00000000000000000003C003C003F80000700E00E03C03800000706003C000000000000000000FC000F03C0E00E00F00;
    175. char_line[ 27 ] = 384'h000000000000000000078003C001FF0000700E00E03C03800000E030078000001FFFFFFFFFFFFFE000F03C0E00E00F00;
    176. char_line[ 28 ] = 384'h0000000000000000000F0003C000FFE000700E00E03C03800001C0180F0000000FFFFFFFFFFFFFF000F03C0E00E00F00;
    177. char_line[ 29 ] = 384'h0000000000000000001C0003C0007FF800700E00E03C03800003800C1E000000000F001E0000000000F03C0E00E00F00;
    178. char_line[ 30 ] = 384'h000000000001000000780003C0001FE000700E00E03C03800007000F3C000000000F001E0000000000F0380E00E00F00;
    179. char_line[ 31 ] = 384'h000000000003800000E00003C0000F8000700E00E03C0380000E0007F8000000000F001E0000080000F0380E00E00F00;
    180. char_line[ 32 ] = 384'h000000000007C00003800003C000030000700E00E03C0380001C0003F0000000000F001E00000C0000F0380E00E00F00;
    181. char_line[ 33 ] = 384'h001FFFFFFFFFE0000E000003C000000000700E00E03C038000300001F0000000000F001FFFFFFF0000F0380E00E00F00;
    182. char_line[ 34 ] = 384'h000FFFFFFFFFF00038000003C000000000700E00E03C038000600007FC000000000FFFFEFFFFFF8000F0380E00E00F00;
    183. char_line[ 35 ] = 384'h000600000000000000000003C000000000700E00E03C03800080000FBF000000000FFFFE44001E0000F0380E00E00F00;
    184. char_line[ 36 ] = 384'h000000000000000000000003C000000000700E00E03C03800000003E0FC00000000F001E04003C0000F0380E00E00F00;
    185. char_line[ 37 ] = 384'h000000000000000000000003C000000000701E7FE03C03800000007C03F80000000F001E06003C0000F0380E00E00F00;
    186. char_line[ 38 ] = 384'h000000000000000000000003C000000000703E0FE03C0380000001F001FF0000000F001E0200380000F0780E00E00F00;
    187. char_line[ 39 ] = 384'h000000000000000000000003C000000000703E07C03C0380000007C0007FF800000F001E0300780000F0780E00E00F00;
    188. char_line[ 40 ] = 384'h000000000000000000000003C000000000607F03803C038000001F00001FFFF8000F001E0300700000F0700E00E00F00;
    189. char_line[ 41 ] = 384'h000000000000000000000003C000000000007F82003C038000007C000007FFF0000FFFFE0180F00000F0700E00E00F00;
    190. char_line[ 42 ] = 384'h000000000000000000000003C00000000000FEE0003C03800001F000000EFFC0000FFFFE0180E00000F0700E00E00F00;
    191. char_line[ 43 ] = 384'h000000000000000000000003C00000000001EE38003C0380000FFFFFFFFF1F80000F001E01C1E00000C0F00E00E00F00;
    192. char_line[ 44 ] = 384'h000000000000000000000003C00000000003CE1E003C0380007E7FFFFFFF8300000F001E00C1C0000000E00E00E00F00;
    193. char_line[ 45 ] = 384'h000000000000000000000003C000000000038E0F003C038003E07800000F0000000F001E00E3C0000000E00E00E00F00;
    194. char_line[ 46 ] = 384'h000000000000000000000003C000000000070E07C03C03801E007800000E0000000F001E006780000001E00E00E7FF00;
    195. char_line[ 47 ] = 384'h000000000000000000000003C0000000000E0E03E03C038000007800000E0000000F001E1C7700000001C00E00E1FE00;
    196. char_line[ 48 ] = 384'h000000000000000000000003C0000000001C0E01F03C038000007800000E0000000F001FF03F00000001C00E00E07E00;
    197. char_line[ 49 ] = 384'h000000000000000000000003C000000000380E00F830038000007800000E0000000F00FF803E00000003800C00E03C00;
    198. char_line[ 50 ] = 384'h000000000000000000000003C000000000700E007800038000007800000E0000000F3FFE001E00000003800800E01800;
    199. char_line[ 51 ] = 384'h000000000000018000000003C000000000E00E007800038000007800000E0000000FFFDE003F00000007000000E00000;
    200. char_line[ 52 ] = 384'h00000000000003C000000003C000000000C00E003800038000007800000E000000FFFC1E00778000000E000000E00000;
    201. char_line[ 53 ] = 384'h00000000000007E000000003C000000001800E001000038000007800000E00000FFFC01E00E3C000000E000000E00000;
    202. char_line[ 54 ] = 384'h3FFFFFFFFFFFFFF000000003C000000003000E000000038000007800000E000007FE001E01C3F000001C000000E00000;
    203. char_line[ 55 ] = 384'h1FFFFFFFFFFFFFF800000003C00000000E000E000000038000007800000E000007E0001E0380FC000038000000E00000;
    204. char_line[ 56 ] = 384'h0C0000000000000000000003C000000018000E00000FCF8000007FFFFFFE00000380001E07007F000070000000E00000;
    205. char_line[ 57 ] = 384'h000000000000000000000003C000000030000E000007FF8000007FFFFFFE00000200001E0E003FF800E0000000E00000;
    206. char_line[ 58 ] = 384'h000000000000000000000003C000000000000E000001FF8000007800000E00000000001E18001FE001C0000000E00000;
    207. char_line[ 59 ] = 384'h000000000000000000000003C000000000000E0000007F0000007800000E00000000001E700007800300000000E00000;
    208. char_line[ 60 ] = 384'h000000000000000000000003C000000000000E0000001E0000007000000C00000000001EC00003000600000000E00000;
    209. char_line[ 61 ] = 384'h0000000000000000000000030000000000000E0000000C0000004000000000000000001F800000000800000000E00000;
    210. char_line[ 62 ] = 384'h000000000000000000000002000000000000080000000000000000000000000000000010000000000000000000800000;
    211. char_line[ 63 ] = 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
    212. char_line[ 64 ] = 384'h000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000;
    213. end
    214. end
    215. //实例化ROM
    216. ROM1_port ROM1_port_inst (
    217. .address ( rom_address ),
    218. .clock ( vga_clk ),
    219. .q ( rom_data )
    220. );
    221. endmodule // data_drive

     3.按键消抖模块

    1. module key_debounce(
    2. input wire clk,
    3. input wire rst_n,
    4. input wire key,
    5. output reg flag,// 0抖动, 1抖动结束
    6. output reg key_value//key抖动结束后的值
    7. );
    8. parameter MAX_NUM = 20'd1_000_000;
    9. reg [19:0] delay_cnt;//1_000_000
    10. reg key_reg;//key上一次的值
    11. always @(posedge clk or negedge rst_n) begin
    12. if(!rst_n) begin
    13. key_reg <= 1;
    14. delay_cnt <= 0;
    15. end
    16. else begin
    17. key_reg <= key;
    18. //当key为1 key 为0 表示按下抖动,开始计时
    19. if(key_reg != key ) begin
    20. delay_cnt <= MAX_NUM ;
    21. end
    22. else begin
    23. if(delay_cnt > 0)
    24. delay_cnt <= delay_cnt -1;
    25. else
    26. delay_cnt <= 0;
    27. end
    28. end
    29. end
    30. //当计时完成,获取key的值
    31. always @(posedge clk or negedge rst_n) begin
    32. if(!rst_n) begin
    33. flag <= 0;
    34. key_value <= 1;
    35. end
    36. else begin
    37. // 计时完成 处于稳定状态,进行赋值
    38. if(delay_cnt == 1) begin
    39. flag <= 1;
    40. key_value <= key;
    41. end
    42. else begin
    43. flag <= 0;
    44. key_value <= key_value;
    45. end
    46. end
    47. end
    48. endmodule

    4.顶层模块

    1. module vga_top (input wire clk,
    2. input wire rst_n,
    3. input wire [ 2:0 ] key,
    4. output wire vga_clk,
    5. output wire h_sync,
    6. output wire v_sync,
    7. output wire [ 4:0 ] rgb_r,
    8. output wire [ 5:0 ] rgb_g,
    9. output wire [ 4:0 ] rgb_b,
    10. output reg [ 3:0 ] led);
    11. reg [ 27:0 ] cnt ;
    12. wire [ 11:0 ] addr_h ;
    13. wire [ 11:0 ] addr_v ;
    14. wire [ 15:0 ] rgb_data ;
    15. wire [ 2:0 ] key_flag ;
    16. wire [ 2:0 ] key_value ;
    17. //vga模块
    18. vga_dirve u_vga_dirve(
    19. .clk ( clk ),
    20. .rst_n ( rst_n ),
    21. .rgb_data ( rgb_data ),
    22. .vga_clk ( vga_clk ),
    23. .h_sync ( h_sync ),
    24. .v_sync ( v_sync ),
    25. .rgb_r ( rgb_r ),
    26. .rgb_g ( rgb_g ),
    27. .rgb_b ( rgb_b ),
    28. .addr_h ( addr_h ),
    29. .addr_v ( addr_v )
    30. );
    31. //数据模块
    32. data_drive u_data_drive(
    33. .vga_clk ( vga_clk ),
    34. .rst_n ( rst_n ),
    35. .addr_h ( addr_h ),
    36. .addr_v ( addr_v ),
    37. .key ( {key_value[ 2 ] && key_flag[ 2 ], key_value[ 1 ] && key_flag[ 1 ], key_value[ 0 ] && key_flag[ 0 ] } ),
    38. .rgb_data ( rgb_data )
    39. );
    40. //按键消抖
    41. key_debounce u_key_debounce0(
    42. .clk ( vga_clk ),
    43. .rst_n ( rst_n ),
    44. .key ( key[ 0 ] ),
    45. .flag ( key_flag[ 0 ] ),
    46. .key_value ( key_value[ 0 ] )
    47. );
    48. key_debounce u_key_debounce1(
    49. .clk ( vga_clk ),
    50. .rst_n ( rst_n ),
    51. .key ( key[ 1 ] ),
    52. .flag ( key_flag[ 1 ] ),
    53. .key_value ( key_value[ 1 ] )
    54. );
    55. key_debounce u_key_debounce2(
    56. .clk ( vga_clk ),
    57. .rst_n ( rst_n ),
    58. .key ( key[ 2 ] ),
    59. .flag ( key_flag[ 2 ] ),
    60. .key_value ( key_value[ 2 ] )
    61. );
    62. // led
    63. always @( posedge clk or negedge rst_n ) begin
    64. if ( !rst_n ) begin
    65. cnt <= 0;
    66. end
    67. else if ( cnt == 50_000_000 - 1 ) begin
    68. cnt <= 0;
    69. end
    70. else begin
    71. cnt <= cnt + 1;
    72. end
    73. end
    74. always @( posedge clk or negedge rst_n ) begin
    75. if ( !rst_n ) begin
    76. led <= 4'b0000;
    77. end
    78. else if ( cnt == 50_000_000 -1 )begin
    79. led <= ~led;
    80. end
    81. else begin
    82. led <= led;
    83. end
    84. end
    85. endmodule // vga_top

    四、效果

    通过按键切换状态,根据不同状态分别输出彩条、字符、图片。

    RTL视图

    顶层

     vga_drive

     data_drive

     视频

    640 ×480分辨率下拍摄     点击下方链接可观看

    https://live.csdn.net/v/230012

    截图如下

    五 、参考

    https://blog.csdn.net/qq_47281915/article/details/125134764

  • 相关阅读:
    移植EasyLogger
    docker安装(Elasticsearch、kibana、IK分词器)8.4.3
    SpringMvc视图解析器
    appium+python自动化测试
    插图精美的html & css教程
    怎么恢复电脑删除的文件?
    java面试笔试题
    Android-AGP之手写你的第一款自定义plugin插件
    离线数仓搭建_02_服务器配置与数据生产
    探索ClickHouse——同时支持导入导出功能的文件格式
  • 原文地址:https://blog.csdn.net/mxh3600/article/details/126196065