基于FPGA的数字时钟

实现功能:

1.可以实现24小时的计时,初始值可以根据程序进行更改;

2.Reset值进行复位,复位后显示00 00 00;

3.在59分50~59分54秒,LED灯会以2Hz的频率闪烁,在59分55~59分59秒,LED灯会以5Hz的频率闪烁;

首先先来介绍一下硬件,这里我们选用的是正点原子的FPGA开发板。

FPGA主控芯片:Cyclone IV E - EP4CE6F17C8

时钟:50MHz。

数码管硬件电路如下:

LEDSEG_A,LEDSEG_B,LEDSEG_C,LEDSEG_D,LEDSEG_E,LEDSEG_F,LEDSEG_G,LEDSEG_DOT,

是数码管的段选信号。

SEL0_T,SEL1_T,SEL2_T,SEL3_T,SEL4_T,SEL5_T是数码管的位选信号,选择的是哪一位。这里为了增加I/O口的驱动能力,我们加了一个PNP管,所以当为低电平时,选择的是当前位。

软件模块图如下:

这里我先将输入的50MHz时钟通过一个锁相环,让其输出50MHz以获得更加稳定的时钟。

count模块的作用是计数,其主要代码如下:

module count(
		input clk,
		input reset,
		output [3:0] count_miao_ge,
		output [2:0] count_miao_shi,
		output [3:0] count_fen_ge,
		output [2:0] count_fen_shi,
		output [3:0] count_shi_ge,
		output [1:0] count_shi_shi
);

reg [31:0] cnt;
reg [3:0] count_miao_ge_reg;
reg [2:0] count_miao_shi_reg;
reg [3:0] count_fen_ge_reg;
reg [2:0] count_fen_shi_reg;
reg [3:0] count_shi_ge_reg;
reg [1:0] count_shi_shi_reg;

assign count_miao_ge = count_miao_ge_reg;  //秒的个位
assign count_miao_shi = count_miao_shi_reg;//秒的十位
assign count_fen_ge = count_fen_ge_reg;//分的个位
assign count_fen_shi = count_fen_shi_reg;//分的十位
assign count_shi_ge = count_shi_ge_reg;//时的个位
assign count_shi_shi = count_shi_shi_reg;//时的十位

always@(posedge clk or negedge reset)
		begin
				if(!reset)
					begin
							cnt <= 32'd0;
							count_miao_ge_reg <= 4'd0;
							count_miao_shi_reg <= 3'd4;
							count_fen_ge_reg <= 4'd9;
							count_fen_shi_reg <= 3'd5;
							count_shi_ge_reg <= 4'd0;
							count_shi_shi_reg <= 2'd0;
					end	
					//当计满一秒并且秒的个位小于9时,秒的个位加一
					else if(cnt == 32'd5000_0000 && count_miao_ge_reg<4'd9)
						begin
							count_miao_ge_reg <= count_miao_ge_reg + 4'd1;
							cnt <= 32'd0;
						end
					//当计满一秒并且秒的个位等于9时,秒的十位加一,秒的个位清零
					else if(cnt == 32'd5000_0000 && count_miao_ge_reg==4'd9 && count_miao_shi_reg<3'd5)
						begin
							count_miao_shi_reg <= count_miao_shi_reg + 3'd1;
							count_miao_ge_reg <= 4'd0;
							cnt <= 32'd0;
						end
					//当计满一秒,秒到达59并且分的个位小于9时,分的个位加1	
					else if(cnt == 32'd5000_0000 && count_miao_ge_reg==4'd9 && count_miao_shi_reg==3'd5 && count_fen_ge_reg<4'd9)
						begin
							count_fen_ge_reg <= count_fen_ge_reg + 4'd1;	
							count_miao_shi_reg <= 3'd0;
							count_miao_ge_reg <= 4'd0;
							cnt <= 32'd0;
						end
					//当计满一秒,秒到达59并且分的个位等于9时,分的十位加1	
					else if(cnt == 32'd5000_0000 && count_miao_ge_reg==4'd9 && count_miao_shi_reg==3'd5 && count_fen_ge_reg==4'd9 && count_fen_shi_reg < 3'd5)
						begin
						   count_fen_shi_reg <= count_fen_shi_reg + 3'd1;
							count_fen_ge_reg <= 4'd0;
							count_miao_shi_reg <= 3'd0;
							count_miao_ge_reg <= 4'd0;
							cnt <= 32'd0;
						end
						//当计满一秒,秒到达59,分等于59时,时的个位小于<9,时的十位小于2时,时的个位加一	
					else if(cnt == 32'd5000_0000 && count_miao_ge_reg==4'd9 && count_miao_shi_reg==3'd5 && count_fen_ge_reg==4'd9 && count_fen_shi_reg ==3'd5 && count_shi_ge_reg < 4'd9 && count_shi_shi < 2'd2)
						begin
							count_shi_ge_reg <= count_shi_ge_reg + 4'd1;
							count_fen_shi_reg <= 3'd0;
							count_fen_ge_reg <= 4'd0;
							count_miao_shi_reg <= 3'd0;
							count_miao_ge_reg <= 4'd0;
							cnt <= 32'd0;
						end
						//当计满一秒,秒到达59,分等于59时,时的个位等于9时,时的十位<2,时的十位加一	
					else if(cnt == 32'd5000_0000 && count_miao_ge_reg==4'd9 && count_miao_shi_reg==3'd5 && count_fen_ge_reg==4'd9 && count_fen_shi_reg ==3'd5 && count_shi_ge_reg == 4'd9 && count_shi_shi < 2'd2)
						begin
							count_shi_shi_reg <= count_shi_shi + 2'd1;
						   count_shi_ge_reg <= 4'd0;
							count_fen_shi_reg <= 3'd0;
							count_fen_ge_reg <= 4'd0;
							count_miao_shi_reg <= 3'd0;
							count_miao_ge_reg <= 4'd0;
							cnt <= 32'd0;
						end
						//当计满一秒,秒到达59,分等于59时,时的个位小于3时,时的十位等于2,时的个位加一
					else if(cnt == 32'd5000_0000 && count_miao_ge_reg==4'd9 && count_miao_shi_reg==3'd5 && count_fen_ge_reg==4'd9 && count_fen_shi_reg ==3'd5 && count_shi_ge_reg < 4'd3 && count_shi_shi == 2'd2)
						begin
							count_shi_ge_reg <= count_shi_ge_reg + 4'd1;
							count_fen_shi_reg <= 3'd0;
							count_fen_ge_reg <= 4'd0;
							count_miao_shi_reg <= 3'd0;
							count_miao_ge_reg <= 4'd0;
							cnt <= 32'd0;
						end
					//当计满一秒,秒到达59,分等于59时,时等于23,所有清零
					else if(cnt == 32'd5000_0000 && count_miao_ge_reg==4'd9 && count_miao_shi_reg==3'd5 && count_fen_ge_reg==4'd9 && count_fen_shi_reg ==3'd5 && count_shi_ge_reg == 4'd3 && count_shi_shi == 2'd2)
						begin
							count_shi_shi_reg <= 2'd0;
							count_shi_ge_reg <= 4'd0;
							count_fen_shi_reg <= 3'd0;
							count_fen_ge_reg <= 4'd0;
							count_miao_shi_reg <= 3'd0;
							count_miao_ge_reg <= 4'd0;
							cnt <= 32'd0;
						end
					else
						begin
							cnt <= cnt + 32'd1;
						end
		end
endmodule

decoding模块是译码模块,就是将每个位转换成相应的数码管的段选。

这里我们是共阳级连接,所以当我们的I/O口输出低电平时有效。

这里0~9对应的码分别是

0:0100_0000

1:0111_1001

2:0010_0100

3:0011_0000

4:0001_1001

5:0001_0010

6:0000_0010

7:0111_1000

8:0000_0000

9:0001_0000

其代码如下:

module decoding(
		input clk,
		input reset,
		input [3:0] count_miao_ge,
		input [2:0] count_miao_shi,
		input [3:0] count_fen_ge,
		input [2:0] count_fen_shi,
		input [3:0] count_shi_ge,
		input [1:0] count_shi_shi,
		output reg [7:0] code_miao_ge,
		output reg [7:0] code_miao_shi,
		output reg [7:0] code_fen_ge,
		output reg [7:0] code_fen_shi,
		output reg [7:0] code_shi_ge,
		output reg [7:0] code_shi_shi
);

always@(posedge clk or negedge reset)
		begin
			if(!reset)
				code_miao_ge <= 8'b1111_1111;
			else
					begin
						case(count_miao_ge)
							4'd0:code_miao_ge <= 8'b1100_0000;
							4'd1:code_miao_ge <= 8'b1111_1001;
							4'd2:code_miao_ge <= 8'b1010_0100;
							4'd3:code_miao_ge <= 8'b1011_0000;
							4'd4:code_miao_ge <= 8'b1001_1001;
							4'd5:code_miao_ge <= 8'b1001_0010;
							4'd6:code_miao_ge <= 8'b1000_0010;
							4'd7:code_miao_ge <= 8'b1111_1000;
							4'd8:code_miao_ge <= 8'b1000_0000;
							4'd9:code_miao_ge <= 8'b1001_0000;
							default:code_miao_ge <= 8'b1011_1111;
						endcase
					end
				
		end

always@(posedge clk or negedge reset)
		begin
			if(!reset)
				code_miao_shi <= 8'b1111_1111;
			else
					begin
						case(count_miao_shi)
							3'd0:code_miao_shi <= 8'b1100_0000;
							3'd1:code_miao_shi <= 8'b1111_1001;
							3'd2:code_miao_shi <= 8'b1010_0100;
							3'd3:code_miao_shi <= 8'b1011_0000;
							3'd4:code_miao_shi <= 8'b1001_1001;
							3'd5:code_miao_shi <= 8'b1001_0010;
							default:code_miao_shi <= 8'b1011_1111;
						endcase
					end
				
		end
		
always@(posedge clk or negedge reset)
		begin
			if(!reset)
				code_fen_ge <= 8'b1111_1111;
			else
					begin
						case(count_fen_ge)
							4'd0:code_fen_ge <= 8'b0100_0000;
							4'd1:code_fen_ge <= 8'b0111_1001;
							4'd2:code_fen_ge <= 8'b0010_0100;
							4'd3:code_fen_ge <= 8'b0011_0000;
							4'd4:code_fen_ge <= 8'b0001_1001;
							4'd5:code_fen_ge <= 8'b0001_0010;
							4'd6:code_fen_ge <= 8'b0000_0010;
							4'd7:code_fen_ge <= 8'b0111_1000;
							4'd8:code_fen_ge <= 8'b0000_0000;
							4'd9:code_fen_ge <= 8'b0001_0000;
							default:code_fen_ge <= 8'b1011_1111;
						endcase
					end
				
		end

always@(posedge clk or negedge reset)
		begin
			if(!reset)
				code_fen_shi <= 8'b1111_1111;
		   else
					begin
						case(count_fen_shi)
							3'd0:code_fen_shi <= 8'b1100_0000;
							3'd1:code_fen_shi <= 8'b1111_1001;
							3'd2:code_fen_shi <= 8'b1010_0100;
							3'd3:code_fen_shi <= 8'b1011_0000;
							3'd4:code_fen_shi <= 8'b1001_1001;
							3'd5:code_fen_shi <= 8'b1001_0010;
							default:code_fen_shi <= 8'b1011_1111;
						endcase
				end
		
	  end

	  
always@(posedge clk or negedge reset)
		begin
			if(!reset)
				code_shi_ge <= 8'b1111_1111;
			else
					begin
						case(count_shi_ge)
							4'd0:code_shi_ge <= 8'b0100_0000;
							4'd1:code_shi_ge <= 8'b0111_1001;
							4'd2:code_shi_ge <= 8'b0010_0100;
							4'd3:code_shi_ge <= 8'b0011_0000;
							4'd4:code_shi_ge <= 8'b0001_1001;
							4'd5:code_shi_ge <= 8'b0001_0010;
							4'd6:code_shi_ge <= 8'b0000_0010;
							4'd7:code_shi_ge <= 8'b0111_1000;
							4'd8:code_shi_ge <= 8'b0000_0000;
							4'd9:code_shi_ge <= 8'b0001_0000;
							default:code_shi_ge <= 8'b1011_1111;
						endcase
					end
				
		end
		
always@(posedge clk or negedge reset)
		begin
			if(!reset)
				code_shi_shi <= 8'b1111_1111;
		   else
					begin
						case(count_shi_shi)
							2'd0:code_shi_shi <= 8'b1100_0000;
							2'd1:code_shi_shi <= 8'b1111_1001;
							2'd2:code_shi_shi <= 8'b1010_0100;
							default:code_shi_shi <= 8'b1011_1111;
						endcase
				end
		
	  end
endmodule

sel_show模块是位选模块,这里我们选用1000Hz的时钟并且用简单的状态机来进行位选。

其代码如下:

module sel_show(
		input clk,
		input reset,
		input [7:0] code_miao_ge,
		input [7:0] code_miao_shi,
		input [7:0] code_fen_ge,
		input [7:0] code_fen_shi,
		input [7:0] code_shi_ge,
		input [7:0] code_shi_shi,
		output reg [7:0] led,
		output reg [5:0] sel
);

reg [15:0] cnt;
reg flag;
//产生1000Hz的时钟
always@(posedge clk or negedge reset)
		begin
			if(!reset)
					begin
						cnt <=16'd0;
						flag <= 1'b0;
					end
				
			else if(cnt == 16'd500_00)
					begin
					   cnt <= 16'd0;
						flag <= 1'b1;
					end
			else
					begin
						cnt <= cnt + 16'd1;
						flag <= 1'b0;
					end
		end

reg [2:0] state;
parameter start = 3'd0; //开始状态
parameter sel_1 = 3'd1; //位选1
parameter sel_2 = 3'd2; //位选2
parameter sel_3 = 3'd3; //位选3
parameter sel_4 = 3'd4; //位选4
parameter sel_5 = 3'd5; //位选5
parameter sel_6 = 3'd6; //位选6
parameter ending = 3'd7;//结束
always@(posedge clk or negedge reset)
		begin
			if(!reset)
				begin
					state <= 3'd0;
					sel <= 6'b000_000;
				end
			else
			case(state)
				start:
					begin
						if(flag == 1'b1)
							state <= sel_1;
						else
							state <= state;
					end
				sel_1:
					begin
						if(flag == 1'b1)
							begin
								state <= sel_2;
								sel <= 6'b111_110;
								led <= code_miao_ge;
							end
						else
							state <= state;
					end
				sel_2:
					begin
						if(flag == 1'b1)
							begin
								state <= sel_3;
								sel <= 6'b111_101;
								led <= code_miao_shi;
							end
						else
							state <= state;
					end
				sel_3:
					begin
						if(flag == 1'b1)
							begin
								state <= sel_4;
								sel <= 6'b111_011;
								led <= code_fen_ge;
							end
						else
							state <= state;
					end
				sel_4:
					begin
						if(flag == 1'b1)
							begin
								state <= sel_5;
								sel <= 6'b110_111;
								led <= code_fen_shi;
							end
						else
							state <= state;
					end
				sel_5:
					begin
						if(flag == 1'b1)
							begin
								state <= sel_6;
								sel <= 6'b101_111;
								led <= code_shi_ge;
							end
						else
							state <= state;
					end
				sel_6:
					begin
						if(flag == 1'b1)
							begin
								state <= ending;
								sel <= 6'b011_111;
								led <= code_shi_shi;
							end
						else
							state <= state;
					end
				ending:
					state <= start;
				default:
					state <= start;
			endcase
		end
endmodule
		

led_flash模块就是控制led灯闪烁的,这里我们选择用计数的方式产生2Hz和5Hz的时钟。

其代码如下:

module led_flash(
		input clk,
		input reset,
	        input [3:0] count_miao_ge,
		input [2:0] count_miao_shi,
		input [3:0] count_fen_ge,
		input [2:0] count_fen_shi,
		output reg Led
);
reg [31:0] cnt_2Hz;
reg [31:0] cnt_5Hz;
reg clk_2Hz;
reg clk_5Hz;
parameter flash_2Hz = 32'd1250_0000;
parameter flash_5Hz = 32'd5000_000;
//产生2Hz的时钟5000_0000/2/2 = 1250_0000
always@(posedge clk or negedge reset)
		begin
				if(!reset)
					begin
						cnt_2Hz <= 32'd0;
					end
				else if(cnt_2Hz == flash_2Hz)
					begin
						clk_2Hz <= ~clk_2Hz;
						cnt_2Hz <= 32'd0;
					end
				else
					cnt_2Hz <= cnt_2Hz + 32'd1;
		end

//产生5Hz的时钟5000_0000/5/2 = 500_0000
always@(posedge clk or negedge reset)
		begin
				if(!reset)
					begin
						cnt_5Hz <= 32'd0;
					end
				else if(cnt_5Hz == flash_5Hz)
					begin
						clk_5Hz <= ~clk_5Hz;
						cnt_5Hz <= 32'd0;
					end
				else
					cnt_5Hz <= cnt_5Hz + 32'd1;
		end		
	
//判断相应的范围并且选取相应的时钟。
always@(posedge clk or negedge reset)
		begin
			if(!reset)
				begin
					Led <= 1'b0;
				end
			else if(count_fen_shi == 3'd5 && count_fen_ge == 4'd9 && count_miao_shi == 3'd5 && count_miao_ge >= 4'd0 && count_miao_ge < 4'd5)
					Led <= clk_2Hz;
			else if(count_fen_shi == 3'd5 && count_fen_ge == 4'd9 && count_miao_shi == 3'd5 && count_miao_ge >= 4'd5 && count_miao_ge <= 4'd9)
					Led <= clk_5Hz;
			else
					Led <= 1'b0;
		end

endmodule

接下来我们用SignalTap进行简单的仿真:

可以看出进行正常的计数。

最后的效果图如下:

 

  • 7
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值