简单的数字钟的实现还是很easy的。至少思路很简单。
但是正是这个简单的数字钟就能很好的体现出了硬件设计思想和软件设计思想之间的差别。
整个系统运用全局时钟,对于一些分频的处理采用使能信号控制。这样能避免出现时序的不满足。
整个系统分为五个模块进行实现:
gen_en : 产生使能信号,使能1HZ的分频和数码管的扫描
sec,min,hour模块:当然是实现时分秒的处理
data_con:对数码管显示数据的预译码处理,并进行动态扫描
整个系统已经经过了初步的测试,基本的功能达到满足,但是没有设置时间的功能,还有就是小时的显示部分并没有做处理,仍然按照60进制进行显示.这部分等到有机会进行时间设置功能的补充后再进行相应的更改。
整个系统的顶层文件为:
//////////////////////////////////////////////////////////////////////////////////
// Company: NEU
// Engineer: zxqwolf
//
// Create Date: 12:00:10 02/02/2013
// Design Name: clock
// Module Name: clock
// Project Name: clock
// Target Devices: EP2C5Q208C8
// Tool versions: Quartus II 11.1
// Description: top file
// Revision 0.01 - File Created
// Additional Comments: 实现了基本的数字钟的功能,但是小时部分的显示仍然按照分秒的显示的处理,
// 采用了60进制,而没有采用24进制,主要是因为暂时无法对此部分进行调试,
// 等需要补充时再进行更改
//
//////////////////////////////////////////////////////////////////////////////////
module clock( //top module
input clk,
input rst_n,
output [7:0]smg_bit, //smg bit select
output [7:0]clock_smg //smg data disp
);
///reg [7:0] clock_smg_r;
///wire clock_smg = clock_smg_r;
wire en,en_data_con;
wire cy_hour,cy_min;
wire [3:0] sec_H,sec_L,min_H,min_L,hour_H,hour_L;
gen_en U0( //generate en signal
.clk(clk),
.rst_n(rst_n),
.en_clk(en),
.en_data_con(en_data_con)
);
hour U1( //disp hour
.clk(clk),
.rst_n(rst_n),
.en(cy_hour),
.cy(),
.hour_H(hour_H),
.hour_L(hour_L)
);
min U2( //disp minute
.clk(clk),
.rst_n(rst_n),
.en(cy_min),
.cy(cy_hour),
.min_H(min_H),
.min_L(min_L)
);
sec U3( ////disp second
.clk(clk),
.rst_n(rst_n),
.en(en),
.cy(cy_min),
.sec_H(sec_H),
.sec_L(sec_L)
);
data_con U4( ///smg control module
.clk(clk),
.rst_n(rst_n),
.en_data_con(en_data_con),
.sec_H(sec_H),
.sec_L(sec_L),
.min_H(min_H),
.min_L(min_L),
.hour_H(hour_H),
.hour_L(hour_L),
.smg_bit(smg_bit),
.timedata(clock_smg)
);
endmodule
gen_en 模块实现如下:
module gen_en(
input clk,
input rst_n,
output en_clk,
output en_data_con
);
reg [25:0] en_cnt;
reg [21:0] en_data_con_cnt;
reg en_r,en_data_con_r;
assign en_clk = en_r;
assign en_data_con = en_data_con_r;
always @(posedge clk or negedge rst_n)
if(!rst_n)
begin
en_r <= 1'b0;
en_cnt <= 26'd0;
en_data_con_cnt <= 22'd0;
end
else
begin
en_cnt <= en_cnt + 1'b1;
en_data_con_cnt <= en_data_con_cnt + 1'b1;
if(en_cnt == 26'h2FAF080)
begin
en_cnt <= 26'd0;
en_r <= 1'b1;
//en_data_con_r <= 1'b0;
end // 1HZ = 1s
else
en_r <= 1'b0;
if(en_data_con_cnt == 22'h1E848)
begin
en_data_con_r <= 1'b1;
en_data_con_cnt <= 22'd0;
end
else
en_data_con_r <= 1'b0;
end
endmodule
时分秒的模块实现代码类似,由于小时部分没有做更改,故小时部分也是一样的实现
module sec(
input clk,
input rst_n,
input en,
output cy,
output [3:0]sec_H,
output [3:0]sec_L
);
//reg [3:0] sec_H_r,sec_L_r;
//assign sec_H_r = sec_H;
//assign sec_L_r = sec_L;
wire cy_L;
counter10 U0(
.clk(clk),
.rst_n(rst_n),
.en(en), //////
.cy(cy_L),
.counter_out(sec_L)
);
counter6 U1(
.clk(clk),
.rst_n(rst_n),
.en(cy_L), //////
.cy(cy),
.counter_out(sec_H)
);
endmodule
module min(
input clk,
input rst_n,
input en,
output cy,
output [3:0]min_H,
output [3:0]min_L
);
wire cy_L;
counter10 U0(
.clk(clk),
.rst_n(rst_n),
.en(en), //////
.cy(cy_L),
.counter_out(min_L)
);
counter6 U1(
.clk(clk),
.rst_n(rst_n),
.en(cy_L), //////
.cy(cy),
.counter_out(min_H)
);
endmodule
module hour(
input clk,
input rst_n,
input en,
output cy,
output [3:0]hour_H,
output [3:0]hour_L
);
wire cy_L;
counter10 U0(
.clk(clk),
.rst_n(rst_n),
.en(en), //////
.cy(cy_L),
.counter_out(hour_L)
);
counter6 U1(
.clk(clk),
.rst_n(rst_n),
.en(cy_L), //////
.cy(cy),
.counter_out(hour_H)
);
endmodule
其中时分秒的实现是通过一个一个十进制的计数器和六进制的计数器进行实现的。通过产生进位脉冲向前进位实现进位。
module counter10(
input clk,
input rst_n,
input en,
output cy,
output [3:0]counter_out
);
reg [3:0]counter_out_r; //output data
assign counter_out = counter_out_r;
reg en_r;
reg cy_r; // carry chain
assign cy = cy_r;
//reg cnt_sta;
always @(posedge clk or negedge rst_n)
if(!rst_n)
begin
cy_r <= 1'b0;
counter_out_r <= 4'd0;
//cnt_sta <= 1'b0;
end
else
begin
en_r <= en;
if(!en && en_r) //检测上升沿脉冲
begin
counter_out_r <= counter_out_r + 1'b1;
if(counter_out_r == 4'b1001)
begin
cy_r <= 1'b0;
counter_out_r <= 4'b0000;
end
else if(counter_out_r == 4'b1000)
begin
//此处是为了产生上升沿进位脉冲,因为进位是同步的,
//所以要等到下一个时钟到来时才能有进位有效信号,故此处提前了一个周期产生进位信号
cy_r <= 1'b1;
end
else
begin
cy_r <= 1'b0;
//cnt_sta <= 1'b0;
end
end
end
endmodule
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
module counter6(
input clk,
input rst_n,
input en,
output cy,
output [3:0]counter_out
);
reg [3:0]counter_out_r; //output data
assign counter_out = counter_out_r;
reg en_r;
reg cy_r; // carry chain
assign cy = cy_r;
//reg cnt_sta;
always @(posedge clk or negedge rst_n)
if(!rst_n)
begin
cy_r <= 1'b0;
counter_out_r <= 4'd0;
//cnt_sta <= 1'b0;
end
else
begin
en_r <= en;
if(!en && en_r) //检测上升沿脉冲
begin
counter_out_r <= counter_out_r + 1'b1;
if(counter_out_r == 4'b0101)
begin
counter_out_r <= 4'b0000;
//cnt_sta <= 1'b0;
cy_r <= 1'b0;
end
else if(counter_out_r == 4'b0100)
begin
cy_r <= 1'b1;
//此处是为了产生上升沿进位脉冲,因为进位是同步的,
//所以要等到下一个时钟到来时才能有进位有效信号,故此处提前了一个周期产生进位信号
//cnt_sta <= 1'b0;
end
else
begin
cy_r <= 1'b0;
//cnt_sta <= 1'b0;
end
end
end
endmodule
module data_con(
input clk,
input rst_n,
input en_data_con,
input [3:0]sec_H,
input [3:0]sec_L,
input [3:0]min_H,
input [3:0]min_L,
input [3:0]hour_H,
input [3:0]hour_L,
output [7:0]smg_bit,
output [7:0]timedata
);
reg [7:0] timedata_r,smg_bit_r;
reg [7:0] disp_state;
reg [3:0] time_4bit;
assign timedata = timedata_r;
assign smg_bit = smg_bit_r;
parameter disp0 = 8'b1111_1110,
disp1 = 8'b1111_1101,
disp2 = 8'b1111_1011,
disp3 = 8'b1111_0111,
disp4 = 8'b1110_1111,
disp5 = 8'b1101_1111,
disp6 = 8'b1011_1111,
disp7 = 8'b0111_1111;
always @(posedge clk or negedge rst_n)
if(!rst_n)
begin
disp_state <= 8'b0000_0000;
smg_bit_r <= 8'b1111_1111;
time_4bit <= 4'b0000;
end
else
if(en_data_con)
begin
case(disp_state)
disp0:begin time_4bit <= sec_L; smg_bit_r <= disp0; disp_state <= disp1;end
disp1:begin time_4bit <= sec_H; smg_bit_r <= disp1; disp_state <= disp2;end
disp2:begin time_4bit <= 4'b1010; smg_bit_r <= disp2; disp_state <= disp3;end
disp3:begin time_4bit <= min_L; smg_bit_r <= disp3; disp_state <= disp4;end
disp4:begin time_4bit <= min_H; smg_bit_r <= disp4; disp_state <= disp5;end
disp5:begin time_4bit <= 4'b1010; smg_bit_r <= disp5; disp_state <= disp6;end
disp6:begin time_4bit <= hour_L; smg_bit_r <= disp6; disp_state <= disp7;end
disp7:begin time_4bit <= hour_H; smg_bit_r <= disp7; disp_state <= disp0;end
default : begin time_4bit <= 4'b1111;smg_bit_r<= disp0; disp_state <= disp0;end
endcase
end
always @(time_4bit or rst_n) //combinational logic
if(!rst_n)
begin
timedata_r <= 8'hff; //bu xian shi
end
else
begin
case(time_4bit)
4'b0000 : timedata_r <= 8'hC0; //0
4'b0001 : timedata_r <= 8'hF9; //1
4'b0010 : timedata_r <= 8'hA4; //2
4'b0011 : timedata_r <= 8'hB0; //3
4'b0100 : timedata_r <= 8'h99; //4
4'b0101 : timedata_r <= 8'h92; //5
4'b0110 : timedata_r <= 8'h82; //6
4'b0111 : timedata_r <= 8'hF8; //7
4'b1000 : timedata_r <= 8'h80; //8
4'b1001 : timedata_r <= 8'h90; //9
4'b1010 : timedata_r <= 8'hBF; //-
default : timedata_r <= 8'hff;
endcase
end
endmodule