本設計中數字跑表的主要功能有:1、具有顯示分、秒以及百分秒的秒表功能,2、具有暫停和復位功能
一、設計准備
輸入端口:
1)復位信號CLR,當CLR=1時輸出全部置0,當CLR=0時系統正常工作。
2)暫停信號PAUSE,當PAUSE=1時暫停計數,當PAUSE=0時正常計數。
3)系統時鍾CLK,CLK=50MHz
輸出端口: 數碼管驅動----DATA[13:0](位寬14位),其中DATA[7:0](后八位)是數碼管顯示值,DATA[13:8](前六位)是數碼管控制端口
按照自頂向下設計,應該分為以下模塊:
分頻1----將下載板上50MHz時鍾分頻為100Hz(周期0.01s)的時鍾,提供給百分計數
分頻2----將下載板上50MHz時鍾分頻為10KHz的時鍾,提供給動態掃描
計數1----100進制計數器,輸入100Hz的時鍾,計數滿100進位
計數2----60進制計數器,輸入百分位,或者秒位的進位,計數滿60向高位進位
數碼管顯示控制----驅動數碼管數據,顯示控制端口。
二、分頻模塊
分頻模塊的輸入為50MHz的系統時鍾clk50m,輸出為分頻后的100Hz時鍾信號clk100和10KHz時鍾信號clk10k,定義了兩個計數寄存器cout1[18:0](19位)和cout2[15:0](16位)。系統時鍾為50MHz,百分秒計數需要100Hz(周期0.01s)的時鍾信號,因此對50MHz進行(50x10^6)/100=500,000次分頻,定義計數器cout1對50MHZ方波上升沿進行計數,從0到499,999循環計數,每滿499,999后cout1就置0重新計數,並且當cout1=499,999時clk100置1。至於再分頻一個10KHz時鍾的原因是動態掃描在100Hz時有明顯閃爍,而在50MHz時閃爍頻率過快導致根本看不清數碼管上的數字。
三、計時模塊
計時模塊的輸入為分頻后的100Hz時鍾信號clk100,輸出為分位、秒位、百分位的個位和百分位的十位[3:0]:ML、SL、MSL、MSH和分位、秒位的十位[2:0]:MH、SH,定義了兩個進位信號cn1和cn2。每個clk100的上升沿到來代表時間過了0.01s,每個cn1的上升沿到來代表時間過了1s,每個cn2的上升沿到來代表時間過了60s。
四、數碼管顯示模塊
顯示模塊的輸入為分頻后的10KHz時鍾信號clk10k,輸出為帶有數碼管控制端口和數碼管顯示值的DATA[12:0],定義了一個位選寄存器dig[2:0]。因為不需要數碼管上的小數點亮所以數碼管顯示值設為7位,而數碼管控制端口只用6只所以是6位,數碼管分共陰極和共陽極兩種,共陰極的1表示亮,共陽極的0表示亮,我是當共陰極來設計的;四位一體數碼管用動態掃描控制,每個clk10k的上升沿到來dig在0到5之間循環,dig的值等於幾顯示控制函數就往那支數碼管里送與之對應的數據。
`timescale 1ns / 1ps module timer(clk50m,clr,pause,data); input clk50m; //輸入50MHz的時鍾信號 input clr; //清零開關 input pause; //暫停開關 output reg[12:0]data; reg [2:0]dig; //數碼管位選 reg [3:0] ML,SL,MSL,MSH; //分位,秒位,百分位的個位和百分位的十位 reg [2:0] MH,SH; //分位,秒位的十位 reg [18:0] cout1; //定義計數寄存器 reg [15:0] cout2; //定義計數寄存器 reg clk100; //定義分頻得到的100Hz時鍾信號 reg clk10k; //頻率10KHz的時鍾信號 reg cn1; //百分位向秒位的進位 reg cn2; //秒位向分位的進位 //-------------------分頻得到100Hz的時鍾信號clk100-------------------- always@(posedge clk50m or posedge clr) if(clr) cout1<=0; else if(cout1 == 19'h7a11f) cout1<=0; else cout1<=cout1+1'b1; always@(posedge clk50m or posedge clr) if(clr) clk100<=0; else if(cout1 == 19'h7a11f) clk100<=1'b1; else clk100<=0; //-------------------分頻得到10KHz的時鍾信號clk10k------------------- always@(posedge clk50m or posedge clr) if(clr) cout2<=0; else if(cout2 == 19'hc34f) cout2<=0; else cout2<=cout2+1'b1; always@(posedge clk50m or posedge clr) if(clr) clk10k<=0; else if(cout2 == 19'hc34f) clk10k<=1'b1; else clk10k<=0; //-----------------------計時模塊-------------------- //----------------百分位計時--------------- always@(posedge clk100 or posedge clr) if(clr) begin {MSH,MSL}<=8'h00;cn1<=0;end //異步復位 else if(!pause) //PAUSE為0時正常計數 begin if(MSL == 4'b1001) begin MSL<=0; if(MSH == 4'b1001) begin MSH<=0; cn1<=1; end else begin MSH<=MSH+1'b1;cn1<=0; end end else begin MSL<=MSL+1'b1; cn1<=0; end end //----------------秒位計時----------------- always@(posedge cn1 or posedge clr) if(clr) begin {SH,SL}<=8'h00;cn2<=0; end else if(SL == 4'b1001) begin SL<=0; if(SH == 5) begin SH<=0; cn2<=1; end else begin SH<=SH+1'b1;cn2<=0; end end else begin SL<=SL+1'b1;cn2<=0; end //---------------分位計時------------------ always@(posedge cn2 or posedge clr) if(clr) begin {MH,ML}<=8'h00; end else if(ML == 4'b1001) begin ML<=0; if(MH == 3'b101) begin MH<=0; end else begin MH<=MH+1'b1; end end else begin ML<=ML+1'b1; end //-------------------數碼管顯示模塊-------------------- always@(posedge clk10k or posedge clr) if(clr) data<=13'b1111111111110; else case(dig) 3'b000:data<={6'b000001,Xrom(MSL)}; 3'b001:data<={6'b000010,Xrom(MSH)}; 3'b010:data<={6'b000100,Xrom(SL)}; 3'b011:data<={6'b001000,Xrom(SH)}; 3'b100:data<={6'b010000,Xrom(ML)}; 3'b101:data<={6'b100000,Xrom(MH)}; default:data<=13'h1fff; endcase //-------------------動態掃描------------------- always@(posedge clk10k or posedge clr) if(clr) dig<=0; else begin if(clk10k == 0) begin if(dig==5) dig<=0; else dig<=dig+1'b1; end else dig<=dig; end //--------------數碼管顯示控制函數--------------- function[6:0] Xrom; input [3:0] sum; case(sum) 4'd0:Xrom=7'h7e; 4'd1:Xrom=7'h30; 4'd2:Xrom=7'h6d; 4'd3:Xrom=7'h79; 4'd4:Xrom=7'h33; 4'd5:Xrom=7'h5b; 4'd6:Xrom=7'h5f; 4'd7:Xrom=7'h70; 4'd8:Xrom=7'h7f; 4'd9:Xrom=7'h7b; default:Xrom=7'h00; endcase endfunction endmodule