實現功能:
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進行簡單的仿真:
可以看出進行正常的計數。
最後的效果圖如下: