Count15
一、题目要求
构建一个4位二进制计数器,计数从0到15(包括15),周期为16。复位输入是同步的,应该将计数器复位为0
二、分析
这里需要设计一个计数器,每来一个时钟信号,则输出q计数一次,即加q+1。如果q大于f(1111),则输出q复位为0。并且如果reset==1,则输出也会复位为0。这里我们可以先判断reset的状态来设置输出q是否复位,进而每有一个上升沿,输出q+1,并且判断如果q大于15(注意题目要求包括15,因此要在q=16时,才复位),则输出为0。代码如下
module top_module (
input clk,
input reset, // Synchronous active-high reset
output [3:0] q);
always @ (posedge clk)
begin
if(reset==1)
q<=4'b0;
else
q<=q+1'b1;
if(q>4'b1111)
q<=4'b0;
end
endmodule
三、仿真图
Count10
一、题目要求
构建一个从0到9(包括9)的十进制计数器,周期为10。复位输入是同步的,应该将计数器复位为0
二、分析
这里需要设计一个计数器,每来一个时钟信号,则输出q计数一次,即加q+1。如果q大于9(1001),则输出q复位为0。并且如果reset==1,则输出也会复位为0。这里我们可以先判断reset的状态来设置输出q是否复位,进而每有一个上升沿,输出q+1,并且判断如果q大于8(此时q=9),则输出为0。代码如下
module top_module (
input clk,
input reset, // Synchronous active-high reset
output [3:0] q);
always @ (posedge clk)
begin
if(reset==1)
q<=4'b0;
else
q<=q+1'b1;
if(q>4'b1000)
q<=4'b0;
end
endmodule
三、仿真图
Count1to10
一、题目要求
制作一个从1数到10的10年计数器。复位输入是同步的,应该将计数器复位为1
(波形图是从1计数到5的,而题目是从1计数到10)
二、分析
这里需要设计一个计数器,每来一个时钟信号,则输出q计数一次,即加q+1。如果q大于9(1001),则输出q复位为1。并且如果reset==1,则输出也会复位为1。这里我们可以先判断reset的状态来设置输出q是否复位,进而每有一个上升沿,输出q+1,并且判断如果q大于10,则输出为1。代码如下
module top_module (
input clk,
input reset, // Synchronous active-high reset
output [3:0] q);
always @ (posedge clk)
begin
if(reset==1)
q<=4'b0001;
else
q<=q+1'b1;
if(q>4'b1001)
q<=4'b0001;
end
endmodule
三、仿真图
Countslow
一、题目要求
构建一个从0到9(包括9)的十进制计数器,周期为10。复位输入是同步的,应该将计数器复位为0。我们希望能够暂停计数器,而不是总是在每个时钟周期增加,因此slowena输入指示计数器何时应该增加。
二、分析
这里需要设计一个计数器,每来一个时钟信号,则输出q计数一次,即加q+1。如果q大于9(包含9),则输出q复位为0。并且如果reset==1,则输出也会复位为0。这里我们可以先判断reset的状态来设置输出q是否复位,进而在reset=0的时候判断slowena,如果slowena=0则输出保持不变,为1则进而每有一个上升沿,输出q+1,并且判断如果q大于8(此时q=9,如果slowena=1则会在下一个时钟信号到来时,复位为0,否则会保持不变),则输出为0。代码如下
module top_module (
input clk,
input slowena,
input reset,
output [3:0] q);
always @ (posedge clk)
begin
if(reset==1)
begin
q<=4'b0;
end
else //reset=0
begin
if(slowena==1)
begin
q<=q+1'b1;
if(q>4'b1000)
q<=4'b0;
end
if(slowena==0)
q<=q;
end
end
endmodule
三、仿真图
Exams/ece241 2014 q7a
一、题目要求
设计1-12计数器,输入输出如下:
Reset:同步活动高电平复位,强制计数器为1
enable:设置计数器运行的高值
Clk:上升沿触发时钟输入
Q[3:0]:计数器的输出
c_enable, c_load, c_d[3:0]为进入提供的4位计数器的控制信号,因此可以验证正确的操作。
您有以下组件可用:
1.下面的4位二进制计数器(count4),它具有Enable和同步并行负载输入(load的优先级高于Enable)。提供了count4模块。在你的电路中实例化。
2.逻辑门
module count4(
input clk,
input enable,
input load,
input [3:0] d,
output reg [3:0] Q
);
c_enable、c_load和c_d输出分别是进入内部计数器的enable、load和d输入的信号。它们的目的是允许检查这些信号的正确性。
二、分析
本题要求设计一个从1计数到12的计数器,并且计数器有同步复位端reset,有效时,输出置位为1。并且还有enable端,只有在enable有效,即高电平时,电路才工作,否则电路输出为1。
clk为时钟上升沿触发器信号。并且题目已经给了你计数器的模块,不需要你重新写计数器的实现代码,只需要实例化模块即可。这里load为同步并行输入信号,一旦出现复位信号或者输出Q计数到12且enable有效时,load便将1输入到计数器当中,使其复位为1。大致模块图如下
这里有一个地方需要注意,Q和enable相与是Q=12且enable=1的情况,因为count4是模块化好了的,正常来讲这里需要用到四个触发器,对应四个输出Q0-Q3(已封装在count4),Q=12,对应二进制1100,所以应该取Q3&Q2&~Q1& ~Q0&enable。这里图上简化了。并且verilog可以用if语句或者三目运算符来设计组合电路,即if((Q==4’b1100&enable)|reset),load=1。或者assign load = (((Q == 4’b1100)&enable) | (reset) ) ? 1’b1 : 1’b0。注意需要定义一个中间变量来存储load1的结果,再接入模块count4。模块conut4的输入信号给1,表示有效即可,这里系统会自动帮你处理。然后根据上述模块图实例化模块即可。代码如下
module top_module (
input clk,
input reset,
input enable,
output [3:0] Q,
output c_enable,
output c_load,
output [3:0] c_d
); //
wire load1;
assign load1 = (((Q == 4'b1100)&enable) | (reset) ) ? 1'b1 : 1'b0;
count4 re_count4(
.clk(clk),
.load(load1),
.enable(enable),
.d(4'b1),
.Q(Q));
assign c_enable = enable;
assign c_load = load1;
assign c_d = 4'b1;
endmodule
三、仿真图
Exams/ece241 2014 q7b
一、题目要求
从一个1000Hz的时钟,得到一个1Hz的信号,称为一赫兹,可以用来驱动一组小时/分钟/秒计数器的使能信号,以创建一个数字挂钟。因为我们想让时钟每秒计数一次,所以一赫兹信号必须每秒精确地断言一个周期。使用模10 (BCD)计数器和尽可能少的其他门构建分频器。还要从您使用的每个BCD计数器输出启用信号(c_enable[0]用于最快的计数器,c_enable[2]用于最慢的计数器)。
为您提供以下BCD计数器。使能值必须为高,计数器才能运行。复位是同步的,设置高迫使计数器为零。电路中的所有计数器必须直接使用相同的1000hz信号。
module bcdcount (
input clk,
input reset,
input enable,
output reg [3:0] Q
);
二、分析
根据题目,我们需要设计一个计数器计数容量为1000,即从0计数到999。题目给了一个模10计数器的模块,因为1000=10 * 10 * 10。因此我们需要三个模10计数就能构成一个模1000的计数器。不妨将这三个计数器的输出按高位到低位记为Q3,Q2,Q1。则Q3Q2Q1从000到999。当计数到999时,Q3Q2Q1复位为0,并且向高位进位为1,即题目代码给的OneHertz=1。所以Q1负责999的个位计数,Q2负责999的十位计数,Q3负责999的百位计数。大概的电路图如下
onehertz前的正方形框表示如果Q3Q2Q1计数到999的逻辑关系,这里省略了其中的电路结构。然后c_enable[0]到c_enable[2]分别为bcd1到bcd3的使能端,高电平有效。电路工作的逻辑是这样的。三个计数器clk,reset都接同一个clk和reset。因为Q3Q2Q1是Q1从0计数到9,满10向高位进1,所以当Q1=9的时候,在下一个clk上升沿到来时,Q1复位为0,而Q1应该加1,即开始工作并且完成加1操作。这时就表示计数到了10。也就是说,只有前一个计数器计满以后,后一个计数器才开始工作,所以三个计数器不是同时工作的。所以Q1一直在完成加1操作,使能端一直为1。当Q1计满,即等于9,Q2使能有效,在下一个时钟信号到来时完成加1操作。当Q1Q2计满,即Q1Q2=99,Q3开始工作,使能端为1。最后判断Q3Q2Q1是否等于999,是则输出1,否则输出0。
因为是模块实例化,所以需要定义三个中间变量Q1,Q2,Q3来暂存三个计数器的输出状态。代码如下
module top_module (
input clk,
input reset,
output OneHertz,
output [2:0] c_enable
); //
reg [3:0] Q1,Q2,Q3;
//按上图先模块化实例,即连接模块
bcdcount count1(
.clk(clk),
.reset(reset),
.enable(c_enable[0]),
.Q(Q1));
bcdcount count2(
.clk(clk),
.reset(reset),
.enable(c_enable[1]),
.Q(Q2));
bcdcount count3(
.clk(clk),
.reset(reset),
.enable(c_enable[2]),
.Q(Q3));
always @ (*)
begin
c_enable[0]<=1'b1;//第一个计数器使能端enable为1
end
always @ (*)
begin
if(Q1==4'd9)
c_enable[1]<=1'b1;
else
c_enable[1]<=1'b0;
end
always @ (*)
begin
if(Q1==4'd9&&Q2==4'd9)
c_enable[2]<=1'b1;
else
c_enable[2]<=1'b0;
end
//判断输出1的代码块,若考虑复位信号替换此处
always @ (*)
begin
if(Q1==4'd9 && Q2==4'd9 && Q3==4'd9)
OneHertz<=1'b1;
else
OneHertz<=1'b0;
end
endmodule
这题比较特别,复位信号reset恒为0,所以不需要考虑,如果考虑的话,需要替换成下列代码
always @ (posedge clk)
begin
if(reset==1'b1)
OneHertz<=1'b0;
else if(Q1==4'd8 && Q2==4'd9 && Q3==4'd9)
OneHertz<=1'b1;
else
OneHertz<=1'b0;
end
注意这里判断的是Q3Q2Q1=998的情况,用999的话会报错,查了资料才知道是因为用always就会延迟一个时钟,所以到998即可,如果用电平触发的话就不会延时,所以可以写到999。
三、仿真图
Countbcd
一、题目要求
构建一个4位BCD(二进制编码的十进制)计数器。每个十进制数字用4位编码:q[3:0]是个位数,q[7:4]是十位,等等。对于信号[3:1],还输出一个enable信号,指示何时应增加前三位数字中的每一位
二、分析
一位的BCD十进制加法器可以从0计数到9。题目要求构建四位的BCD,即十进制加法器,可以从0000计数到9999。每个十进制用4位编码表示,如果同步复位信号reset有效,则在下一个时钟上升沿输出值0,否则按下列思路进行运算。因为q[3:0]表示个位,个位需要一直加1,一旦个位计数到9,则此时ena[1]等于1(ena表示前三位何时需要加1,注意前三位指千位百位十位),表示十位此时需要加1,则十位q[7:4]的值加1,个位归零,重复下一次加1操作。同样一旦个位q[3:0]和十位q[7:4]都加到9,此时ena[2]=1,表示百位需要加1。则百位q[11:8]加1,。当个十百位计数到999时,ena[3]=1,表示千位需要加1,千位q[15:12]加1。所以reset控制输出是否置零,ena控制对应位是否需要加1。这样,根据逻辑关系可以得到下列代码
module top_module (
input clk,
input reset, // Synchronous active-high reset
output [3:1] ena,
output [15:0] q);
//个位
always @ (posedge clk)
begin
if(reset==1)
begin
q[3:0]<=4'b0;
end
else if(q[3:0]==4'd9)
begin
q[3:0]<=4'b0;
end
else
begin
q[3:0]<=q[3:0]+1'b1;
end
end
assign ena[1]=(q[3:0]==4'd9)? 1'b1:1'b0;
//十位
always @ (posedge clk)
begin
if(reset==1)
begin
q[7:4]<=4'b0;
end
else if(ena[1]==1'b1)
begin
if(q[7:4]==4'd9)
begin
q[7:4]<=4'b0;
end
else
begin
q[7:4]<=q[7:4]+1'b1;
end
end
end
assign ena[2]=(q[3:0]==4'd9&&q[7:4]==4'd9)? 1'b1:1'b0;
//百位
always @ (posedge clk)
begin
if(reset==1)
begin
q[11:8]<=4'b0;
end
else if(ena[2]==1'b1)
begin
if(q[11:8]==4'd9)
begin
q[11:8]<=4'b0;
end
else
begin
q[11:8]<=q[11:8]+1'b1;
end
end
end
assign ena[3]=(q[3:0]==4'd9&&q[7:4]==4'd9&&q[11:8]==4'd9)? 1'b1:1'b0;
//千位
always @ (posedge clk)
begin
if(reset==1)
begin
q[15:12]<=4'b0;
end
else if(ena[3]==1'b1)
begin
if(q[15:12]==4'd9)
begin
q[15:12]<=4'b0;
end
else
begin
q[15:12]<=q[15:12]+1'b1;
end
end
end
endmodule
三、仿真图
Count clock
一、题目要求
创建一组适合作为12小时时钟使用的计数器(带有am/pm指示器)。您的计数器由一个快速运行的时钟进行计时,每当您的时钟应该增加时(即每秒一次),就会有一个脉冲。
reset将时钟重置到12:00 AM。pm是0表示AM, 1表示pm。hh、mm和ss是两个BCD(二进制编码十进制)数字,分别表示小时(01-12)、分钟(00-59)和秒(00-59)。Reset具有比enable更高的优先级,并且即使在未启用时也可能发生。
二、分析
本题是设计一个12小时的时钟,其中hh[7:0]表示小时位,范围为1到12,mm[7:0]表示分钟位,范围为00到59,ss[7:0]表示秒位,范围为00到59。所以应从01:00:00计数到12:59:59。pm=0表示AM早上(00时到12时),pm=1表示PM下午(即13时到24时)。秒位一直处于计数状态,即每来一个时钟上升沿就计数一次。一旦秒计数到59,则给出一个进位信号,此时分钟位mm加1,秒位清零,分钟位等待下一个秒向分钟的进位信号才能继续加1。同样的,当分钟和秒位计数到59分59秒时,向小时位给出一个进位信号,小时位加1,分钟和秒位清零。而reset为复位信号,一旦reset有效,输出会被置位为12时00分00秒,另外如果计数到12时59分59秒,则复位为01:00:00。reset优先级最高,一旦reset无效,而使能端ena有效,则开始计数。如果ena=0,则输出保持不变,在波形图里边当ena=0的时候,hh和mm,ss都保持为8’h12,8‘h00,8’h02不变。秒位从00计数到59,共有两位,低位从0计数到9,则向高位进一,使得高位从0计数到5。分钟位和小时位同理。
故逻辑如下:定义以下变量
reg [3:0] hh_low,mm_low,ss_low;//表示小时位,分钟位和秒位的低位
reg [3:0] hh_high,mm_high,ss_high;//表示小时位,分钟位和秒位的高位
wire ss_low_to_high;//秒位的低位向高位的进位信号
wire ss_high_to_mm_low;//秒位的高位向分钟位低位的进位信号
wire mm_low_to_high;//分钟位的低位向分钟位高位的进位信号
wire mm_high_to_hh_low;//分钟位的高位向小时位的进位信号
wire hh_low_to_hh_high;//小时位的低位向小时位的高位的进位信号
//高位和低位合并
assign hh={hh_high,hh_low};
assign mm={mm_high,mm_low};
assign ss={ss_high,ss_low};
在时钟信号clk的上升沿,如果reset有效,则输出置位为12:00:00。这里暂不考虑复位的情况。这里还要注意在不考虑reset的情况下,ena控制的整个时钟的开始和暂停,ena=1,开始计数,否则保持不变。所以下边每次判断是否计数时都要考虑ena的状态
秒位:先判断ena的状态,如果ena=1,则ss_low开始计数,一旦计数到9,即ss_low=9,秒位的低位向高位的进位信号ss_low_to_high=1,同时ss_low清零。此时ss_high加1。所以ss_high高位加1的条件是ss_low=9且ena=1。此时时钟为 ??:??:?9。同样一旦ss_high计数到5,即ss_high=5,并且ss_low=9,秒位的高位向分钟位低位的进位信号ss_high_to_mm_low=1,此时mm_low加1,同时ss_high清零,因为此时ss_low等于9,在下一个时钟信号会自动清零(上一个判断已经给出清零的条件),所以这样直接令ss_high=0即可。所以mm_low开始计数的条件是ss_low=9且ss_high=5且ena=1。此时时钟为??:??:59。如果reset有效则秒位全部清零
分钟位:mm_low开始计数,一旦计数到9,即mm_low=9,并且ss_low=9,ss_high=5,则分钟位的低位向分钟位高位的进位信号mm_low_to_high=1,此时mm_high开始计数,同时mm_low清零,所以mm_high开始计数的条件为ss_low=9,ss_high=5,mm_low=9,ena=1。
此时时钟为??:?9:59。mm_high一旦开始计数到5,且ss_low=9,ss_high=5,mm_low=9,此时分钟位的高位向小时位的进位信号mm_high_to_hh_low=1,hh_low开始计数。所以hh_low的计数条件为ss_low=9,ss_high=5,mm_low=9,mm_high=5,ena=1。同时mm_high清零。此时时钟为??:59:59。如果reset有效则分钟位全部清零
小时位:因为小时位是从01计数到12的,所以时钟应该从01:00:00计数到12:59:59(如果是00计数到11就是00:00:00到11:59:59,这是我们生活中常用的,本题比较特殊)。因为reset有效的时候是复位到12时的,所以先考虑hh_low,如果reset有效,则hh_low=2。否则hh_low开始计数,hh_low有两种情况需要分析。第一种是如果是从01:00:00计数到09:59:59,即如果ss_low=9,ss_high=5,mm_low=9,mm_high=5,hh_low=9,hh_high=0,ena=1,则hh_low=0(09:59:59再加1就是10:00:00)。第二种是如果是从10:00:00计数到12:59:59,即如果ss_low=9,ss_high=5,mm_low=9,mm_high=5,hh_low=2,hh_high=1,ena=1,则hh_low=1(12:59:59再加1就是01:00:00)。
hh_high位的判断如下,如果reset等于1,即有效,复位为12:00:00,所以hh_high=1,如果为12:59:59,即ss_low=9,ss_high=5,mm_low=9,mm_high=5,hh_low=2,hh_high=1,ena=1,则hh_high=0(12:59:59再加1就是01:00:00)。如果是从01:00:00计数到09:59:59,则判断条件为s_low=9,ss_high=5,mm_low=9,mm_high=5,hh_low=9,hh_high=0,ena=1,则hh_high=1即可。
pm位:如果复位信号reset=1有效,pm=0。否则如果计数到11:59:59,pm=1,再计数到下一个计数到11:59:59时,pm取0。故我们直接让pm翻转即可。翻转可以用取反的逻辑关系得到。不需要给pm赋初值,系统默认上电为低电平。
根据上述思路得到以下代码,代码很长但理解了上述逻辑很容易写出来
module top_module(
input clk,
input reset,
input ena,
output pm,
output [7:0] hh,
output [7:0] mm,
output [7:0] ss);
reg [3:0] hh_low,mm_low,ss_low;//表示小时位,分钟位和秒位的低位
reg [3:0] hh_high,mm_high,ss_high;//表示小时位,分钟位和秒位的高位
wire ss_low_to_high;//秒位的低位向高位的进位信号
wire ss_high_to_mm_low;//秒位的高位向分钟位低位的进位信号
wire mm_low_to_high;//分钟位的低位向分钟位高位的进位信号
wire mm_high_to_hh_low;//分钟位的高位向小时位的进位信号
wire hh_low_to_hh_high;//小时位的低位向小时位的高位的进位信号
//高位和低位合并
assign hh={hh_high,hh_low};
assign mm={mm_high,mm_low};
assign ss={ss_high,ss_low};
//秒位的低位开始计数
always @ (posedge clk)
begin
if(reset==1)
begin
ss_low<=4'b0;
end
else if(ena==1)//ena是使能信号,只有为1时,时钟才开始计数
begin
if(ss_low==4'd9) //从0计数到9,即 **:**:*9
begin
ss_low<=4'b0;
end
else
begin
ss_low<=ss_low+1'b1;
end
end
end
assign ss_low_to_high=(ss_low==4'd9 && ena==1'b1)? 1'b1:1'b0;
//秒位的高位位开始计数
always @ (posedge clk)
begin
if(reset==1)
begin
ss_high<=4'b0;
end
else if(ss_low_to_high==1)
begin
if(ss_low==4'd9 && ss_high==4'd5 && ena) // **:**:59
begin
ss_high<=4'b0;
end
else
begin
ss_high<=ss_high+1'b1;
end
end
end
assign ss_high_to_mm_low=(ss_low==4'd9 && ss_high==4'd5 && ena==1'b1)? 1'b1:1'b0;
//分钟位的低位位开始计数
always @ (posedge clk)
begin
if(reset==1)
begin
mm_low<=4'b0;
end
else if(ss_high_to_mm_low==1'b1)
begin
if(ss_low==4'd9 && ss_high==4'd5 && mm_low==4'd9 && ena==1'b1) // **:*9:59
begin
mm_low<=4'b0;
end
else
begin
mm_low<=mm_low+1'b1;
end
end
end
assign mm_low_to_high=(ss_low==4'd9 && ss_high==4'd5 && mm_low==4'd9 && ena==1'b1)? 1'b1:1'b0;
//分钟位的高位开始计数
always @ (posedge clk)
begin
if(reset==1)
begin
mm_high<=4'b0;
end
else if(mm_low_to_high==1)
begin
if(ss_low==4'd9 && ss_high==4'd5 && mm_low==4'd9 &&mm_high==4'd5&& ena==1'b1)//**:59:59
begin
mm_high<=4'b0;
end
else
begin
mm_high<=mm_high+1'b1;
end
end
end
assign mm_high_to_hh_low=(ss_low==4'd9 && ss_high==4'd5 && mm_low==4'd9 && mm_high==4'd5 && ena==1'b1)? 1'b1:1'b0;
//小时位的低位计数
always @ (posedge clk)
begin
if(reset==1)
begin
hh_low<=4'd2;
end
else if(mm_high_to_hh_low==1)
begin
if(ss_low==4'd9 && ss_high==4'd5 && mm_low==4'd9 && mm_high==4'd5 && hh_low==4'd2 && hh_high==4'd1 && ena==1'b1)//11:59:59
begin
hh_low<=4'd1;
end
else if(ss_low==4'd9 && ss_high==4'd5 && mm_low==4'd9 && mm_high==4'd5 && hh_low==4'd9 && hh_high==4'd0 && ena==1'b1)//09:59:59
begin
hh_low<=4'd0;
end
else
begin
hh_low<=hh_low+1'b1;
end
end
end
assign hh_low_to_hh_high = (ss_low==4'd9 && ss_high==4'd5 && mm_low==4'd9 && mm_high==4'd5 && hh_low==4'd9 && hh_high==4'd0 && ena==1'b1)? 1'b1:1'b0;
//小时位的高位计数
always @ (posedge clk)
begin
if(reset==1)
begin
hh_high<=4'b1;
end
else if(ss_low==4'd9 && ss_high==4'd5 && mm_low==4'd9 && mm_high==4'd5 && hh_low==4'd2 && hh_high==4'd1 && ena)//12:59:59--01:00:00
hh_high<=4'b0;
else if(hh_low_to_hh_high) //09:59:59--10:00:00
begin
hh_high<=1'b1;
end
end
//pm的状态判断
always @ (posedge clk)
begin
if(reset==1)
begin
pm<=1'b0;
end
else if(ss_low==4'd9 && ss_high==4'd5 && mm_low==4'd9 && mm_high==4'd5 && hh_low==4'd1 && hh_high==4'd1 && ena==1'b1)
begin
pm <= ~pm;
end
end
endmodule
三、仿真图