本文简单介绍了Verilog,并使用Verilog设计了一款计数器
前言
就当前来说,学习Verilog仍然具有很大的价值,尤其是对于从事或有兴趣从事数字电路设计、集成电路设计、电子系统设计或硬件工程领域的人来说。
一、Verilog是什么?
Verilog是一种硬件描述语言(HDL),用于描述数字电路和系统的结构和行为。它广泛用于数字电路设计、集成电路设计和电子系统设计领域。
Verilog最早由Gateway Design Automation公司于1984年开发,现在已经成为通用的硬件描述语言,并被广泛应用于各种数字电路设计任务中。它的设计目标是提供一种可读性强、易于理解和精确描述数字电路的语言,以便设计工程师能够使用它来描述、设计和验证数字电路。
Verilog提供了描述数字逻辑元素(如门、寄存器、触发器等)和它们之间连接的语法和语义。使用Verilog,可以对数字电路的逻辑功能、时序特性和结构进行建模。Verilog代码由模块组成,模块定义了数字电路的接口和行为。通过实例化各个模块并连接它们,可以构建更复杂的电路和系统。
Verilog还提供了一些高级功能,如层次结构建模、测试向导和仿真功能,这些功能有助于验证电路和系统的正确性。
总而言之,Verilog是一种用于描述数字电路和系统的硬件描述语言,被广泛应用于电子设计自动化领域,并在数字电路设计、集成电路设计和电子系统设计中发挥重要作用。
二、设计计数器
1.设计思路
在这里,我采用了数字电路设计的方法去设计了一款有时钟信号驱动的模为三位数的计数器,即用两个三个不同的模值的计数器来联立构成一个模更大的计数器,并用数码管显示其数值。该设计思路代码虽然较长,但其代码结构更容易观察。当然,存在更直接简洁的设计方法,这里并没有展示。
2.代码
module CNT (CLK,RST,EN,M,DOUT1,DOUT2,DOUT3,COUT1,COUT2); //模块接口声明:该模块具有6个输入端口(CLK、RST、EN、M)和5个4位输出端口(DOUT1, DOUT2, DOUT3, COUT1, COUT2)
input CLK,EN,RST,M;
output[3:0] DOUT1,DOUT2,DOUT3,COUT1,COUT2;
reg[3:0] Q1,Q2,Q3; //寄存器声明:模块内部定义了三个4位宽的寄存器 Q1、Q2 和 Q3 用于存储计数值。
reg[6:0] SG0,SG1,SG2;
reg COUT1,COUT2,COUT3,cnt,clk1;
assign DOUT1=Q1;
assign DOUT2=Q2;
assign DOUT3=Q3;
//分频计数器:使用 `always @(posedge CLK)` 块实现了一个分频计数器。每当 CLK 上升沿触发时,计数器 cnt 自增,当 cnt 达到49999999(约50MHz时钟下的分频)时,将 clk1 置为高电平,并将 cnt 重置为0,用来生成一个较低频率的时钟信号 clk1。
always @(posedge CLK)
begin cnt=cnt+1;
if (cnt>49999999) begin clk1=1'b1; cnt=0; end
else clk1=1'b0; //50000000分频
end
//计数器 Q1 的递增和溢出:使用 `always @(posedge clk1 or negedge RST)` 块实现了 Q1 的递增和溢出检测。当 RST 为低电平时,将 Q1 重置为0;当 EN 为高电平时,在每个 clk1 的上升沿触发时,如果 Q1 小于 9,则 Q1 递增1,否则将 Q1 重置为0。
always @(posedge clk1 or negedge RST)
begin
if (!RST) Q1 <= 0;
else if(EN)
begin
if (Q1<9) Q1 <= Q1+1;
else Q1<=4'b0000;
end
end
always @(Q1)
if (Q1==4'h9) COUT1=1'b1;
else COUT1=1'b0;
//计数器 Q2 的递增和溢出:使用 `always @(negedge COUT1 or negedge RST)` 块实现了 Q2 的递增和溢出检测。当 RST 为低电平时,将 Q2 重置为0;当 EN 为高电平时,在每个 COUT1 信号的负边沿或 RST 的负边沿触发时,如果 Q2 小于 9,则 Q2 递增1,否则将 Q2 重置为0。
always @(negedge COUT1 or negedge RST)
begin
if (!RST) Q2 <= 0;
else if(EN)
begin
if (Q2<9) Q2 <= Q2+1;
else Q2<=4'b0000;
end
end
always @(Q2)
if (Q2==4'h9) COUT2=1'b1;
else COUT2=1'b0;
//计数器 Q3 的递增和溢出:使用 `always @(negedge COUT2 or negedge RST)` 块实现了 Q3 的递增和溢出检测。当 RST 为低电平时,将 Q3 重置为0;当 EN 为高电平时,在每个 COUT2 信号的负边沿或 RST 的负边沿触发时,如果 Q3 小于 (1+M)(M 是一个输入参数),则 Q3 递增1,否则将 Q3 重置为0。
always @(negedge COUT2 or negedge RST)
begin
if (!RST) Q3 <= 0;
else if(EN)
begin
if (Q3<(1+M)) Q3 <= Q3+1;
else Q3<=4'b0000;
end
end
//7段数码管显示:在 `always @(posedge clk1)` 块中,根据 Q1、Q2 和 Q3 的值,使用 case 语句为 DOUT1、DOUT2 和 DOUT3 分配相应的7段译码值,将其分别赋给 SG0、SG1 和 SG2 用于7段数码管的显示。
always @(posedge clk1)
begin
case (DOUT1)
0:SG0<=7'b1000000; 1:SG0<=7'b1111001;
2:SG0<=7'b0100100; 3:SG0<=7'b0110000;
4:SG0<=7'b0011001; 5:SG0<=7'b0010010;
6:SG0<=7'b0000010; 7:SG0<=7'b1111000;
8:SG0<=7'b0000000; 9:SG0<=7'b0010000; //7段译码值
default: SG0=7'b0000000;
endcase
case (DOUT2)
0:SG1<=7'b1000000; 1:SG1<=7'b1111001;
2:SG1<=7'b0100100; 3:SG1<=7'b0110000;
4:SG1<=7'b0011001; 5:SG1<=7'b0010010;
6:SG1<=7'b0000010; 7:SG1<=7'b1111000;
8:SG1<=7'b0000000; 9:SG1<=7'b0010000; //7段译码值
default: SG1=7'b0000000;
endcase
case (DOUT3)
0:SG2<=7'b1000000; 1:SG2<=7'b1111001;
2:SG2<=7'b0100100; 3:SG2<=7'b0110000;
4:SG2<=7'b0011001; 5:SG2<=7'b0010010;
6:SG2<=7'b0000010; 7:SG2<=7'b1111000;
8:SG2<=7'b0000000; 9:SG2<=7'b0010000; //7段译码值
default: SG2=7'b0000000;
endcase
end
endmodule
总结
在总体上,这段代码实现了一个计数器模块,通过输入时钟信号 CLK、复位信号 RST、使能信号 EN 和参数 M,以及内部的计数器和逻辑电路,实现了基于分频的计数器功能,并将计数结果分别显示在三个4位的数码管上。同时,根据计数值和溢出情况,产生了两个溢出标志 COUT1 和 COUT2。