• FPGA——用VGA时序显示图像(3)(代码)


    FPGA——用VGA时序显示图像原理详解(1)_居安士的博客-CSDN博客_vga时序

    FPGA——用VGA时序显示图像原理详解(2)_居安士的博客-CSDN博客_vga显示时序

    关于VGA时序的原理可以看上面2篇(建议先看),这一篇接(2)写VGA的代码实现


    首先关于VGA时序,我们一共需要控制的信号线有5条:行同步+场同步+红+绿+蓝

    1. input clk,
    2. input rst,
    3. output hs ,//行同步信号
    4. output vs ,//场同步信号
    5. output de ,//有效数据
    6. output [7:0] rgb_r,//red
    7. output [7:0] rgb_g,//green
    8. output [7:0] rgb_b //blue

    我们需要控制何时把hs和vs拉高,拉低,就需要根据数据手册上,不同图像的像素来设置前肩,后肩,同步信号,数据有效信号(如何查看数据手册已经在前面解析过)这里建议大家使用条件编译的方法来练习,这样可以方便我们后续图像像素变化时进行修改

    1. //640x480 25.175Mhz 按照数据手册修改参数
    2. `ifdef VIDEO_640_480
    3. parameter H_ACTIVE = 16'd640; //行有效
    4. parameter H_FP = 16'd16; //行前肩
    5. parameter H_SYNC = 16'd96; //行同步
    6. parameter H_BP = 16'd48; //行后肩
    7. parameter V_ACTIVE = 16'd480; //场有效
    8. parameter V_FP = 16'd10; //场前肩
    9. parameter V_SYNC = 16'd2; //场同步
    10. parameter V_BP = 16'd33; //场后肩
    11. parameter HS_POL = 1'b0; //
    12. parameter VS_POL = 1'b0; //
    13. `endif

    设置好了这些参数之后,我们需要设置2个计数器,分别是行计数器和场计数器,当一行计数完成之后,场计数器+1

    1. //行计数器进行计数
    2. always@(posedge clk)begin
    3. if(rst)begin
    4. h_cnt<=12'd0;
    5. end
    6. else if(h_cnt==H_total-1)begin
    7. h_cnt<=12'd0;
    8. end
    9. else begin
    10. h_cnt<=h_cnt+12'd1;
    11. end
    12. end
    13. //场计数器进行计数
    14. always@(posedge clk)begin
    15. if(rst)begin
    16. v_cnt<=12'd0;
    17. end
    18. else if(h_cnt==H_total-1)begin//行同步信号拉高一次,v_cnt+1
    19. if(v_cnt==V_total-1)begin
    20. v_cnt<=12'd0;
    21. end
    22. else begin
    23. v_cnt<=v_cnt+12'd1;
    24. end
    25. end
    26. else begin
    27. v_cnt<=v_cnt;
    28. end
    29. end

    接下来我们就可以根据计数器,输出行同步信号和场同步信号

     这里,计数是从前肩开始,所以当行计数器=前肩,行同步信号拉高,计数器=前肩+行同步,行同步信号拉低

    1. //产生行同步信号
    2. always@(posedge clk)begin
    3. if(reset)begin
    4. hs_reg<=1'd0;
    5. end
    6. else if(h_cnt==H_FP-1)begin
    7. hs_reg<=1'd1;
    8. end
    9. else if(h_cnt==H_FP+H_SYNC-1)begin
    10. hs_reg<=1'd0;
    11. end
    12. else begin
    13. hs_reg<=hs_reg;
    14. end
    15. end

    场同步信号类似,需要注意的是,每一个场计数器里面都有行总个数个周期(eg: v_cnt=V_HP到v_cnt=V_HP+1时里面其实有640个clk,在哪个clk拉高呢?),但是我们的场计数器只能在一个确定的时刻拉高,所以这里还需&&上一个特定的时刻

    1. //产生场同步信号
    2. always@(posedge clk or posedge rst)
    3. begin
    4. if(rst == 1'b1)
    5. vs_reg <= 1'd0;
    6. else if((v_cnt == V_FP - 1) && (h_cnt == H_FP - 1))//场同步信号开始,&&(h_cnt == H_FP - 1)目的是在多个时钟周期里面选择一个时钟拉高场同步
    7. vs_reg <= 1'd1;//HS_POL=1
    8. else if((v_cnt == V_FP + V_SYNC - 1) && (h_cnt == H_FP - 1))//场同步信号结束
    9. vs_reg <= 1'd0;
    10. else
    11. vs_reg <= vs_reg;
    12. end

    数据有效的指示信号de,是在行有效&&场有效时输出

    行有效是在当行计数器=前肩+行同步+后肩,行同步信号拉高,计数器=前肩+行同步+后肩+数据个数,行同步信号拉低

    场有效信号与场同步信号相似,也需要&&上一个特定的时刻

    1. //产生行有效信号
    2. always@(posedge clk or posedge rst)
    3. begin
    4. if(rst == 1'b1)
    5. h_active <= 1'b0;
    6. else if(h_cnt == H_FP + H_SYNC + H_BP - 1)//行有效开始
    7. h_active <= 1'b1;
    8. else if(h_cnt == H_TOTAL - 1)//行有效结束
    9. h_active <= 1'b0;
    10. else
    11. h_active <= h_active;
    12. end
    13. //产生场有效信号
    14. always@(posedge clk or posedge rst)
    15. begin
    16. if(rst == 1'b1)
    17. v_active <= 1'd0;
    18. else if((v_cnt == V_FP + V_SYNC + V_BP - 1) && (h_cnt == H_FP - 1))//场有效开始
    19. v_active <= 1'b1;
    20. else if((v_cnt == V_TOTAL - 1) && (h_cnt == H_FP - 1)) //场有效结束
    21. v_active <= 1'b0;
    22. else
    23. v_active <= v_active;
    24. end

    接下来需要实现RGB分量的输出,这里实现彩条数据的输出,只需要给RGB某个颜色的值,就可以实现某个颜色的输出。

    1. reg[7:0] rgb_r_reg; //
    2. reg[7:0] rgb_g_reg; //绿
    3. reg[7:0] rgb_b_reg; //
    4. always@(posedge clk)begin
    5. if(rst)begin
    6. rgb_r_reg<=8'd0;
    7. rgb_g_reg<=8'd0;
    8. rgb_b_reg<=8'd0;
    9. end
    10. else begin
    11. rgb_r_reg<=8'd0;
    12. rgb_g_reg<=8'd0;
    13. rgb_b_reg<=8'hff;
    14. end
    15. end
    16. assign rgb_r = rgb_r_reg;
    17. assign rgb_g = rgb_g_reg;
    18. assign rgb_b = rgb_b_reg;

    仿真一下:

    可以看出RGB分量输出没问题, 貌似也是一幅图一幅图地输出了,我们放大看一下计数情况

    首先看行同步信号输出情况,可以看出行计数器一共计数800,是对的,行前肩结束之后,行同步信号拉高了,之后持续了行同步时间,没有问题

     

     再看看场同步信号,确实是一幅图传输完毕后输出一次

     de信号也是符合的

     完整代码如下:

    1. module VGA(
    2. input clk,
    3. input rst,
    4. output hs ,//行同步信号
    5. output vs ,//场同步信号
    6. output de ,//有效数据
    7. output [7:0] rgb_r,//red
    8. output [7:0] rgb_g,//green
    9. output [7:0] rgb_b //blue
    10. );
    11. //640x480 25.175Mhz 按照数据手册修改参数
    12. //`ifdef VIDEO_640_480
    13. parameter H_ACTIVE = 16'd640; //行有效
    14. parameter H_FP = 16'd16; //行前肩
    15. parameter H_SYNC = 16'd96; //行同步
    16. parameter H_BP = 16'd48; //行后肩
    17. parameter V_ACTIVE = 16'd480; //场有效
    18. parameter V_FP = 16'd10; //场前肩
    19. parameter V_SYNC = 16'd2; //场同步
    20. parameter V_BP = 16'd33; //场后肩
    21. parameter HS_POL = 1'b0; //
    22. parameter VS_POL = 1'b0; //
    23. //`endif
    24. parameter H_total=H_ACTIVE+H_FP+H_SYNC+H_BP;//行总时间
    25. parameter V_total=V_ACTIVE+V_SYNC+V_FP+V_BP;//场总时间
    26. reg hs_reg;//行同步信号寄存
    27. reg vs_reg;//场同步信号寄存
    28. //定义行场计数器
    29. reg [11:0]h_cnt;
    30. reg [11:0]v_cnt;
    31. reg[7:0] rgb_r_reg; //
    32. reg[7:0] rgb_g_reg; //绿
    33. reg[7:0] rgb_b_reg; //
    34. always@(posedge clk)begin
    35. if(rst)begin
    36. rgb_r_reg<=8'd0;
    37. rgb_g_reg<=8'd0;
    38. rgb_b_reg<=8'd0;
    39. end
    40. else begin
    41. rgb_r_reg<=8'd0;
    42. rgb_g_reg<=8'd0;
    43. rgb_b_reg<=8'hff;
    44. end
    45. end
    46. assign rgb_r = rgb_r_reg;
    47. assign rgb_g = rgb_g_reg;
    48. assign rgb_b = rgb_b_reg;
    49. reg h_active; //行有效
    50. reg v_active; //场有效
    51. wire video_active; //数据有效
    52. assign video_active = h_active & v_active;//数据有效=行有效且列有效
    53. assign de=video_active;
    54. //行计数器进行计数
    55. always@(posedge clk)begin
    56. if(rst)begin
    57. h_cnt<=12'd0;
    58. end
    59. else if(h_cnt==H_total-1)begin
    60. h_cnt<=12'd0;
    61. end
    62. else begin
    63. h_cnt<=h_cnt+12'd1;
    64. end
    65. end
    66. //场计数器进行计数
    67. always@(posedge clk)begin
    68. if(rst)begin
    69. v_cnt<=12'd0;
    70. end
    71. else if(h_cnt==H_total-1)begin//行同步信号拉高一次,v_cnt+1
    72. if(v_cnt==V_total-1)begin
    73. v_cnt<=12'd0;
    74. end
    75. else begin
    76. v_cnt<=v_cnt+12'd1;
    77. end
    78. end
    79. else begin
    80. v_cnt<=v_cnt;
    81. end
    82. end
    83. //产生行同步信号
    84. always@(posedge clk)begin
    85. if(rst)begin
    86. hs_reg<=1'd0;
    87. end
    88. else if(h_cnt==H_FP-1)begin
    89. hs_reg<=1'd1;
    90. end
    91. else if(h_cnt==H_FP+H_SYNC-1)begin
    92. hs_reg<=1'd0;
    93. end
    94. else begin
    95. hs_reg<=hs_reg;
    96. end
    97. end
    98. //产生场同步信号
    99. always@(posedge clk or posedge rst)
    100. begin
    101. if(rst == 1'b1)
    102. vs_reg <= 1'd0;
    103. else if((v_cnt == V_FP - 1) && (h_cnt == H_FP - 1))//场同步信号开始,&&(h_cnt == H_FP - 1)目的是在多个时钟周期里面选择一个时钟拉高场同步
    104. vs_reg <= 1'd1;
    105. else if((v_cnt == V_FP + V_SYNC - 1) && (h_cnt == H_FP - 1))//场同步信号结束
    106. vs_reg <= 1'd0;
    107. else
    108. vs_reg <= vs_reg;
    109. end
    110. //产生行有效信号
    111. always@(posedge clk or posedge rst)
    112. begin
    113. if(rst == 1'b1)
    114. h_active <= 1'b0;
    115. else if(h_cnt == H_FP + H_SYNC + H_BP - 1)//行有效开始
    116. h_active <= 1'b1;
    117. else if(h_cnt == H_total - 1)//行有效结束
    118. h_active <= 1'b0;
    119. else
    120. h_active <= h_active;
    121. end
    122. //产生场有效信号
    123. always@(posedge clk or posedge rst)
    124. begin
    125. if(rst == 1'b1)
    126. v_active <= 1'd0;
    127. else if((v_cnt == V_FP + V_SYNC + V_BP - 1) && (h_cnt == H_FP - 1))//场有效开始
    128. v_active <= 1'b1;
    129. else if((v_cnt == V_total - 1) && (h_cnt == H_FP - 1)) //场有效结束
    130. v_active <= 1'b0;
    131. else
    132. v_active <= v_active;
    133. end
    134. endmodule

  • 相关阅读:
    buuctf-[网鼎杯 2020 朱雀组]phpweb
    java计算机毕业设计医疗器械销售电子商城源码+系统+mysql数据库+lw文档
    彻底解决 K8s 节点本地存储被撑爆的问题
    YOLOv5算法改进(12)— 如何去更换主干网络(1)(包括代码+添加步骤+网络结构图)
    [附源码]计算机毕业设计springboot旅游度假村管理系统
    Unity实现摄像机向屏幕中间发射射线射击物体
    【Python】【OpenCV】定位二维码
    柯桥托业TOEIC考试和PETS哪个含金量高?
    三步实现Mybatis(Mybatis-Plus)多数据源配置
    【算法】算法题-20231117
  • 原文地址:https://blog.csdn.net/weixin_46188211/article/details/126954671