正点原子 发表于 2019-5-30 11:41:57

【正点原子FPGA连载】第十九章 VGA方块移动实验--摘自【正点原子】开拓者 FPGA 开发指南

本帖最后由 正点原子 于 2020-10-23 11:33 编辑

1)实验平台:正点原子开拓者FPGA开发板
2)平台购买地址:https://item.taobao.com/item.htm?id=579749209820
3)全套实验源码+手册+视频下载地址:http://www.openedv.com/thread-281143-1-1.html
4)本实例源码下载:
5)对正点原子FPGA感兴趣的同学可以加群讨论:712557122点击加入:
6)关注正点原子公众号,获取最新资料更新


第十九章 VGA方块移动实验

在VGA彩条显示实验中,我们成功地在显示器上显示出了静态的彩条图案。本章我们通过在屏幕上显示一个移动的小方块,来给大家演示如何使用VGA接口显示动态图案。本章包括以下几个部分:1         1.1         VGA简介1.2         实验任务1.3         硬件设计1.4         程序设计1.5         下载验证

1.1      VGA简介我们在“VGA彩条显示实验”中对VGA视频传输标准作了详细的介绍,包括VGA接口定义、行场同步时序、以及显示分辨率等。如果大家对这部分内容不是很熟悉的话,请参考“VGA彩条显示实验”中的VGA简介部分。1.2      实验任务本章的实验任务是使用开拓者开发板上的VGA接口在显示器上显示一个不停移动的方块,要求方块移动到边界处时能够改变移动方向。显示分辨率为640*480,刷新速率为60hz。1.3      硬件设计VGA接口部分的硬件设计原理及本实验中各端口信号的管脚分配与“VGA彩条显示实验”完全相同,请参考“VGA彩条显示实验”中的硬件设计部分。1.4      程序设计图19.4.1是根据本章实验任务画出的系统框图。其中,时钟分频模块负责产生像素时钟,VGA驱动模块产生行场同步信号及像素点的纵横坐标,VGA显示模块输出图像数据。
图 19.4.1 VGA方块移动实验系统框图在“VGA彩条显示实验”中,我们利用VGA驱动模块输出的像素点的横坐标,在VGA显示模块中完成了彩条图案的绘制。而在本次实验中,为了完成方块的显示,需要同时使用像素点的横坐标和纵坐标来绘制方块所在的矩形区域,另外还需要知道矩形区域左上角的顶点坐标。由于VGA显示的图像在行场同步信号的同步下不停的刷新,因此只要连续改变方块左上角顶点的坐标,并在新的坐标点处重新绘制方块,即可实现方块移动的效果。各模块端口及信号连接如图 19.4.2所示:
图 19.4.2 顶层模块原理图图19.4.2中的顶层模块(vga_blockmove)、时钟分频模块(vga_pll)以及VGA驱动模块(vga_driver)均与“VGA彩条显示实验”完全相同,只对VGA显示模块(vga_display)作了修改。因此,这里我们重点讲解VGA显示模块,其他部分大家可以参考“VGA彩条显示实验”。VGA显示模块的代码如下:1   modulevga_display(2       input             vga_clk,                  //VGA驱动时钟3       input             sys_rst_n,               //复位信号4      5       input      [ 9:0]pixel_xpos,               //像素点横坐标6       input      [ 9:0]pixel_ypos,               //像素点纵坐标   7       outputreg pixel_data                //像素点数据8       );   9   10//parameterdefine   11parameterH_DISP = 10'd640;                   //分辨率——行12parameterV_DISP = 10'd480;                   //分辨率——列1314localparamSIDE_W=10'd40;                  //边框宽度15localparamBLOCK_W = 10'd40;                  //方块宽度16localparamBLUE    =16'b00000_000000_11111;    //边框颜色 蓝色17localparamWHITE   =16'b11111_111111_11111;    //背景颜色 白色18localparamBLACK   =16'b00000_000000_00000;    //方块颜色 黑色1920//reg define21reg [ 9:0] block_x;                           //方块左上角横坐标22reg [ 9:0] block_y;                           //方块左上角纵坐标23reg div_cnt;                           //时钟分频计数器24reg      h_direct;                            //方块水平移动方向,1:右移,0:左移25reg      v_direct;                            //方块竖直移动方向,1:向下,0:向上2627//wire define   28wiremove_en;                                 //方块移动使能信号,频率为100hz2930//*****************************************************31//**                  main code32//*****************************************************33assignmove_en = (div_cnt== 22'd250000- 1'b1) ? 1'b1 : 1'b0;3435//通过对vga驱动时钟计数,实现时钟分频36always@(posedgevga_clk or negedgesys_rst_n) begin         37      if(!sys_rst_n)38          div_cnt <=22'd0;39      elsebegin40          if(div_cnt <22'd250000 -1'b1)41            div_cnt <= div_cnt +1'b1;42          else43            div_cnt <= 22'd0;                   //计数达10ms后清零44      end45end4647//当方块移动到边界时,改变移动方向48always@(posedgevga_clk or negedgesys_rst_n) begin         49      if(!sys_rst_n)begin50          h_direct <=1'b1;                     //方块初始水平向右移动51          v_direct <=1'b1;                     //方块初始竖直向下移动52      end53      elsebegin54          if(block_x ==SIDE_W - 1'b1)         //到达左边界时,水平向右55            h_direct <= 1'b1;            56          else                                    //到达右边界时,水平向左57          if(block_x ==H_DISP - SIDE_W - BLOCK_W)58            h_direct <= 1'b0;            59          else60            h_direct <= h_direct;61            62          if(block_y ==SIDE_W - 1'b1)         //到达上边界时,竖直向下63            v_direct <= 1'b1;               64          else                                    //到达下边界时,竖直向上65          if(block_y ==V_DISP - SIDE_W - BLOCK_W)66            v_direct <= 1'b0;            67          else68            v_direct <= v_direct;69      end70end7172//根据方块移动方向,改变其纵横坐标73always@(posedgevga_clk or negedgesys_rst_n) begin         74      if(!sys_rst_n)begin75          block_x <=22'd100;                     //方块初始位置横坐标76          block_y <=22'd100;                     //方块初始位置纵坐标77      end78      elseif(move_en) begin79          if(h_direct)80            block_x <= block_x +1'b1;          //方块向右移动81          else82            block_x <= block_x -1'b1;          //方块向左移动83            84          if(v_direct)85            block_y <= block_y +1'b1;          //方块向下移动86          else87            block_y <= block_y -1'b1;          //方块向上移动88      end89      elsebegin90          block_x <=block_x;91          block_y <=block_y;92      end93end9495//给不同的区域绘制不同的颜色96always@(posedgevga_clk or negedgesys_rst_n) begin         97      if(!sys_rst_n)98          pixel_data <= BLACK;99      elsebegin100         if((pixel_xpos <SIDE_W) ||(pixel_xpos >=H_DISP - SIDE_W)101         ||(pixel_ypos <SIDE_W) ||(pixel_ypos >=V_DISP - SIDE_W))102             pixel_data <= BLUE;               //绘制边框为蓝色103         else104         if((pixel_xpos >=block_x) &&(pixel_xpos <block_x + BLOCK_W)105         &&(pixel_ypos >=block_y) &&(pixel_ypos <block_y + BLOCK_W))106             pixel_data <= BLACK;                //绘制方块为黑色107         else108             pixel_data <= WHITE;                //绘制背景为白色109   end110 end111112 endmodule代码中14至18行声明了一系列的变量,方便大家修改边框尺寸、方块大小、以及各部分的颜色等。其中边框尺寸和方块宽度均以像素点为单位。当方块的宽度确定时,如果我们知道方块左上方顶点的坐标,就能轻而易举的画出整个方块区域。因此,我们将方块的移动简化为其左上角顶点的移动。由于VGA驱动时钟相对于方块移动速度而言过快,我们通过计数器对时钟计数,得到一个频率为100hz的脉冲信号move_en,用它作为使能信号来控制方块的移动(33~45行)。方块的移动方向分为水平方向h_direct和竖直方向v_direct,由程序的47至70行可知,当方块移动到上下边框时,竖直移动方向改变;当方块移动到左右边框时,水平移动方向改变。程序72至93行根据方块的移动方向,在使能信号move_en到来时改变其左上角顶点的纵横坐标值。当move_en的频率为100hz时,方块每秒钟在水平和竖直方向上分别移动100个像素点的距离,也可以通过调整move_en的频率,来加快或减慢方块移动的速度。程序95至110行根据VGA驱动模块输出的纵横坐标判断当前像素点所在的区域,对不同区域中的像素点赋以不同的颜色值,从而实现边框、方块以及背景颜色的绘制。图19.4.3为VGA显示模块显示一行图像时SignalTap抓取的波形图,图中包含了一个完整的行扫描周期,其中的有效图像部分被划分为三个不同的颜色区域:左右两侧蓝色边框(pixel_data = 001F)、中间虚线处的黑色方块(pixel_data = 0000)、以及两者之间的白色背景区域(pixel_data = FFFF)。
图 19.4.3 SignalTap波形图1.5      下载验证首先我们打开VGA方块移动工程,在工程所在的路径下打开vga_blockmove/par文件夹,在里面找到“vga_blockmove.qpf”并双击打开。注意工程所在的路径名只能由字母、数字以及下划线组成,不能出现中文、空格以及特殊字符等。工程打开后如图 19.5.1所示。
图 19.5.1 VGA方块移动工程然后将VGA连接线一端连接显示器,另一端与开发板上的VGA接口连接。再将下载器一端连电脑,另一端与开发板上对应端口连接,最后连接电源线并打开电源开关。开拓者开发板实物图如下所示:图 19.5.2 开拓者开发板实物图接下来我们下载程序,验证VGA显示方块移动的功能。工程打开后通过点击工具栏中的“Programmer”图标打开下载界面,通过“Add File”按钮选择vga_blockmove/par/output_files目录下的“vga_ blockmove.sof”文件。开发板电源打开后,在程序下载界面点击“HardwareSetup”,在弹出的对话框中选择当前的硬件连接为“USB-Blaster”。然后点击“Start”将工程编译完成后得到的sof文件下载到开发板中,如图 19.5.3所示。
图 19.5.3 程序下载界面下载完成后观察显示器显示的图案如图 19.5.4所示,图中的黑色方块能够不停的移动,且碰撞到蓝色边框时能改变移动方向,说明VGA方块移动程序下载验证成功。
图 19.5.4 VGA方块移动效果图


polarbear 发表于 2019-5-30 11:50:57

这描述语言真的写成C言语风格了
页: [1]
查看完整版本: 【正点原子FPGA连载】第十九章 VGA方块移动实验--摘自【正点原子】开拓者 FPGA 开发指南