 
					
				2013.09.14
跟着版主视频学,完成第五份课后作业,代码如下。
注:版主视频中提到的 7段数码管代码查询工具,版主在群里共享了一份,我把它上传到了服务器上,链接为
http://share.eepw.com.cn/share/download/id/90001
	`timescale 1ns / 1ps
`define ONE_SECOND  26'd49999999 //50MHz时钟, 因此计数器要计数 50M次=50*1000*1000 就为1秒
	//////////////////////////////////////////////////////////////////////////////////
//学号: 136.finema
// 
//创建时间:    21:49:14 09/14/2013
//名称:dig_display_dip
//功能:数码管静态循环显示,用DIP控制哪个数码管亮
//算法:
////////////////////////////////////////////////////////////////////////////////// 
	module dig_display_dip(sys_clk,
       sys_rst,
       dip,
       dig_seg,
       dig_bit);
 input sys_clk;   //输入时钟信号
 input sys_rst;   //输入复位信号
 input [7:0] dip;  //输入DIP
 
 output [7:0] dig_seg;  //输出数码管段码
 output [7:0] dig_bit;  //输出数码管位码
 
 //变量定义 
 reg [7:0] dig_seg;
 wire [7:0] dig_bit;
 
 reg [25:0] timeCounter;  //时间计数器.  
 reg [7:0] charIndex;   //字符索引.  
 
 //计数器的逻辑处理
 always @(posedge sys_clk,negedge sys_rst) //只对时钟上升沿信号和复位下降沿信号敏感
 begin
  if (!sys_rst)
   timeCounter <=26'd0;   
  else
   begin
    if (timeCounter==`ONE_SECOND)
     timeCounter<=26'd0;
    else
     timeCounter<=timeCounter+1'b1;
   end
 end
 
 
 //led的逻辑处理
 always @(posedge sys_clk,negedge sys_rst)
 begin
  if (!sys_rst)
   begin   
    charIndex <=8'd0;
   end
  else
   begin
    if (timeCounter==`ONE_SECOND)
     begin                        
      charIndex <=charIndex+1'b1;            
     end
    else
     begin    
      charIndex <= charIndex;
      if (charIndex>8'd16)     
       charIndex <=8'd0;      
     end
       
   end
 end
	
 
 //数码管显示
 always @(charIndex)
 begin
  case (charIndex)
   8'd0: dig_seg<=8'hC0;  //0
   8'd1: dig_seg<=8'hF9;  //1
   8'd2: dig_seg<=8'hA4;  //2
   8'd3: dig_seg<=8'hB0;  //3
   8'd4: dig_seg<=8'h99;  //4
   8'd5: dig_seg<=8'h92;  //5
   8'd6: dig_seg<=8'h82;  //6
   8'd7: dig_seg<=8'hF8;  //7
   8'd8: dig_seg<=8'h80;  //8
   8'd9: dig_seg<=8'h90;  //9
   8'd10: dig_seg<=8'h88; //A
   8'd11: dig_seg<=8'h83; //B
   8'd12: dig_seg<=8'hC6; //C
   8'd13: dig_seg<=8'hA1; //D
   8'd14: dig_seg<=8'h86; //E
   8'd15: dig_seg<=8'h8E; //F
   8'd16: dig_seg<=8'h7F; //.
   default: dig_seg<=8'hC0;
  endcase
 end
 
 //连续赋值,8个数码管根据DIP导通
 assign dig_bit = dip; 
endmodule
我用到的tcl文件,内容如下:
 
					
				关于 TCL 可以看网友284-xiacf88推荐的
http://www.cnblogs.com/yuphone/archive/2010/01/18/1650612.html
我用到的tcl文件,内容如下:
	
#CPLD 时钟脚
set_location_assignment PIN_12 -to sys_clk
	#CPLD 复位脚
set_location_assignment PIN_14 -to sys_rst
	#8个数码管
set_location_assignment PIN_82 -to dig_seg[0]
set_location_assignment PIN_86 -to dig_seg[1]
set_location_assignment PIN_76 -to dig_seg[2]
set_location_assignment PIN_84 -to dig_seg[3]
set_location_assignment PIN_91 -to dig_seg[4]
set_location_assignment PIN_90 -to dig_seg[5]
set_location_assignment PIN_88 -to dig_seg[6]
set_location_assignment PIN_81 -to dig_seg[7]
	set_location_assignment PIN_77 -to dig_bit[0]
set_location_assignment PIN_78 -to dig_bit[1]
set_location_assignment PIN_83 -to dig_bit[2]
set_location_assignment PIN_85 -to dig_bit[3]
set_location_assignment PIN_87 -to dig_bit[4]
set_location_assignment PIN_89 -to dig_bit[5]
set_location_assignment PIN_92 -to dig_bit[6]
set_location_assignment PIN_95 -to dig_bit[7]
	#DIP
set_location_assignment PIN_29 -to dip[0]
set_location_assignment PIN_30 -to dip[1]
set_location_assignment PIN_33 -to dip[2]
set_location_assignment PIN_34 -to dip[3]
set_location_assignment PIN_35 -to dip[4]
set_location_assignment PIN_36 -to dip[5]
set_location_assignment PIN_37 -to dip[6]
set_location_assignment PIN_38 -to dip[7]
 
					
				2013.09.15
跟着版主视频学习,完成第六份课后作业——数码管动态显示。
代码如下:
`timescale 1ns / 1ps
	//////////////////////////////////////////////////////////////////////////////////
//学号: 136.finema
// 
//创建时间:    17:35:14 09/15/2013
//名称:dig_scan
//功能:8个数码码管动态显示方式显示0~7,刷新率1ms
//算法:
//////////////////////////////////////////////////////////////////////////////////
	
module dig_scan(sys_clk,
       sys_rst,
       dig_seg,
       dig_bit);
 
 input sys_clk;   //输入时钟信号
 input sys_rst;   //输入复位信号
	 output [7:0] dig_seg;  //输出数码管段码
 output [7:0] dig_bit;  //输出数码管位码
	 parameter TIME_INIT_VALUE = 26'd0;  //常量: 时间计数器初始值 
 parameter ONE_SECOND = 26'd4999_9999; //50MHz时钟, 因此计数器要计数 50M次=50*1000*1000 就为1秒
 parameter ONE_MILLI_SECOND = 16'd49999; //50MHz时钟, 1毫秒
	 //变量定义 
 reg [7:0] dig_seg;
 reg [7:0] dig_bit;
 
 reg [25:0] timeCounter;  //时间计数器.  
 reg [2:0] charIndex;   //字符索引.  8个字符
 
 //计数器的逻辑处理
 always @(posedge sys_clk,negedge sys_rst) //只对时钟上升沿信号和复位下降沿信号敏感
 begin
  if (!sys_rst)
   timeCounter <= TIME_INIT_VALUE;   
  else
   begin
    if (timeCounter==ONE_MILLI_SECOND)
     timeCounter<=TIME_INIT_VALUE;
    else
     timeCounter<=timeCounter+1'b1;
   end
 end
 
 
 //led的逻辑处理
 always @(posedge sys_clk,negedge sys_rst)
 begin
  if (!sys_rst)
   begin   
    charIndex <=3'd0;
    dig_bit = 8'b1111_1110;
   end
  else
   begin
    if (timeCounter==ONE_MILLI_SECOND)
     begin                        
      charIndex <=charIndex+1'b1; 
      dig_bit = {dig_bit[6:0],dig_bit[7]}; //位选左移
     end        
   end
 end
	 
 //数码管译码
 always @(charIndex)
 begin
  case (charIndex)
   3'd0: dig_seg<=8'hC0;  //0
   3'd1: dig_seg<=8'hF9;  //1
   3'd2: dig_seg<=8'hA4;  //2
   3'd3: dig_seg<=8'hB0;  //3
   3'd4: dig_seg<=8'h99;  //4
   3'd5: dig_seg<=8'h92;  //5
   3'd6: dig_seg<=8'h82;  //6
   3'd7: dig_seg<=8'hF8;  //7
   default: dig_seg<=8'hC0; //0
  endcase
 end
 
endmodule
 
					
				
理解VGA时序
2014/4/12
(学号:136-finema)
1. 前言最近一段时间,看见EEPW-CPLD群里的很多网友和我一样在弄CPLD 的VGA实验,和很多人一样,我一开始也是搞不掂,后来经过咨询51FPGA版主、查看网上的资料、多次仿真才弄清楚了VGA是怎么回事。撰写本文,主要是为了自己理清所学内容,希望也能对大家有帮助。
在此先感谢51FPGA和EEPW,谢谢他们把我这菜鸟带进了 CPLD-FPGA这多姿多彩的世界。
2. 背景知识本文以学习生成 640*480@60Hz VGA信号为目标,要继续阅读,首先你要对老式VGA显示器是如何显示东西的,以及对VGA的场、行周期、刷新率等概念搞清楚,不清楚去查Baidu或Google。
也可看:http://www.cnblogs.com/spartan/archive/2011/08/16/2140546.html
(我的理解就是:1 场= 1帧; 而1帧 有 480行,每1行有640列;完成一行扫描需要的时间就是行周期;刷新率就是 1秒中刷新了多少帧。)
3. 时序总览
相信你看了资料,也会理解不透彻,特别是时序部分,关键是动起手来。
废话少说了,先看一下ModelSim仿真的时序图(见图1),比你看资料中的手工画的时序图直观多了。
	 
 
图1
图1中红线部分就是“场信号(vsync)”, 蓝线部分就是“行信号(hsync)”也叫“水平信号”。
图中我们可以数出有3段“场信号(vsync)”即3帧。
4. 场信号时序(vsync)那么场信号时序包含了什么呢,我们看一下VGA定的标准。
见http://tinyvga.com/vga-timing/640x480@60Hz
整理得到640*480@60Hz的场信号定义,见表1。
| 同步脉冲 | 后沿 | 显示脉冲 (即可见部分) | 前沿 | 合计 | 单位 | 
| 2 | 33 | 480 | 10 | 525 | 行周期 | 
表1
从表1我们得知“场信号”的同步脉冲有2个行周期长(注意:这里指的是行周期,而不是时钟周期),好了我们放大一下图1,可以清楚的验证这一点。见图2。
	 
 
图2
也就是说2个行周期后,1帧的场同步信号就结束了,再经过 33+480+10=523个行周期后,下1帧的场同步信号才会来。
5. 行信号时序(hsync)那么1行的周期到底有多长呢,行信号的时序又包含那些东西呢?我们还是看VGA的标准。见http://tinyvga.com/vga-timing/640x480@60Hz
整理得到640*480@60Hz的行信号定义,见表2。
| 同步脉冲 | 后沿 | 显示脉冲 (即可见部分) | 前沿 | 合计 | 单位 | 
| 96 | 48 | 640 | 16 | 800 | 时钟周期 | 
表2
我们把图1的“行信号(hsync)”波形放大,见图3,可看到“hcount=96”,即“行信号”的同步脉冲有96个时钟周期,与表2的描述相符。
	 
 
图3
6. 可见部分可见部分(即显示脉冲)是什么,我们把表1和表2的数据合并得到表3。
| 
 | 同步脉冲 | 后沿 | 显示脉冲 (即可见部分) | 前沿 | 合计 | 单位 | 
| 场信号 | 2 | 33 | 480 | 10 | 525 | 行周期 | 
| 行信号 | 96 | 48 | 640 | 16 | 800 | 时钟周期 | 
表3
所谓可见部分,就是每1帧中,场信号的计数“hcount”在35到515之间(区间长度为480)并且行信号的计数“vcount”在144到784之间(区间长度为640),RGB的值才有效,其它范围VGA显示器不会显示RGB的值。
那么不在范围内的计数器的值有什么作用呢,老式VGA显示器就是靠他们来进行消隐的,对于液晶显示器,我想没什么可用之地。
7. 时钟那么我们要生成 640*480@60Hz 的VGA信号,需要多快的时钟才能起作用呢,我们来算一下:
525*800*60Hz=25200000Hz=25.2MHz≈25MHz
更精确点的计算:
525*800*60Hz *1000/1001=25174825.174825174825174825174825Hz≈25MHz
也就是说至少需要25MHz的时钟,我们才能正确生成640*480@60Hz 的VGA信号。(我们会看到一些接了50MHz 晶振的CPLD,其HDL代码就有分频处理。)
那么显示1帧需要多长时间呢?精确点的计算就是:
525*800/25.174≈16683微妙
8. 源代码 8.1. Verilog代码
代码源于网络,自身修改了一下,以便于仿真,参照前面所说,自己琢磨代码。
//VGA 640*480@60Hz彩色信号显示
module VGA2(
sys_rst,
clock,
switch,
disp_RGB,
hsync,
vsync
);
input sys_rst; //复位信号
input clock; //系统输入时钟 50MHz
input [1:0]switch;
output [2:0]disp_RGB; //VGA数据输出
output hsync; //VGA行同步信号
output vsync; //VGA场同步信号
reg [9:0] hcount; //VGA行扫描计数器
reg [9:0] vcount; //VGA场扫描计数器
reg [2:0] data;
reg [2:0] h_dat;
reg [2:0] v_dat;
//reg [9:0] timer;
//reg flag;
wire hcount_ov;
wire vcount_ov;
wire dat_act;
wire hsync;
wire vsync;
reg vga_clk; //VGA时钟
//VGA行、场扫描时序参数表
parameter hsync_end = 10'd95,
hdat_begin = 10'd143,
hdat_end = 10'd783,
hpixel_end = 10'd799,
vsync_end = 10'd1,
vdat_begin = 10'd34,
vdat_end = 10'd514,
vline_end = 10'd524;
//always @(posedge clock)
//begin
// vga_clk = ~vga_clk;
// //vga_clk <= ~vga_clk;
//end
always @(posedge clock,negedge sys_rst)
begin
if (!sys_rst)
begin
vga_clk = 0;
end
else
begin
vga_clk = ~vga_clk; //50MHz 分频成 25MHz
//vga_clk <= ~vga_clk;
end
end
//************************VGA驱动部分*******************************
//行扫描
//always @(posedge clock,negedge sys_rst)
//begin
// if (!sys_rst)
// begin
// hcount <= 10'd0;
// end
// else
// begin
// if (hcount_ov)
// hcount <= 10'd0;
// else
// hcount <= hcount + 10'd1;
// end
//end
always @(posedge vga_clk,negedge sys_rst)
begin
if (!sys_rst)
begin
hcount <= 10'd0;
end
else
begin
if (hcount_ov)
hcount <= 10'd0;
else
hcount <= hcount + 10'd1;
end
end
assign hcount_ov = (hcount == hpixel_end);
//场扫描
//always @(posedge clock,negedge sys_rst)
//begin
// if (!sys_rst)
// begin
// vcount <= 10'd0;
// end
// else
// begin
// if (hcount_ov)
// begin
// if (vcount_ov)
// vcount <= 10'd0;
// else
// vcount <= vcount + 10'd1;
// end
// end
//end
always @(posedge vga_clk,negedge sys_rst)
begin
if (!sys_rst)
begin
vcount <= 10'd0;
end
else
begin
if (hcount_ov)
begin
if (vcount_ov)
vcount <= 10'd0;
else
vcount <= vcount + 10'd1;
end
end
end
assign vcount_ov = (vcount == vline_end);
//数据、同步信号输
assign dat_act = ((hcount >= hdat_begin) && (hcount < hdat_end))
&& ((vcount >= vdat_begin) && (vcount < vdat_end));
assign hsync = (hcount > hsync_end);
assign vsync = (vcount > vsync_end);
assign disp_RGB = (dat_act) ? data : 3'h00;
//************************显示数据处理部分*******************************
//图片显示延时计数器
/*always @(posedge vga_clk)
begin
flag <= vcount_ov;
if(vcount_ov && ~flag)
timer <= timer + 1'b1;
end
*/
always @(posedge vga_clk)
begin
case(switch[1:0])
2'd0: data <= h_dat; //选择横彩条
2'd1: data <= v_dat; //选择竖彩条
2'd2: data <= (v_dat ^ h_dat); //产生棋盘格
2'd3: data <= (v_dat ~^ h_dat); //产生棋盘格
endcase
end
always @(posedge vga_clk) //产生竖彩条
begin
if(hcount < 223)
v_dat <= 3'h7; //白
else if(hcount < 303)
v_dat <= 3'h6; //黄
else if(hcount < 383)
v_dat <= 3'h5; //青
else if(hcount < 463)
v_dat <= 3'h4; //绿
else if(hcount < 543)
v_dat <= 3'h3; //紫
else if(hcount < 623)
v_dat <= 3'h2; //红
else if(hcount < 703)
v_dat <= 3'h1; //蓝
else
v_dat <= 3'h0; //黑
end
always @(posedge vga_clk) //产生横彩条
begin
if(vcount < 94)
h_dat <= 3'h7; //白
else if(vcount < 154)
h_dat <= 3'h6; //黄
else if(vcount < 214)
h_dat <= 3'h5; //青
else if(vcount < 274)
h_dat <= 3'h4; //绿
else if(vcount < 334)
h_dat <= 3'h3; //紫
else if(vcount < 394)
h_dat <= 3'h2; //红
else if(vcount < 454)
h_dat <= 3'h1; //蓝
else
h_dat <= 3'h0; //黑
end
endmodule
8.2. ModelSim测试激励代码
`timescale 1 ns/ 1 ps
module VGA2_test();
// constants
// general purpose registers
// test vector input registers
reg clock;
reg sys_rst;
reg [1:0] switch;
// wires
wire [2:0] disp_RGB;
wire hsync;
wire vsync;
//时钟 50MHz
initial
begin
clock = 0;
forever #10 clock = ~clock;
end
//复位信号
initial
begin
sys_rst = 1;
# 10 sys_rst = 0;
# 50 sys_rst = 1;
end
initial
begin
switch[1:0] = 2'd1;
end
// assign statements (if any)
VGA2 VGA2_inst (
.sys_rst(sys_rst),
.clock(clock),
.disp_RGB(disp_RGB),
.hsync(hsync),
.switch(switch),
.vsync(vsync)
);
endmodule
8.3. TCL脚本文件
注意:本文件内容只适用于 EEPW-CPLD-DIY活动的板子。如果用于其它板子,请自己修改相关内容。
#CPLD 时钟脚
set_location_assignment PIN_12 -to clock
#CPLD 复位脚
set_location_assignment PIN_14 -to sys_rst
#行同步信号
set_location_assignment PIN_1 -to hsync
#场同步信号
set_location_assignment PIN_2 -to vsync
#RGB脚
set_location_assignment PIN_8 -to disp_RGB[0]
set_location_assignment PIN_5 -to disp_RGB[1]
set_location_assignment PIN_4 -to disp_RGB[2]
#拨码开关控制显示效果
set_location_assignment PIN_29 -to switch[0]
set_location_assignment PIN_30 -to switch[1]
9. 显示效果
	9.1. 横条  
 
9.2. 竖条
 
 
9.3. 方格
 
 
10. 参考资料
http://bbs.****.com/BLOG_ARTICLE_219303.HTM
http://www.epanorama.net/documents/pc/vga_timing.html
http://tinyvga.com/vga-timing/640x480@60Hz
http://share.eepw.com.cn/share/download/id/165148
 
					
				27楼的内容,已经整理成word文档,上传到服务器。
http://share.eepw.com.cn/share/download/id/165361
51-FPGA 版主提供 640*480@60Hz的例程,可以从以下链接下载。
http://share.eepw.com.cn/share/download/id/165148
回复
| 有奖活动 | |
|---|---|
| 硬核工程师专属补给计划——填盲盒 | |
| “我踩过的那些坑”主题活动——第002期 | |
| 【EEPW电子工程师创研计划】技术变现通道已开启~ | |
| 发原创文章 【每月瓜分千元赏金 凭实力攒钱买好礼~】 | |
| 【EEPW在线】E起听工程师的声音! | |
| 高校联络员开始招募啦!有惊喜!! | |
| 【工程师专属福利】每天30秒,积分轻松拿!EEPW宠粉打卡计划启动! | |
| 送您一块开发板,2025年“我要开发板活动”又开始了! | |

 
					
				 
			
			
			
						
			 我要赚赏金
 我要赚赏金 STM32
STM32 MCU
MCU 通讯及无线技术
通讯及无线技术 物联网技术
物联网技术 电子DIY
电子DIY 板卡试用
板卡试用 基础知识
基础知识 软件与操作系统
软件与操作系统 我爱生活
我爱生活 小e食堂
小e食堂

