Verilog实现VGA字符显示
实现目标
在显示器中以640*480的分辨率显示0-9、A-Z、‘:’、‘*’的任意字符,字符大小为7*8的像素规模。
实现原理
1、基本的VGA显示
所有VGA显示差不多都是基于下面这一段Verilog代码的,时钟分频、行同步信号hs、场同步信号vs、rgb颜色值,这些都是必不可少的,还要注意的是对于640*480的分辨率,显示器真正可显示的区域为行计数介于31~510、列计数介于144~783之间(实际上对不同的显示器可能会有几个像素的差异),在这个范围之外都必须把rgb值设置为全0,否则会对显示造成干扰。
下面代码效果为在显示器屏幕中央显示一个绿色矩形方块。
// vga_display.v `timescale 1ns / 1ps module vga_display( input clk, input rst, output reg [2:0] r, output reg [2:0] g, output reg [1:0] b, output hs, output vs ); // 显示器可显示区域 parameter UP_BOUND = 31; parameter DOWN_BOUND = 510; parameter LEFT_BOUND = 144; parameter RIGHT_BOUND = 783; // 屏幕中央的矩形方块 parameter up_pos = 211; parameter down_pos = 330; parameter left_pos = 384; parameter right_pos = 543; wire pclk; reg [1:0] count; reg [9:0] hcount, vcount; // 获得像素时钟25MHz assign pclk = count[1]; always @ (posedge clk or posedge rst) begin if (rst) count <= 0; else count <= count+1; end // 列计数与行同步 assign hs = (hcount < 96) ? 0 : 1; always @ (posedge pclk or posedge rst) begin if (rst) hcount <= 0; else if (hcount == 799) hcount <= 0; else hcount <= hcount+1; end // 行计数与场同步 assign vs = (vcount < 2) ? 0 : 1; always @ (posedge pclk or posedge rst) begin if (rst) vcount <= 0; else if (hcount == 799) begin if (vcount == 520) vcount <= 0; else vcount <= vcount+1; end else vcount <= vcount; end // 设置显示信号值 always @ (posedge pclk or posedge rst) begin if (rst) begin r <= 0; g <= 0; b <= 0; end else if (vcount>=UP_BOUND && vcount<=DOWN_BOUND && hcount>=LEFT_BOUND && hcount<=RIGHT_BOUND) begin if (vcount>=up_pos && vcount<=down_pos && hcount>=left_pos && hcount<=right_pos) begin r <= 3'b000; g <= 3'b111; b <= 2'b00; end else begin r <= 3'b000; g <= 3'b000; b <= 2'b00; end end else begin r <= 3'b000; g <= 3'b000; b <= 2'b00; end end endmodule
2、基于RAM和字模的VGA显示
我们都知道电脑有显存,它存储了显示器每个像素应该显示的rgb颜色值,显存不断被刷新,于是可以显示动态的图像。基于此,最简单的想法就是可以在Verilog里面定义一个640*480的8位寄存器二维数组作为VGA显示的显存,然后在reset信号使能的时候对每个数组单元赋值,这样我们就用一个数组存储了一幅静态图像,然后在VGA扫描显示的时候,分别根据寄存器数组的值来设置各个像素的rgb值。
显然,上面的方法是可行的,只不过工程浩大,难以实现!试想,要在屏幕显示一个7*8的字符就要分别设置56个寄存器的值,而且每个寄存器都要根据不同的字符设置不同的值,这是多么可怕的事情!
除此之外,可以考虑通过一个通用的RAM_set模块来一次性设置一个字符对应的寄存器的值。以显示两个字符为例(字符颜色白色,背景黑色),通过Verilog声明一个长度为14的8位寄存器数组reg [7:0] p[13:0],因为两个字符占用2*7*8=14*8个像素,所以p[i][j]=0表示第i+1列第j+1行像素为黑色,反之1为白色。这样的话,就可以分别把p[13:7]、p[6:0]通过RAM_set来设置。RAM_set模块可以根据要显示的不同字符的字模给寄存器赋不同的值。
图1 常见字符字模图
实现代码
下面的代码实现在显示器屏幕中央显示两个字符"3D"。
// vga_char_display.v `timescale 1ns / 1ps module vga_char_display( input clk, input rst, output reg [2:0] r, output reg [2:0] g, output reg [1:0] b, output hs, output vs ); // 显示器可显示区域 parameter UP_BOUND = 31; parameter DOWN_BOUND = 510; parameter LEFT_BOUND = 144; parameter RIGHT_BOUND = 783; // 屏幕中央两个字符的显示区域 parameter up_pos = 267; parameter down_pos = 274; parameter left_pos = 457; parameter right_pos = 470; wire pclk; reg [1:0] count; reg [9:0] hcount, vcount; wire [7:0] p[13:0]; RAM_set u_ram_1 ( .clk(clk), .rst(rst), .data(6'b00_0011), .col0(p[0]), .col1(p[1]), .col2(p[2]), .col3(p[3]), .col4(p[4]), .col5(p[5]), .col6(p[6]) ); RAM_set u_ram_2 ( .clk(clk), .rst(rst), .data(6'b00_1101), .col0(p[7]), .col1(p[8]), .col2(p[9]), .col3(p[10]), .col4(p[11]), .col5(p[12]), .col6(p[13]) ); // 获得像素时钟25MHz assign pclk = count[1]; always @ (posedge clk or posedge rst) begin if (rst) count <= 0; else count <= count+1; end // 列计数与行同步 assign hs = (hcount < 96) ? 0 : 1; always @ (posedge pclk or posedge rst) begin if (rst) hcount <= 0; else if (hcount == 799) hcount <= 0; else hcount <= hcount+1; end // 行计数与场同步 assign vs = (vcount < 2) ? 0 : 1; always @ (posedge pclk or posedge rst) begin if (rst) vcount <= 0; else if (hcount == 799) begin if (vcount == 520) vcount <= 0; else vcount <= vcount+1; end else vcount <= vcount; end // 设置显示信号值 always @ (posedge pclk or posedge rst) begin if (rst) begin r <= 0; g <= 0; b <= 0; end else if (vcount>=UP_BOUND && vcount<=DOWN_BOUND && hcount>=LEFT_BOUND && hcount<=RIGHT_BOUND) begin if (vcount>=up_pos && vcount<=down_pos && hcount>=left_pos && hcount<=right_pos) begin if (p[hcount-left_pos][vcount-up_pos]) begin r <= 3'b111; g <= 3'b111; b <= 2'b11; end else begin r <= 3'b000; g <= 3'b000; b <= 2'b00; end end else begin r <= 3'b000; g <= 3'b000; b <= 2'b00; end end else begin r <= 3'b000; g <= 3'b000; b <= 2'b00; end end endmodule
// RAM_set.v `timescale 1ns / 1ps module RAM_set( input clk, input rst, input [5:0] data, output reg [7:0] col0, output reg [7:0] col1, output reg [7:0] col2, output reg [7:0] col3, output reg [7:0] col4, output reg [7:0] col5, output reg [7:0] col6 ); always @(posedge clk or negedge rst) begin if (!rst) begin col0 <= 8'b0000_0000; col1 <= 8'b0000_0000; col2 <= 8'b0000_0000; col3 <= 8'b0000_0000; col4 <= 8'b0000_0000; col5 <= 8'b0000_0000; col6 <= 8'b0000_0000; end else begin case (data) 6'b00_0000: // "0" begin col0 <= 8'b0000_0000; col1 <= 8'b0011_1110; col2 <= 8'b0101_0001; col3 <= 8'b0100_1001; col4 <= 8'b0100_0101; col5 <= 8'b0011_1110; col6 <= 8'b0000_0000; end 6'b00_0001: // "1" begin col0 <= 8'b0000_0000; col1 <= 8'b0000_0000;; col2 <= 8'b0100_0010; col3 <= 8'b0111_1111; col4 <= 8'b0100_0000; col5 <= 8'b0000_0000;; col6 <= 8'b0000_0000; end 6'b00_0010: // "2" begin col0 <= 8'b0000_0000; col1 <= 8'b0100_0010; col2 <= 8'b0110_0001; col3 <= 8'b0101_0001; col4 <= 8'b0100_1001; col5 <= 8'b0100_0110; col6 <= 8'b0000_0000; end 6'b00_0011: // "3" begin col0 <= 8'b0000_0000; col1 <= 8'b0010_0010; col2 <= 8'b0100_0001; col3 <= 8'b0100_1001; col4 <= 8'b0100_1001; col5 <= 8'b0011_0110; col6 <= 8'b0000_0000; end 6'b00_0100: // "4" begin col0 <= 8'b0000_0000; col1 <= 8'b0001_1000; col2 <= 8'b0001_0100; col3 <= 8'b0001_0010; col4 <= 8'b0111_1111; col5 <= 8'b0001_0000; col6 <= 8'b0000_0000; end 6'b00_0101: // "5" begin col0 <= 8'b0000_0000; col1 <= 8'b0010_0111; col2 <= 8'b0100_0101; col3 <= 8'b0100_0101; col4 <= 8'b0100_0101; col5 <= 8'b0011_1001; col6 <= 8'b0000_0000; end 6'b00_0110: // "6" begin col0 <= 8'b0000_0000; col1 <= 8'b0011_1110; col2 <= 8'b0100_1001; col3 <= 8'b0100_1001; col4 <= 8'b0100_1001; col5 <= 8'b0011_0010; col6 <= 8'b0000_0000; end 6'b00_0111: // "7" begin col0 <= 8'b0000_0000; col1 <= 8'b0110_0001; col2 <= 8'b0001_0001; col3 <= 8'b0000_1001; col4 <= 8'b0000_0101; col5 <= 8'b0000_0011; col6 <= 8'b0000_0000; end 6'b00_1000: // "8" begin col0 <= 8'b0000_0000; col1 <= 8'b0011_0110; col2 <= 8'b0100_1001; col3 <= 8'b0100_1001; col4 <= 8'b0100_1001; col5 <= 8'b0011_0110; col6 <= 8'b0000_0000; end 6'b00_1001: // "9" begin col0 <= 8'b0000_0000; col1 <= 8'b0010_0110; col2 <= 8'b0100_1001; col3 <= 8'b0100_1001; col4 <= 8'b0100_1001; col5 <= 8'b0011_1110; col6 <= 8'b0000_0000; end 6'b00_1010: // "A" begin col0 <= 8'b0000_0000; col1 <= 8'b0111_1100; col2 <= 8'b0001_0010; col3 <= 8'b0001_0001; col4 <= 8'b0001_0010; col5 <= 8'b0111_1100; col6 <= 8'b0000_0000; end 6'b00_1011: // "B" begin col0 <= 8'b0000_0000; col1 <= 8'b0111_1111; col2 <= 8'b0100_1001; col3 <= 8'b0100_1001; col4 <= 8'b0100_1001; col5 <= 8'b0011_0110; col6 <= 8'b0000_0000; end 6'b00_1100: // "C" begin col0 <= 8'b0000_0000; col1 <= 8'b0011_1110; col2 <= 8'b0100_0001; col3 <= 8'b0100_0001; col4 <= 8'b0100_0001; col5 <= 8'b0010_0010; col6 <= 8'b0000_0000; end 6'b00_1101: // "D" begin col0 <= 8'b0000_0000; col1 <= 8'b0111_1111; col2 <= 8'b0100_0001; col3 <= 8'b0100_0001; col4 <= 8'b0100_0001; col5 <= 8'b0011_1110; col6 <= 8'b0000_0000; end 6'b00_1110: // "E" begin col0 <= 8'b0000_0000; col1 <= 8'b0111_1111; col2 <= 8'b0100_1001; col3 <= 8'b0100_1001; col4 <= 8'b0100_1001; col5 <= 8'b0100_0001; col6 <= 8'b0000_0000; end 6'b00_1111: // "F" begin col0 <= 8'b0000_0000; col1 <= 8'b0111_1111; col2 <= 8'b0000_1001; col3 <= 8'b0000_1001; col4 <= 8'b0000_1001; col5 <= 8'b0000_0001; col6 <= 8'b0000_0000; end 6'b01_0000: // "G" begin col0 <= 8'b0000_0000; col1 <= 8'b0011_1110; col2 <= 8'b0100_0001; col3 <= 8'b0100_1001; col4 <= 8'b0100_1001; col5 <= 8'b0011_1010; col6 <= 8'b0000_0000; end 6'b01_0001: // "H" begin col0 <= 8'b0000_0000; col1 <= 8'b0111_1111; col2 <= 8'b0000_1000; col3 <= 8'b0000_1000; col4 <= 8'b0000_1000; col5 <= 8'b0111_1111; col6 <= 8'b0000_0000; end 6'b01_0010: // "I" begin col0 <= 8'b0000_0000; col1 <= 8'b0000_0000; col2 <= 8'b0100_0001; col3 <= 8'b0111_1111; col4 <= 8'b0100_0001; col5 <= 8'b0000_0000; col6 <= 8'b0000_0000; end 6'b01_0011: // "J" begin col0 <= 8'b0000_0000; col1 <= 8'b0010_0000; col2 <= 8'b0100_0001; col3 <= 8'b0100_0001; col4 <= 8'b0011_1111; col5 <= 8'b0000_0001; col6 <= 8'b0000_0000; end 6'b01_0100: // "K" begin col0 <= 8'b0000_0000; col1 <= 8'b0111_1111; col2 <= 8'b0000_1000; col3 <= 8'b0001_0100; col4 <= 8'b0010_0010; col5 <= 8'b0100_0001; col6 <= 8'b0000_0000; end 6'b01_0101: // "L" begin col0 <= 8'b0000_0000; col1 <= 8'b0111_1111; col2 <= 8'b0100_0000; col3 <= 8'b0100_0000; col4 <= 8'b0100_0000; col5 <= 8'b0100_0000; col6 <= 8'b0000_0000; end 6'b01_0110: // "M" begin col0 <= 8'b0000_0000; col1 <= 8'b0111_1111; col2 <= 8'b0000_0010; col3 <= 8'b0000_1100; col4 <= 8'b0000_0010; col5 <= 8'b0111_1111; col6 <= 8'b0000_0000; end 6'b01_0111: // "N" begin col0 <= 8'b0000_0000; col1 <= 8'b0111_1111; col2 <= 8'b0000_0010; col3 <= 8'b0000_0100; col4 <= 8'b0000_1000; col5 <= 8'b0111_1111; col6 <= 8'b0000_0000; end 6'b01_1000: // "O" begin col0 <= 8'b0000_0000; col1 <= 8'b0011_1110; col2 <= 8'b0100_0001; col3 <= 8'b0100_0001; col4 <= 8'b0100_0001; col5 <= 8'b0011_1110; col6 <= 8'b0000_0000; end 6'b01_1001: // "P" begin col0 <= 8'b0000_0000; col1 <= 8'b0111_1111; col2 <= 8'b0000_1001; col3 <= 8'b0000_1001; col4 <= 8'b0000_1001; col5 <= 8'b0000_0110; col6 <= 8'b0000_0000; end 6'b01_1010: // "Q" begin col0 <= 8'b0000_0000; col1 <= 8'b0011_1110; col2 <= 8'b0100_0001; col3 <= 8'b0101_0001; col4 <= 8'b0110_0001; col5 <= 8'b0111_1110; col6 <= 8'b0000_0000; end 6'b01_1011: // "R" begin col0 <= 8'b0000_0000; col1 <= 8'b0111_1111; col2 <= 8'b0000_1001; col3 <= 8'b0001_1001; col4 <= 8'b0010_1001; col5 <= 8'b0100_0110; col6 <= 8'b0000_0000; end 6'b01_1100: // "S" begin col0 <= 8'b0000_0000; col1 <= 8'b0010_0110; col2 <= 8'b0100_1001; col3 <= 8'b0100_1001; col4 <= 8'b0100_1001; col5 <= 8'b0011_0010; col6 <= 8'b0000_0000; end 6'b01_1101: // "T" begin col0 <= 8'b0000_0000; col1 <= 8'b0000_0001; col2 <= 8'b0000_0001; col3 <= 8'b0111_1111; col4 <= 8'b0000_0001; col5 <= 8'b0000_0001; col6 <= 8'b0000_0000; end 6'b01_1110: // "U" begin col0 <= 8'b0000_0000; col1 <= 8'b0011_1111; col2 <= 8'b0100_0000; col3 <= 8'b0100_0000; col4 <= 8'b0100_0000; col5 <= 8'b0011_1111; col6 <= 8'b0000_0000; end 6'b01_1111: // "V" begin col0 <= 8'b0000_0000; col1 <= 8'b0001_1111; col2 <= 8'b0010_0000; col3 <= 8'b0100_0000; col4 <= 8'b0010_0000; col5 <= 8'b0001_1111; col6 <= 8'b0000_0000; end 6'b10_0000: // "W" begin col0 <= 8'b0000_0000; col1 <= 8'b0011_1111; col2 <= 8'b0100_0000; col3 <= 8'b0011_0000; col4 <= 8'b0100_0000; col5 <= 8'b0011_1111; col6 <= 8'b0000_0000; end 6'b10_0001: // "X" begin col0 <= 8'b0000_0000; col1 <= 8'b0110_0011; col2 <= 8'b0001_0100; col3 <= 8'b0000_1000; col4 <= 8'b0001_0100; col5 <= 8'b0110_0011; col6 <= 8'b0000_0000; end 6'b10_0010: // "Y" begin col0 <= 8'b0000_0000; col1 <= 8'b0000_0011; col2 <= 8'b0000_0100; col3 <= 8'b0111_1000; col4 <= 8'b0000_0100; col5 <= 8'b0000_0011; col6 <= 8'b0000_0000; end 6'b10_0011: // "Z" begin col0 <= 8'b0000_0000; col1 <= 8'b0110_0001; col2 <= 8'b0101_0001; col3 <= 8'b0100_1001; col4 <= 8'b0100_0101; col5 <= 8'b0100_0011; col6 <= 8'b0000_0000; end 6'b11_1110: // " " begin col0 <= 8'b0000_0000; col1 <= 8'b0000_0000; col2 <= 8'b0000_0000; col3 <= 8'b0000_0000; col4 <= 8'b0000_0000; col5 <= 8'b0000_0000; col6 <= 8'b0000_0000; end 6'b11_1111: // ":" begin col0 <= 8'b0000_0000; col1 <= 8'b0000_0000; col2 <= 8'b0011_0110; col3 <= 8'b0011_0110; col4 <= 8'b0000_0000; col5 <= 8'b0000_0000; col6 <= 8'b0000_0000; end default: // "*" begin col0 <= 8'b0000_0000; col1 <= 8'b0010_0010; col2 <= 8'b0001_0100; col3 <= 8'b0000_1000; col4 <= 8'b0001_0100; col5 <= 8'b0010_0010; col6 <= 8'b0000_0000; end endcase end end endmodule
相关推荐
这是本人自己写的程序,加上注释,与大家分享,虽然平台是Xilinx,但是放在quartus 里面一样能用啊!你了解的!!!
内容摘要:请看csdn博文 csdn博文链接如下: ... 注意!注意!...3、图像字符叠加,利用VGA时序的特点,在图像指定位置叠加字符,视频实时输出; 4、纯verilog实现实时时钟计数,并叠加到输出视频中;
FPGA设计VGA接口显示字符Verilog设计Quartus工程源码文件,FPGA型号Cyclone4E系列中的EP4CE10F17C8,Quartus版本18.0。 module vga_char( input sys_clk, //系统时钟 input sys_rst_n, //复位信号 //VGA接口 ...
Verilog VGA 显示图片切换程序,采用字符形式显示多幅哆啦a梦图片。并进行自动切换图片。图片大小为100*100的图片。采用数组形式存储。
ISE13.2下的VGA格子显示程序 verilog
基于FPGA的VGA接口实现和字符显示_贾伟伟.caj 基于FPGA的VGA接口显示技术_刘占军.caj 基于FPGA的VGA控制原理_薛枫 - 副本.caj 基于FPGA的VGA控制原理_薛枫.caj 基于FPGA的VGA显示实验方法_徐吉锋.caj 基于FPGA的实时...
能在VGA上显示色带和文字,文字是位于屏幕中间的
用verilog描述的FPGA控制VGA显示字符
基于FPGA设计的字符VGA LCD显示实验Verilog逻辑源码Quartus工程文件+文档说明,通过字符转换工具将字符转换为 8 进制 mif 文件存放到单端口的 ROM IP 核中,再从 ROM 中把转换后的数据读取出来显示到 VGA 上,FPGA...
fpga实现vga显示字符,使用Verilog,需要修改
Verilog编写的基于SPARTAN板的VGA接口显示程序.zip VGA显示IP核(包括驱动).zip VHDL实现对图像的采集和压缩.zip VHDL编写的PCI代码(PCI2.2兼容).zip xilinx 3s400开发板厂家光盘源码(按键防抖动).zip Xilinx DDR2...
Verilog HDL语言编写的基于M4K块配置ROM的字符数据存储VGA显示实验代码,引脚分配适用于21EDA的EP2C8Q208开发板, 详细解说请参见特权同学《深入浅出玩转FPGA》视频教程中的《Lesson30:SF-EP1C开发板实验9——基于M4...
利用FPGA驱动ov7670,将采集到的视频流存放到SDRAM中,通过VGA进行读取显示,显示分辨率640*480(60hz),经过下板验证,采集图像清晰流畅,达到了基本要求。该工程所有代码全部独立完成。此设计是基于EP4C10F17C8...
电子课设源码,包含VGA图片显示,VGA字符显示,PS2键盘协议解析和输入获取,蜂鸣器音乐播放,游戏界面友好。
verilog实现vga接口,可以在显示器上显示一个字符,具体显示什么字符可以按自己喜好更改相应数据。
# 频率计 ## 文件说明 frequencey.v 频率和占空比部分,可以根据频率大小,自动切换采样方法以提高精度,输出频率的二进制 bin2dec.v 把输出的频率转换为十进制,并把十进制的每一位转换为四位二进制...vga字符显示
19.字符显示实验.pdf 20.SD卡读取BMP图片显示例程.pdf 21.OV5640摄像头显示例程.pdf 22.彩色视频图像转黑白例程.pdf 23.SOBEL边缘检测例程.pdf 24.AD9238波形显示例程.pdf 25.AD7606波形显示例程.pdf 26.ADDA测试...
它们都是输入信号,输出是VGA,在电脑屏幕实现VGA显示字符,游戏画面 第3章 贪吃蛇游戏设计 3.1 VGA显示模块设计 显示器扫描方式分为逐行扫描和隔行扫描:逐行扫描是扫描从屏幕左上角一点开始,从左像右逐点扫描,...
我们分阶段实施该项目,首先从MATLAB实现开始,然后将逻辑移植到C,最后在Verilog中实现某些部分。 这有助于测试,调试和基准化我们的实施。 概述 我们的项目使用DE1-SoC板上的FPGA和HPS来实现纸牌的字符识别算法。 ...
主要问题在于想利用M4K来存储要显示到VGA屏幕上的字模数据,而昨天为了方便开了一个很大位宽的M4K,结果就照成了M4K的利用率大大下降,原来不到8K的数据居然占用了7个M4K块,感觉不爽。所以今天绞尽脑汁是想出了解决...