置顶

FPGA数字钟设计实现(源码)

通过设计实例,深入理解自顶向下设计方法,系统设计规范、系统设计、模块设计和系统仿真与实现各阶段的设计内容,初步掌握规范的数字系统设计方法并实践。

一、实验目的:

通过设计实例,深入理解自顶向下设计方法,系统设计规范、系统设计、模块设计和系统仿真与实现各阶段的设计内容,初步掌握规范的数字系统设计方法并实践。

二、实验要求:

1、系统概述:设计一个用 LED 7段显示器显示的24小时制数字钟。

2、系统目标:

(1)用8个LED 显示时间,如9点25分10秒显示为,09-25-10。

(2)设置2个按键,按键SET用于工作模式选择,按键UP用于设置数值.(可选)

(3)按SET键循环设置工作模式为:正常显示->时设置-〉分设置-〉秒设置。在设置工作模式时,被设置相应数字按1秒速率闪烁,其它数字不变.

(4)在设置工作模式时,按UP键一次,被设置相应数字增加1,加到最大值后再加返回0,如小时加到23后再加就返回0,分和秒加到59后再加返回0 。

3、系统设计依据:

外部输入时钟为40MHZ,通过分频产生秒脉冲信号,用模60计数器对其计数产生分脉冲信号,对分脉冲用模60计数器对其计数产生时脉冲信号,再用模24计数器对时脉冲计数,即可实现一天24小时的时间信号,通过7段LED数码管显示出来则为基本数字钟,校时电路通过两个外部异步按键对“时"、“分”、“秒”显示数字进行校对调整.

4、系统实现要求:

要求用Mars—EP1C3—EDA实验平台。芯片与封装选择:本设计用EP1C3T FPGA实现,144脚封装,输入输出为LVTTL电平。

5、系统验证及测试要求:

用Mars-EP1C3—EDA实验平台搭建模拟测试平台测试,测试验证数字钟实现设计目标。

三、系统设计关键技术

1、按键消抖

FPGA数字钟设计实现(源码) - 第1张

图3-1

由图3—l可见,在按键闭合和断开时产生了多个边沿,而在实际中每按一次键,我们只需要一组稳定的上升或下降边沿,所以对于电路中的按键信号,如果我们不滤除抖动的话,还是简单的读取信号的边沿,会引起一次按键被误读多次,这样就会引起电路的误动作.为了保证按一次键电路只有一次正确的响应,即在键闭合稳定时读取键的状态,就要求电路中必须采取滤除抖动的措施。

原理:在设计中用时钟信号(key_clk)进行采样,对于按键输入信号,当两次采样信号相同时,这是判定已经稳定的按下或放开了按键,D触发器相应的被置成0态或1态。如两次采样结果不相同,则触发器维持原输出信号不变,由于直接由触发器输出的信号时间宽度可能过长,所以在触发器后再接一级同步化电路,保证每次输出的信号只占有一个时钟周期的宽度.应用这种方法去滤除抖动,关键是确定采样时钟的频率,保证两次采样的时间间隔能够大于按键的抖动时间,且小于正常按键时的按键稳定闭合时间.

2、采用BCD码的计数模式

时、分、秒的计数都采用BCD码计数,如果采用二进制计数,分的最大计数值为59,只需要6位就可以,因为时的计数值要通过两个数码管显示,所以计数值需要经过两级译码才能驱动数码管使其正常显示,必须先把计数值译码成高低四位的BCD码,然后再分别把高、低四位BCD码译码成数码管的显示编码。如果直接采用BCD码计数,只需要一次译码就可以正常显示计数值,故采用BCD码计数更方便,简化电路。

3、数码管的动态显示

数码管的动态扫描,就是轮流向各位数码管送出字形码和相应的位选,利用发光管的余辉和人眼视觉暂留作用,使人的感觉好像各位数码管同时在显示。数码管的轮流扫描频率不能太小,否则数码管不能同时显示,一般扫描频率在500Hz到1Khz即可。本设计中的数码管位选信号为低电平有效,数码管的段为低显,复位后把位选信号d_col赋值为8’b1111_1110,然后以1Khz的扫描频率使其循环左移,并送出相应位的字形码,即可实现数码管的动态显示。

四、系统详细设计方案:

1、系统设计分析:

数字钟是一个将“ 时”,“分”,“秒"显示于人的视觉器官的计时装置.它的计时周期为24小时,显示满刻度为23时59分59秒,另外应有校时功能。秒信号产生器是整个系统的时基信号,它直接决定计时系统的精度,通过将外部输入时钟为40MHZ分频实现.将标准秒信号送入“秒计数器”,“秒计数器”采用60进制计数器,每累计60秒发生一个“分脉冲"信号,该信号将作为“分计数器”的时钟脉冲。“分计数器”也采用60进制计数器,每累计60分钟,发出一个“时脉冲”信号,该信号将被送到“时计数器"。“时计数器”采用24进制计时器,可实现对一天24小时的累计。

将“时”、“分"、“秒”计数器的输出值经七段显示译码器译码,通过八位LED七段显示器显示出来,显示格式为“时-分—秒”。   

通过Set和Up按键对“时"、“分”、“秒”显示数字进行校对调整,Set键循环控制工作模式,即“正常显示”、“时设置”、“分设置"、“秒设置”的循环控制,在设置工作模式时,被设置相应数字按1秒速率闪烁,其它数字不变.Up键实现调整状态时相应时间的快速加“1”以实现时间校准.

2、系统时钟和复位规划:

本设计采用一个全局时钟clk和复位reset。

3、顶层模块划分及模块功能说明

系统分为5个模块,Freq_div模块,Clock_cnt模块,Clock_ctl模块,Key_ctl模块和Display模块。系统框图如图4—1所示,图4-2是顶层模块设计.

输入信号:

clk:系统时钟;                   reset:系统复位;

set:工作模式选择按键;           up:调时按键;

输出信号:

d_col[7:0]:八位LED动态选择;

d_out[7:0]:LED显示数据;

FPGA数字钟设计实现(源码) - 第2张

图4—1 系统框图

FPGA数字钟设计实现(源码) - 第3张

图4-2 顶层模块设计

4、每个模块详细功能说明,信号定义及时序定义

(1)Freq_div模块:将40M Hz的系统时钟进行分频产生三种时钟使能信号:scan_clk(1khz)、key_clk(100hz)、s_clk(1hz).

输入信号:

clk:系统时钟 rst_n:复位信号

输出信号:

scan_clk:数码管扫描频率 key_clk:按键采样频率

s_clk:1s时钟信号

(2)Key_ctl模块:完成对按键的同步、去抖功能,输出稳定的按键信号set_en、up_en。

输入信号:

clk:系统时钟 rst_n:复位信号

set:模式设置按键 up:计数值加按键

输出信号:

Set_en:模式设置使能信号 up_en:按键加使能信号

(3)Clock_ctl模块:通过set_en信号对“正常显示”、“时设置”、“分设置”、“秒设置”模式的循环控制,并产生设置信号h_set(时)、m_set(分)、s_set(秒)供Clock_cnt使用。

输入信号:

Clk:系统时钟 ; reset:复位信号;

set_en:工作模式选择信号;

输出信号:

H_set:时设置使能信号; M_set:分设置使能信号,

S_set:秒设置使能信号 ; 状态机信号:

Normal:正常显示状态; Hour_set:时设置状态;

Minute_set:分设置状态; Second_set:秒设置状态。

(4)Clock_cnt模块:完成数字钟的正常显示和数字钟的时、分、秒的校时,在校时模式下,通过ctl信号控制LED的闪烁,也就是间隔1s输出时间数据。

输入信号:

Clk:系统时钟 reset:复位信号;

up_en:校时信号 s_clk:1秒脉冲信号;

h_set:时设置使能信号; m_set:分设置使能信号,

s_set:秒设置使能信号;

输出信号:

h_data:时输出信号; m_data:分输出信号;

s_data:秒输出信号;

(5)Display模块:LED的动态显示,显示格式“时—分—秒”。

输入信号:

reset:复位信号; clk:系统时钟信号

scan_clk:数码管扫描信号 h_data:时信号;

m_data:分信号; s_data:秒信号;

输出信号:

d_col:数码管的位选择信号

d_out:译码后驱动数码管信号

五、系统设计仿真及测试方案

A、采用Quartusii和Modelsim的功能仿真,采用Quartusii的时序仿真分析,验证设计的正确性。

B、在Mars—EP1C3—EDA实验平台上实现本设计,并测试其正确性。具体方案如图4—3所示。

FPGA数字钟设计实现(源码) - 第4张

图4-3

C、实验板信号定义

本设计信号名实验板信号名FPGA引脚备注本设计信号名实验板信号名FPGA引脚备注
d_out[0]display7p5低显dp段d_col[2]Dis_A6P10低显示
d_out[1]display6p4低显g段d_col[3]Dis_A5P7低显示
d_out[2]display5p3低显f段d_col[4]Dis_A4P6低显示
d_out[3]display4p2低显e段d_col[5]Dis_A3P11低显示
d_out[4]display3p1低显d段d_col[6]Dis_A2P26低显示
d_out[5]display2p143低显c段d_col[7]Dis_A1P27低显示
d_out[6]display1p141低显b段setKEY1p107按下为低
d_out[7]display0p142低显a段upKEY2p106按下为低
d_col[0]Dis_A8P31低显示clkCLK_40Mp1640M时钟
d_col[1]Dis_A7P28低显示resetSYS_RSTp144低复位

表4-1

六、模块详细设计及功能仿真

1、Freq_div模块设计及功能仿真:

(1)模块设计

分频电路的原理:分频电路实际上就是一个计数器,根据系统提供的时钟频率和你所需的时钟频率计算出计数的值,当计数值达到设置的值时,使输出变化一次。系统提供的时钟频率为40MHz,该模块包括三个分频电路:原理如图2-4所示。

第一步:将系统时钟40_000分频产生1KHz信号scan_clk;

第二步:将1KHz进行10分频产生100Hz信号key_clk;

第三步:将100Hz进行100分频产生1Hz信号s_clk.

FPGA数字钟设计实现(源码) - 第5张

图6—1

(2)功能仿真

为了减小仿真时间和难度,把分频值改小进行仿真。设置clk周期为2ns。

设置对clk进行4分频产生scan_clk;

设置对scan_clk进行3分频产生key_clk;

设置对key_clk进行5分频产生s_clk。

FPGA数字钟设计实现(源码) - 第6张

图6—2

有图知,scan_clk周期为:8ns=4Tclk。key_clk周期为:24ns=3Tscan_clk。S_clk周期为:120ns=5Tkey_clk=。分频功能正确。

2、Key_ctl模块设计及功能仿真

该模块主要功能是对异步的按键信号同步处理,并消除按键抖动。原理:先用D触发器打两级,然后间隔10ms(key_clk有效)采样,把两次采样值相与,比较两次采样值是否同一,由于直接由触发器输出的信号时间宽度可能过长,所以在触发器后再接一级同步化电路,保证每次输出的有效信号只占有一个时钟周期的宽度。图6-3是set按键的同步消抖处理电路,up的原理与其相同。

(1)模块设计

FPGA数字钟设计实现(源码) - 第7张

图6—3 Set 按键消抖原理 

(2)功能仿真

FPGA数字钟设计实现(源码) - 第8张

图6-4 

有图6—4知,按键set的前沿抖动时间为120ns,后沿抖动时间为130ns,按键的稳定时间为540ns,故可设置采样间隔为200ns,有set_en波形可知,当两次的采样信号结果相同时,这时输出信号才可能发生变化,对应的按键的稳定闭合或断开,当两次的采样信号结果不同时,认为输入的信号为抖动信号,这时电路输出维持原状态不变,同时由于有同步化的处理,输出信号的高电平宽度只为系统时钟的一个周期。

3、Clcok_ctl模块设计及功能仿真

(1)模块算法设计

FPGA数字钟设计实现(源码) - 第9张

图4—7

(2)、功能仿真

FPGA数字钟设计实现(源码) - 第10张

有图可知,复位状态后进入:“正常显示"状态,输出控制信号:h_set=0,m_set=0,s_set=0;此后set_en按键每按一次状态发生一次变化,从“正常显示”→“时设置”→“分设置”→“秒设置”这样循环变化,并输出相应控制信号, “时设置”状态下输出控制信号:h_set=1,m_set=0,s_set=0;“分设置"状态下输出控制信号:h_set=0,m_set=1,s_set=0;“秒设置”状态下输出控制信号:h_set=0,m_set=0,s_set=1。工作模式转换和输出都正确。

4、Clock_cnt计数模块设计及功能仿真

(1)模块算法设计

时设置闪烁算法流程图

FPGA数字钟设计实现(源码) - 第11张 “分设置"、“秒设置"闪烁原理和“时设置原理一样"。

正常显示算法流程图:

采用BCD码计数,秒计计数值满之后向分进一位,让秒值清零,否则秒值自身加1,分计数值满之后向时进一位,让分值清零,否则分值加1,时计数值满之后,时清零,重新回到秒计数,这样循环执行.

FPGA数字钟设计实现(源码) - 第11张

图4—11

时设置算法流程图:

FPGA数字钟设计实现(源码) - 第12张

图4-8

分设置和秒设置算法流程和时设置流程类似。

(2)功能仿真

设置复位后时间初值为“23—45—09".

①“正常显示":设置h_set=0,m_set=0,s_set=0;

FPGA数字钟设计实现(源码) - 第13张

有图可知,“正常显示”状态下,不管up_en是否按下,时、分、秒的计数都正确。

②“时设置”:设置h_set=1,m_set=0,s_set=0;

FPGA数字钟设计实现(源码) - 第14张

有图知,“时设置”状态下,按键按下一次h_data加1,并间隔一个s_clk周期,输出时计数值h_data,功能正确

③“分设置”:设置h_set=0,m_set=1,s_set=0;

FPGA数字钟设计实现(源码) - 第15张

有图知,“分设置”状态下,按键按下一次m_data加1,并间隔一个s_clk周期,输出分计数值m_data,功能正确

④“秒设置”:设置h_set=0,m_set=0,s_set=1;

FPGA数字钟设计实现(源码) - 第16张

有图知,“秒设置"状态下,按键按下一次s_data加1,并间隔一个s_clk周期,输出时计数值s_data,功能正确。

5、display显示模块设计及功能仿真

(1)模块设计

FPGA数字钟设计实现(源码) - 第17张

显示原理:用1ms的扫描信号循环控制数码的某一位有效,在相应为有效时输出数据经译码后驱动数码管,比如:d_col=8’b1111_1110,8位数码管的最低位有效,此时将秒的低四位数据(s_data[3:0])译码,驱动数码管,若此时s_data[3:0]=4'd9=4’b1001,数码管此时将显示“9”.

数码管译码表:

ledled显示编码(d_out)
4’b00008'b0000_0011
4’b00018'b1001_1111
4’b00108’b0010_0101
4'b00118'b0000_1101
4’b01008'b1001_1001
4’b01018'b0100_1001
4’b01108'b0100_0001
4’b01118’b0001_1111
4'b10008’b0000_0001
4’b10018’b0001_1001
4'b10108'b1111_1101
4’b11118'b1111_1111

说明:4’b1010,经译码后显示“-”,4’b1111,经译码后,LED不亮。

(2)功能仿真

FPGA数字钟设计实现(源码) - 第18张

设置时间初值为“23—45—09”,控制数码管位选择的信号d_col复位状态后为“8’b1111_1110”,然后在扫描频率作用下位选信号循环左移,并输出相应的时间数据译码值,从“秒低四位”→“秒高四位”→“-”→“分低四位”→“分高四位”→“-”→“时第四位"→“时高四位”这样循环送出数据。显示数据正确。

七、系统功能仿真

计数初始设置:设置系统复位后时间初值为“23—45—09";

分频设置:设置clk周期为2ns。设置对clk进行5分频产生scan_clk;设置对scan_clk进行5分频产生key_clk;设置对key_clk进行4分频产生s_clk。

(1)正常显示模式

FPGA数字钟设计实现(源码) - 第19张
FPGA数字钟设计实现(源码) - 第20张

(2)设置模式

FPGA数字钟设计实现(源码) - 第21张

有图可以知系统功能正确.

八、系统综合实现及静态时序分析

FPGA数字钟设计实现(源码) - 第22张

综合后的RTL级电路

FPGA数字钟设计实现(源码) - 第23张

静态时序分析报告

FPGA数字钟设计实现(源码) - 第24张

设置建立时间为1ns

九、实际系统测试

设置系统复位后时间初值为“23—45—09”,然后全编译,下载到实验板,按KEY1(set键)可以进行正常的模式选择,从正常显示->时设置-〉分设置-〉秒设置,每按下一次循环一次。并且在设置工作模式时,可以看到被设置相应数字按1秒速率闪烁,其它数字不变,功能正确。达到了设计的要求.

在设置工作模式时,每按KEY2(UP)键一次,被设置相应数字增加1,加到最大值后再加返回0,如小时加到23后再加就返回0,分和秒加到59后再加返回0 .功能正确。达到了设计的要求.

十、总结

经过两周的学习,初步掌握了一简单个数字系统的设计方法和设计流程;深入了解了数字系统自顶向下的设计方法,顶层设计、模块详细设计、各个模块仿真、系统仿真和时序分析。

刚开始设计时,忽略了好多细节,比如按键的消抖原理,不能用软件的消抖原理来设计硬件电路,为什么要采用BCD码计数,处于设置模式时怎么控制数码管的闪烁,这问题困扰了好久,通过陈老师讲解,以及和其他同学的相互沟通,把这些难题都解决了.

现在明白了做设计前写设计方案的重要性,只要方案正确可行,后面写代码以及调试,都很简单。自己在写设计方案方面还有好多不足,以后需多多学习。

在写代码时,要以FPGA的设计规范为准则,比如模块、信号的命名要有一定的意义;使用if..。else语句时,必须严格的逐层缩进对齐;代码后必须加入详细、清晰的注释行以增强代码的可读性和可移植性;等等.

附录:源代码和测试代码

Freq_div模块:

源代码:

module Freq_div
(
	// {{ALTERA_ARGS_BEGIN}} DO NOT REMOVE THIS LINE!
	clk, rst_n, scan_clk, s_clk, key_clk
	// {{ALTERA_ARGS_END}} DO NOT REMOVE THIS LINE!
);
// Port Declaration

	// {{ALTERA_IO_BEGIN}} DO NOT REMOVE THIS LINE!
	input clk;
	input rst_n;
	output scan_clk;
	output s_clk;
	output key_clk;
	// {{ALTERA_IO_END}} DO NOT REMOVE THIS LINE!
	
	reg scan_clk;
	reg s_clk;
	reg key_clk;
	
	reg[15:0] cnt1;	
	always@(posedge clk or negedge rst_n)
	begin
		if(!rst_n)	begin scan_clk〈=0;
						  cnt1<=16’d0;
					end
		else if(cnt1==16'd39_999) 
			 begin cnt1〈=16'd0;
					scan_clk<=1;
			 end
		else begin cnt1〈=cnt1+16’d1;
					scan_clk<=0;
			 end
	end
	
	reg[3:0] cnt2;
	always@(posedge clk or negedge rst_n)
	begin
		if(!rst_n)	begin 
					key_clk<=0;
					cnt2〈=4’d0;
					end
		else if(scan_clk) 
			 begin
				if(cnt2==4'd9) begin 
					      cnt2〈=4'd0;
					      key_clk〈=1;
					      end
		        else begin 
					cnt2〈=cnt2+4'd1;
					key_clk〈=0;
					end
			 end
		else key_clk<=0;
	end
	
	reg[6:0] cnt3;
	always@(posedge clk or negedge rst_n)
	begin
		if(!rst_n)	begin 
					 s_clk<=0;
					 cnt3〈=7'd0;
					end
		else if(key_clk) 
		     begin
			  if(cnt3==7’d99) begin 
					      cnt3〈=7’d0;
					      s_clk〈=1;
					      end
		      else begin 
					cnt3<=cnt3+7’d1;
					s_clk〈=0;
					end
			 end
		else s_clk〈=0;
	end
endmodule

测试代码:

`timescale 1ns/1ns
module freq_div_tb;
   reg rst_n,clk;
   wire key_clk,scan_clk,s_clk;
   always #1 clk=~clk;
   initial
   begin
       clk=0;
       rst_n=0;
       #3 rst_n=1;
       #200_000 $stop;
   end
   freq_div freq_div(clk, rst_n, scan_clk, s_clk, key_clk);
endmodule

Key_ctl模块:

FPGA数字钟设计实现(源码) - 第25张

Clock_ctl模块:

源代码:

module Clock_ctl
(
	// {{ALTERA_ARGS_BEGIN}} DO NOT REMOVE THIS LINE!
	clk, rst_n, set_en, h_set, m_set, s_set
	// {{ALTERA_ARGS_END}} DO NOT REMOVE THIS LINE!
);
// Port Declaration

	// {{ALTERA_IO_BEGIN}} DO NOT REMOVE THIS LINE!
	input clk;
	input rst_n;
	input set_en;
	output h_set;
	output m_set;
	output s_set;
	// {{ALTERA_IO_END}} DO NOT REMOVE THIS LINE!
	
	reg h_set;
	reg m_set;
	reg s_set;
	parameter[1:0] normal=2'b00,hour_set=2'b01,
				   minute_set=2'b10,second_set=2’b11;
	reg[1:0] current_state,next_state;
	
	always@(posedge clk or negedge rst_n)
	begin
		if(!rst_n) begin 
					current_state〈=normal;
					end
		else current_state<=next_state;
	end
	
	always@(current_state or set_en)
	begin
		case(current_state)
		normal:    if(set_en)	next_state<=hour_set;
				    else 		next_state<=normal;
		hour_set:  if(set_en)		next_state<=minute_set;
				    else 		next_state<=hour_set;
		minute_set:if(set_en)		next_state<=second_set;
				    else 		next_state<=minute_set;
		second_set:if(set_en)		next_state〈=normal;
				    else 		next_state<=second_set;
		endcase
	end
	
	always@(current_state)
	begin
		case(current_state)
		normal:		begin h_set〈=0;m_set<=0;s_set〈=0;end
		hour_set:	begin h_set〈=1;m_set<=0;s_set<=0;end
		minute_set:	begin h_set<=0;m_set〈=1;s_set<=0;end
		second_set:	begin h_set〈=0;m_set<=0;s_set〈=1;end
		endcase
	end
endmodule

测试代码:

`timescale 1ns/1ns
module clock_ctl_tb;
   reg clk;
	reg rst_n;
	reg set_en;
	wire h_set;
	wire m_set;
	wire s_set;
   
   always #5 clk=~clk;
   
   initial
   begin
       rst_n=0;
       clk=0;
       set_en=0;
       #13 rst_n=1;
       #13 set_en=1;
       #10 set_en=0;
       #23 set_en=1;
       #10 set_en=0;
       #23 set_en=1;
       #10 set_en=0;
       #23 set_en=1;
       #10 set_en=0;
       #23 set_en=1;
       #10 set_en=0;
       #10 rst_n=0;
       #12 $stop; 
   end
   clock_ctl  clock_ctl(clk,rst_n,set_en,h_set,m_set,s_set);
endmodule

Clock_cnt模块:

源代码:

module Clock_cnt
(
	// {{ALTERA_ARGS_BEGIN}} DO NOT REMOVE THIS LINE!
	clk, h_set, m_set, s_set, up_en, rst_n, s_clk, h_data, m_data, s_data
	// {{ALTERA_ARGS_END}} DO NOT REMOVE THIS LINE!
);
// Port Declaration

	// {{ALTERA_IO_BEGIN}} DO NOT REMOVE THIS LINE!
	input clk;
	input h_set;
	input m_set;
	input s_set;
	input up_en;
	input rst_n;
	input s_clk;
	output [7:0] h_data;
	output [7:0] m_data;
	output [7:0] s_data;
	// {{ALTERA_IO_END}} DO NOT REMOVE THIS LINE!
	
	reg [7:0] hour;
	reg [7:0] min;
	reg [7:0] sec;
	reg [2:0] ctl;
	
	assign h_data=ctl[2]?8'b1111_1111:hour;
	assign m_data=ctl[1]?8’b1111_1111:min;
	assign s_data=ctl[0]?8’b1111_1111:sec;
	
	always@(posedge clk or negedge rst_n)
	begin
		if(!rst_n) 
		 begin
		    ctl〈=3’d0;
		    hour<=8'h23;
			min<=8'h45;
			sec<=8'h09;
		  end
		else begin
				if(h_set==0&&m_set==0&&s_set==0)//normal
				  begin
				   ctl〈=3'd0;
				   if(s_clk)
					begin
				     if(sec==8'h59)//seconds counter
						begin
						 sec<=8’h0;
						 if(min==8’h59)//minute counter
							begin
						      min〈=8'h0;
						      if(hour==8'h23)//hour counter
									hour〈=8'h0;
							  else 		//hour counter
								begin        
									if(hour[3:0]==4'd9)
									  begin
									    hour[3:0]〈=4’d0;
									    hour[7:4]〈=hour[7:4]+4’d1;
									   end
									 else hour[3:0]〈=hour[3:0]+4’d1;
								end
						    end
						  else begin//minute counter
							    if(min[3:0]==4'd9)
							      begin
									min[3:0]〈=4’d0;
									min[7:4]<=min[7:4]+4’d1;
							      end
							    else min[3:0]〈=min[3:0]+4'd1;
							   end
						end
					 else begin //seconds counter
							if(sec[3:0]==4’d9)
								begin sec[3:0]<=4’d0;
								      sec[7:4]<=sec[7:4]+4'd1;
								end
							else sec[3:0]<=sec[3:0]+4’d1;
						  end
				    end
				  end
			else if(h_set==1&&m_set==0&&s_set==0) //hour set
					begin
					  if(up_en) 				//up_en down
					    begin
						  if(hour==8'h23)
								hour〈=8'h0;
						  else 
							  begin  
								if(hour[3:0]==4'd9)
								  begin
								   hour[3:0]<=4’d0;
								   hour[7:4]〈=hour[7:4]+4'd1;
								  end
								else hour[3:0]〈=hour[3:0]+4'd1;
							  end
						end
					   else if(s_clk) 
								begin 
									ctl[2]<=~ctl[2];
									ctl[1:0]<=2'b00;
								end
					end
			else if(h_set==0&&m_set==1&&s_set==0)
					begin
					  if(up_en) 
					    begin
						  if(min==8’h59)//minute set
								min〈=8’h0;
							else 
							  begin  //minute set
								if(min[3:0]==4'd9)
								  begin
								   min[3:0]〈=4’d0;
								   min[7:4]〈=min[7:4]+4’d1;
								  end
								else min[3:0]〈=min[3:0]+4'd1;
							  end
						end
					   else if(s_clk) 
								begin 
									ctl[2]<=0;
									ctl[1]<=~ctl[1];
									ctl[0]<=0;
								end
					end
			else if(h_set==0&&m_set==0&&s_set==1)
					begin
					  if(up_en) 
					    begin
						  if(sec==8'h59)//second set
								sec〈=8'h0;
							else 
							  begin  //second set
								if(sec[3:0]==4'd9)
								  begin
								   sec[3:0]<=4'd0;
								   sec[7:4]〈=sec[7:4]+4’d1;
								  end
								else sec[3:0]<=sec[3:0]+4’d1;
							  end
						end							  
					  else if(s_clk) 
								begin 
									ctl[2]〈=0;
									ctl[1]〈=0;
									ctl[0]<=~ctl[0];
								end
					end
			end
	end
endmodule

测试代码:

`timescale 1ns/1ns
module clock_cnt_tb;
    reg clk;
    reg h_set;
    reg m_set;
    reg s_set;
    reg up_en;
    reg rst_n;
    reg s_clk;
    wire[7:0] h_data;
    wire[7:0] m_data;
    wire[7:0] s_data;
    
    always #1 clk=~clk;
    always begin
             #2 s_clk=0;
             #8 s_clk=1;
           end   
    initial
    begin
        clk=0;
        s_clk=0;
        h_set=0;
        m_set=0;
        s_set=0;
        rst_n=0;
        up_en=0;
        #12 rst_n=1;//normal
        #81 up_en=1;
        #2 up_en=0;
        #21 up_en=1;
        #2 up_en=0;
        #10000 h_set=1;//hour set
        #51 up_en=1;
        #2 up_en=0;
        #21 up_en=1;
        #2 up_en=0;
        #21 up_en=1;
        #2 up_en=0;h_set=0;//normal
        #100 m_set=1;//minute set
        #53 up_en=1;
        #2 up_en=0;
        #21 up_en=1;
        #2 up_en=0;
        #21 up_en=1;
        #2 up_en=0;
        #21 up_en=1;
        #2 up_en=0;m_set=0;//normal
        #100 s_set=1;//second set
        #53 up_en=1;
        #2 up_en=0;
        #21 up_en=1;
        #2 up_en=0;
        #21 up_en=1;
        #2 up_en=0;
        #21 up_en=1;
        #2 up_en=0;s_set=0;
        #100 $stop;
    end
    clock_cnt clock(clk,h_set,m_set,s_set,up_en,rst_n,s_clk,h_data,m_data,s_data);
endmodule

Display模块:

源代码:

module Display
(
	// {{ALTERA_ARGS_BEGIN}} DO NOT REMOVE THIS LINE!
	clk, scan_clk, rst_n, h_data, m_data, s_data, d_out, d_col
	// {{ALTERA_ARGS_END}} DO NOT REMOVE THIS LINE!
);
// Port Declaration

	// {{ALTERA_IO_BEGIN}} DO NOT REMOVE THIS LINE!
	input clk;
	input scan_clk;
	input rst_n;
	input [7:0] h_data;
	input [7:0] m_data;
	input [7:0] s_data;
	output [7:0] d_out;
	output [7:0] d_col;
	// {{ALTERA_IO_END}} DO NOT REMOVE THIS LINE!
	reg[7:0] d_col;
	reg[7:0] d_out;
	reg[3:0] led;
	always@(posedge clk or negedge rst_n)
	begin
		if(!rst_n) d_col<=8'b1111_1110;
		else if(scan_clk)
			d_col〈={d_col[6:0],d_col[7]};
	end
	
	always@(d_col or s_data or m_data or h_data)
	begin
		case(d_col)
			8'b1111_1110:led<=s_data[3:0];
			8’b1111_1101:led〈=s_data[7:4];
			8’b1111_1011:led<=4’b1010;
			8’b1111_0111:led〈=m_data[3:0];
			8'b1110_1111:led〈=m_data[7:4];
			8'b1101_1111:led<=4'b1010;
			8’b1011_1111:led<=h_data[3:0];
			8’b0111_1111:led〈=h_data[7:4];
			default:led<=4’b1010;
		endcase
	end
	
	always@(led)			//送数据
	begin
		case(led)
			4'b0000:d_out=8’b0000_0011;
			4'b0001:d_out=8’b1001_1111;
			4'b0010:d_out=8’b0010_0101;
			4'b0011:d_out=8'b0000_1101;
			4'b0100:d_out=8’b1001_1001;
			4’b0101:d_out=8'b0100_1001;
			4’b0110:d_out=8’b0100_0001;
			4’b0111:d_out=8’b0001_1111;
			4’b1000:d_out=8'b0000_0001;
			4'b1001:d_out=8'b0001_1001;
			4’b1010:d_out=8'b1111_1101;
			default:d_out=8’b1111_1111;
		endcase
	end
endmodule

测试代码:

`timescale 1ns/1ns
module display_tb;
	reg clk;
	reg scan_clk;
	reg rst_n;
	reg[7:0] h_data;
	reg[7:0] m_data;
	reg[7:0] s_data;
	wire[7:0] d_ctl;
	wire[7:0] d_out;
	
	always #5 clk=~clk;
	always #5 scan_clk=~scan_clk;
	
	initial
	begin
	   clk=0;
	   scan_clk=0;
	   rst_n=0;
	   h_data=8'h23;
	   m_data=8'h45;
	   s_data=8'h09;
	   #13 rst_n=1;
	   #200 $stop;
	end
	
	display display(clk,scan_clk,rst_n,h_data,m_data,s_data,d_ctl,d_out);

endmodule
本文原创,作者:FPGA小白,其版权均为FPGA在线课程-FPGA在线学习-成电国芯|成电少年学®FPGA智库-FPGA学习资料-z.shaonianxue.cn所有。
如需转载,请注明出处:https://z.shaonianxue.cn/3091.html