1.一个四位计数器
BCD_Counter.v
module BCD_Counter(Clk,Cin,Rst_n,Cout,q);
input Clk;//计数器基准时钟
input Cin;//计数器进位输入
input Rst_n;//系统复位
output reg Cout;//计数器进位输出
output [3:0]q;//计数值输出
reg [3:0]cnt;//计数器的寄存器
always@(posedge Clk or negedge Rst_n)//执行计数的过程
if(Rst_n == 1'b0)
cnt <= 4'd0;
else if(Cin == 1'b1)begin
if(cnt == 4'd9)
cnt <= 4'd0;
else
cnt <= cnt + 1'b1;
end
else
cnt <= cnt;
always@(posedge Clk or negedge Rst_n)//产生进位输出信号
if(Rst_n == 1'b0)
Cout <= 1'b0;
else if(Cin == 1'b1 && cnt == 4'd8)
Cout <= 1'b1;
else
Cout <= 1'b0;
//cnt计数值作为输出
assign q = cnt;
endmodule
BCD_Counter_tb.v
`timescale 1ns/1ns
`define clock_period 20
module BCD_Counter_tb;
//激励信号
reg Clk;
reg Cin;
reg Rst_n;
wire Cout;
wire [3:0]q;
//端口连接
BCD_Counter BCD_Counter0(
.Clk(Clk),
.Cin(Cin),
.Cout(Cout),
.Rst_n(Rst_n),
.q(q)
);
initial Clk = 1'b1;
always#(`clock_period/2)Clk = ~Clk;
initial begin
Rst_n = 1'b0;
Cin = 1'b0;
#(`clock_period*200);
Rst_n = 1'b1;
#(`clock_period*20);
repeat(30)begin
Cin = 1'b1;
#(`clock_period);
Cin = 1'b0;
#(`clock_period*5);
end
#(`clock_period*20);
$stop;
end
endmodule
仿真波形:每一次Cin输出1, 就会计数一次(q加一)。q计数10的时候,Cout输出一次高电平。
2.两个四位计数器级联
BCD_Counter_top.v
module BCD_Counter_top(Clk,Cin,Rst_n,Cout,q);
input Clk;//计数器基准时钟
input Cin;//计数器进位输入
input Rst_n;//系统复位
output Cout;//计数器进位输出
output [11:0]q;//计数值输出
reg [3:0]cnt;//计数器的寄存器
wire Cout0,Cout1;
wire [3:0]q0,q1,q2;
assign q = {q2,q1,q0};
BCD_Counter BCD_Counter0(
.Clk(Clk),
.Cin(Cin),
.Cout(Cout0),
.Rst_n(Rst_n),
.q(q0)
);
BCD_Counter BCD_Counter1(
.Clk(Clk),
.Cin(Cout0),
.Cout(Cout1),
.Rst_n(Rst_n),
.q(q1)
);
BCD_Counter BCD_Counter2(
.Clk(Clk),
.Cin(Cout1),
.Cout(Cout),
.Rst_n(Rst_n),
.q(q2)
);
endmodule
BCD_Counter_top_tb.v
`timescale 1ns/1ns
`define clock_period 20
module BCD_Counter_top_tb;
//激励信号
reg Clk;
reg Cin;
reg Rst_n;
wire Cout;
wire [11:0]q;
//端口连接
BCD_Counter_top BCD_Counter_top0(
.Clk(Clk),
.Cin(Cin),
.Cout(Cout),
.Rst_n(Rst_n),
.q(q)
);
initial Clk = 1'b1;
always#(`clock_period/2)Clk = ~Clk;
initial begin
Rst_n = 1'b0;
Cin = 1'b0;
#(`clock_period*200);
Rst_n = 1'b1;
#(`clock_period*20);
Cin = 1'b1;
#(`clock_period*5000);
$stop;
end
endmodule
仿真波形:由于是三个四位计数器级联,理想结果是计数值q加到999的时候进位输出,然后q值清零。
3 .调试 修改代码
将判断条件改成 4'd8
再次仿真,观察到结果还是不对,添加counter0,1,2的波形,ctr+G 分组查看
如图,当counter0的q 值为9时,会产生一个Cout信号,这个Cout信号只有当一个时钟上升沿的时候才能被捕获到。 当下一个时钟上升沿来了,捕获Cout信号进行一次自加。 所以这个过程中q值的自加滞后了一个时钟。 当counter1的q值为9时,再产生一个Cout信号,等待下一个时钟上升沿到来时这个Cout信号才被捕获到,又滞后了一次。
改进代码:
这段代码,使得Cout的值滞后了一拍。所以要改成组合逻辑,就不用使用D触发器,就不会出现滞后一拍的情况。
修改成如下:
同时必须修改Cout类型 ,删掉reg,否则会报错
满足条件时 Cout输出1, 否则输出0。
分析与综合后,来到modelsim, 从新编译BCD_Counter文件
最后Cout在q值计数到999时输出1, 达到理想的结果