VCG显示——汉字,数字,图像

news/2024/11/13 9:06:04/

详细的介绍资料:

【从零开始走进FPGA】 玩转VGA

http://www.cnblogs.com/spartan/archive/2011/08/16/2140546.html

【FPGA实验】基于DE2-115平台的VGA显示_vga接口实验 de2-115-CSDN博客

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

一.VCG原理

1.1 VCG引脚原理

1.2 VCG显示原理

VGA 显示器显示图像,并不是直接让图像在显示器上显示出来,而是采用扫描的方式,将构成图像的像素点,在行同步信号和场同步信号的同步下,按照从上到下、由左到右的顺序扫描到显示屏上。

详细介绍请参考:【FPGA】VGA显示文字、彩条、图片——基于DE2-115-CSDN博客

二.VCG显示自定义字符

2.1 点阵汉字生成

使用“PCtoLCD2002”生成汉字

2.2生成BMP文件

文件->保存为BMP格式,打开图片得到完整字符

2.3生成txt文件

保存字符,得到

三.VGA显示条纹

3.1实现流程

输出颜色竖条

// 状态输出逻辑,根据不同的状态输出不同的RGB数据
always @( * ) begincase ( states_current )//彩条states_1 : beginif ( addr_h == 0 ) beginrgb_data = black;endelse if ( addr_h >0 && addr_h <81 ) beginrgb_data = red;endelse if ( addr_h >80 && addr_h <161 ) beginrgb_data = orange;// rgb_data = red;endelse if ( addr_h >160 && addr_h <241 ) beginrgb_data = yellow;endelse if ( addr_h >240 && addr_h <321 ) beginrgb_data = green;endelse if ( addr_h >320 && addr_h <401 ) beginrgb_data = blue;endelse if ( addr_h >400 && addr_h <481 ) beginrgb_data = indigo;endelse if ( addr_h >480 && addr_h <561 ) beginrgb_data = purple;endelse if ( addr_h >560 && addr_h <641 ) beginrgb_data = white;endelse beginrgb_data = black;endend

3.2实现效果

四.VGA输出一幅彩色图像

4.1bmp图片转hex文件

使用BMP2Mif软件将bmp格式图片转换为mif文件

转换后的.mif文件:

4.2引入ROM ip核

新建Quartus工程,产生ROM IP核,将生成的mif文件保存在ROM中
双击选择ROM:1-PORT

更改设置,words大小设置要大于图片大小(50x49x24=58800< 65536),然后next

4.3代码实现

data_drive.v文件里,从ikun_rom取出图片数据。

五.代码

5.1 时钟分频

分别使用640×480 60HZ和800×600 72HZ,对应时钟分别为25M和50M,需要使用PLL进行分频 时钟频率 = 行帧长 × 列帧长 * 刷新率

640 ×480 60HZ对应时钟频率= 800 ×525 × 60 = 25.2M

ip核里面找到ALTPLL

基础时钟选择50M

0默认输出50M即可, c1分频到25M,如需其他时钟频率可以自己进行设置

5.2 vga驱动模块

vga.drive.v

// /*
module vga_dirve (input			wire						clk,            //系统时钟    input			wire						rst_n,          //复位input			wire		[ 15:0 ]		rgb_data,       //RGB--565,即pixel_data[15:11]控制R、pixel_data[10:5]控制G、pixel_data[4:0]控制Boutput			wire							vga_clk,    //vga时钟 25Moutput			reg							h_sync,     //行同步信号output			reg							v_sync,     //场同步信号output			reg		[ 11:0 ]				addr_h, //行地址output			reg		[ 11:0 ]				addr_v,  //列地址output			wire		[ 4:0 ]				rgb_r,  //红基色output			wire		[ 5:0 ]				rgb_g,  //绿基色output			wire		[ 4:0 ]				rgb_b  //蓝基色
);// 定义VGA信号的参数,基于640x480 60Hz的VGA模式
// 640 * 480 60HZ
localparam	 H_FRONT = 16; // 行同步前沿信号周期长
localparam	 H_SYNC  = 96; // 行同步信号周期长
localparam	 H_BLACK = 48; // 行同步后沿信号周期长
localparam	 H_ACT   = 640; // 行显示周期长
localparam	 V_FRONT = 11; // 场同步前沿信号周期长
localparam	 V_SYNC  = 2; // 场同步信号周期长
localparam	 V_BLACK = 31; // 场同步后沿信号周期长
localparam	 V_ACT   = 480; // 场显示周期长// 800 * 600 72HZ
// localparam	 H_FRONT = 40; // 行同步前沿信号周期长
// localparam	 H_SYNC  = 120; // 行同步信号周期长
// localparam	 H_BLACK = 88; // 行同步后沿信号周期长
// localparam	 H_ACT   = 800; // 行显示周期长
// localparam	 V_FRONT = 37; // 场同步前沿信号周期长
// localparam	 V_SYNC  = 6; // 场同步信号周期长
// localparam	 V_BLACK = 23; // 场同步后沿信号周期长
// localparam	 V_ACT   = 600; // 场显示周期长// 计算总的行和场周期
localparam	H_TOTAL = H_FRONT + H_SYNC + H_BLACK + H_ACT; // 行周期 16+96+48+640 = 800
localparam	V_TOTAL = V_FRONT + V_SYNC + V_BLACK + V_ACT; // 列周期 11+2+6+31+480 = 512
reg			[ 11:0 ]			cnt_h			; // 行计数器 0-799
reg			[ 11:0 ]			cnt_v			; // 场计数器 0-524
reg			[ 15:0 ]			rgb			; // 对应显示颜色值// 对应计数器开始、结束、计数信号
wire							flag_enable_cnt_h			;
wire							flag_clear_cnt_h			;
wire							flag_enable_cnt_v			;
wire							flag_clear_cnt_v			;
wire							flag_add_cnt_v  			;
wire							valid_area      			;// 25M时钟 行周期*场周期*刷新率 = 800 * 525 * 60
wire							clk_25			;
// 50M时钟 1040 * 666 * 72
wire							clk_50			;
//PLL
pll	pll_inst (.areset ( ~rst_n ),.inclk0 ( clk ),.c0 ( clk_50 ), //50M.c1 ( clk_25 ) //25M
);//根据不同分配率选择不同频率时钟
assign vga_clk = clk_25;// 行计数
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) begincnt_h <= 0;endelse if ( flag_enable_cnt_h ) beginif ( flag_clear_cnt_h ) begincnt_h <= 0;endelse begincnt_h <= cnt_h + 1;endendelse begincnt_h <= 0;end
end
assign flag_enable_cnt_h = 1;
assign flag_clear_cnt_h  = cnt_h == H_TOTAL - 1;// 行同步信号
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) beginh_sync <= 1;endelse if ( cnt_h == H_SYNC - 1 ) begin // 同步周期时为1h_sync <= 0;endelse if ( flag_clear_cnt_h ) begin // 其余为0h_sync <= 1;endelse beginh_sync <= h_sync;end
end// 场计数
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) begincnt_v <= 0;endelse if ( flag_enable_cnt_v ) beginif ( flag_clear_cnt_v ) begincnt_v <= 0;endelse if ( flag_add_cnt_v ) begincnt_v <= cnt_v + 1;endelse begincnt_v <= cnt_v;endendelse begincnt_v <= 0;end
endassign flag_enable_cnt_v = flag_enable_cnt_h;
assign flag_clear_cnt_v  = cnt_v == V_TOTAL - 1;
assign flag_add_cnt_v    = flag_clear_cnt_h;// 场同步信号
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) beginv_sync <= 1;endelse if ( cnt_v == V_SYNC - 1 ) beginv_sync <= 0;endelse if ( flag_clear_cnt_v ) beginv_sync <= 1;endelse beginv_sync <= v_sync;end
end// 对应有效区域行地址 1-640
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) beginaddr_h <= 0;endelse if ( valid_area ) beginaddr_h <= cnt_h - H_SYNC - H_BLACK + 1;endelse beginaddr_h <= 0;end
end
// 对应有效区域列地址 1-480
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) beginaddr_v <= 0;endelse if ( valid_area ) beginaddr_v <= cnt_v -V_SYNC - V_BLACK + 1;endelse beginaddr_v <= 0;end
end
// 有效显示区域
assign valid_area = cnt_h >= H_SYNC + H_BLACK && cnt_h <= H_SYNC + H_BLACK + H_ACT && cnt_v >= V_SYNC + V_BLACK && cnt_v <= V_SYNC + V_BLACK + V_ACT;// 显示颜色
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) beginrgb <= 16'h0;endelse if ( valid_area ) beginrgb <= rgb_data;endelse beginrgb <= 16'b0;end
end
assign rgb_r = rgb[ 15:11 ];
assign rgb_g = rgb[ 10:5 ];
assign rgb_b = rgb[ 4:0 ];
endmodule // vga_dirve
// */

5.3 显示数据生成模块

data_drive.v


module data_drive (input			wire						vga_clk,      // VGA时钟输入input			wire						rst_n,        // 复位信号,低电平有效input			wire		[ 11:0 ]		addr_h,       // 水平地址输入input			wire		[ 11:0 ]		addr_v,       // 垂直地址输入input			wire		[ 2:0 ]		 key,          // 三个按键输入output			reg		[ 15:0 ]				rgb_data      // 输出的RGB数据);// 定义一些颜色的16位表示
localparam	red    = 16'd63488;
localparam	orange = 16'd64384;
localparam	yellow = 16'd65472;
localparam	green  = 16'd1024;
localparam	blue   = 16'd31;
localparam	indigo = 16'd18448;
localparam	purple = 16'd32784;
localparam	white  = 16'd65503;
localparam	black  = 16'd0;//显示的名字
// 存储显示字符的每一行数据
// reg [ 383:0 ] char_line[ 64:0 ];//李菊芳-632109160602  -16
//16行,每行152个bit
// reg [ 152:0 ] char_line[ 15:0 ];//李菊芳-632109160602 ——32
//32*3+16*13 = 304 304/8 = 38
reg [ 303:0 ] char_line[ 31:0 ];// 定义显示状态的参数
localparam	states_1 = 1; // 彩条
localparam	states_2 = 2; // 字符
localparam	states_3 = 3; // 图片// 图片的尺寸参数
// parameter	height = 78; // 图片高度
// parameter	width  = 128; // 图片宽度//ikun2
parameter	height = 52; // 图片高度
parameter	width  = 52; // 图片宽度// 当前状态和下一个状态的寄存器
reg			[ 2:0 ]			states_current			; // 当前状态
reg			[ 2:0 ]			states_next			    ; // 下个状态// ROM的地址寄存器和数据输出
reg			[ 13:0 ]		rom_address				; // ROM地址
// wire		[ 15:0 ]		rom_data				; // 图片数据
wire		[ 23:0 ]		rom_data				; // 显示彩色图片数据// 状态机的标志位
wire							flag_enable_out1			; // 文字有效区域标志
wire							flag_enable_out2			; // 图片有效区域标志
wire							flag_clear_rom_address		; // ROM地址清零标志
wire							flag_begin_h			    ; // 图片显示行开始标志
wire							flag_begin_v			    ; // 图片显示列开始标志// 状态转移逻辑
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) beginstates_current <= states_1;// 复位时设置初始状态为彩条endelse beginstates_current <= states_next;// 否则转移到下一个状态end
end// 状态判断逻辑,根据按键输入更新下一个状态
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) beginstates_next <= states_1;endelse if ( key[ 0 ] ) beginstates_next <= states_1;endelse if ( key[ 1 ] ) beginstates_next <= states_2;endelse if ( key[ 2 ] ) beginstates_next <= states_3;endelse beginstates_next <= states_next;end
end// 状态输出逻辑,根据不同的状态输出不同的RGB数据
always @( * ) begincase ( states_current )//彩条states_1 : beginif ( addr_h == 0 ) beginrgb_data = black;endelse if ( addr_h >0 && addr_h <81 ) beginrgb_data = red;endelse if ( addr_h >80 && addr_h <161 ) begin// rgb_data = orange;rgb_data = red;endelse if ( addr_h >160 && addr_h <241 ) beginrgb_data = yellow;endelse if ( addr_h >240 && addr_h <321 ) beginrgb_data = green;endelse if ( addr_h >320 && addr_h <401 ) beginrgb_data = blue;endelse if ( addr_h >400 && addr_h <481 ) beginrgb_data = indigo;endelse if ( addr_h >480 && addr_h <561 ) beginrgb_data = purple;endelse if ( addr_h >560 && addr_h <641 ) beginrgb_data = white;endelse beginrgb_data = black;endend//字符states_2 : beginif ( flag_enable_out1 ) begin//480*640// rgb_data = char_line[ addr_v-208 ][ 532 - addr_h ]? white:black;rgb_data = char_line[ addr_v-224 ][ 472 - addr_h ]? white:black;endelse beginrgb_data = black;endend//图片states_3 : beginif ( flag_enable_out2 ) beginrgb_data = rom_data;endelse beginrgb_data = black;endenddefault: begincase ( addr_h )0 : rgb_data      = black;1 : rgb_data      = red;81 : rgb_data     = orange;161: rgb_data     = yellow;241: rgb_data     = green;321: rgb_data     = blue;401: rgb_data     = indigo;481: rgb_data     = purple;561: rgb_data     = white;default: rgb_data = rgb_data;endcaseendendcase
end//李骏飞的居中显示参数
//32*3+16*13 = 304 304/8 = 38
// 根据当前状态和地址范围设置标志位
parameter ljf_width = 304;  // 字符数据的宽度
parameter ljf_height = 32;  // 字符数据的高度
assign flag_enable_out1 = states_current == states_2 && addr_h >= (640 - ljf_width) / 2 && addr_h <  ((640 - ljf_width) / 2) + ljf_width && addr_v >= (480 - ljf_height) / 2 && addr_v <  ((480 - ljf_height) / 2) + ljf_height;// assign flag_begin_h     = addr_h > ( ( 640 - width ) / 2 ) && addr_h < ( ( 640 - width ) / 2 ) + width + 1;
// assign flag_begin_v     = addr_v > ( ( 480 - height )/2 ) && addr_v <( ( 480 - height )/2 ) + height + 1;
assign flag_begin_h     = addr_h >= ( ( 640 - width ) / 2 ) && addr_h < ( ( 640 - width ) / 2 ) + width ;
assign flag_begin_v     = addr_v >= ( ( 480 - height )/2 ) && addr_v <( ( 480 - height )/2 ) + height ;
assign flag_enable_out2 = states_current == states_3 && flag_begin_h && flag_begin_v;//ROM地址计数器
always @( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) beginrom_address <= 0;// 复位时清零ROM地址endelse if ( flag_clear_rom_address ) begin //计数满清零rom_address <= 0;endelse if ( flag_enable_out2 ) begin  //在有效区域内+1rom_address <= rom_address + 1;endelse begin  //无效区域保持rom_address <= rom_address;end
end
assign flag_clear_rom_address = rom_address == height * width - 1 || states_current != states_3;// 初始化显示文字的逻辑
always@( posedge vga_clk or negedge rst_n ) beginif ( !rst_n ) begin//李菊芳-632109160602 ——32//32*3+16*13 = 304 304/8 = 38char_line[0] =  304'h0000000000000000000000000000000000000000000000000000000000000000000000000000;char_line[1] =  304'h0000000000000000000000000000000000000000000000000000000000000000000000000000;char_line[2] =  304'h0003800000101000002008000000000000000000000000000000000000000000000000000000;char_line[3] =  304'h0003C000001C1C0000380E000000000000000000000000000000000000000000000000000000;char_line[4] =  304'h000380100018180000300C000000000000000000000000000000000000000000000000000000;char_line[5] =  304'h000380380018181800300C300000000000000000000000000000000000000000000000000000;char_line[6] =  304'h3FFFFFFC3FFFFFFC1FFFFFF8000001E007C007E0008003C007C0008001E003C001E003C007E0;char_line[7] =  304'h180FE0000098180000300C000000061818600838018006201820018006180620061806200838;char_line[8] =  304'h001FF00000D8180000330C0000000C18303010181F800C3030101F800C180C300C180C301018;char_line[9] =  304'h003FB80000F8180000318C00000008183018200C01801818301801800818181808181818200C;char_line[10] = 304'h 007B9C00019000200030C800000018003018200C01801818600801801800181818001818200C;char_line[11] = 304'h 00F39E0001FFFFF000006000000010003018300C01801808600C01801000180810001808300C;char_line[12] = 304'h 01E38F800300003000004030000010000018300C0180300C600C01801000300C1000300C300C;char_line[13] = 304'h 03C387F0020300301FFFFFF8000030000018000C0180300C600C01803000300C3000300C000C;char_line[14] = 304'h 07838DFE0483083000060000000033E0003000180180300C600C018033E0300C33E0300C0018;char_line[15] = 304'h 1FFFFEF808431C300006000000003630006000180180300C600C01803630300C3630300C0018;char_line[16] = 304'h 38401F3010631830000C00007FFE381803C000300180300C701C01803818300C3818300C0030;char_line[17] = 304'h 60003C0020633030000C008000003808007000600180300C302C01803808300C3808300C0060;char_line[18] = 304'h 0001F00000232330000FFFC00000300C001800C00180300C186C0180300C300C300C300C00C0;char_line[19] = 304'h 0001E0000FFFFFB0000C00C00000300C000801800180300C0F8C0180300C300C300C300C0180;char_line[20] = 304'h 0001E010000F0030000C01800000300C000C03000180300C000C0180300C300C300C300C0300;char_line[21] = 304'h 0001C038000B8030001801800000300C000C02000180300C00180180300C300C300C300C0200;char_line[22] = 304'h 7FFFFFFC001B6030001801800000300C300C04040180180800180180300C1808300C18080404;char_line[23] = 304'h 3801C00000333830003001800000180C300C08040180181800100180180C1818180C18180804;char_line[24] = 304'h 0001C00000631C20003001800000180830081004018018183030018018081818180818181004;char_line[25] = 304'h 0001C00000C30C200060030000000C183018200C01800C30306001800C180C300C180C30200C;char_line[26] = 304'h 0001C0000183046000C0030000000E3018303FF803C0062030C003C00E3006200E3006203FF8;char_line[27] = 304'h 0001C000020300600180C300000003E007C03FF81FF803C00F801FF803E003C003E003C03FF8;char_line[28] = 304'h 003FC0000C030FE002003E000000000000000000000000000000000000000000000000000000;char_line[29] = 304'h 0007C000300303C00C001E000000000000000000000000000000000000000000000000000000;char_line[30] = 304'h 0003800000020080300008000000000000000000000000000000000000000000000000000000;char_line[31] = 304'h 0000000000000000000000000000000000000000000000000000000000000000000000000000;end
end// /*
//ikun
// ROM实例化,根据地址输出数据
ikun_rom	ikun_rom_inst (
.address ( rom_address ),
.clock ( vga_clk ),
.q ( rom_data )
);
// */endmodule // data_drive


http://www.ppmy.cn/news/1471348.html

相关文章

Spring响应式编程之Reactor操作符

操作符 操作符Processo<T,R>&#xff08;1&#xff09;创建操作符&#xff08;2&#xff09;转换操作符&#xff08;3&#xff09;组合操作符&#xff08;4&#xff09;条件操作符&#xff08;5&#xff09;错误处理操作符 操作符Processo<T,R> 操作符并不是响应式…

webpack 中 require.context() 的用法

一、什么是 require.context It allows you to pass in a directory to search, a flag indicating whether subdirectories should be searched too, and a regular expression to match files against. – webpack 官方说明 一个 webpack 的 api &#xff0c;通过该函数可以获…

【运维项目经历|035】ISCSI存储优化与自动化部署项目

🍁博主简介: 🏅云计算领域优质创作者 🏅2022年CSDN新星计划python赛道第一名 🏅2022年CSDN原力计划优质作者 ​ 🏅阿里云ACE认证高级工程师 ​ 🏅阿里云开发者社区专家博主 💊交流社区:CSDN云计算交流社区欢迎您的加入! 目录 项目名称 项目背景 项目目标 …

CSS 变量的优势

CSS 变量(Custom Properties)&#xff1a;灵活的样式定义与复用 在 CSS 中,我们通常会使用一些固定的值来定义样式,比如颜色、字体大小、边距等。但随着项目的不断发展和需求的变化,这些固定值可能会变得难以维护和复用。这就是 CSS 变量(Custom Properties)派上用场的地方。 …

基于Python+OpenCV的车牌识别停车场管理系统(PyQt界面)【含Python源码 MX_009期】

简介&#xff1a; 基于Python和OpenCV的车牌识别停车场管理系统是一种利用计算机视觉技术来自动识别停车场进出车辆的系统。该系统通过摄像头捕获车辆图像&#xff0c;并使用OpenCV库中的图像处理和模式识别技术来识别图像中的车牌号码。一旦车牌被成功识别&#xff0c;系统就会…

【计算机网络】第四章.网络层 网络层重点知识总结(2)

&#x1f970;欢迎阅读&#xff0c;来和 小哇 一起进步&#xff01;✊ &#x1f308;感谢大家的阅读、点赞、收藏和关注&#x1f495; &#x1f451;目录 无分类编址CIDR 1、网络前缀 2、地址块 3、地址掩码&#xff08;子网掩码&#xff09; 4、路由聚合 5、在路由中的意…

中年帕金森:守护健康,从容面对生活挑战

在快节奏的现代生活中&#xff0c;中年人群面临着越来越多的健康挑战。其中&#xff0c;帕金森病作为一种常见的神经系统疾病&#xff0c;逐渐引起了人们的关注。帕金森病不仅影响患者的身体健康&#xff0c;还对其日常生活造成极大的困扰。那么&#xff0c;我们该如何应对中年…

企业微信内嵌H5项目接入聊天功能

产品需求是,在列表中把符合条件的列表接入聊天功能,以下是详细步骤: 1.引入企业微信 <script src"https://res.wx.qq.com/wwopen/js/jsapi/jweixin-1.0.0.js"></script> 2.获取wx签名(必须要) /*** 获取wx签名**/ export function getWxJsApi(data) {r…