Verilog设计—简易LED数字时钟

文章目录

目录

设计方案概述

1、分频器模块设计

2、计数器模块设计

3、LED显示模块设计

4、顶层模块设计 


设计方案概述

Verilog设计—简易LED数字时钟_第1张图片

Verilog设计—简易LED数字时钟_第2张图片 系统设计框图

本任务设计了一个简易数字钟,能实现小时、分钟和秒的计时及显示,其中,通过控制时、分和秒实现时钟计时的计数模块是本次设计的核心。

计数模块的关键在于能够理解三个计时单位之间的联系,即秒计数满60产生一个向分钟的进位,分钟计数满60产生一个向小时的进位,这两个进位信号将小时、分和秒联系起来,是理解本设计的关键点。

为时钟设计一个初值设置控制信号,按下设置信号时能利用开发板上的拨码开关或按键对时间进行校对设置。

  • 任务分析

计数信号来自于开发板提供的时钟信号,这里采用的晶振频率为10KHz,而秒的计数周期是1秒,因此需要对该时钟信号进行分频(10KHz→1Hz),因此,分频器模块是本任务中另一个重要模块。

根据常识,“秒”、“分”和“小时”之间存在各自独立又互相联系的计数和进位关系,“秒”和“分”的计数模式相同,每计数满60个时钟清零并重新开始计数,相当于一个六十进制的计数器。“小时”的计数模式是每计数满24个时钟就进行清零并重新开始计数,相当于一个二十四进制的计数器。所以,六十进制和二十四进制的计数器模块设计是本任务的核心模块。

“秒”、“分”和“小时”的计时过程都需要通过LED显示器进行显示,所以还需要设计显示控制模块。

根据以上分析,本任务需要设计的模块如下:

  1. 分频器模块;

  2. 分、秒和小时的计数器模块;

  3. 显示控制模块。


1、分频器模块设计

Verilog设计—简易LED数字时钟_第3张图片

  • freq_div.v

module freq_div(clk, clk_1); //clk:输入时钟信号;   clk_1: //输出时钟信号
    input clk;
    output clk_1;
    reg[13:0] counter=14'd0;  //定义计数器,用于计数时钟(计数10000,需要用14位计数器)
    reg clk_1=0;
    always@(posedge clk)
		if(counter == 14'd4999) //如果等于4999
			begin
				counter <= 14'b0;     //把counter恢复成0
				clk_1  <= ~clk_1;     //把clk_1翻转
			end
		else
			counter <= counter + 1'b1; //counter 继续计数
endmodule
  • tb_freq_div.v(用于测试)

`timescale 1us/1ns     

module tb_led_clock();
  reg CLK;
  parameter period = 100;  //100us = 1/(10K) Hz
  top inst_top(.clk(CLK));
 
  initial 
    begin
      CLK= 0;
      forever 
        #(period/2) CLK = ~CLK; 
    end
endmodule
分频器模块测试—T1实验结果

2、计数器模块设计

Verilog设计—简易LED数字时钟_第4张图片

信号名

I/O

位宽

含义

clk_1

I

1 bit

分频后周期为1s的时钟输出

hor

O

5 bits

小时计数结果的输出(0-23

min

O

6 bits

分钟计数结果的输出(0-59

sec

O

6 bits

秒钟计数结果的输出(0-59

  • count.v

module count(clk_1,  sec, min, hor);

	input clk_1;
	
	reg scarry, mcarry, hcarry;
	
	output reg [4:0] hor=23; 
	output reg [5:0] min=59;
	output reg [5:0] sec=49;

	always@(posedge clk_1)
	  begin
			if (sec==6'b111011)    //秒针计数到59
				begin
					 sec <= 6'b000000;
					 scarry <= 1'b1;    //秒向分进位1
				end
			 else
				begin
					 sec <= sec+1'b1;
					 scarry <= 1'b0;
				end
		end

	always@(posedge scarry)
	  begin
			if (min == 6'b111011)    //分针计数到59
				begin
					 min <= 6'b000000;
					 mcarry <= 1'b1;    //分向小时进位1
				end
			 else
				begin
					 min <= min+1'b1;
					 mcarry <= 1'b0;
				end
	  end
  
	 always@(posedge mcarry)
	  begin
			if (hor==5'b10111)    //计数到23
					 hor <= 5'b00000;			
			 else
					 hor <= hor+1'b1;
		end
endmodule
  • tb_count.v(用于测试)

`timescale 1ms/1ps

module tb_count();
  reg CLK_1;
  parameter period=1000;
  count T1(.clk_1(CLK_1));
 
  initial 
    begin
      CLK_1= 0;
      forever
        #(period/2) CLK_1 = ~CLK_1;  //周期为1s,用作测试
    end
endmodule

计数器模块测试—T2实验结果

3、LED显示模块设计

Verilog设计—简易LED数字时钟_第5张图片 LED显示模块设计

信号名

I/O

位宽

含义

clk

I

1bits

时钟信号,10KHz基频(用作动态数码管的移位扫描)

clk_1

I

1bits

时钟信号,1Hz频率(用作整点提示led的延时)

hor

I

5 bits

时计数结果,hour

min

I

6 bit

分钟计数结果,minute

sec

I

6 bits

秒计数结果,second

led_SEL

O

3 bits

控制数码管动态扫描的位累加变量

led_dis

O

8 bits

数码管段选,"7段+1dp"

led

O

4 bits

4个led灯,作整点提示

  • led_dis.v

module led_dis(
	clk, clk_1,
	hor,min,sec, 
	led_SEL,
	led_dis,
	led
	);
	
	input clk,clk_1;
	input [4:0] hor;
	input [5:0] min;
	input [5:0] sec;

	reg [3:0] horh,horl;
	reg [3:0] minh,minl;
	reg [3:0] sech,secl;
	reg [3:0] disp_Temp; 
	reg [2:0] led_count=3'b000;
	
	output reg [2:0] led_SEL=3'b000;
	output reg [7:0] led_dis=8'b101_1011; 
	output reg [3:0] led;
	
	reg [7:0] disp_code=8'b101_1011;
	reg [3:0] led_remind=4'b0000;
	integer i;
	
	always@(hor) //将hour的二进制码转换成BCD码,并将十位数、个位数保存至horh、horl
		begin 
			horh=4'd0;
			horl=4'd0;
			for(i=4;i>=0;i=i-1)
				begin	
					if(horh>=5)
						horh=horh+3;
					if(horl>=5)
						horl=horl+3;
					horh = horh<<1;
					horh[0] = horl[3];
					horl = horl<<1;
					horl[0]= hor[i];
				end		
		end	

	always@(min) //将minute的二进制码转换成BCD码,并将十位数、个位数保存至minh、minl
		begin 
			minh=4'd0;
			minl=4'd0;
			for(i=5; i>=0; i=i-1)
				begin	
					if(minh>=5)
						minh=minh+3;
					if(minl>=5)
						minl=minl+3;
					minh = minh<<1;
					minh[0] = minl[3];
					minl = minl<<1;
					minl[0]= min[i];
				end		
		end
	
	always@(sec) //将second的二进制码转换成BCD码,并将十位数、个位数保存至sech、secl
		begin 
			sech=4'd0;
			secl=4'd0;
			for(i=5; i>=0; i=i-1)
				begin	
					if(sech>=5)
						sech=sech+3;
					if(secl>=5)
						secl=secl+3;
					sech = sech<<1;
					sech[0] = secl[3];
					secl = secl<<1;
					secl[0]= sec[i];
				end		
		end	
	
	always@(led_SEL) 
		begin 
			case(led_SEL+1)
				3'b000: disp_Temp <= horh;
				3'b001: disp_Temp <= horl;
				3'b010: disp_Temp <= 10;
				3'b011: disp_Temp <= minh;
				3'b100: disp_Temp <= minl;
				3'b101: disp_Temp <= 10;
				3'b110: disp_Temp <= sech; 
				3'b111: disp_Temp <= secl;
				default: disp_Temp <= horh;
			endcase
		end

	always@(disp_Temp) //--显示转换
		begin 
			case(disp_Temp)	//低位数的可能值:0~9
				5'd0: disp_code <=8'b0011_1111;
				5'd1: disp_code <=8'b0000_0110;
				5'd2: disp_code <=8'b0101_1011;
				5'd3: disp_code <=8'b0100_1111;
				5'd4: disp_code <=8'b0110_0110;
				5'd5: disp_code <=8'b0110_1101;
				5'd6: disp_code <=8'b0111_1101; 
				5'd7: disp_code <=8'b0000_0111;
				5'd8: disp_code <=8'b0111_1111;
				5'd9: disp_code <=8'b0110_1111; 
				default: disp_code <=8'b0100_0000;  //显示'-'
			endcase
		end
		
	always@(posedge clk) 
		begin //扫描累加
			  led_dis <= disp_code;
			  led_SEL <= led_SEL + 1'b1;
		end
	
	always@(posedge clk_1) 	
		begin
			if(min==59  &&  sec>54)   //在59分55秒开始提示
				led_count<=led_count+1; 
			else
				led_count<=3'b000;
		end
	
	always@(led_count)
		begin 
			case(led_count)
				3'b000: led_remind <= 4'b0000;
				3'b001: led_remind <= 4'b0001;
				3'b010: led_remind <= 4'b0011;
				3'b011: led_remind <= 4'b0111;
				3'b100: led_remind <= 4'b1111;
				default:led_remind <= 4'b0000;
			endcase
			led<=led_remind;
		end
endmodule
  • tb_led_dis.v(用于测试)

`timescale 1us/1ns     

module tb_led_dis();
	reg [4:0] HOR;
	reg [5:0] MIN, SEC;
	reg CLK,CLK_1;
    parameter period = 100;  //100us = 1/(10K) Hz
    
	led_dis T3(.clk(CLK),.clk_1(CLK_1).hor(HOR),.min(MIN),.sec(SEC));
	
	parameter delay = 1000000;

    initial 
        begin
            CLK= 0;
            forever 
                #(period/2) CLK = ~CLK;
        end

  initial 
    begin
      CLK_1= 0;
      forever
        #(period/2) CLK_1 = ~CLK_1;  //周期为1s,用作测试
    end
	
	initial 
		begin
			#delay	HOR=5'd1; MIN=6'd12; SEC=6'd35;
			#delay	HOR=5'd11; MIN=6'd59; SEC=6'd12;
			#delay	HOR=5'd00; MIN=6'd34; SEC=6'd56;
			#delay	HOR=5'd23; MIN=6'd28; SEC=6'd00;
			#delay	;
		end

	
endmodule


Verilog设计—简易LED数字时钟_第6张图片 LED显示模块—T3实验结果

4、顶层模块设计 

先设置top.v为顶层文件(右键“top”→Set as Top-Level Entity

  • 添加三个.v文件(引入子模块,类似于C语言中的导入.h文件操作)

Verilog设计—简易LED数字时钟_第7张图片

Verilog设计—简易LED数字时钟_第8张图片

  • tb_top.v

module top(
   clk,
	hor, min, sec,
	led_dis, led_SEL,
	led
);
	input clk;
	
	output [4:0] hor;
	output [5:0] min, sec;
	output [2:0] led_SEL;
	output [7:0] led_dis;
	output [3:0] led;
	
	wire clk_1;
	freq_div inst_fre_div(
		.clk(clk),
		.clk_1(clk_1)
	);
	wire [4:0] hor;
	wire [5:0] min,sec;
	count inst_count(
		.clk_1(clk_1),
		.hor(hor),
		.min(min),
		.sec(sec)
	);
	
	wire [7:0] led_dis;
	wire [2:0] led_SEL;
	wire [3:0] led;
	led_dis inst_led(
		.clk(clk),
		.clk_1(clk_1),
		.hor(hor),.min(min),.sec(sec),
		.led_SEL(led_SEL),
		.led_dis(led_dis),
		.led(led)
	);
endmodule

 


Verilog设计—简易LED数字时钟_第9张图片

PS:直接编写一个tb_led_clock.v就可以了,不用指定其顶层还是底层模块

  • tb_led_clock.v

`timescale 1us/1ns     

module tb_led_clock();
  reg CLK;
  parameter period = 100;  //100us = 1/10K Hz
  top inst_top(.clk(CLK));
 
  initial 
    begin
      CLK= 0;
      forever 
        #(period/2) CLK = ~CLK; 
    end
endmodule

Verilog设计—简易LED数字时钟_第10张图片

Verilog设计—简易LED数字时钟_第11张图片

Verilog设计—简易LED数字时钟_第12张图片

 

  • 拓展功能——复位、调时

Verilog设计—简易LED数字时钟_第13张图片

Verilog设计—简易LED数字时钟_第14张图片

 

你可能感兴趣的:(FPGA课程)