博客
关于我
基于FPGA的VGA控制器实现(2)
阅读量:707 次
发布时间:2019-03-17

本文共 5473 字,大约阅读时间需要 18 分钟。

以下是经过优化后的文章内容:

FPGA实现VGA白框45度移动

项目意义

本项目旨在实现VGA显示器上的白框进行45度移动。通过前一篇博客中对VGA时序的简单了解,我们认识到实际应用中如何将这些时序有效结合,是一个持续探索的问题。本系列两篇文章将详细阐述VGA时序在工程中的具体应用。

工程功能

该工程的主要目标是实现VGA显示器上一个白框沿45度路径移动。移动路线的实现依赖于VGA时序的有效控制,从而完成精确的图像偏移。具体而言,这一过程涉及两个关键维度:横向偏移量和移动条件的控制。

  • 横向偏移量控制(x):ranging from 0 to 440 pixels
  • 移动条件控制:在扫描一幅图像的过程中,当水平计数器cnt_h和垂直计数器cnt_v满足特定条件(如cnt_h达到H_TOTAL_TIME减去1时,同时cnt_v达到V_ADDR_TIME减去1)时,调整横向偏移量,从而实现45度移动。
  • 工程时序

    本项目的时序设计基于传统VGA时序控制,具体包括以下几个关键部分:

  • 计数器控制:确保cnt_hcnt_v按照预定义的VGA时序循环更新,保证图像完整扫描。
  • 同步信号控制:通过hsyncvsync信号的生成,确保VGA时序的正确同步。
  • 偏移量更新:根据预设规则,增加或减少横向偏移量,以实现白框的移动效果。
  • 工程代码

    以下为本次项目的核心Verilog代码,基于前一篇博客的基础进行优化和扩展:

    timescale 1ns / 1psmodule vga_drive(    input vga_clk,    input rst_n,    output hsync,    output vsync,    output [7:0] vga_data);// 定义参数和内部信号localparam H_TOTAL_TIME = 800;localparam H_ADDR_TIME = 640;localparam H_SYNC_TIME = 96;localparam H_BACK_PORCH = 40;localparam H_LEFT_BORDER = 8;localparam V_TOTAL_TIME = 525;localparam V_ADDR_TIME = 480;localparam V_SYNC_TIME = 2;localparam V_BACK_PORCH = 25;localparam V_LEFT_BORDER = 8;localparam HIGH = 200;localparam WIDTH = 200;reg [12:0] cnt_h;reg [12:0] cnt_v;reg [8:0] x;reg [8:0] y;reg flag_x;reg flag_y;// 主要逻辑always @(posedge vga_clk or negedge rst_n)    if (rst_n == 1'b0)        cnt_h <= 13'd0;    else if (cnt_h == (H_TOTAL_TIME-1'b1))        cnt_h <= 13'd0;    else        cnt_h <= cnt_h + 1'b1;always @(posedge vga_clk or negedge rst_n)    if (rst_n == 1'b0)        cnt_v <= 13'd0;    else if ((cnt_v == (V_TOTAL_TIME-1'b1)) && (cnt_h == (H_TOTAL_TIME-1'b1)))        cnt_v <= 13'd0;    else if (cnt_h == (H_TOTAL_TIME-1'b1))        cnt_v <= cnt_v + 1'b1;    else        cnt_v <= cnt_v;// 同步信号控制always @(posedge vga_clk or negedge rst_n)    if (rst_n == 1'b0)        hsync <= 1'b1;    else if (cnt_h == (H_TOTAL_TIME-1'b1))        hsync <= 1'b1;    else if (cnt_h >= (H_SYNC_TIME-1'b1))        hsync <= 1'b0;    else        hsync <= hsync;always @(posedge vga_clk or negedge rst_n)    if (rst_n == 1'b0)        vsync <= 1'b1;    else if ((cnt_v == (V_TOTAL_TIME-1'b1)) && (cnt_h == (H_TOTAL_TIME-1'b1)))        vsync <= 1'b1;    else if ((cnt_v >= (V_SYNC_TIME-1'b1)) && (cnt_h == (H_TOTAL_TIME-1'b1)))        vsync <= 1'b0;    else        vsync <= vsync;// 条件触发的横向偏移量调整always @(posedge vga_clk or negedge rst_n)    if (rst_n == 1'b0)        x <= 9'd0;    else if ((flag_x == 1'b0) && (cnt_v == (V_TOTAL_TIME-1'b1)) && (cnt_h == (H_TOTAL_TIME-1'b1)))        x <= x + 1'b1;    else if ((flag_x == 1'b1) && (cnt_v == (V_TOTAL_TIME-1'b1)) && (cnt_h == (H_TOTAL_TIME-1'b1)))        x <= x - 1'b1;    else        x <= x;// 进行横向偏移量的条件判断always @(posedge vga_clk or negedge rst_n)    if (rst_n == 1'b0)        flag_x <= 1'b0;    else if ((x >= (H_ADDR_TIME - HIGH - 1'b1)) && (cnt_v == (V_TOTAL_TIME-1'b1)) && (cnt_h == (H_TOTAL_TIME-1'b1)))        flag_x <= 1'b1;    else if ((x <= 1'b1) && (cnt_v == (V_TOTAL_TIME-1'b1)) && (cnt_h == (H_TOTAL_TIME-1'b1)))        flag_x <= 1'b0;    else        flag_x <= flag_x;// 垂直方向的位置判断always @(posedge vga_clk or negedge rst_n)    if (rst_n == 1'b0)        y <= 9'd0;    else if ((flag_y == 1'b0) && (cnt_v == (V_TOTAL_TIME-1'b1)) && (cnt_h == (H_TOTAL_TIME-1'b1)))        y <= y + 1'b1;    else if ((flag_y == 1'b1) && (cnt_v == (V_TOTAL_TIME-1'b1)) && (cnt_h == (H_TOTAL_TIME-1'b1)))        y <= y - 1'b1;    else        y <= y;// 横向位置的判断更新always @(posedge vga_clk or negedge rst_n)    if (rst_n == 1'b0)        flag_y <= 1'b0;    else if ((y >= (V_ADDR_TIME - WIDTH - 1'b1)) && (cnt_v == (V_TOTAL_TIME-1'b1)) && (cnt_h == (H_TOTAL_TIME-1'b1)))        flag_y <= 1'b1;    else if ((y <= 1'b1) && (cnt_v == (V_TOTAL_TIME-1'b1)) && (cnt_h == (H_TOTAL_TIME-1'b1)))        flag_y <= 1'b0;    else        flag_y <= flag_y;// 背景数值控制always @(posedge vga_clk or negedge rst_n)    if (rst_n == 1'b0)        vga_data <= 8'd0;    else if ((cnt_h >= (H_SYNC_TIME + H_BACK_PORCH + H_LEFT_BORDER - 1'b1) + x) && (cnt_h <= (H_SYNC_TIME + H_BACK_PORCH + H_LEFT_BORDER - 1'b1) + x + HIGH) && (cnt_v >= (V_SYNC_TIME + V_BACK_PORCH + V_LEFT_BORDER) + y) && (cnt_v <= (V_SYNC_TIME + V_BACK_PORCH + V_LEFT_BORDER) + y + WIDTH))         vga_data <= 8'b111_111_11;    else if (cnt_h >= (H_SYNC_TIME + H_BACK_PORCH + H_LEFT_BORDER - 1'b1) && (cnt_h <= (H_SYNC_TIME + H_BACK_PORCH + H_LEFT_BORDER + H_ADDR_TIME - 1'b1)))        if (cnt_v >= (V_SYNC_TIME + V_BACK_PORCH + V_LEFT_BORDER) && (cnt_v <= (V_SYNC_TIME + V_BACK_PORCH + V_LEFT_BORDER + 13'd160)))            vga_data <= 8'b111_000_00;        else if (cnt_v >= (V_SYNC_TIME + V_BACK_PORCH + V_LEFT_BORDER + 160) && (cnt_v <= (V_SYNC_TIME + V_BACK_PORCH + V_LEFT_BORDER + 13'd320)))            vga_data <= 8'b000_111_00;        else if (cnt_v >= (V_SYNC_TIME + V_BACK_PORCH + V_LEFT_BORDER + 320) && (cnt_v <= (V_SYNC_TIME + V_BACK_PORCH + V_LEFT_BORDER + 13'd480)))            vga_data <= 8'b000_000_11;        else            vga_data <= 8'd0;    end    else        vga_data <= 8'd0;endmodule

    测试代码

    以下为优化后的测试代码,可直接在工程中使用:

    timescale 1ns / 1psmodule vga_tb();reg vga_clk;reg rst_n;wire hsync;wire vsync;wire [7:0] vga_data;initial begin    vga_clk = 1'b0;    rst_n <= 1'b0;    # (`CLOCK*100)    rst_n <= 1'b1;endalways # (`CLOCK / 2) vga_clk <= ~vga_clk;vga_drive vga_drive_inst(    .vga_clk(vga_clk),    .rst_n(rst_n),    .hsync(hsync),    .vsync(vsync),    .vga_data(vga_data));endmodule

    总结

    在实际工程应用中,VGA时序控制是实现图形显示核心的一部分。本项目通过对VGA时序的深入理解,完成了横向偏移控制的实现,为VGA显示器的应用开辟了新的可能性。通过适当调整横向偏移量和垂直位置信号,可以实现图像的精确移动和显示效果。

    如需进一步技术支持或了解具体实现细节,请随时留言或加入相关技术社区!

    转载地址:http://nesez.baihongyu.com/

    你可能感兴趣的文章
    MySQL 备份 Xtrabackup
    查看>>
    mYSQL 外键约束
    查看>>
    mysql 多个表关联查询查询时间长的问题
    查看>>
    mySQL 多个表求多个count
    查看>>
    mysql 多字段删除重复数据,保留最小id数据
    查看>>
    MySQL 多表联合查询:UNION 和 JOIN 分析
    查看>>
    MySQL 大数据量快速插入方法和语句优化
    查看>>
    mysql 如何给SQL添加索引
    查看>>
    mysql 字段区分大小写
    查看>>
    mysql 字段合并问题(group_concat)
    查看>>
    mysql 字段类型类型
    查看>>
    MySQL 字符串截取函数,字段截取,字符串截取
    查看>>
    MySQL 存储引擎
    查看>>
    mysql 存储过程 注入_mysql 视图 事务 存储过程 SQL注入
    查看>>
    MySQL 存储过程参数:in、out、inout
    查看>>
    mysql 存储过程每隔一段时间执行一次
    查看>>
    mysql 存在update不存在insert
    查看>>
    Mysql 学习总结(86)—— Mysql 的 JSON 数据类型正确使用姿势
    查看>>
    Mysql 学习总结(87)—— Mysql 执行计划(Explain)再总结
    查看>>
    Mysql 学习总结(88)—— Mysql 官方为什么不推荐用雪花 id 和 uuid 做 MySQL 主键
    查看>>