博客
关于我
基于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 优化器 key_mysql – 选择*和查询优化器
    查看>>
    MySQL 优化:Explain 执行计划详解
    查看>>
    Mysql 会导致锁表的语法
    查看>>
    mysql 使用sql文件恢复数据库
    查看>>
    mysql 修改默认字符集为utf8
    查看>>
    Mysql 共享锁
    查看>>
    MySQL 内核深度优化
    查看>>
    mysql 内连接、自然连接、外连接的区别
    查看>>
    mysql 写入慢优化
    查看>>
    mysql 分组统计SQL语句
    查看>>
    Mysql 分页
    查看>>
    Mysql 分页语句 Limit原理
    查看>>
    MySql 创建函数 Error Code : 1418
    查看>>
    MySQL 创建新用户及授予权限的完整流程
    查看>>
    mysql 创建表,不能包含关键字values 以及 表id自增问题
    查看>>
    mysql 删除日志文件详解
    查看>>
    mysql 判断表字段是否存在,然后修改
    查看>>
    MySQL 到底能不能放到 Docker 里跑?
    查看>>
    mysql 前缀索引 命令_11 | Mysql怎么给字符串字段加索引?
    查看>>
    MySQL 加锁处理分析
    查看>>