当前位置:   article > 正文

基于Quartus Prime平台FPGA关于VGA显示的模块化设计:VGA八种单色屏1s切换显示、横条纹、竖条纹、棋盘格显示、显示模式按键可调、数码管显示单色屏序号_verilog的vga横彩条显示,竖彩条显示,棋盘格显示

verilog的vga横彩条显示,竖彩条显示,棋盘格显示

一:VGA协议简介

VGA(Video Graphics Array)是一种显示接口标准,它最初由IBM于1987年推出。VGA协议定义了计算机视频输出信号的格式和特性。它主要用于连接计算机和显示器之间的传输,实现图像和视频的显示。

VGA协议支持最高分辨率为640x480像素,色彩深度为16位色(即65,536种颜色)。它使用模拟信号传输,通过15个针脚的连接器将图像信号传送到显示器。VGA协议还定义了一些控制信号,用于在显示设备上调整图像的参数,例如水平和垂直同步信号、显示器ID等。

尽管VGA协议的分辨率和色彩深度相对较低,但它是计算机和显示器之间的广泛接口,被广泛应用于台式机、笔记本电脑和显示器等设备上。

二、VGA端口结构

<1>接口实物图

 VGA15针接口                                                                标准VGA母接口

    <2>理论模型图

 主要针介绍:

VGA 15针端口,也称为VGA D-sub 15针接口,是常见的VGA连接器,用于连接计算机和显示器之间的视频信号传输。下面是VGA 15针端口的功能介绍:

1. 红色信号(Red):通过这个引脚传输红色信号,用于显示图像中的红色分量。
2. 绿色信号(Green):通过这个引脚传输绿色信号,用于显示图像中的绿色分量。
3. 蓝色信号(Blue):通过这个引脚传输蓝色信号,用于显示图像中的蓝色分量。
4. 水平同步信号(HSync):通过这个引脚传输水平同步信号,用于同步显示器上图像的扫描行。
5. 垂直同步信号(VSync):通过这个引脚传输垂直同步信号,用于同步显示器上图像的扫描帧。
6. 地线(Ground):这些引脚用于电路的接地连接,确保信号的稳定和可靠传输。
7. DDC(Display Data Channel):这个引脚允许计算机和显示器之间进行双向通信,以交换显示器的信息和设置。

VGA 15针接口是模拟信号接口,支持最高分辨率为640x480像素。

由下图不难看出Red管脚有5个输入端,Green有6个输入端口,Blue有5个端口,且都只有一个输出端口,也就是说在输出时他们分别输送5位、6位、5位表示的颜色数据,而这些端口共有16位用来表示不同颜色,2的16次方是65536种不同的颜色数据

 <3>成色原理

由于人的肉眼有感知 红 绿 蓝 三种不同颜色的锥体细胞,因此色彩空间通常可以由三种基本色来表达。三种基色是相互独立的,任何一种基色都不能有其它两种颜色合成。红 绿 蓝 是三基色,这三种颜色合成的颜色范围最为广泛。我们的RGB信号就是三基色的运用,对这三个信号赋予不同的数值,混合起来便是不同的色彩

三、VGA成像扫描原理

VGA成像扫描原理是指VGA显示器是如何通过扫描线和逐行显示的方式来显示图像的。

 

下面是VGA成像扫描原理的简要介绍:

1. 水平扫描线:VGA显示器从左到右,一行一行地扫描整个屏幕。每一行开始时,水平同步信号(HSync)会告诉显示器开始新行的扫描。显示器通过红色、绿色和蓝色的信号输入,根据每个像素的颜色值来显示相应的颜色。

行时序:

2. 垂直扫描帧:当一行扫描完成后,垂直同步信号(VSync)会告诉显示器开始新的帧扫描。显示器从上到下,一帧一帧地扫描整个屏幕。垂直同步信号会告诉显示器开始扫描新帧的第一行。

列时序:

3. 刷新率:VGA显示器的刷新率指的是每秒钟显示的帧数。一般情况下,VGA显示器的刷新率为72Hz,意味着显示器可以每秒刷新72帧图像。每个帧由多个扫描行组成,每一行由多个像素点组成。

每帧的时序:

(声明:该图片转自图片右下角博主)找了好多图都没找到比这更好的

4. 分辨率:VGA显示器的分辨率指的是水平和垂直方向上的像素数。常见的VGA分辨率是800x600像素,意味着每行显示800个像素,每帧显示600行。

通过不断扫描每个像素点,并根据其颜色值来显示相应的颜色,VGA显示器可以逐行逐行地构建整个图像。由于VGA采用模拟信号传输,图像的质量可能受到干扰或信号衰减的影响,导致图像出现模糊、噪点或失真等问题。

四、常见分辨率的参数

以800*600/72Hz为例,800*600/72Hz是指刷新频率为72Hz,分辨率为800X600。这个是标准 VGA 显示驱动。
刷新频率为72Hz,是指1秒显示72幅图像。
从表中可以看出,该分辨率行同步信号,同步脉冲是120个基准时钟,显示后沿是84个基准时钟,显示区域是800个基准时钟,显示前沿是16个基准时钟,那么一行一共有1040个基准时钟。
该分辨率场同步信号,同步脉冲是6行(6*1040个基准时钟),显示后沿是23行(23*1040个基准时钟),显示区域为600行(600*1040个基准时钟),显示前沿为37行(37*1040个基准时钟),一共有666行(666*1040个基准时钟)。
基准时钟是多少呢?由于1秒显示72幅图像,所以一幅图像显示的时间是1/72秒。一幅图像占用了1040*666个基准时钟,所以基准时钟周期=(1/72)/(1040*666)秒,约为20.0521ns。那么基准时钟周期就约为50 MHz ,实验中我们取50M(正好是开发板EP4CE22F17C6的系统时钟,不需要再另外分频)。

五、 实验要求

1:实现八种颜色全屏显示,且要求每秒变换一种颜色,并将颜色的序号通过数码管显示

2:竖条纹显示

3:横条纹显示

4:棋盘间隔显示

 六、基于Verilog的代码实现

 <1>顶层文件

模块名要与工程名相同,文件名可以不一样

  1. module VGA4( //顶层模块:将各个模块组合
  2. //外部接口
  3. input clk, //系统时钟50MHz
  4. input rst_n,//低电平复位
  5. input[1:0] button,
  6. output clkout_1s,
  7. output[3:0] G,
  8. output[3:0] count,//模式一全屏显示计数
  9. output [7:0] seg,//7位数码管显示
  10. output vga_vs,//VGA行同步信号
  11. output vga_hs,//VGA列同步信号
  12. output [4:0] vga_r,//红色输出信号
  13. output [5:0] vga_g,//绿色输出信号
  14. output [4:0] vga_b //蓝色输出信号
  15. );
  16. //内部信号:模块内部的接口信号
  17. //wire [4:0] en_rgb_r;
  18. //wire [5:0] en_rgb_g;
  19. //wire [4:0] en_rgb_b;
  20. //模块例化
  21. vga vga( //接入分频时钟,限定显示的有效区域 ,将区域三等分
  22. .clk (clk),
  23. .button (button),
  24. .rst_n (rst_n),
  25. .vga_vs (vga_vs),
  26. .clkout_1s (clkout_1s),
  27. .vga_hs (vga_hs),
  28. .count (count),
  29. .vga_r (vga_r),
  30. .vga_g (vga_g),
  31. .vga_b (vga_b)
  32. );
  33. Nixie_Tube Nixie_Tube(//数码管显示部分
  34. .clk (clk),
  35. .button (button),
  36. .rst_n (rst_n),
  37. .count (count),
  38. .seg (seg),
  39. .G (G)
  40. );
  41. endmodule

 <2>VGA驱动模块

  1. module vga( //显示分辨率为800 * 600 *72 MHZ
  2. //端口信号:模块的输入输出接口
  3. input clk, //连接至系统时钟,为50MHz
  4. input rst_n, //低电平复位
  5. input [1:0] button,//拨档开关选择显示模式
  6. output[4:0] vga_r,//颜色使能信号输出以及赋值
  7. output [5:0] vga_g,
  8. output [4:0] vga_b,
  9. output reg vga_hs,//VGA列同步信号
  10. output reg [3:0] count,//颜色序号计数
  11. output reg vga_vs,//VGA行同步信号
  12. output [2:0] en_rgb,//rRGB使能
  13. output reg clkout_1s //1s时钟,用于计数和数码管显示
  14. );
  15. //----------------VGA时序-----------------------------------
  16. // 显示模式 时钟
  17. // 800*600@72 50Mhz
  18. // 同步 后沿 有效 前沿 周期
  19. //hs 120 64 800 56 1040
  20. //vs 6 23 600 37 666
  21. //VGA显示相应参数
  22. parameter hy_all = 11'd1040, //列时序
  23. hy_a = 11'd120,
  24. hy_b = 11'd64,
  25. hy_c = 11'd800,
  26. hy_d = 11'd56,
  27. vy_all = 11'd666, //行时序
  28. vy_a = 11'd6,
  29. vy_b = 11'd23,
  30. vy_c = 11'd600,
  31. vy_d = 11'd37;
  32. //用计数器限定VGA显示相应区域,通过“行扫描,列填充”的方式
  33. reg [10:0] cnt_h,cnt_v;
  34. always@(posedge clk or posedge rst_n) //列计数
  35. if(rst_n)
  36. cnt_h <= 11'd0;
  37. else if(cnt_h == (hy_all-1))
  38. cnt_h <= 11'd0;
  39. else
  40. cnt_h <= cnt_h + 1'b1;
  41. always@(posedge clk or posedge rst_n)//在一列计数完之后将行加1
  42. if(rst_n)
  43. cnt_v <= 11'd0;
  44. else if(cnt_v == (vy_all-1))
  45. cnt_v <= 11'd0;
  46. else if(cnt_h ==(hy_all-1))
  47. cnt_v <= cnt_v + 1'b1;
  48. //限定列同步信号
  49. always @(posedge clk or posedge rst_n)
  50. if(rst_n)
  51. vga_hs <= 1'b1;
  52. else if(cnt_h ==(hy_all-1))
  53. vga_hs <= 1'b0;//同步信号低有效
  54. else if(cnt_h == hy_a)
  55. vga_hs <= 1'b1;
  56. //限定行同步信号
  57. always @(posedge clk or posedge rst_n)
  58. if(rst_n)
  59. vga_vs <= 1'b0;
  60. else if(cnt_v ==(vy_all-1))
  61. vga_vs <= 1'b0;
  62. else if(cnt_v == vy_a)
  63. vga_vs <= 1'b1;
  64. reg [31:0] cnt_1s;
  65. always @(posedge clk or posedge rst_n)//1s分频
  66. if (rst_n)
  67. cnt_1s <= 0;
  68. else
  69. begin
  70. if (cnt_1s == 32'd2500_0000-1)
  71. begin
  72. cnt_1s <= 0;
  73. clkout_1s <= ~clkout_1s; // 每过 0.5s 就反转时钟信号,1s信号
  74. end
  75. else
  76. begin
  77. cnt_1s <= cnt_1s + 1; // 计数器增加
  78. end
  79. end
  80. //计数模块
  81. always @(posedge clkout_1s or posedge rst_n)
  82. begin
  83. if(rst_n)
  84. begin
  85. count<=0;
  86. end
  87. else
  88. begin
  89. if(button==2'b00)
  90. begin
  91. if(count<=7)
  92. count<=count+1;
  93. else
  94. count<=0;
  95. end
  96. else
  97. begin count<=0;end
  98. end
  99. end
  100. reg [4:0]reg_enr;
  101. reg [5:0]reg_eng;
  102. reg [4:0]reg_enb;
  103. always @(posedge clk or posedge rst_n)
  104. begin
  105. if(rst_n)
  106. begin reg_enr=5'b11111;reg_eng=6'b111111;reg_enb=5'b11111;end
  107. else
  108. begin
  109. if(button==2'b00)
  110. begin//全屏显示
  111. case(count)
  112. 0:begin reg_enr <=5'b00000;reg_eng <=6'b000000;reg_enb <=5'b11111;end
  113. 1:begin reg_enr <=5'b00000;reg_eng <=6'b111111;reg_enb <=5'b00000;end
  114. 2:begin reg_enr <=5'b00000;reg_eng <=6'b111111;reg_enb <=5'b11111;end
  115. 3:begin reg_enr <=5'b11111;reg_eng <=6'b000000;reg_enb <=5'b00000;end
  116. 4:begin reg_enr <=5'b11111;reg_eng <=6'b000000;reg_enb <=5'b11111;end
  117. 5:begin reg_enr <=5'b11111;reg_eng <=6'b111111;reg_enb <=5'b00000;end
  118. 6:begin reg_enr <=5'b11111;reg_eng <=6'b111111;reg_enb <=5'b11111;end
  119. 7:begin reg_enr <=5'b11100;reg_eng <=6'b111000;reg_enb <=5'b00000;end
  120. default:begin reg_enr <=5'b10111;reg_eng <=6'b100111;reg_enb <=5'b10111;end
  121. endcase
  122. end
  123. else if(button==2'b01)//横屏显示
  124. begin
  125. if(cnt_v > 28 && cnt_v <= 28 + 10'd150) begin reg_enr <=5'b00000;reg_eng <=6'b000000;reg_enb <=5'b11111;end
  126. else if(cnt_v > 28 + 10'd150 && cnt_v <= 28 + 10'd300) begin reg_enr <=5'b00000;reg_eng <=6'b111111;reg_enb <=5'b00000;end
  127. else if(cnt_v > 28 + 10'd300 && cnt_v <= 28 + 10'd450) begin reg_enr <=5'b11111;reg_eng <=6'b000000;reg_enb <=5'b00000;end
  128. else if(cnt_v > 28 + 10'd450 && cnt_v <= 28 + 10'd600) begin reg_enr <=5'b11111;reg_eng <=6'b111111;reg_enb <=5'b11000;end
  129. end
  130. else if(button==2'b10)//竖屏显示
  131. begin
  132. if(cnt_h > 183 && cnt_h <= 183 + 10'd200) begin reg_enr <=5'b11111;reg_eng <=6'b000000;reg_enb <=5'b11111;end
  133. else if(cnt_h > 183 + 10'd200 && cnt_h <= 183 + 10'd400) begin reg_enr <=5'b11111;reg_eng <=6'b111111;reg_enb <=5'b00000;end
  134. else if(cnt_h > 183 + 10'd400 && cnt_h <= 183 + 10'd600) begin reg_enr <=5'b11111;reg_eng <=6'b111111;reg_enb <=5'b11111;end
  135. else if(cnt_h > 183 + 10'd600 && cnt_h <= 183 + 10'd800) begin reg_enr <=5'b10100;reg_eng <=6'b111000;reg_enb <=5'b00110;end
  136. end
  137. else if(button==2'b11)
  138. begin
  139. if((cnt_v > 28 && cnt_v <= 28 + 10'd150)&&(cnt_h > 183 && cnt_h <= 183 + 10'd200)
  140. ||(cnt_v > 28+10'd150 && cnt_v <= 28 + 10'd300)&&(cnt_h > 183+ 10'd200&& cnt_h <= 183 + 10'd400)
  141. ||(cnt_v > 28+10'd300 && cnt_v <= 28 + 10'd450)&&(cnt_h > 183+ 10'd400&& cnt_h <= 183 + 10'd600)
  142. ||(cnt_v > 28+10'd450 && cnt_v <= 28 + 10'd600)&&(cnt_h > 183+ 10'd600&& cnt_h <= 183 + 10'd800))
  143. //(cnt_v >= vy_a+ vy_b && cnt_v <= vy_a + vy_b + 10'd200列范围)&&(cnt_h >= hy_a + hy_b+ 10'd600行范围&& cnt_h <= hy_a + hy_b + 10'd800)
  144. begin
  145. reg_enr <=5'b00000;
  146. reg_eng <=6'b000000;
  147. reg_enb <=5'b11111;
  148. end
  149. else if((cnt_v > 28 && cnt_v <= 28 + 10'd150)&&(cnt_h > 183+10'd600 && cnt_h <= 183 + 10'd800)
  150. ||(cnt_v > 28+10'd150 && cnt_v <= 28 + 10'd300)&&(cnt_h > 183+ 10'd400&& cnt_h <= 183 + 10'd600)
  151. ||(cnt_v > 28+10'd300 && cnt_v <= 28 + 10'd450)&&(cnt_h > 183+ 10'd200&& cnt_h <= 183 + 10'd400)
  152. ||(cnt_v > 28+10'd450 && cnt_v <= 28 + 10'd600)&&(cnt_h > 183&& cnt_h <= 183 + 10'd200))
  153. begin
  154. reg_enr <=5'b11100;
  155. reg_eng <=6'b011100;
  156. reg_enb <=5'b10101;
  157. end
  158. else if((cnt_v > 28 && cnt_v <= 28 + 10'd150)&&(cnt_h > 183+10'd200 && cnt_h <= 183 + 10'd400)
  159. ||(cnt_v > 28+10'd150 && cnt_v <= 28 + 10'd300)&&(cnt_h > 183&& cnt_h <= 183 + 10'd200)
  160. ||(cnt_v > 28+10'd300 && cnt_v <= 28 + 10'd450)&&(cnt_h > 183+ 10'd600&& cnt_h <= 183 + 10'd800)
  161. ||(cnt_v > 28+10'd450 && cnt_v <= 28 + 10'd600)&&(cnt_h > 183+10'd400&& cnt_h <= 183 + 10'd600))
  162. begin
  163. reg_enr <=5'b00100;
  164. reg_eng <=6'b011010;
  165. reg_enb <=5'b00101;
  166. end
  167. else if((cnt_v > 28 && cnt_v <= 28 + 10'd150)&&(cnt_h > 183+10'd400 && cnt_h <= 183 + 10'd600)
  168. ||(cnt_v > 28+10'd150 && cnt_v <= 28 + 10'd300)&&(cnt_h > 183+ 10'd600&& cnt_h <= 183 + 10'd800)
  169. ||(cnt_v > 28+10'd300 && cnt_v <= 28 + 10'd450)&&(cnt_h > 183&& cnt_h <= 183 + 10'd200)
  170. ||(cnt_v > 28+10'd450 && cnt_v <= 28 + 10'd600)&&(cnt_h > 183+10'd200&& cnt_h <= 183 + 10'd400))
  171. begin
  172. reg_enr <=5'b10101;
  173. reg_eng <=6'b111110;
  174. reg_enb <=5'b10101;
  175. end
  176. end
  177. end
  178. end
  179. //rgb使能
  180. assign vga_r=reg_enr;//将寄存器值赋给颜色数据传输线
  181. assign vga_g=reg_eng;
  182. assign vga_b=reg_enb;
  183. endmodule

<3>数码管显示模块

  1. module Nixie_Tube(
  2. input clk,
  3. input[1:0]button,
  4. input rst_n,
  5. input[3:0]count,
  6. output reg [7:0]seg,//7位数码管显示
  7. output reg[3:0] G//数码管使能
  8. );
  9. reg[31:0]cnt_1ms,clkout_1ms;
  10. //1ms时钟信号
  11. always @ (posedge clk)
  12. if(cnt_1ms==49999)
  13. cnt_1ms<=0;
  14. else
  15. cnt_1ms<=cnt_1ms+1;
  16. always @ (posedge clk)
  17. if(cnt_1ms<=24999)
  18. clkout_1ms<=0;
  19. else
  20. clkout_1ms<=1;
  21. reg [2:0]cnt_clkout_1ms;
  22. always @ (posedge clkout_1ms)
  23. begin
  24. if (cnt_clkout_1ms==3)
  25. cnt_clkout_1ms <=0;
  26. else
  27. cnt_clkout_1ms <= cnt_clkout_1ms + 1;
  28. end
  29. reg [3:0]qout;
  30. always @ (posedge clkout_1ms)
  31. begin
  32. if(button==2'b00)
  33. case(cnt_clkout_1ms)
  34. 0:begin
  35. qout <= count;
  36. G <= 4'b1110;
  37. end
  38. 1:begin
  39. qout <= 1'b0;
  40. G <= 4'b1101;
  41. end
  42. 2:begin
  43. qout <= button/2;
  44. G <= 4'b1011;
  45. end
  46. 3:begin
  47. qout <= button%2;
  48. G <= 4'b0111;
  49. end
  50. endcase
  51. else
  52. begin
  53. case(cnt_clkout_1ms)
  54. 0:begin
  55. qout <= 4'd9;
  56. G <= 4'b1110;
  57. end
  58. 1:begin
  59. qout <= 4'd9;
  60. G <= 4'b1101;
  61. end
  62. 2:begin
  63. qout <= button/2;
  64. G <= 4'b1011;
  65. end
  66. 3:begin
  67. qout <= button%2;
  68. G <= 4'b0111;
  69. end
  70. endcase
  71. end
  72. end
  73. always @(*)
  74. begin
  75. case(qout)
  76. 1:begin seg = 8'b01100000;end//1
  77. 2:begin seg = 8'b11011010;end//2
  78. 3:begin seg = 8'b11110010;end//3
  79. 4:begin seg = 8'b01100110;end//4
  80. 5:begin seg = 8'b10110110;end//5
  81. 6:begin seg = 8'b10111110;end//6
  82. 7:begin seg = 8'b11100000;end//7
  83. 8:begin seg = 8'b11111110;end//8
  84. 9:begin seg = 8'b00000010;end//-
  85. default:begin seg = 8'b11111100;end//0
  86. endcase
  87. end
  88. endmodule

 <5>测试文件

  1. `timescale 1 ns/ 1 ns
  2. module VGA4_vlg_tst();
  3. reg [1:0] button;
  4. reg clk;
  5. reg rst_n;
  6. wire [3:0] G;
  7. wire clkout_1s;
  8. wire [3:0] count;
  9. wire [7:0] seg;
  10. wire [4:0] vga_b;
  11. wire [5:0] vga_g;
  12. wire vga_hs;
  13. wire [4:0] vga_r;
  14. wire vga_vs;
  15. VGA4 i1 (
  16. .G(G),
  17. .button(button),
  18. .clk(clk),
  19. .clkout_1s(clkout_1s),
  20. .count(count),
  21. .rst_n(rst_n),
  22. .seg(seg),
  23. .vga_b(vga_b),
  24. .vga_g(vga_g),
  25. .vga_hs(vga_hs),
  26. .vga_r(vga_r),
  27. .vga_vs(vga_vs)
  28. );
  29. initial
  30. begin
  31. rst_n=0
  32. clk=0;
  33. $display("Running testbench");
  34. end
  35. always
  36. begin
  37. #30
  38. clk=~clk;
  39. end
  40. endmodule

 七、Quratus Prim :RTL Viewer

<1>整体视图

 <2>VGA模块

<3>数码管显示Nixie_Tube模块

 八、仿真波形

行时序和场时序仿真波形(深红色是因为没有给值,有需要的都者可以自行添加)

观察可以发现vga_vs低电平持续的时间为vga_hs的6个周期,这个的原理和不同VGA屏显示的时序有关

 九、硬件管脚分配

<1>硬件管脚参考资料

<2>Quartues管脚分配

十、硬件下载效果演示

前两位数码管只有在拨档开关为00时才会正常计数计数内容为单色屏的序号否则为--

后两位数码管显示未拨档开关的状态值:button<=2'b00 单色屏   button<=2'b01 横屏显示  button<=2'b10  竖屏显示  button<=2'b11 棋盘格显示

十一、存在的问题:

问题一:count正常计数,数码管正常显示,但是单色屏不能正常显示它只会在极短的时间内闪八种不同的颜色

问题二:可以看到除了竖屏正常显示外,其他的颜色都为渐变色

  这两个问题的原因我找了好久但是没有找出来,太痛苦了,希望有知道原因的读者可以不吝赐教,不胜感激

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/799340
推荐阅读
相关标签
  

闽ICP备14008679号