FPGA设计-计数时钟

一.设计要求

        用FPGA控制6个数码管。FPGA上电时刻计时,两个为一组,分别显示时、分、秒数值。

二.设计过程

        1.端口列表

信号名I/O位宽功能
clkI1时钟
rst_nI1复位
tube_dataO8数码管段选
tube_placeO6数码管位选

        2.逻辑框图

        3.时、分、秒信号产生模块

        使用4个计数器实现。其中一个计数器实现一秒计数,一个计数器实现0-59秒计数,一个计数器实现0-59分计数,一个计数器实现0-23时计数。时、分、秒计数器的计数结果直接给到数码管模块。Verilog代码如下:

//时、分、秒产生模块

module time_get( clk , rst_n ,
                 shi , fen , miao
               );

input clk;          //50MHz
input rst_n;

output [7:0] shi;   //小时
output [7:0] fen;   //分钟
output [7:0] miao;  //秒

//--------------------------------
//计数50_000_000产生一秒信号

reg [31:0] cnt0;
wire add_cnt0;
wire end_cnt0;

always @( posedge clk or negedge rst_n ) begin
	if( !rst_n )
		cnt0 <= 32'd0;
	
	else if( add_cnt0 ) begin
		if( end_cnt0 )
			cnt0 <= 32'd0;
		else 
			cnt0 <= cnt0 + 1'b1;
	end
end

assign add_cnt0 = 1'b1;
assign end_cnt0 = add_cnt0 && cnt0 == 50_000_000-1;

//--------------------------------
//秒计数器

reg [7:0] cnt1;
wire add_cnt1;
wire end_cnt1;

always @( posedge clk or negedge rst_n ) begin
	if( !rst_n )
		cnt1 <= 8'd0;
	
	else if( add_cnt1 ) begin
		if( end_cnt1 )
			cnt1 <= 8'd0;
		else 
			cnt1 <= cnt1 + 1'b1;
	end
end

assign add_cnt1 = end_cnt0;
assign end_cnt1 = add_cnt1 && cnt1 == 60-1;

//--------------------------------
//分钟计数器

reg [7:0] cnt2;
wire add_cnt2;
wire end_cnt2;

always @( posedge clk or negedge rst_n ) begin
	if( !rst_n ) 
		cnt2 <= 8'd0;
		
	else if( add_cnt2 ) begin
		if( end_cnt2 )
			cnt2 <= 8'd0;
		else 
			cnt2 <= cnt2 + 1'b1;
	end
end

assign add_cnt2 = end_cnt1;
assign end_cnt2 = add_cnt2 && cnt2 == 60-1;

//--------------------------------
//小时计数器

reg [7:0] cnt3;
wire add_cnt3;
wire end_cnt3;

always @( posedge clk or negedge rst_n ) begin 
	if( !rst_n )
		cnt3 <= 8'd0;
		
	else if( add_cnt3 ) begin
		if( end_cnt3 )
			cnt3 <= 8'd0;
		else 
			cnt3 <= cnt3 + 1'b1;
	end
end

assign add_cnt3 = end_cnt2;
assign end_cnt3 = add_cnt3 && cnt3 == 24-1;

//--------------------------------

assign miao = cnt1;
assign fen = cnt2;
assign shi = cnt3;

//--------------------------------

endmodule		

        4.数码管模块

        数码管模块把时、分、秒计数器的计数结果用移位加三算法拆为个、十位,并根据状态机对应的状态给数码管相应的段选与位选信号。Verilog代码如下:

//数码管驱动

module tube( clk , rst_n ,
             shi , fen , miao ,
				 tube_data , tube_place
			  );
			  
input clk;
input rst_n;
input [7:0] shi;
input [7:0] fen;
input [7:0] miao;

output reg [7:0] tube_data;
output reg [5:0] tube_place;

//--------------------------------
//数据存储

//不带小数点
reg [7:0] number_data[9:0];   //0-9的数据
always @( negedge rst_n ) begin
	number_data[0] <= 8'hc0;
	number_data[1] <= 8'hf9;
	number_data[2] <= 8'ha4;
	number_data[3] <= 8'hb0;
	number_data[4] <= 8'h99;
	number_data[5] <= 8'h92;
	number_data[6] <= 8'h82;
	number_data[7] <= 8'hf8;
	number_data[8] <= 8'h80;
	number_data[9] <= 8'h90;
end

//带小数点
reg [7:0] number_data_dot[9:0];
always @( negedge rst_n ) begin
	number_data_dot[0] <= 8'h40;
	number_data_dot[1] <= 8'h79;
	number_data_dot[2] <= 8'h24;
	number_data_dot[3] <= 8'h30;
	number_data_dot[4] <= 8'h19;
	number_data_dot[5] <= 8'h12;
	number_data_dot[6] <= 8'h02;
	number_data_dot[7] <= 8'h78;
	number_data_dot[8] <= 8'h00;
	number_data_dot[9] <= 8'h10;
end

//---------------------------------
//移位加三算法

reg [15:0] temp_miao;
reg [15:0] temp_fen;
reg [15:0] temp_shi;

always @( miao[7:0] ) begin
	temp_miao = 16'd0;
	
	temp_miao[7:0] = miao[7:0];   //写入第8位
	repeat(8) begin           //循环8次
	if( temp_miao[11:8] > 4 )
		temp_miao[11:8] = temp_miao[11:8] + 2'b11;
	if( temp_miao[15:12] > 4 )
		temp_miao[15:12] = temp_miao[15:12] + 2'b11;
	temp_miao[15:1] = temp_miao[14:0];    //左移一位
	end
end

///

always @( fen[7:0] ) begin
	temp_fen = 16'd0;

	temp_fen[7:0] = fen[7:0];   //写入第8位
	repeat(8) begin           //循环8次
		if( temp_fen[11:8] > 4 )
			temp_fen[11:8] = temp_fen[11:8] + 2'b11;
		if( temp_fen[15:12] > 4 )
			temp_fen[15:12] = temp_fen[15:12] + 2'b11;
		temp_fen[15:1] = temp_fen[14:0];    //左移一位
	end
end

///

always @( shi[7:0] ) begin
	temp_shi = 16'd0;

	temp_shi[7:0] = shi[7:0];   //写入第8位
	repeat(8) begin           //循环8次
		if( temp_shi[11:8] > 4 )
			temp_shi[11:8] = temp_shi[11:8] + 2'b11;
		if( temp_shi[15:12] > 4 )
			temp_shi[15:12] = temp_shi[15:12] + 2'b11;
		temp_shi[15:1] = temp_shi[14:0];    //左移一位
	end
end

//--------------------------------
//状态机

//时间计数器
reg [15:0] cnt_ms;    //1ms计数器
wire add_cnt_ms;      //加1条件
wire end_cnt_ms;      //结束条件

always @( posedge clk or negedge rst_n ) begin
	if( !rst_n )
		cnt_ms <= 16'd0;
		
	else if( add_cnt_ms ) begin
		if( end_cnt_ms )
			cnt_ms <= 160'd0;
		else
			cnt_ms <= cnt_ms + 1'b1;
	end

end

assign add_cnt_ms = 1'b1;
assign end_cnt_ms = add_cnt_ms && ( cnt_ms == 50000-1 );  //每个1ms产生高电平 //50000-1

reg [7:0] cnt_10ms;    //10ms计数器
wire add_cnt_10ms;
wire end_cnt_10ms;     

always @( posedge clk or negedge rst_n ) begin
	if( !rst_n )
		cnt_10ms <= 8'd0;
		
	else if( add_cnt_10ms ) begin
		if( end_cnt_10ms )
			cnt_10ms <= 8'd0;
		else 
			cnt_10ms <= cnt_10ms + 1'b1;
	end
end

assign add_cnt_10ms = end_cnt_ms;
assign end_cnt_10ms = add_cnt_10ms && ( cnt_10ms == 1-1 );

/

parameter s0 = 3'd0,
          s1 = 3'd1,
			 s2 = 3'd2,
			 s3 = 3'd3,
			 s4 = 3'd4,
			 s5 = 3'd5;
			 //状态表
			 
reg [2:0] state_c;    //现态
reg [2:0] state_n;    //次态 			 
			 
always @( posedge clk or negedge rst_n ) begin
	if( !rst_n ) 
		state_c <= s0;
		
	else 
		state_c <= state_n;
end

//

wire s0_to_s1_start;
wire s1_to_s2_start;
wire s2_to_s3_start;
wire s3_to_s4_start;
wire s4_to_s5_start;
wire s5_to_s0_start;

assign s0_to_s1_start = state_c == s0 && end_cnt_10ms;
assign s1_to_s2_start = state_c == s1 && end_cnt_10ms;
assign s2_to_s3_start = state_c == s2 && end_cnt_10ms;
assign s3_to_s4_start = state_c == s3 && end_cnt_10ms;
assign s4_to_s5_start = state_c == s4 && end_cnt_10ms;
assign s5_to_s0_start = state_c == s5 && end_cnt_10ms;

//

always @( * ) begin
	case( state_c )
		s0 : begin
			if( s0_to_s1_start )
				state_n = s1;
			else 
				state_n = state_c;
		end
		
		s1 : begin
			if( s1_to_s2_start )
				state_n = s2;
			else 
				state_n = state_c;
		end
		
		s2 : begin
			if( s2_to_s3_start )
				state_n = s3;
			else 
				state_n = state_c;
		end
		
		s3 : begin
			if( s3_to_s4_start )
				state_n = s4;
			else 
				state_n = state_c;
		end
		
		s4 : begin
			if( s4_to_s5_start )
				state_n = s5;
			else 
				state_n = state_c;
		end
		
		s5 : begin
			if( s5_to_s0_start )
				state_n = s0;
			else 
				state_n = state_c;
		end
		
		default : state_n = s0;
	endcase
end

/
//位选输出

always @( posedge clk or negedge rst_n ) begin
	if( !rst_n )
		tube_place <= 6'd0;
	
	else if( state_c == s0 )
		tube_place <= 6'b011111;
	else if( state_c == s1 )
		tube_place <= 6'b101111;
	else if( state_c == s2 )
		tube_place <= 6'b110111;
	else if( state_c == s3 )
		tube_place <= 6'b111011;
	else if( state_c == s4 )
		tube_place <= 6'b111101;
	else if( state_c == s5 )
		tube_place <= 6'b111110;
end

//端选输出

always @( posedge clk or negedge rst_n ) begin
	if( !rst_n )
		tube_data <= 8'd0;
		
	else if( state_c == s0 )
		tube_data <= number_data[ temp_shi[15:12] ];
	else if( state_c == s1 )
		tube_data <= number_data_dot[ temp_shi[11:8] ];
	else if( state_c == s2 )
		tube_data <= number_data[ temp_fen[15:12] ];
	else if( state_c == s3 )
		tube_data <= number_data_dot[ temp_fen[11:8] ];
	else if( state_c == s4 )
		tube_data <= number_data[ temp_miao[15:12] ];
	else if( state_c == s5 )
		tube_data <= number_data[ temp_miao[11:8] ];
end
	
endmodule

        5.顶层模块

//top

module jssz_top( clk , rst_n ,
                 tube_data , tube_place
					 );

input clk;
input rst_n;

output [7:0] tube_data;
output [5:0] tube_place;
 
//------------------------------

wire [7:0] shi;
wire [7:0] fen;
wire [7:0] miao;
 
time_get time_get( 
                  .clk( clk ) , 
						.rst_n( rst_n ) ,
                  .shi( shi ) , 
						.fen( fen ) , 
						.miao( miao )
				   );
					
//------------------------------
					
wire [7:0] tube_data;
wire [5:0] tube_place;
					
tube tube( 
           .clk( clk ) , 
			  .rst_n( rst_n ) ,
           .shi( shi ) , 
			  .fen( fen ) , 
			  .miao( miao ) ,
			  .tube_data( tube_data ) ,
			  .tube_place( tube_place )
			 );
					
endmodule

 

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值