zoukankan      html  css  js  c++  java
  • VGA实验:显示字符

    这个实验是在看了特权写的《深入浅出玩转FPGA》之后自己写的也算自己做一个小小的练习吧,目的是在屏幕上显示一行字:DIY 逻辑分析仪。

    由于试验中用到取字模的软件PCtoLCD2002,所以首先介绍下这个软件。

    软件的设置如上图。

    采用阴码格式,逐列扫面,高位在前的方式,所谓“高位在前”就是扫描图像的最先扫到的点放在前面,例如:**...... 八个像素点,*代表亮,.代表不亮,此时扫到的代码为:11000000,存到存储器中时候为:0xc0,所以当你要去从存储器中取数的时候应该先去取最高位。在程序中:rom_data[31-x].因为你去取第0个点的值的时候,它是存在存储器的最高位。

    我是把取出来的自摸一个一个敲到mif文件中的,但是看到网友Crazy Bingo 是用自己写的软件C2Mif v1.0 转换软件生成的,有时间学学。因为我的方法太笨了,当代码很多时,敲的你很郁闷,而且也很容易出错,但不好找出错误。

    下面就是模块了

    首先是同步模块

     1 module sync_module (clk_25m,rst_n,valid,x,y,hsync,vsync);
    2 input clk_25m;
    3 input rst_n;
    4 output valid;
    5 output hsync,vsync;
    6 output [9:0]x;
    7 output [9:0]y;
    8
    9 /************************************/
    10
    11
    12 /************************************/
    13
    14 reg [9:0]count_h;
    15
    16 always @ (posedge clk_25m or negedge rst_n)
    17 if (!rst_n)
    18 count_h<=10'd0;
    19 else if (count_h==10'd799)
    20 count_h<=10'd0;
    21 else
    22 count_h<=count_h+1'b1;
    23
    24 /*************************************/
    25
    26
    27 /*************************************/
    28
    29 reg [9:0]count_v;
    30
    31 always @ (posedge clk_25m or negedge rst_n)
    32 if(!rst_n)
    33 count_v<=10'd0;
    34 else if(count_v==10'd524)
    35 count_v<=10'd0;
    36 else if (count_h==10'd799)
    37 count_v<=count_v+1'b1;
    38
    39 /**************************************/
    40
    41
    42 /**************************************/
    43
    44 reg isready;
    45
    46 always @ (posedge clk_25m or negedge rst_n)
    47 if (!rst_n)
    48 isready<=1'b0;
    49 else if ((count_h >=10'd144 && count_h <=10'd784) &&
    50 (count_v >=10'd35 && count_v <=10'd515))
    51 isready <=1'b1;
    52 else
    53 isready <=1'b0;
    54
    55 /****************************************/
    56
    57
    58 /****************************************/
    59 assign valid=isready;
    60 assign hsync= (count_h<10'd96)?1'b0:1'b1;
    61 assign vsync= (count_v<10'd2)?1'b0:1'b1;
    62
    63
    64
    65 assign x=count_h;
    66 assign y=count_v;
    67
    68 /***************************************/
    69
    70 endmodule

    同步模块和上次没有什么改变,就不做解释了。

    下面重要的是VGA控制模块

     1 module vga_control (clk_25m,rst_n,vga_r,vga_g,vga_b,x,y,valid,rom_addr,rom_data);
    2 input clk_25m;
    3 input rst_n;
    4 input [9:0]x;
    5 input[9:0]y;
    6 input valid;
    7 input [31:0]rom_data;
    8 output [7:0]rom_addr;
    9 output [9:0]vga_r;
    10 output [9:0]vga_g;
    11 output [9:0]vga_b;
    12
    13 /*****************************/
    14
    15
    16 /*****************************/
    17
    18 reg [7:0]addr;
    19 always @(posedge clk_25m or negedge rst_n)
    20 if(!rst_n) addr <= 8'd0;
    21 else if(x == 10'd242) addr <= 8'd0;
    22 else addr <= addr+1'b1;
    23
    24
    25 wire dis_topic = (y> 10'd39) & (y< 10'd72)
    26 & (x> 10'd245) & (x < 10'd470);
    27
    28
    29 /********************************/
    30
    31
    32 /********************************/
    33
    34 reg [9:0]r;
    35 reg [9:0]g;
    36 reg [9:0]b;
    37
    38 always @ (posedge clk_25m)
    39 if(!valid) begin
    40 r<=10'd0;
    41 g<=10'd0;
    42 b<=10'd0;
    43 end
    44 else if(dis_topic) begin
    45 if(rom_data[10'd71-y])
    46 begin
    47 r<=10'h000;
    48 g<=10'h3ff;
    49 b<=10'h000;
    50 end
    51 else begin
    52 r<=10'h3ff;
    53 g<=10'h3ff;
    54 b<=10'h3ff;
    55 end
    56 end
    57 else begin
    58 r<=10'h3ff;
    59 g<=10'h3ff;
    60 b<=10'h3ff;
    61 end
    62
    63 /********************************/
    64
    65
    66 /********************************/
    67 assign rom_addr=addr;
    68 assign vga_r=r;
    69 assign vga_b=b;
    70 assign vga_g=g;
    71
    72 endmodule
    73
    74
    75
    76
    77
    78
    79
    80


    第7和8行定义了一个rom的端口,这个rom中存的是“DIY 逻辑分析仪”这几个字的代码,采用32*32的大小,就是一个汉字占用的点数是高32位,宽32位,一个英文字符是高32位宽16位,所以总共占用的空间是高32位,宽224位。这里存储是采用32位宽和224深度的存储器。




         如上图所示,字符的第一列共32位,存在存储器的地址位addr0的地方,第二列存在addr1的地方。所以深度为224.当从存储器中取数的时候,扫描屏幕的一行,对应存储器中一列,如上图中剪头所示,例如:显示字符的第一行,访问的存储器依次为:addr0,rom_data[31];addr1,rom_data[31];addr2,rom_data[31];....;addr223,rom_data[31];

          第18行是定义了一个地址寄存器addr,当检测到x=242时候,地址为0,以后每来一个clk,地址递增。

          第25行定义显示区域是x从246到479,y从40到71;但第18行当x=242时候就地址就开始有效,为什么后面是从246开始显示?呵呵,这地方是个细节,因为每个模块之间传输数据都要延迟一个clk,同步模块计算出x,y坐标,传到VGA控制模块,VGA控制模块检测到正确的x,y坐标时给rom模块地址,然后从rom模块去数据要耗掉3个时钟周期,但是在例化rom模块时候对输出数据又寄存了一下,所以又耗掉一个周期,所以总共耗掉4个周期,也就是说,如果想在x=246那个点显示就需要提前4个周期送数据,所以要从x=242的时候就开始送数据。

         第44-50行使显示“DIY 逻辑分析仪”这几个字,45行的rom_data[71-y],是因为取模时候是高位在前,y坐标对应显示的开始点位y=40,也就是说y=40 的点对应显示的零点,也即:y-40。又存储器是32位:0-31,所以从存储器中取数与y的关系为:31-(y-40)=71-y。48行定义显示颜色为绿色 ,颜色可以根据自己喜欢的自己调节。

     1 module vga_2 (vga_clk,clk,rst_n,hsync,vsync,sync_n,blank_n,vga_r,vga_b,vga_g);
    2 input clk;
    3 input rst_n;
    4 output hsync;
    5 output vsync;
    6 output sync_n;
    7 output blank_n;
    8 output [9:0]vga_r;
    9 output [9:0]vga_g;
    10 output [9:0]vga_b;
    11 output vga_clk;
    12
    13
    14 /****************************/
    15
    16
    17 assign sync_n=1'b0;
    18 assign blank_n=hsync && vsync;
    19
    20 /****************************/
    21
    22 wire vga_clk;
    23
    24 vga_pll U1(
    25 .inclk0(clk),
    26 .c0(vga_clk));
    27
    28 /***************************/
    29
    30
    31 /***************************/
    32 wire [7:0] rom_addr;
    33 wire [31:0]rom_data;
    34
    35 vga_rom_topic vga_rom_topic_inst (
    36 .address ( rom_addr ),
    37 .clock ( vga_clk ),
    38 .q ( rom_data )
    39 );
    40
    41
    42 /**************************/
    43
    44
    45 /**************************/
    46 wire [9:0]x;
    47 wire [9:0]y;
    48
    49 sync_module U2(
    50 .clk_25m(vga_clk),
    51 .rst_n(rst_n),
    52 .valid(valid),
    53 .x(x),
    54 .y(y),
    55 .hsync(hsync),
    56 .vsync(vsync));
    57
    58 /**************************/
    59
    60
    61 /**************************/
    62
    63 vga_control U3(
    64 .clk_25m(vga_clk),
    65 .rst_n(rst_n),
    66 .vga_r(vga_r),
    67 .vga_g(vga_g),
    68 .vga_b(vga_b),
    69 .x(x),
    70 .y(y),
    71 .valid(valid),
    72 .rom_addr(rom_addr),
    73 .rom_data(rom_data));
    74
    75
    76
    77
    78 /*****************************/
    79
    80
    81 endmodule

    以上代码是顶层模块的代码。

    显示结果如下:

  • 相关阅读:
    python-模块-tkinter
    Linux-命令-基本-反引号``或$()
    Linux-命令-基本-time,ctime,atime
    Linux-命令-基本-find-exec
    Linux-命令-cp,mkdir
    Linux-命令-setup,ifup,ls,cd,touch重定向
    Linux-Buffer和Cache
    给Access数据库文件减肥
    GPT转MBR怎么转?
    Windows XP解决显示桌面图标消失的问题
  • 原文地址:https://www.cnblogs.com/tony1224/p/2243603.html
Copyright © 2011-2022 走看看