数码管电子时钟


前言

一、回顾数码管

  Cyclone IV开发板上的数码管一共有6个,我们每次只能选择其中一个显示,怎么解决电子时钟时、分、秒同时显示呢?要实现电子时钟首先要了解什么是余晖效应。
  余晖效应一般指视觉暂留。 视觉暂留现象即视觉暂停现象(Persistence of vision,Visual staying phenomenon,duration of vision)又称“余晖效应”。只要数码管位选信号切换得足够快,数码管由亮到灭这一过程是需要一段时间的,由于时间很短,我们的眼睛是没有办法分清此时此刻数码管的状态,给人的感觉就是数码管是一直亮的。以此来达到欺骗人眼的效果,这样就可以实现同时显示时、分、秒。

在这里插入图片描述

图1. 数码管动态显示

二、任务描述

  使用数码管设计电子时钟,计数器部分有3种实现方法:

  1. 采用1个计数器,模为24x60x60;
  2. 采用3个计数器,模分别为24、60、60;
  3. 采用6个计数器分别计数时、分、秒的个位、十位;
  • 方法1:计数器个数少,设计简单,但是后面数码管译码时,需要对计数值取余、取整,分离出时、分、秒的个位和十位,比较耗费组合逻辑资源;
  • 方法2:3个计数器,后面数码管译码时,需要对时、分、秒计数值取余、取整,分离出时、分、秒的个位和十位,比较耗费组合逻辑资源;
  • 方法3:6个计数器,相对复杂一点,但是计数值直接就是时、分、秒的个位和十位值,不需要除法器进行取余、取整操作,使用的触发器资源略多,但节省组合逻辑资源。
      本实验使用方法1,其他方法同学们可以自行尝试。

在这里插入图片描述

图2. 电子时钟

  我们最后实现的效果如图2所示,由于开发板上的数码管没有冒号(:),所以我们直接忽略冒号。


三、系统框图

  • 计数器模块:产生时、分、秒计数值;
  • 数码管驱动模块:对时、分、秒计数值进行译码,产生驱动数码管动态显示数字的位选信号和段选信号。

示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。

图3. 系统框图

四、模块调用

在这里插入图片描述

图4. 模块关系示意图

五、模块原理图

在这里插入图片描述

图5. 模块原理图

六、工程源码

6.2 时钟计数模块代码

module counter(
	input wire 		  clk  ,//时钟
	input wire 		  rst_n,//复位信号
	
	output reg [4:0] hour  ,//小时
	output reg [5:0] min   ,//分钟
	output reg [5:0] sec//秒
	
);

parameter MAX_NUM = 26'd49_999_999;//1s
parameter TOTAL_SEC = 17'd86399   ;//24x60x60s
reg [25:0] cnt_sec ;//秒计数器
reg [16:0] cnt_time;//计时器

//计时1s秒钟模块
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		cnt_sec <= 26'd0;
	end 
	else if(cnt_sec == MAX_NUM)begin
		cnt_sec <= 26'd0;
	end 
	else begin
		cnt_sec <= cnt_sec + 1'd1;
	end 
end 

//时间模块
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		cnt_time <= 17'd0;
	end 
	else if(cnt_time == TOTAL_SEC && cnt_sec == MAX_NUM)begin
		cnt_time <= 17'd0;
	end 
	else if(cnt_sec == MAX_NUM)begin
		cnt_time <= cnt_time + 1'd1;
	end 
	else begin
		cnt_time <= cnt_time;
	end 
end 

//取出时分秒模块
always@(*)begin
	hour = cnt_time / 12'd3600          ;//小时
	min  = (cnt_time % 12'd3600) / 6'd60;//分钟
	sec  = (cnt_time % 12'd3600) % 6'd60;//秒
end 
endmodule 

6.2 数码管驱动模块代码

module seg_driver(
	input wire 			clk	 ,//时钟
	input wire 			rst_n,//复位信号
	input wire [4:0] 	hour ,//小时
	input wire [5:0] 	min	 ,//分钟
	input wire [5:0] 	sec	 ,//秒
	
	output reg [5:0]	seg_sel,
	output reg [7:0] 	seg_ment
);

parameter CNT_20US = 10'd999;//20微秒
wire [3:0] 	sec_low  ;//秒的低位
wire [2:0] 	sec_high ;//秒的高位
wire [3:0] 	min_low  ;//分钟的低位
wire [2:0] 	min_high ;//分钟的高位
wire [1:0] 	hour_low ;//小时的低位
wire [1:0] 	hour_high;//小时的高位
reg  [9:0]	cnt		 ;//计数器,计20us时间
reg  [3:0] 	number	 ;//显示时分秒寄存器

//计时模块
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		cnt <= 10'd0; 	
	end 
	else if(cnt == CNT_20US)begin
		cnt <= 10'd0;
	end 
	else begin
		cnt <= cnt + 1'd1;
	end 
end 

//位选信号切换模块
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		seg_sel <= 6'b011111;//初始化第一个数码管亮
	end 
	else if(cnt == CNT_20US)begin
		seg_sel <= {seg_sel[0],seg_sel[5:1]};//每隔20us进行位移操作
	end 
	else begin
		seg_sel <= seg_sel;//其他时间保持不变
	end 
end 

//位选信号译码模块
always@(*)begin
	case(seg_sel)
		6'b011111: number = sec_low  ;//秒的低位给第一个数码管显示
		6'b101111: number = sec_high ;//秒的高位给第二个数码管显示
		6'b110111: number = min_low  ;//分钟的低位给第三个数码管显示
		6'b111011: number = min_high ;//分钟的高位给第四个数码管显示
		6'b111101: number = hour_low ;//小时的低位给第五个数码管显示
		6'b111110: number = hour_high;//小时的高位给第六个数码管显示
		default:   number = sec_low  ;
	endcase 
end 

//段选信号译码模块
always@(posedge clk or negedge rst_n)begin
	if(!rst_n)begin
		seg_ment <= 8'b1100_0000;//初始化显示0
	end
	else begin
		case(number)
			4'd0:		seg_ment <= 8'b1100_0000;//数码管显示0
			4'd1:		seg_ment <= 8'b1111_1001;//数码管显示1
			4'd2: 		seg_ment <= 8'b1010_0100;//数码管显示2
			4'd3: 		seg_ment <= 8'b1011_0000;//数码管显示3
			4'd4: 		seg_ment <= 8'b1001_1001;//数码管显示4
			4'd5: 		seg_ment <= 8'b1001_0010;//数码管显示5
			4'd6: 		seg_ment <= 8'b1000_0010;//数码管显示6
			4'd7: 		seg_ment <= 8'b1111_1000;//数码管显示7
			4'd8: 		seg_ment <= 8'b1000_0000;//数码管显示8
			4'd9:    	seg_ment <= 8'b1001_0000;//数码管显示9
			default:	seg_ment <= 8'b1100_0000;//数码管显示0
		endcase 
	end 
end 

assign sec_low   = sec % 4'd10 ;//秒的低位如59秒--->9
assign sec_high  = sec / 4'd10 ;//秒的高位如59秒--->5
assign min_low   = min % 4'd10 ;//分钟的低位如59--->9
assign min_high  = min / 4'd10 ;//分钟的高位如59--->5
assign hour_low  = hour % 4'd10;//小时的低位如23--->3
assign hour_high = hour / 4'd10;//小时的高位如23--->2
endmodule 

6.3 顶层模块代码

module digital_clock(
	input wire 			clk  ,//时钟
	input wire 			rst_n,//复位信号
	
	output wire [5:0] seg_sel,//数码管位选信号
	output wire [7:0] seg_ment//数码管段选信号

);
parameter MAX_NUM = 26'd49_999_999;//1s
parameter TOTAL_SEC = 17'd86399   ;//60x24x24s
parameter CNT_20US = 10'd999     ;//20us
wire [4:0] 	hour;//小时
wire [5:0] 	min ;//分钟
wire [5:0] 	sec ;//秒	

//实例化计数器模块
counter#(.MAX_NUM(MAX_NUM),
		.TOTAL_SEC(TOTAL_SEC)) u_counter(
.clk  	(clk)  ,
.rst_n	(rst_n),
          
.hour 	(hour) ,
.min	(min)  ,
.sec	(sec)
	
);

//实例化数码管驱动模块
seg_driver#(.CNT_20US(CNT_20US)) u_seg_driver(
.clk	 	(clk)    ,
.rst_n		(rst_n)  ,
.hour	 	(hour)   ,
.min	 	(min)    ,
.sec	 	(sec)    ,
          
.seg_sel	(seg_sel),
.seg_ment	(seg_ment)
);

endmodule 

七、仿真测试

7.1 测试代码

`timescale 1ns/1ns
module digital_clock_tb();

parameter MAX_NUM   = 26'd5  ;//100ns
parameter TOTAL_SEC = 17'd100;//100x5x100ns
parameter CNT_20US  = 11'd1  ;//20ns,位选信号切换间隔
parameter CYCLE     = 20     ;//20ns,模拟时钟
reg clk  ;//时钟寄存器
reg rst_n;//复位寄存器

wire [5:0] seg_sel ;//位选信号
wire [7:0] seg_ment;//段选信号

always#(CYCLE/2) clk = ~clk;//模拟时钟信号
//初始化
initial begin
	clk   = 1'b0				  ;//时钟初始化为0
	rst_n = 1'b0				  ;//复位信号初始化为0
	#(CYCLE)    				  ;//延迟一个周期
	rst_n = 1'b1				  ;//复位信号置1
	#(MAX_NUM * TOTAL_SEC * CYCLE);//延迟一段时间
	$stop						  ;//停止
end 

//实例化数字时钟顶层模块
digital_clock#(.MAX_NUM(MAX_NUM)    ,
			   .TOTAL_SEC(TOTAL_SEC),
			   .CNT_20US(CNT_20US))	
u_digital_clock(
.clk    	(clk)    ,//时钟
.rst_n  	(rst_n)  ,//复位信号
		    		
.seg_sel	(seg_sel),//数码管位选信号
.seg_ment(seg_ment)//数码管段选信号

);
endmodule 

7.2 仿真结果

在这里插入图片描述

图6. 仿真结果

八、管脚信息

元件管脚
SEL0A4
SEL1B4
SEL2A3
SEL3B3
SEL4A2
SEL5B1
DIG0B7
DIG1A8
DIG2A6
DIG3B5
DIG4B6
DIG5A7
DIG6B8
DIG7A5
CLOCK(时钟)E1
KEY1E15
表1. 管脚信息表

九、运行效果

数码管电子时钟


总结

  电子时钟是在数码管动态显示实验基础上开发的项目,只要你熟悉数码管动态显示项目流程,在开发电子时钟的时候也会游刃有余。以上就是数码管电子时钟的全部内容,后期将推出什么是ip课程。敬请期待,谢谢你的观看!

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值