用Verilog实现时钟芯片
时钟芯片基础——60进制计数器
设计目的
让nexys 4板上的7段码LED显示时钟信息,其中包括时钟的小时,分钟,秒钟部分,且能够实现时钟的停止计时信号,手动调整小时,分钟模块功能。
设计思路
值得一提的是这里的信号我都用上升沿检测来实现,这样每个模块都可以直接接受时钟信号,而进位信号或者其他的控制信号都可以通过上升沿检测模块来提供一个上升沿信号来实现
- 首先利用分频器产生固定频率的信号来实现每秒钟计数频率和7段码数码管的工作的要求频率。计数功能由单独的秒级,分钟级和小时级三个分别的计数模块负责,秒级和分钟级的计数模块输出进位信号让下一部分自增。
- 计数模块存在输入的RST信号,当接受到RST信号时,计数模块内部寄存器全部清0,所以全部重新计数。
- 秒级计数模块存在输入的停止信号,当接受到停止信号时秒级计数模块停止计数,内部寄存器不再发生改变,所以不再产生进位信号让分钟级计数单位发生改变。
- 分钟级和小时级计数模块存在状态改变信号,当状态信号为1时,分钟级和小时级计数模块不再接受来自上一级的时钟进位信号,转而接受手动调整开关产生的自增信号,实现手动调整小时和分钟的数值;当状态信号为0时,分钟级和小时级计数模块正常接受来自上一级的时钟进位信号,同时忽略手动调整开关产生的自增信号。
- 时钟模块之间的进位信号和手动调整状态下的自增信号都通过上升沿检测实现只输入给相应的模块一个时钟周期的高电平,所以所有模块的时钟信号都可以接受系统时钟。
设计原理图
代码实现
在之前的博客中已经写了60进制计数器的实现,这个时钟芯片不外乎就类似于两个60进制的计数器和一个24进制的计数器,同时两两之间有进位信号。
同时还增加了停止,手动调整这两个功能。其中停止功能只需要停止秒级信号的计数,而手动调整这个功能只需要为分钟模块和小时模块输入增加或减少信号,而控制模块只需要增加它的状态量,让它能实现6个位依次点亮,所以需要6个状态,其他的模块都不需要改变
秒级计数模块
module Counter60(
input clk,
input rst,
//input up,//技术模式转换
input palse,//停止计数信号
output reg [5:0]cnt,
output reg cout//传入下一个时钟模块信号
);
//variation declaration
// reg state,state_next;//1 represents up
// reg c,c_next;//show wherther up?
//state logic
[email protected](posedge clk,posedge rst)
if(rst)begin
cnt<=0;
cout<=0;
end
else
if(palse)//高电平停止计数
cnt<=cnt;//暂停
else//开始计数
// if(up)//高电平上升计数
if(cnt==59)begin
cnt<=0;
cout<=1;//在59的时候进位输出一个计数信号
end
else begin
cnt<=cnt+1;
cout<=0;
end
分钟级计数模块
module Counter60_minute(
input clk,
input rst,
input change,//改变模式信号,SW3
input add,
// input subject,//上升和下降信号
output reg cout,
output reg [5:0]cnt
);
//variation declaration
reg state,state_next;
reg cout_next;
reg [5:0]cnt_next;
//output logic
[email protected](posedge clk,posedge rst)
if(rst==1)begin
cnt<=5'b00000;
cout<=0;
state<=0;//0模式为正常计数模式
end
else begin
cnt<=cnt_next;
cout<=cout_next;
state<=state_next;
end
//next state logic
[email protected]*
begin
state_next<=state;
cout_next<=cout;
cnt_next<=cnt;
case(state)
0:begin//正常计数信号
if(change==1)
state_next<=1;//进入信号改变阶段
else
state_next<=0;
if(cnt==59) begin
cnt_next<=0;
cout_next<=1;//产生上升沿
state_next<=0;
end
else begin//正常计数
cnt_next<=cnt+1;
state_next<=0;
cout_next<=0;//回归下降沿
end
end
1:begin //修改计数器示数状态
if(change==0)
state_next<=0;//进入进入正常计数阶段
else
state_next<=1;
if(add)//出现自增信号,示数加1
if(cnt==60)
cnt_next<=0;
else
cnt_next<=cnt+1;//自增1
else
cnt_next<=cnt;//没有自增信号
end
default: begin
state_next<=0;//进入到正常计数状态
cout_next<=0;
cnt_next<=0;
end//在default里面赋初值?
endcase
end
endmodule
小时级计数模块
module Counter24(
input clk,
input rst,
// output reg cout,
output reg [5:0]cnt
);
[email protected](posedge clk,posedge rst)
if(rst)
cnt<=0;
else
if(cnt==24)//等待第24个信号
cnt<=0;
else
cnt<=cnt+1;
endmodule
控制模块
module Controller(
input clk,
input rst,
input [3:0]H1,
input [3:0]L1,
input [3:0]H2,
input [3:0]L2,
input [3:0]L3,
input [3:0]H3,//增加输入信号
output reg [3:0]Q,
output reg [7:0]AN
);
//variation declaration
reg [2:0]state;
reg [2:0]state_next;//一共6个状态位
reg [3:0]Q_next;
reg [7:0]AN_next;
//FSMD state
[email protected](posedge clk,posedge rst)
if(rst==1) begin
state<=0;
Q<=4'H0;
AN<=8'H00;//全灭清零测试
end
else begin
state<=state_next;
AN<=AN_next;
Q<=Q_next;
end
//next state logic & output logic
[email protected]*
begin
state_next<=state;
AN_next<=AN;
Q_next<=Q;
case(state)
0: begin
Q_next<=L1;//output equals low
AN_next<=8'b11111110;//turn on the 8th led//高电平选中数码管位数
state_next<=1;//next stage is high
end
1: begin
Q_next<=H1;//output equals HIGH
AN_next<=8'b11111101;//turn on the 7th led
state_next<=2;//next stage is LOW
end
2:begin
Q_next<=L2;//output equals low
AN_next<=8'b11110111;//turn on the 8th led
state_next<=3;//next stage is high
end
3:begin
Q_next<=H2;//output equals low
AN_next<=8'b11101111;//turn on the 8th led
state_next<=4;//next stage is high
end
4:begin
Q_next<=L3;//output equals low
AN_next<=8'b10111111;//turn on the 8th led
state_next<=5;//next stage is high
end
5:begin
Q_next<=H3;//output equals low
AN_next<=8'b01111111;//turn on the 8th led
state_next<=0;//next stage is high
end
default:begin
Q_next<=H3;//output equals low
AN_next<=8'b01111111;//turn on the 8th led
state_next<=0;//next stage is high
end
endcase
end
endmodule