【FPGA】VGA显示文字、彩条、图片——基于DE2-115

这篇具有很好参考价值的文章主要介绍了【FPGA】VGA显示文字、彩条、图片——基于DE2-115。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、VGA概述

1.1 简述

  • **VGA(Video Graphics Array)**视频图形阵列是IBM于1987年提出的一个使用模拟信号的电脑显示标准。VGA接口即电脑采用VGA标准输出数据的专用接口。VGA接口共有15针,分成3排,每排5个孔,显卡上应用最为广泛的接口类型,绝大多数显卡都带有此种接口。它传输红、绿、蓝模拟信号以及同步信号(水平和垂直信号)。
    【FPGA】VGA显示文字、彩条、图片——基于DE2-115
  • 大多数计算机与外部显示设备之间都是通过模拟VGA接口连接,计算机内部以数字方式生成的显示图像信息,被显卡中的数字/模拟转换器转变为R、G、B三原色信号和行、场同步信号,信号通过电缆传输到显示设备中。对于模拟显示设备,如模拟CRT显示器,信号被直接送到相应的处理电路,驱动控制显像管生成图像。而对于LCD、DLP等数字显示设备,显示设备中需配置相应的A/D(模拟/数字)转换器,将模拟信号转变为数字信号。在经过D/A和A/D两次转换后,不可避免地造成了一些图像细节的损失。VGA接口应用于CRT显示器无可厚非,但用于连接液晶之类的显示设备,则转换过程的图像损失会使显示效果略微下降。
    而且可以从接口处来判断显卡是独显还是集成显卡,VGA接口竖置的说明是集成显卡,VGA接口横置说明是独立显卡(一般的台式主机都可以用此方法来查看)。

1.2 管脚定义

  • 管脚定义
管脚 定义
1 红基色 red
2 绿基色 green
3 蓝基色 blue
4 地址码 ID Bit
5 自测试 ( 各家定义不同 )
6 红地
7 绿地
8 蓝地
9 保留 ( 各家定义不同 )
10 数字地
11 地址码
12 地址码
13 行同步
14 场同步
15 地址码 ( 各家定义不同)

大家要是想了解更多的内容,比如原理等,可点击下方连接去百度百科查看:
百度百科-VGA

1.3 行、场时序及分辨率

  • VGA时序标准

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • 行同步时序:(行时序的各种信号,可对照下面的表格里的显示参数)

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • 场同步时序

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • VGA的不同分辨率显示参数

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • 将行同步时序图与场同步时序图结合起来就构成了 VGA 时序图:

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

红色区域表示在一个完整的行扫描周期中,Video 图像信息只在此区域有效,黄色区域表示在一个完整的场扫描周期中,Video 图像信息只在此区域有效,两者相交的橙色区域,就是 VGA 图像的最终显示区域。

其他可详见此博主的博客(点击跳转)

二、VGA显示文字

笔主整篇文章中使用的板子都是 EP4CE115F29C7,使用其他板子问题不大,但引脚绑定不太一样,可自行对应板子查找更改。

  • 引脚

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

2.1 点阵汉字生成

  • VGA显示文字主要要用到点阵汉字,笔主这里用的是朋友推荐的一个网站,好用,感觉比PCtoLCD2002 好用。指路网站:单片机-LCD-LED-OLED中文点阵生成软件
  • 生成

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • 在下面的字符里,使用中间那一栏,如图

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • 将那些字节复制粘贴到你的txt文件里(自己建一个就行)
  • 然后进行整理(笔主这里的学号名字是已经整理好的)

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • 用替换将原理点阵里的 , 0x 替换为(没错就是空白,不要输入空格,就是什么都不填),然后再把前面两列的0x删掉就可以了,最后一个字节那里打上 ; 就OK了。

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

2.2 工程建立

  • 笔主这里用的软件是Quartus 18.1
  • 自己新建一个工程(网上步骤很多,笔主之前的文章好像也写过),目录结构如下:
    【FPGA】VGA显示文字、彩条、图片——基于DE2-115
名称 作用
doc 一些说明文档、仿真、上板结果等
ip 知识产权
prj 工程文件
rtl 源文件(.v)
tb 仿真文件
  • rtl 源文件里主要有:
    【FPGA】VGA显示文字、彩条、图片——基于DE2-115
名称 作用
vga_top 顶层文件:主要是模块例化
vga_param 参数定义:对各种不同的分辨率的显示参数定义
data_gen 数据读取模块
vga_ctrl VGA驱动、控制模块
  • tb里还有一个仿真测试文件 vga_tb

2.3 引入ip核-实现特定时钟频率+不同分辨率显示

  • 为了正确在 640*480 的分辨率下显示,需要一个25MHz的时钟,我们需要引入 PLL ip核
  • 搜索PLL,如图:

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • 将文件存到 ip 里,笔主这里已经添加过了

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • 直接next

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • next
    【FPGA】VGA显示文字、彩条、图片——基于DE2-115
  • 一路next到如下界面,设置为25MHz

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • 为了显示不同分辨率,笔主这里另一个分辨率为 800*600,需要一个40MHz的时钟,我们这里再加一个时钟 c1

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • 然后next到最后界面,选中生成例化模块,这里自己编写代码的时候运用比较方便

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • 改变分辨率步骤
    ①更改vga_param 里的 define 后面的名称,比如
    define vga_640_480 改为 define vga_800_600 (“ ` ”被省略了,博客里显示不出来)
    【FPGA】VGA显示文字、彩条、图片——基于DE2-115
    ②vga_top里定义了时钟频率
    【FPGA】VGA显示文字、彩条、图片——基于DE2-115
    ③改变一下1、2 处就行,比如 vga_25 改为 vga_40
    【FPGA】VGA显示文字、彩条、图片——基于DE2-115

其他分辨率更改都是类似。

2.3 代码实现

  • vga_param
  • 笔主因为老师要求不同分辨率,所以只定义两种,其他可自行添加(根据前面的那个分辨率显示参数表格)
`define vga_640_480//这里在你使用不同分辨率的时候要改变

//笔主因为老师要求不同分辨率,所以定义两种,其他可自行添加(根据前面的那个分辨率显示参数表格)

`ifdef  vga_640_480
    //执行操作A
    `define H_Right_Border  8
    `define H_Front_Porch   8
    `define H_Sync_Time     96
    `define H_Back_Porch    40
    `define H_Left_Border   8
    `define H_Data_Time     640
    `define H_Total_Time    800

    
    `define V_Bottom_Border  8
    `define V_Front_Porch    2
    `define V_Sync_Time      2
    `define V_Back_Porch     25
    `define V_Top_Border     8
    `define V_Data_Time      480
    `define V_Total_Time     525

`elsif  vga_800_600
    //执行操作B
    `define H_Right_Border  0
    `define H_Front_Border  40
    `define H_Sync_Time     128
    `define H_Back_Porch    88
    `define H_Left_Border   0
    `define H_Data_Time     800
    `define H_Total_Time    1056

    
    `define V_Bottom_Border  0
    `define V_Front_Porch    1
    `define V_Sync_Time      4
    `define V_Back_Porch     23
    `define V_Top_Border     0
    `define V_Data_Time      600
    `define V_Total_Time     628
`endif 
  • vga_ctrl
`include "vga_param.v"

module vga_ctrl (
    input   wire              clk         , //vga clk 640*480 25.2MHz
    input   wire              rst_n       , //复位信号
    input   wire   [23:0]     data_disp   , //

    output  reg    [10:0]     h_addr      , //数据有效显示区域行地址
    output  reg    [10:0]     v_addr      , //数据有效显示区域场地址

    output  reg               vsync       , //
    output  reg               hsync       , //

    output  reg    [07:0]     vga_r       , //RGB三色
    output  reg    [07:0]     vga_g       , //
    output  reg    [07:0]     vga_b       , //
    output  reg               vga_blk     , //VGA 消隐信号
    output  wire              vga_clk       //

);
//参数定义
    parameter   H_SYNC_STA = 1 ,//行同步开始信号
                H_SYNC_STO = `H_Sync_Time ,//行同步停止
                H_Data_STA = `H_Sync_Time + `H_Back_Porch + `H_Left_Border,//行数据开始
                H_Data_STO = `H_Sync_Time + `H_Back_Porch + `H_Left_Border + `H_Data_Time ,//行数据开始

                V_SYNC_STA = 1 ,
                V_SYNC_STO = `V_Sync_Time ,
                V_Data_STA = `V_Sync_Time + `V_Back_Porch + `V_Top_Border,
                V_Data_STO = `V_Sync_Time + `V_Back_Porch + `V_Top_Border + `V_Data_Time;

    reg     [11:00]     cnt_h_addr  ; //行地址计数器
    wire                add_h_addr  ;
    wire                end_h_addr  ;

    reg     [11:00]     cnt_v_addr  ; //场地址计数器
    wire                add_v_addr  ;
    wire                end_v_addr  ;

//行地址计数器
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            cnt_h_addr <= 12'd0;
        end
        else if (add_h_addr) begin
            if (end_h_addr) begin
                cnt_h_addr <= 12'd0;
            end
            else begin
                cnt_h_addr <= cnt_h_addr + 12'd1;
            end
        end
        else begin
            cnt_h_addr <= cnt_h_addr;
        end
    end

    assign   add_h_addr = 1'b1;
    assign   end_h_addr = add_h_addr && cnt_h_addr >= `H_Total_Time - 1;


//场地址计数器
   always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            cnt_v_addr <= 12'd0;
        end
        else if (add_v_addr) begin
            if (end_v_addr) begin
                cnt_v_addr <= 12'd0;
            end
            else begin
                cnt_v_addr <= cnt_v_addr + 12'd1;
            end
        end
        else begin
            cnt_v_addr <= cnt_v_addr;
        end
    end

    assign   add_v_addr =  end_h_addr;
    assign   end_v_addr = add_v_addr && cnt_v_addr >= `V_Total_Time - 1;


//行场同步信号
//行同步信号
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            hsync <= 1'b1;
        end
        else if (cnt_h_addr == H_SYNC_STA - 1) begin
            hsync <= 1'b0;
        end
        else if (cnt_h_addr == H_SYNC_STO - 1)begin
            hsync <= 1'b1;
        end
        else begin
            hsync <= hsync;
        end
    end

//场同步信号
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            vsync <= 1'b1;
        end
        else if (cnt_v_addr == V_SYNC_STA - 1) begin
            vsync <= 1'b0;
        end
        else if (cnt_v_addr == V_SYNC_STO - 1)begin
            vsync <= 1'b1;
        end
        else begin
            vsync <= vsync;
        end
    end

    assign   vga_clk  = ~clk;

//数据有效显示区域定义
//行
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            h_addr <= 11'd0;
        end
        else if ((cnt_h_addr >= H_Data_STA) && (cnt_h_addr <= H_Data_STO)) begin
            h_addr <= cnt_h_addr - H_Data_STA;
        end
        else begin
            h_addr <= 11'd0;
        end
    end

//场
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            v_addr <= 11'd0;
        end
        else if ((cnt_v_addr >= V_Data_STA) && (cnt_v_addr <= V_Data_STO)) begin
            v_addr <= cnt_v_addr - V_Data_STA;
        end
        else begin
            v_addr <= 11'd0;
        end
    end

//显示数据
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            vga_r <= 8'd0;
            vga_g <= 8'd0;
            vga_b <= 8'd0;
            vga_blk <= 1'b0;
        end
        else if ((cnt_h_addr >= H_Data_STA -1) && (cnt_h_addr <= H_Data_STO - 1)
                    && (cnt_v_addr >= V_Data_STA -1 ) && (cnt_v_addr <= V_Data_STO -1)) begin
            vga_r = data_disp[23:16];//data_dis[23-:8]
            vga_g = data_disp[15:08];//data_dis[15-:8]
            vga_b = data_disp[07:00];//data_dis[07-:8]
            vga_blk <= 1'b1;
        end
        else begin
            vga_r <= 8'd0;
            vga_g <= 8'd0;
            vga_b <= 8'd0;
            vga_blk <= 1'b0;
        end
    end
endmodule
  • data_gen
module data_gen (
    input   wire              clk         , //vga clk 640*480 25.2MHz
    input   wire              rst_n       , //复位信号

    input   wire   [10:0]     h_addr      , //数据有效显示区域行地址
    input   wire   [10:0]     v_addr      , //数据有效显示区域场地址

    output  reg    [23:0]     data_disp     //数据

);

    reg [ 223:0 ] char_line[ 15:0 ];//16*14个字符=224,224*16的字符存储区
//参数定义
    parameter
        BLACK   = 24'h000000,
        RED     = 24'hFF0000,
        GREEN   = 24'h00FF00,
        BLUE    = 24'h0000FF,
        YELLOW  = 24'hFFFF00,
        SKY_BULE= 24'h00FFFF,
        PURPLE  = 24'hFF00FF,
        GRAY    = 24'hC0C0C0,
        WHITE   = 24'hFFFFFF; 
    parameter
        H_VLD   = 640,
        // H_VLD   = 800,
        V_VLD   = 480,
        // V_VLD   = 600,
        
        PIC_W   = 224,
        PIC_H   = 16,

        X_START = (H_VLD - PIC_W >> 1)-1,//正中间
        Y_START = (V_VLD - PIC_H >> 1)- 1;

    reg   [10:00] pix_x,pix_y;//字符显示坐标

//显示区域
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            pix_x <= 11'd0;
            pix_y <= 11'd0;
        end
        else if ((h_addr >= X_START - 1 && h_addr < X_START + PIC_W)
                && (v_addr >= Y_START && v_addr < Y_START + PIC_H)) begin
            pix_x <= h_addr - X_START;
            pix_y <= v_addr - Y_START;
        end
        else begin
            pix_x = 11'h7FF;
            pix_y = 11'h7FF;
        end
    end
    
//显示颜色
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            data_disp <= WHITE;
        end
        else if (pix_x != 11'h7FF && pix_y != 11'h7FF) begin
            if (char_line[pix_y][223 - pix_x] == 1'b1) begin
                data_disp <= PURPLE ;
            end
            else begin
                data_disp <= WHITE   ;
            end
        end
        else 
            data_disp <= BLACK;
    end
    
//初始化显示文字
    always@( posedge clk or negedge rst_n ) begin
        if ( !rst_n ) begin//将前面得到的点阵放在这里~
          char_line[ 0 ]  = 224'h01001000000000000000000000000000000000000000000000000000;
          char_line[ 1 ]  = 224'h010008fe000000000000000000000000000000000000000000000000;
          char_line[ 2 ]  = 224'h02807f10000000000000000000000000000000000000000000000000;
          char_line[ 3 ]  = 224'h0440222018003c000800380018007e001800180018003c003c003c00;
          char_line[ 4 ]  = 224'h0820147c240042003800440024004200240024002400420042004200;
          char_line[ 5 ]  = 224'h10107f44400042000800420042000400420040004200420042004200;
          char_line[ 6 ]  = 224'h2fe84454400002000800420042000400420040004200420042004200;
          char_line[ 7 ]  = 224'hc10648545c000400080042004200080042005c004200020002002400;
          char_line[ 8 ]  = 224'h01005254620018000800460042000800420062004200040004001800;
          char_line[ 9 ]  = 224'h3ff844544200040008003a0042001000420042004200080008002400;
          char_line[ 10 ] = 224'h01004854420002000800020042001000420042004200100010004200;
          char_line[ 11 ] = 224'h11105154420042000800020042001000420042004200200020004200;
          char_line[ 12 ] = 224'h11084228220042000800240024001000240022002400420042004200;
          char_line[ 13 ] = 224'h210444241c003c003e0018001800100018001c0018007e007e003c00;
          char_line[ 14 ] = 224'h45048842000000000000000000000000000000000000000000000000;
          char_line[ 15 ] = 224'h02003082000000000000000000000000000000000000000000000000;
        end
    end
    
endmodule
  • vga_top
module vga_top (
    input   wire              clk   ,
    input   wire              rst_n ,

    output  wire              vsync       , //
    output  wire              hsync       , //
    output  wire    [07:00]   vga_r       , //RGB三色
    output  wire    [07:00]   vga_g       , //
    output  wire    [07:00]   vga_b       , //
    output  wire              vga_blk     , //  
    output  wire              vga_clk       //  

);
    wire [23:00] data_disp;
    wire            vga_25;
    wire            vga_40;//60MHz

    wire            locked;  

    wire [10:00] h_addr;
    wire [10:00] v_addr;

    wire            reset;

    assign reset = rst_n & locked;


    // pll	u_pll (
	// .areset ( !rst_n     ),
	// .inclk0 ( clk        ),
	// .c0     ( vga_25    )
	// );

    pll_25	pll_25_inst (
	.areset ( ~rst_n ),
	.inclk0 ( clk ),
	.c0 ( vga_25 ),
    .c1 ( vga_40 ),
	.locked (locked)
	);


    data_gen u_data_gen(
        .clk         (vga_25  ), //vga clk 640*480 25.2MHz
        .rst_n       (reset    ), //复位信号
        .h_addr      (h_addr   ), //数据有效显示区域行地址
        .v_addr      (v_addr   ), //数据有效显示区域场地址

        .data_disp   (data_disp)  //
    );
    vga_ctrl u_vga_ctrl(
        .clk         (vga_25 ), //vga clk 640*480 25.2MHz
        .rst_n       (reset    ), //复位信号
        .data_disp   (data_disp), //
        
        .h_addr      (h_addr   ), //数据有效显示区域行地址
        .v_addr      (v_addr   ), //数据有效显示区域场地址
        .vsync       (vsync    ), //
        .hsync       (hsync    ), //
        .vga_r       (vga_r    ), //RGB三色
        .vga_g       (vga_g    ), //
        .vga_b       (vga_b    ), //
        .vga_blk     (vga_blk  ), //
        .vga_clk     (vga_clk  )  //
    );
endmodule
  • vga_tb
module vga_top (
    input   wire              clk   ,
    input   wire              rst_n ,

    output  wire              vsync       , //
    output  wire              hsync       , //
    output  wire    [07:00]   vga_r       , //RGB三色
    output  wire    [07:00]   vga_g       , //
    output  wire    [07:00]   vga_b       , //
    output  wire              vga_blk     , //  
    output  wire              vga_clk       //  

);
    wire [23:00] data_disp;
    wire            vga_25;//25MHz
    wire            vga_40;//40MHz

    wire            locked;  

    wire [10:00] h_addr;
    wire [10:00] v_addr;

    wire            reset;
    
    assign reset = rst_n & locked;

    pll_25	pll_25_inst (
	.areset ( ~rst_n ),
	.inclk0 ( clk ),
	.c0 ( vga_25 ),
    .c1 ( vga_40 ),
	.locked (locked)
	);


    data_gen u_data_gen(
        .clk         (vga_25  ), //vga clk 640*480 25.2MHz
        .rst_n       (reset    ), //复位信号
        .h_addr      (h_addr   ), //数据有效显示区域行地址
        .v_addr      (v_addr   ), //数据有效显示区域场地址

        .data_disp   (data_disp)  //
    );
    vga_ctrl u_vga_ctrl(
        .clk         (vga_25 ), //vga clk 640*480 25.2MHz
        .rst_n       (reset    ), //复位信号
        .data_disp   (data_disp), //
        
        .h_addr      (h_addr   ), //数据有效显示区域行地址
        .v_addr      (v_addr   ), //数据有效显示区域场地址
        .vsync       (vsync    ), //
        .hsync       (hsync    ), //
        .vga_r       (vga_r    ), //RGB三色
        .vga_g       (vga_g    ), //
        .vga_b       (vga_b    ), //
        .vga_blk     (vga_blk  ), //
        .vga_clk     (vga_clk  )  //
    );
endmodule

2.4 上板验证

  • 640*480分辨率显示下:显示在正中间

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • 800*600分辨率显示下:可见因为分辨率的改变而数据读取模块的行场未改变,位置向左上偏移了一些,是正常的。

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

三、VGA显示彩条

这里彩条很简单,均匀显示,没有考虑每个彩条所显示的区域。

3.1 代码实现

  • data_gen
module data_gen (
    input   wire              clk         , //vga clk 640*480 25.2MHz
    input   wire              rst_n       , //复位信号

    input   wire   [10:0]     h_addr      , //数据有效显示区域行地址
    input   wire   [10:0]     v_addr      , //数据有效显示区域场地址

    output  reg    [23:0]     data_disp     //

);

//参数定义
    parameter
        BLACK   = 24'h000000,
        RED     = 24'hFF0000,
        GREEN   = 24'h00FF00,
        BLUE    = 24'h0000FF,
        YELLOW  = 24'hFFFF00,
        SKY_BULE= 24'h00FFFF,
        PURPLE  = 24'hFF00FF,
        GRAY    = 24'hC0C0C0,
        WHITE   = 24'hFFFFFF; 
        
    always @(posedge clk or negedge rst_n) begin
        if(!rst_n)begin
            data_disp <= WHITE;
        end
        else begin//彩条
            case (h_addr)
                0   : data_disp <= BLACK    ;
                80  : data_disp <= RED      ;
                160 : data_disp <= GREEN    ;
                240 : data_disp <= BLUE     ;
                320 : data_disp <= YELLOW   ;
                400 : data_disp <= SKY_BULE ;
                480 : data_disp <= PURPLE   ;
                560 : data_disp <= GRAY     ;
                default: data_disp <= data_disp ;
            endcase
        end
    end
endmodule
  • 其他 .v 文件与前文一致。

3.2 上板验证

  • 640*480分辨率显示下:显示在正中间

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • 800*600分辨率显示下:彩条变得不均匀,但符合预期。

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

四、VGA显示图片

4.1 24位位图

  • 在前面的学习中了解到图像的格式有多种,例如JPEG,BMP,PNG,JPG等,图像的位数也有单色、16色、256色、4096色、16位真彩色、24位真彩色、32位真彩色在这里插入图片描述这几种。
    VGA的驱动程序显示的格式为RGB565,我们先找到一张需要显示的彩色图片,经过处理,将该图片转化为ROM可以存储的格式,然后VGA驱动程序从ROM中读取数据,输出到VGA显示屏显示。尽量 选一张小的图片,因为ROM存储空间有限。
  • 可以用电脑自带的 画图 软件,将一张图片转为 bmp 格式

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • 使用BMP2Mif软件将 bmp 格式图片转换为 Mif 文件。

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • 转换后的.mif文件:

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

4.2 引入ROM ip核

  • 新建Quartus工程,产生ROM IP核,将生成的mif文件保存在ROM中
  • 搜索ROM,双击选择ROM:1-PORT
    【FPGA】VGA显示文字、彩条、图片——基于DE2-115
  • 选择存储的位置,一般为了方便管理就存储在ip中

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • 更改设置,word大小设置要大于图片大小(52x52x24 < 65536),然后next
    【FPGA】VGA显示文字、彩条、图片——基于DE2-115
  • 取消勾选q,然后next
    【FPGA】VGA显示文字、彩条、图片——基于DE2-115
  • 如果是16位位图,就加载HEX文件,然后next

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • 这里因为我们转换的是24位位图,所以在ROM里要引入 .mif 文件。(16位位图不用管)

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • 勾选上输出 inst,方便例化,然后finish

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • 这里同时要调用前面的pll ip核生成一个25mHz的时钟。

4.3 代码实现

  • 在data_gen.v文件里,从ROM取出图片数据。
module data_gen (
    input   wire              clk         , //vga clk 640*480 25.2MHz
    input   wire              rst_n       , //复位信号

    input   wire   [10:0]     h_addr      , //数据有效显示区域行地址
    input   wire   [10:0]     v_addr      , //数据有效显示区域场地址

    output  reg    [23:0]     data_disp     //

);

    
    reg			[ 13:0 ]		rom_address				; // ROM地址
    wire		[ 23:0 ]		rom_data				; // 图片数据

    wire						flag_enable_out2			; // 图片有效区域
    wire						flag_clear_rom_address		; // 地址清零
    wire						flag_begin_h			    ; // 图片显示行
    wire						flag_begin_v			    ; // 图片显示列
    
    parameter	height = 52; // 图片高度
    parameter	width  = 52; // 图片宽度

    reg [ 223:0 ] char_line[ 15:0 ];//16*14个字符=224,224*16的字符存储区
//参数定义
    parameter
        BLACK   = 24'h000000,
        RED     = 24'hFF0000,
        GREEN   = 24'h00FF00,
        BLUE    = 24'h0000FF,
        YELLOW  = 24'hFFFF00,
        SKY_BULE= 24'h00FFFF,
        PURPLE  = 24'hFF00FF,
        GRAY    = 24'hC0C0C0,
        WHITE   = 24'hFFFFFF; 

    always @( posedge clk or negedge rst_n) begin
    if(!rst_n)begin
        data_disp = BLACK;
    end
    else if ( flag_enable_out2 ) begin
        data_disp = rom_data;
    end
    else begin
        data_disp = BLACK;
    end
    end

    //ROM地址计数器
    always @( posedge clk or negedge rst_n ) begin
        if ( !rst_n ) begin
            rom_address <= 0;
        end
        else if ( flag_clear_rom_address ) begin //计数满清零
            rom_address <= 0;
        end
            else if ( flag_enable_out2 ) begin  //在有效区域内+1
            rom_address <= rom_address + 1;
            end
        else begin  //无效区域保持
            rom_address <= rom_address;
        end
    end
    assign flag_clear_rom_address = rom_address == height * width - 1;
    assign flag_begin_h     = h_addr > ( ( 640 - width ) / 2 ) && h_addr < ( ( 640 - width ) / 2 ) + width + 1;
    assign flag_begin_v     = v_addr > ( ( 480 - height )/2 ) && v_addr <( ( 480 - height )/2 ) + height + 1;
    assign flag_enable_out2 = flag_begin_h && flag_begin_v;

    //实例化ROM
    rom	rom_inst (
    .address    ( rom_address   ),
    .clock      ( clk           ),
    .q          ( rom_data      )
    );
endmodule
  • 其他 .v 文件与前文一致。

4.4 上板验证

  • 640*480分辨率显示下:显示在正中间

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

  • 800*600分辨率显示下:图片向上偏移,符合预期。

【FPGA】VGA显示文字、彩条、图片——基于DE2-115

tb文件

  • vga_tb
`timescale 1ns/1ps

`define clk_period 20 //时钟周期参数定义

module vga_tb ();

//激励信号
    reg              clk         ;
    reg              rst_n       ;
//观测信号
    wire              vsync       ;
    wire              hsync       ;
    wire   [07:0]     vga_r       ;
    wire   [07:0]     vga_g       ;
    wire   [07:0]     vga_b       ;
    wire              vga_blk     ;
    wire              vga_clk     ;

    //ASCII 显示颜色字符
    reg    [63:00]      CHAR_CLO    ;
    parameter
        BLACK   = 24'h000000,
        RED     = 24'hFF0000,
        GREEN   = 24'h00FF00,
        BLUE    = 24'h0000FF,
        YELLOW  = 24'hFFFF00,
        SKY_BULE= 24'h00FFFF,
        PURPLE  = 24'hFF00FF,
        GRAY    = 24'hC0C0C0,
        WHITE   = 24'hFFFFFF; 
    always @(*) begin
        case(u_vga_top.data_disp)
            BLACK    :  CHAR_CLO = "BLACK   ";
            RED      :  CHAR_CLO = "RED     ";
            GREEN    :  CHAR_CLO = "GREEN   ";
            BLUE     :  CHAR_CLO = "BLUE    ";
            YELLOW   :  CHAR_CLO = "YELLOW  ";
            SKY_BULE :  CHAR_CLO = "SKY_BULE";
            PURPLE   :  CHAR_CLO = "PURPLE  ";
            GRAY     :  CHAR_CLO = "GRAY    ";
            WHITE    :  CHAR_CLO = "WHITE   ";

            // default  :  CHAR_CLO = "WHITE   ";
            default  :  CHAR_CLO = CHAR_CLO;
            // default  :  WHITE = "WHITE   ";
        endcase
    end

//模块例化
    vga_top u_vga_top(
        .clk         (clk    ),
        .rst_n       (rst_n  ),

        .vsync       (vsync  ),   
        .hsync       (hsync  ),   
        .vga_r       (vga_r  ),       
        .vga_g       (vga_g  ),   
        .vga_b       (vga_b  ),   
        .vga_blk     (vga_blk),  
        .vga_clk     (vga_clk)   
    );

//系统初始化
    //时钟生成
    initial clk = 1'b0;
    always #(`clk_period / 2 ) clk = ~clk;

    //其他激励
    initial begin
        // clk = 1'b1;
        rst_n = 1'b0;
        #(`clk_period * 20 + 3)
        rst_n = 1'b1; //产生复位
        #(`clk_period * 20);
        
        repeat(2)begin
            @(negedge vsync);
        end

        #(`clk_period * 20000)
        $stop;

    end
endmodule

可自行验证文章来源地址https://www.toymoban.com/news/detail-431814.html

小小的总结

  • VGA显示,难点在于显示驱动模块,行场同步时序的代码编写,可以先写计数器和大模块,一些内部信号与标志信号可以逐步完善;其次就是数据显示中显示区域代码的编写。
  • VGA显示,显示彩条部分还可以改进,可以定义不同彩条的显示区域。显示文字主要就是显示位置的确定与汉字点阵的生成,汉字点阵还是费了一些功夫,最开始实在没找到一个比较合适的转换工具和方法,后来在朋友的帮助指点下终于可以了。显示图片一定要注意24位位图的话在ROM里面引入的是 .mif 文件,16位位图的话就引入hex文件。
  • 代码或哪一部分有问题欢迎留言指正。

参考文献

  1. 百度百科-VGA
  2. VGA显示原理、时序标准及相关参数
  3. 【FPGA实验】基于DE2-115平台的VGA显示

到了这里,关于【FPGA】VGA显示文字、彩条、图片——基于DE2-115的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • FPGA—VGA 显示器显示彩条(附代码)

    目录 1. 理论 2. 实操 2.1 顶层设计 2.1.1 模块框图 2.1.2 代码编写  2.1.3 仿真验证 2.2 时钟生成模块 2.3 VGA时序控制模块 2.3.1 模块框图 2.3.2 波形图绘制 2.3.3 代码编写 2.3.4 仿真验证 2.4 图像数据生成模块 2.4.1 模块框图 2.4.2 波形图绘制 2.4.3 代码编写 3.总结 VGA简介        图像显示

    2024年02月09日
    浏览(83)
  • 利用Quartus Prime实现DE2-115流水灯

    什么是fpga? FPGA(Field Programmable Gate Array)是在PAL (可编程阵列逻辑)、GAL(通用阵列逻辑)等可编程器件的基础上进一步发展的产物。它是作为专用集成电路(ASIC)领域中的一种半定制电路而出现的,既解决了定制电路的不足,又克服了原有可编程器件门电路数有限的缺点

    2024年02月07日
    浏览(26)
  • Quartus乒乓球游戏电路verilog代码DE2-115开发板

    名称:Quartus乒乓球游戏电路verilog代码DE2-115开发板(文末下载) 软件:Quartus 语言:Verilog 代码功能: 乒乓球游戏电路 设计任务 设计一个数字系统,模拟 选手 A(左方)和选手 B(右方) 的乒乓球比赛游戏,要求具有 如下功能: 1 裁判按开始键后开始 比赛,首先左方 A 发球,每方 发5个

    2024年02月01日
    浏览(36)
  • 多功能交通灯控制系统VHDL十字路口红绿灯倒计时DE2-115开发板代码

    名称:多功能交通灯控制系统VHDL十字路口红绿灯倒计时DE2-115开发板 软件:Quartus II 语言:VHDL 代码功能: 要求设计一个多功能交通灯控制系统。并进行软件仿真与硬件实现。要求做到  (1)主干道绿灯亮时,支干道红灯亮,反之亦然,两者交替允许通行,主干道每次放行60s,支干道每

    2024年02月04日
    浏览(53)
  • FPGA-DE2-115-实验一-亮度可调流水灯

    前言: 本文主要介绍了集成电路EDA这门课程的相关实验及代码。使用的软件是Quartus Ⅱ,该实验使用fpga芯片为cyclone IV EP4CE115F29C7。 (1)熟悉流水灯的工作原理; (2)了解设计中的优化方案; (3)进一步掌握PWM信号的设计; 利用FPGA板及4个LED发光二极管,设计一个亮度可调

    2024年02月04日
    浏览(33)
  • 基于FPGA的VGA图像显示

    引言:本文我们介绍利用FPGA实现VGA图像显示,主要介绍VGA硬件接口、VGA接口时序原理以及FPGA代码实现VGA接口时序、仿真等内容。 VGA(Video Graphics Array)视频图形阵列是IBM于1987年提出的一个使用模拟信号的电脑显示标准。VGA接口即电脑采用VGA标准输出数据的专用接口。VGA接口

    2024年02月06日
    浏览(26)
  • FPGA-DE2-115-实验二-模块化多功能数字钟

    前言: 本文主要介绍了集成电路EDA这门课程的相关实验及代码。使用的软件是Quartus Ⅱ,该实验使用fpga芯片为cyclone IV EP4CE115F29C7。 本次实验我们需要实现生活中常见的电子手表的所有功能。 我们知道: 电子手表有五个功能,包括:时间显示功能,夜光模式功能,计时功能,闹钟功能

    2024年02月04日
    浏览(47)
  • 使用FPGA驱动GS2972(3G-SDI模式)外同步(HSYNC VSYNC DE)或内(BT1120)同步输出彩条调试

    原创文章,转载请说明出处。qq_742875810原创。 GS2972是HD-SDI/3G-SDI视频、音频串化器。其使用非常简单,但是要想把该芯片驱动起来,真心不容易。需要了解相关视频标准、传输标准、显示标准,协议较多,版本较多,彻底了解并非一件简单的事情。笔者经过大量阅读,将驱动

    2024年02月11日
    浏览(27)
  • FPGA_工程_基于Rom的VGA图像显示

    一 工程框图 框图中,CLK_in,Vga_ctrl,Vga_pic模块已有,只需要对顶层模块进行修改,并将rom ip例化添加到Vga_pic模块的.v文件中,对Vga_pic的.v文件进行一定修改。 二 理论补充 显示图像的方法:                           使用matlab将图像格式转化为,.mif数据文件,再使用.m

    2024年02月20日
    浏览(28)
  • 基于FPGA:运动目标检测(VGA显示,原理图+源码+硬件选择)

        话不多说,先上视频看效果。 基于FPGA:运动目标检测 开发板Altera:EP4CE10F17C8 摄像头:OV5640 缓存数据:SDRAM 板子是自己制作的     根据帧差法的实现流程,设计的双端口SDRAM控制器,一侧读写端口用做帧缓存,另一个端口用来缓存视频流,如图所示。     在使用

    2024年02月04日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包