VGA成像原理与简单实现
本篇文章简单记录VGA成像原理与时序解析,使用Verilog初步实现。如有错误,还请批评指正,谢谢。
提示:以下是本篇文章正文内容,下面案例可供参考
在 VGA 标准兴起的时候,常见的彩色显示器一般由 CRT(阴极射线管)构成,色彩是由 RGB 三基色组成。显示是用逐行扫描的方式解决。阴极射线枪发出的电子束打在涂有荧光粉的荧光屏上,产生 RGB 三基色,合成一个彩色像素,扫描从屏幕的左上方开始,从左到右,从上到下进行扫描,每扫完一行,电子束都回到屏幕的下一行左边的起始位置。

在这期间,CRT 对电子束进行消隐。每行结束时,用行同步信号进行行同步;扫描完所有行,用场同步信号进行场同步,并使扫描回到屏幕的左上方。同时进行场消隐,预备下一场的扫描。
1.下图为VGA成像的综合时序:下图中,黑底的JAMES人物图像就是我们希望显示的图像内容。我们的目的就是要让该图像恰好完全显示在显示器上。而 CRT 显示器是基于电子枪的,通过电子轰击荧光粉来产生明暗不同的亮度,从而实现图像线索。所以这一幅图像,可以理解为横向的很多行图像向下依次平铺构成的,而每一行图像,又可以理解为由多个像素点从左向右依次平铺构成的。电子枪每次只能点亮一个点上的荧光粉,所以需要像我们人眼看文章一样,从左向右一个字一个字的看,看完一行内容后,再把视线回到左侧,另起一行开始看,这也就是 CRT 的成像方式。
2.行扫描:虽然扫描的时候是按照一行一行的方式进行的,但不是扫描完一行有效数据段之后就立马返回,而是会继续向右扫描一段区域,这个区域称为右边界区域( horizontal right border ),该区域己经不在有效的显示范围内,如果从物理结构的角度来说,这一段对应的荧光屏玻璃上就不再有荧光粉了,但是电子枪还在继续向右走,大家可以形象理解为显示器右边的黑边。同样的,显示器左边也有这样一段黑边,在开始显示有效数据之前,电子枪扫描到的这段区城同样也是没有荧光粉的,不会显示图像,这个区城称为左边界区域( horizontal left border )。
当电子枪扫描一行图像到达荧光屏的最右端后,其并不会自动回到最左边准备下一行,而是需要有一个通知信号,通知其回去,这个通知信号就是行同步信号脉冲( horizontal sync pulse )。行同步信号是一个脉冲,当该脉冲出现后,电子枪的指向会在一定时间内从最右侧回到显示屏的最左侧。而这个回去的过程需要耗费一定的时间,这个时间就称为 (horizontal back porch) 。这也是这个名词中 back 的意义所在,即出现行同步信号后,电子尬从显示屏最石侧回到最左侧的时间。当电子枪扫描过了右侧没有荧光粉的区城后还没有收到回到最左侧的命令(行同步信号脉冲)之前,电子枪需要关闭以实现消隐,这个消隐的时间段就称为 (horizontal front porch),直观一点理解就是完成了一行图像的扫描,但还没收到回到最左侧命令之前的一段时间。

3.场扫描:场扫描与行扫描原理类似。

设计VGA成像需要找到几个关键时间节点:
行扫描时间节点:(以640*480为例)
1.行脉冲的开始位置HS_Begin(HS_YC下降沿) =0
2.行脉冲的结束位置HS_End (HS_YC上升沿)=96(Pclk)
3.行数据开始输出位置Hdata_Begin=96+40+8
4.行数据停止输出位置Hdata_End=96+40+8+640
5.行同步信号的结束位置Hsync_end=96+40+8+640+8+8 = 800
场扫描时间节点:
1.场脉冲的开始位置VS_Begin(VS_YC下降沿)=0
2.场脉冲的结束位置VS_End (VS_YC上升沿)=2(Line)
3.场数据开始输出位置Vdata_Begin=2+25+8
4.场数据停止输出位置Vdata_End=2+25+8+480
5.场同步信号的结束位置Vsync_end=2+25+8+480+8+2 = 525
相关参数如下表表所示:

`timescale 1ns / 1ps
//
// Create Date: 2022/11/30 15:18:34
// Module Name: VGA_CTRL_640x480
// Project Name: 640x480图像输出
// Revision: VIVADO 2018.3
// Name:小王在努力...
//
module VGA_CTRL_640x480(
clk,
reset,
Data,
Data_request,
HS_YS,
VS_YS,
VGA_BLK,
RGB_output
);
input clk;
input reset;
input [23:0]Data; //输入数据
output reg Data_request; //数据请求脉冲信号
output reg HS_YS; //行同步脉冲信号
output reg VS_YS; //场同步脉冲信号
output reg VGA_BLK; //VGA有效数据显示脉冲信号
output reg [23:0]RGB_output; //RGB输出值
parameter [9:0]Hsync_end = 10'd800;
parameter [6:0]HS_END = 7'd96;
parameter [9:0]Vsync_end = 10'd525;
parameter [1:0]VS_END = 2'd2;
parameter [7:0]Hdata_begin = 8'd144;
parameter [9:0]Hdata_end = 10'd784;
parameter [5:0]Vdata_begin = 6'd35;
parameter [9:0]Vdata_end = 10'd515;
reg [9:0]H_cnt;
always @ (posedge clk or negedge reset)
if(!reset)
H_cnt <= 0;
else if(H_cnt >= Hsync_end -1 )
H_cnt <= 0;
else
H_cnt <= H_cnt + 1'b1;
// 行同步脉冲信号
always @ (posedge clk)
HS_YS <= (H_cnt <= HS_END-1 )?0:1;
reg [9:0]V_cnt;
always @ (posedge clk or negedge reset)
if(!reset)
V_cnt <= 0;
else if( H_cnt == Hsync_end -1)begin
if(V_cnt >= Vsync_end-1)
V_cnt <= 0;
else
V_cnt <= V_cnt + 1;
end
else
V_cnt <= V_cnt ;
//场同步脉冲信号
always @ (posedge clk)
VS_YS <= (V_cnt <= VS_END-1 )?0:1;
// Data_request 数据请求脉冲
always @ (posedge clk)
Data_request <= (H_cnt >= Hdata_begin - 1 )&&(H_cnt <= Hdata_end - 2)&&(V_cnt >= Vdata_begin)&&(V_cnt <= Vdata_end -1);
//VGA_BLK数据开始发送脉冲
always @ (posedge clk)
VGA_BLK <= Data_request;
//RGB_output 数据接收
always @ (posedge clk)
RGB_output <= (Data_request) ?Data:0;
endmodule
`timescale 1ns / 1ps
//
// Create Date: 2022/11/30 16:07:54
// Design Name: VGA_CTRL
// Module Name: VGA_CTRL_TB
// Project Name: VGA_CTRL
// Revision:2018.3
// Revision 0.01 - File Created
// Name:小王在努力...
//
module VGA_CTRL_TB();
reg clk;
reg reset;
reg [23:0]Data; //输入数据
wire Data_request; //数据请求信号
wire HS_YS; //行同步脉冲信号
wire VS_YS; //场同步脉冲信号
wire VGA_BLK; //VGA有效数据显示脉冲信号
wire [23:0]RGB_output; //RGB输出值
VGA_CTRL_640x480 VGA_CTRL_640x480_TB(
clk,
reset,
Data,
Data_request,
HS_YS,
VS_YS,
VGA_BLK,
RGB_output
);
initial clk = 1;
always #20 clk = ~clk;
initial begin
reset = 0;
#201;
reset = 1;
#20000000;
$stop;
end
always @ (posedge clk or negedge reset)
if(!reset)
Data <= 0;
else if(Data_request)
Data <= Data + 1;
else
Data <= Data;
endmodule
1.验证行扫描时间节点

验证HS_End 根据上图HS_YS(白线与黄线间隔)低点平时间为3.84us。此处采用的clk时钟频率为25MHZ,于是根据计算(3.84*1000/40)=96,此处与第三节行脉冲的结束位置HS_End (HS_YC上升沿)=96(Pclk)吻合,故此处验证成功。

验证·Hdata_Begin 根据上图HS_YS与VGA_BLK之间时间(白线与蓝线)为5.76us,经计算为144个clk时间,于是行数据开始输出位置Hdata_Begin=96+40+8验证成立。

验证Hdata_End 根据上图HS_YS与VGA_BLK之间时间(白线与蓝线)为31.36us,经计算为784个clk时间,于是行数据停止输出位置Hdata_End=96+40+8+640验证成立。

验证Hsync_end 根据上图HS_YS(白线与蓝线间隔)时间为32us,经计算为800个clk时间。此处与第三节行同步信号的结束位置Hsync_end = 800吻合,故此处验证成功。

根据640x480数据发送要求,每行应该有640个数据如上图发送Data为0-639而RGB_output接收也为640个数据,没有丢失,至此行数据节点验证完成。
1.验证场扫描时间节点
验证VS_End 根据上图VS_YS(白线与黄线间隔)低点平时间为64us。此处采用的clk时钟频率为25MHZ,于是根据计算(64*1000/40/800)=2,此处与第三节场脉冲的结束位置VS_End (VS_YC上升沿)=2(Line)吻合,故此处验证成功。

验证·Vdata_Begin 根据上图VS_YS与VGA_BLK之间时间(白线与蓝线)为1120us,经计算为35个Line时间,于是场数据开始输出位置Vdata_Begin=35验证成立。

验证Hdata_End 根据上图HS_YS与VS_YS之间时间(蓝线与黄线)为16.48us,经计算为515个Line时间,于是场数据停止输出位置Vdata_End=515验证成立。

验证Vsync_end 根据上图VS_YS(白线与蓝线间隔)时间为18.8ms,经计算为525个clk时间。此处与第三节场同步信号的结束位置Vsync_end = 525吻合,故此处验证成功。

根据640x480数据发送要求,每次应该有480行数据如上图发送Data时间间隔为(两个蓝线之间)15.36ms,经计算为480Line。而RGB_output接收也为480Line个数据,没有丢失,至此场数据节点验证完成。
【附件:】链接:https://pan.baidu.com/s/1uz4Npx6kqVGRXeGbd_HtnQ?pwd=cldn
提取码:cldn
我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden
有没有办法在这个简单的get方法中添加超时选项?我正在使用法拉第3.3。Faraday.get(url)四处寻找,我只能先发起连接后应用超时选项,然后应用超时选项。或者有什么简单的方法?这就是我现在正在做的:conn=Faraday.newresponse=conn.getdo|req|req.urlurlreq.options.timeout=2#2secondsend 最佳答案 试试这个:conn=Faraday.newdo|conn|conn.options.timeout=20endresponse=conn.get(url
我想在Ruby中创建一个用于开发目的的极其简单的Web服务器(不,不想使用现成的解决方案)。代码如下:#!/usr/bin/rubyrequire'socket'server=TCPServer.new('127.0.0.1',8080)whileconnection=server.acceptheaders=[]length=0whileline=connection.getsheaders想法是从命令行运行这个脚本,提供另一个脚本,它将在其标准输入上获取请求,并在其标准输出上返回完整的响应。到目前为止一切顺利,但事实证明这真的很脆弱,因为它在第二个请求上中断并出现错误:/usr/b
我意识到这可能是一个非常基本的问题,但我现在已经花了几天时间回过头来解决这个问题,但出于某种原因,Google就是没有帮助我。(我认为部分问题在于我是一个初学者,我不知道该问什么......)我也看过O'Reilly的RubyCookbook和RailsAPI,但我仍然停留在这个问题上.我找到了一些关于多态关系的信息,但它似乎不是我需要的(尽管如果我错了请告诉我)。我正在尝试调整MichaelHartl'stutorial创建一个包含用户、文章和评论的博客应用程序(不使用脚手架)。我希望评论既属于用户又属于文章。我的主要问题是:我不知道如何将当前文章的ID放入评论Controller。
我的工作要求我为某些测试自动生成电子邮件。我一直在四处寻找,但未能找到可以快速实现的合理解决方案。它需要在outlook而不是其他邮件服务器中,因为我们有一些奇怪的身份验证规则,我们需要保存草稿而不是仅仅发送邮件的选项。显然win32ole可以做到这一点,但我找不到任何相当简单的例子。 最佳答案 假设存储了Outlook凭据并且您设置为自动登录到Outlook,WIN32OLE可以很好地完成此操作:require'win32ole'outlook=WIN32OLE.new('Outlook.Application')message=
华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o
C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.
//1.验证返回状态码是否是200pm.test("Statuscodeis200",function(){pm.response.to.have.status(200);});//2.验证返回body内是否含有某个值pm.test("Bodymatchesstring",function(){pm.expect(pm.response.text()).to.include("string_you_want_to_search");});//3.验证某个返回值是否是100pm.test("Yourtestname",function(){varjsonData=pm.response.json
在前面两节的例子中,主界面窗口的尺寸和标签控件显示的矩形区域等,都是用C++代码编写的。窗口和控件的尺寸都是预估的,控件如果多起来,那就不好估计每个控件合适的位置和大小了。用C++代码编写图形界面的问题就是不直观,因此Qt项目开发了专门的可视化图形界面编辑器——QtDesigner(Qt设计师)。通过QtDesigner就可以很方便地创建图形界面文件*.ui,然后将ui文件应用到源代码里面,做到“所见即所得”,大大方便了图形界面的设计。本节就演示一下QtDesigner的简单使用,学习拖拽控件和设置控件属性,并将ui文件应用到Qt程序代码里。使用QtDesigner设计界面在开始菜单中找到「Q
MIMO技术的优缺点优点通过下面三个增益来总体概括:阵列增益。阵列增益是指由于接收机通过对接收信号的相干合并而活得的平均SNR的提高。在发射机不知道信道信息的情况下,MIMO系统可以获得的阵列增益与接收天线数成正比复用增益。在采用空间复用方案的MIMO系统中,可以获得复用增益,即信道容量成倍增加。信道容量的增加与min(Nt,Nr)成正比分集增益。在采用空间分集方案的MIMO系统中,可以获得分集增益,即可靠性性能的改善。分集增益用独立衰落支路数来描述,即分集指数。在使用了空时编码的MIMO系统中,由于接收天线或发射天线之间的间距较远,可认为它们各自的大尺度衰落是相互独立的,因此分布式MIMO