[Four-bit binary counter](Count15 - HDLBits (01xz.net))
module top_module (
input clk,
input reset, // Synchronous active-high reset
output [3:0] q);
always@(posedge clk)begin
if(reset)begin
q<=4'b0000;
end
else begin
q<=q+4'b0001;
end
end
endmodule
[Decade counter](Count10 - HDLBits (01xz.net))
module top_module (
input clk,
input reset, // Synchronous active-high reset
output [3:0] q);
always@(posedge clk)begin
if(reset)begin
q<=4'b0;
end
else begin
if(q>=4'd9)begin
q<=4'b0;
end
else begin
q<=q+4'b0001;
end
end
end
endmodule
[Decade counter again](Count1to10 - HDLBits (01xz.net))
module top_module (
input clk,
input reset,
output [3:0] q);
always@(posedge clk)begin
if(reset)begin
q<=4'b0001;
end
else begin
if(q>=4'b1010)begin
q<=4'b0001;
end
else begin
q<=q+1'b0001;
end
end
end
endmodule
[Slow decade counter](Countslow - HDLBits (01xz.net))
module top_module (
input clk,
input slowena,
input reset,
output [3:0] q);
always@(posedge clk)begin
if(reset)begin
q<=4'b0;
end
else if(slowena)begin
if(q==4'b1001)begin
q<=4'b0000;
end
else begin
q<=q+1'b0001;
end
end
end
endmodule
(33条消息) cannot match operand(s) in the condition to the corresponding edges in the enclosing event control o_cant match operand_muyangshaonian的博客-CSDN博客 在编写中遇到的报错,解决方法分享一下
[Counter 1-12](Exams/ece241 2014 q7a - HDLBits (01xz.net))
module top_module (
input clk,
input reset,
input enable,
output [3:0] Q,
output c_enable,
output c_load,
output [3:0] c_d
);
assign c_enable = enable;
assign c_load = reset | ((Q == 4'd12) && (enable == 1'b1));
assign c_d = c_load ? 4'd1 : 4'd0;
count4 the_counter (clk, c_enable, c_load, c_d , Q);
endmodule
- 针对这个题,首先要了解二进制计数器的端口,尤其是 load 负载端,例子可见《搭建你的数字积木》P 94-4.4.2,预制控制端口 load,当 load 为高电平时,预置数据输入端 d 的数值被送入计数器的寄存器。所以结合本题信息,c_load 信号用来判断是否置入信息,即是 0 或 1 或并不置入(这是三种状态),而 c_load 的这三状态又受控于三个信号,reset、Q?=12、enable?=1。
也即是此代码 assign c_load = reset | ((Q == 4'd12) && (enable == 1'b1));
: reset 优先级最高,当 reset 为 1,不用考虑后续,直接复位,c_load=1
当 reset 为 0,可如下图
![[e37547befc04a891ec034246e6e232f.jpg]]
只有最后一种情况时,c_load=1,置数
- 当 c_load=1,为 c_d 置入 0001,即回到初始值,符合题目要求;当 c_load 不等于 1 时,不用向 c_d 置入数,是无效状态,
assign c_d = c_load ? 4'd1 : 4'd0;
中的 d 0 为任何状态均可,只要写入一个数避免其产生锁存器即可,尝试验证,填入别的数依然验证成立
- HDLBits (103) — 1-12计数器 - 哔哩哔哩 (bilibili.com) 此为 B 站上的另一种写法,用了两个 always 模块,分开书写也可
- 此题有联想到数电中的芯片,有机会的再写一篇,将小芯片实物与 Verilog 语言相配对
[Counter 1000](Exams/ece241 2014 q7b - HDLBits (01xz.net))
module top_module (
input clk,
input reset,
output OneHertz,
output [2:0] c_enable
); //
wire[3:0] one, ten, hundred;
assign c_enable = {one == 4'd9 && ten == 4'd9, one == 4'd9, 1'b1};
assign OneHertz = {one == 4'd9 && ten == 4'd9 && hundred == 4'd9};
bcdcount counter0 (clk, reset, c_enable[0], one);
bcdcount counter1 (clk, reset, c_enable[1], ten);
bcdcount counter2 (clk, reset, c_enable[2], hundred);
endmodule
- 此题重点分为两部分实现,一是从 0 到 999 的逐位计数,二是实现分频
- 逐位计数:用三个 BCD 计数器分别去对个位、十位、百位表示(理念类似于数电实验中的逐位计数),个位计数永远是在进行的,故 c_enable(个位)始终为 1,因此也是最快计数器;十位计数只有等待各位到 9,才会触发一次进位,故判断条件为
one == 4'd9
,因此为较慢计数器;百位计数器则更慢,只有显示 99 时,才会进位,因此最慢
- 此处的分频操作理解为,当 1 kHz 完成后才会生成一个 1 Hz,所以只有当显示 999 时,才会生成一个 OneHertz 信号
[4-digit decimal counter](Countbcd - HDLBits (01xz.net))
module top_module (
input clk,
input reset, // Synchronous active-high reset
output [3:1] ena,
output [15:0] q);
reg [3:0]ones;
reg [3:0]tens;
reg [3:0]hundreds;
reg [3:0]thousands;
always@(posedge clk)begin
if(reset)begin
ones<=4'b0;
end
else begin
if(ones==4'd9)begin
ones<=4'b0;
end
else begin
ones<=ones+4'd1;
end
end
end
always@(posedge clk)begin
if(reset)begin
tens<=4'b0;
end
else begin
if(ones==4'd9&&tens==4'd9)begin
tens<=4'b0;
end
else if(ones==4'd9)begin
tens<=tens+4'd1;
end
end
end
always@(posedge clk)begin
if(reset)begin
hundreds<=4'b0;
end
else begin
if(ones==4'd9&&tens==4'd9&&hundreds==4'd9)begin
hundreds<=4'b0;
end
else if(ones==4'd9&&tens==4'd9)begin
hundreds<=hundreds+4'd1;
end
end
end
always@(posedge clk)begin
if(reset)begin
thousands<=4'b0;
end
else begin
if(ones==4'd9&&tens==4'd9&&hundreds==4'd9&&thousands==4'd9)begin
thousands<=4'b0;
end
else if(ones==4'd9&&tens==4'd9&&hundreds==4'd9)begin
thousands<=thousands+4'd1;
end
end
end //上面的四个模块分别是对个十百千位进行逐位递增判断
assign q={thousands,hundreds,tens,ones}; //对最终输出开始赋值
assign ena[1] = (ones == 4'd9) ? 1'b1 : 1'b0;
assign ena[2] = ((ones == 4'd9) && (tens == 4'd9)) ? 1'b1 : 1'b0;
assign ena[3] = ((ones == 4'd9) && (tens == 4'd9) && (hundreds == 4'd9)) ? 1'b1 : 1'b0; //与上一题一致
endmodule
[Count clock](Count clock - HDLBits (01xz.net))
module top_module(
input clk,
input reset,
input ena,
output pm,
output [7:0] hh,
output [7:0] mm,
output [7:0] ss);
reg pm_temp;
reg [3:0]hh_ones,hh_tens;
reg [3:0]mm_ones,mm_tens;
reg [3:0]ss_ones,ss_tens; //每一位都是由各自的两位组成
always@(posedge clk)begin //此模块只对秒的个位进行判断
if(reset)begin
ss_ones<=4'b0;
end
else begin
if(ena)begin //只有一个使能端
if(ss_ones==4'd9)begin
ss_ones<=4'b0;
end
else begin
ss_ones<=ss_ones+4'd1;
end
end
end
end
always@(posedge clk)begin //此模块只对秒的十位进行判断
if(reset)begin
ss_tens<=4'b0;
end
else begin
if(ena)begin //只有一个使能端
if(ss_tens==4'd5&&ss_ones==4'd9)begin
ss_tens<=4'b0;
end
else if(ss_ones==4'd9)begin
ss_tens<=ss_tens+4'd1;
end
end
end
end
always@(posedge clk)begin //此模块只对分的个位进行判断
if(reset)begin
mm_ones<=4'b0;
end
else begin
if(ena)begin //只有一个使能端
if(ss_tens==4'd5&&ss_ones==4'd9&&mm_ones==4'd9)begin
mm_ones<=4'b0;
end
else if(ss_tens==4'd5&&ss_ones==4'd9)begin
mm_ones<=mm_ones+4'd1;
end
end
end
end
always@(posedge clk)begin //此模块只对分的十位进行判断
if(reset)begin
mm_tens<=4'b0;
end
else begin
if(ena)begin //只有一个使能端
if(ss_tens==4'd5&&ss_ones==4'd9&&mm_ones==4'd9&&mm_tens==4'd5)begin
mm_tens<=4'b0;
end
else if(ss_tens==4'd5&&ss_ones==4'd9&&mm_ones==4'd9)begin
mm_tens<=mm_tens+4'd1;
end
end
end
end
always@(posedge clk)begin //此模块只对小时的个位进行判断
if(reset)begin
hh_ones<=4'b0010; //因为复位要回到中午十二点
end
else begin
if(ena)begin //只有一个使能端
if(ss_tens==4'd5&&ss_ones==4'd9&&mm_ones==4'd9&&mm_tens==4'd5&&hh_ones==4'd9)begin //从9点到10点,小时位
//的个位也从非零变化成0
hh_ones<=4'b0;
end
else if(ss_tens==4'd5&&ss_ones==4'd9&&mm_ones==4'd9&&mm_tens==4'd5&&hh_ones==4'd2&&hh_tens==4'd1)begin
hh_ones<=4'b1;
end //这个是专门为了中午十二点到下午一点的变化而准备的
else if(ss_tens==4'd5&&ss_ones==4'd9&&mm_ones==4'd9&&mm_tens==4'd5)begin //别的情况都是递增了
hh_ones<=hh_ones+4'd1;
end
end
end
end
always@(posedge clk)begin //此模块只对小时的十位进行判断
if(reset)begin
hh_tens<=4'b0001; //回到中午十二点
end
else begin
if(ena)begin //只有一个使能端
if(ss_tens==4'd5&&ss_ones==4'd9&&mm_ones==4'd9&&mm_tens==4'd5&&hh_ones==4'b0010&&hh_tens==4'b0001)begin
hh_tens<=4'b0;
end
else if(ss_tens==4'd5&&ss_ones==4'd9&&mm_ones==4'd9&&mm_tens==4'd5&&hh_ones==4'd9&&hh_tens==4'b0)begin
hh_tens<=4'b0001;
end
end
end
end
always@(posedge clk)begin
if(reset)begin
pm_temp<=1'b0;
end
else if(hh_tens==4'd1&&hh_ones==4'd1&&mm_tens==4'd5&&mm_ones==4'd9&&ss_tens==4'd5&&ss_ones==4'd9)begin
pm_temp<=~pm_temp;
end
end
assign pm=pm_temp;
assign ss = {ss_tens, ss_ones};
assign mm = {mm_tens, mm_ones};
assign hh = {hh_tens, hh_ones};
endmodule
- 此题代码量较大,但是只要细心分析,并没有多少思维上的难度,是基于前几题的提高版。
- 针对小时、分、秒的逐位判断,我采用的事每一位均用一个 4 位 BCD 码表示,代码会稍加麻烦,可见 B 站上的这种写法,以一个整体来判断小时或分或秒 HDLBits (106) — 12小时时钟 - 哔哩哔哩 (bilibili.com)
- 小时位的性质较特殊,所以可以直接描述,不用像较低位要不断用 if-else 判断
******
总结:
- 这一节 Counters(计数器)的题目灵活且量大,屡屡让我回忆起当时数电实验的芯片,会在后续补充代码与芯片的配合分析,计数器是一种很有意思的设计,方法多样