首页 > 分享 > 计数器的Verilog实现

计数器的Verilog实现

一、计数器简介

        计数器是一种在数字电子系统中常见的逻辑电路,用于记录输入脉冲或时钟信号的数量。计数器的作用是在输入信号发生变化时,将一个内部计数值递增或递减。通常用于测量时间、频率、脉冲数量等。

        常见的计数器有:

递增计数器(Up Counter): 每次输入一个时钟脉冲时,计数器的值递增。当达到最大计数值时,计数器可以溢出,重新从零开始。

递减计数器(Down Counter): 每次输入一个时钟脉冲时,计数器的值递减。当达到最小计数值时,计数器可以溢出,重新从最大值开始。

同步计数器(Synchronous Counter): 计数操作与时钟信号同步进行。所有触发器在同一时钟边沿触发。

异步计数器(Asynchronous Counter): 计数操作不一定与时钟信号同步。不同阶段的触发器可以在不同时钟边沿触发。

可编程计数器: 允许用户根据需要编程计数器的初始值、最大值、最小值等参数。

环形计数器(Ring Counter): 一种特殊的计数器,只有一个触发器处于“1”的状态,其余为“0”,而且这个“1”在每个时钟脉冲中移动。

        本文按照明德杨的框架详细阐述如何编写计数器Verilog代码。

二、计数器代码规则

        在构建计数器时,只需要考虑三部分,即初值,计数条件和结束值。初值最好设为0,计数值为计数个数减1。在明德杨规范中,计数条件写为aa_cnt,结束计数条件为add_cnt&&cnt==x-1。即当计数到x且满足计数条件时结束计数,增加add_cnt这一条件的目的在于区分复位值和初始默认值(在初始时认为计数条件不满足,即逻辑值为0)。同时明德杨还规定在限定范围时,最好使用>=和<符号,避免对于边界值的考虑。例如要取前6个数,则cnt>=0&&cnt<6,从5开始取10个数,cnt>=5&&cnt<10+5。

以下题为例:

 要求计数器从0到9之间计数,上升沿触发,同步复位,复位到0。计数模块的代码编写如下:

always@(posedge clk)

begin

if(reset)

q<=4'b0000;

else if(add_cnt)//计数条件

begin

if(end_cnt)//计数结束条件

q<=4'b0000;

else

q<=q+1;

end

end

 接下来对其中的计数条件和结束计数条件作描述

always@(posedge clk)

begin

add_cnt=1'b1;

end

assign end_cnt=add_cnt&&(q==10-1);

三、示例(时钟)

大致中文翻译为:

创建一组适用于12小时制时钟(带有AM/PM指示器)的计数器。您的计数器由一个快速运行的时钟信号(clk)驱动,每当时钟应该递增时(即每秒一次),ena信号会脉冲一次。

reset信号将时钟复位为12:00 AM。pm信号用于表示AM为0,PM为1。hh、mm和ss分别表示小时(01-12)、分钟(00-59)和秒(00-59),每个都是用二进制编码十进制(BCD)表示。在不启用时,复位具有更高的优先级,并且可以在未启用时发生。

以下时序图显示了从上午11:59:59滚动到下午12:00:00的行为,以及同步复位和启用的行为。

设计计数结构

要实现时钟计数,则需要构建三个计数模块,时、分、秒。其中每个计数模块中要分为十位和个位,个位的计数范围为0~9,十位的计数范围为0~6,综合来看,分、秒的计数范围都为0~59,时的计数范围为0~11。

秒的个位计数条件为使能信号ena脉冲,即add_s_ones=ena。结束条件为end_s_ones=add_s_ones&&(s_ones==4'd9)。十位计数条件为add_s_tens=end_s_ones,结束条件为end_s_tens=add_s_tens&&(s_tens==4'd5)。即当秒钟的个位计数到9时,复位到0,同时十位计数1;

分的个位计数条件为add_m_ones=end_s_tens,结束条件为end_m_tens=add_m_ones&&(s_ones==4'd9)。十位的计数条件为add_m_tens=end_s_ones,结束条件为end_m_tens=add_m_tens&&(m_tens==4'd5);

对于时位的设计稍显复杂。当时位是0时,个位可以由0增加到9,个位再复位到0,同时十位增加到1,当时位是1,个位只能由0增加到2,然后十位个位都复位到0。因此十位为0 时,个位的结束条件为end_h_ones_0=add_h_ones&&(h_ones==4'd9),十位为1时个位的结束条件为end_h_ones_1=add_h_ones && ((h_ones == 4'd2) && (h_tens == 4'd1))。当个位为2十位为1时,结束十位为1 的状态,因此有end_h_tens_1 = add_h_tens && end_h_ones_1。当个位为9时,结束十位为0的状态,因此有end_h_tens_0 =add_h_tens && end_h_ones_0。

代码实现

1.变量设定

reg pm_temp;//区分上午下午

reg [3:0] s_ones;//秒的个位

reg [3:0] s_tens;//秒的十位

reg [3:0] m_ones;//分的个位

reg [3:0] m_tens;//分的十位

reg [3:0] h_ones;//时的个位

reg [3:0] h_tens;//时的十位

wireadd_s_ones;//秒的个位开始计数条件

wireend_s_ones;//秒的个位结束计数条件

wireadd_s_tens;//秒的十位开始计数条件

wireend_s_tens;//秒的十位结束计数条件

wireadd_m_ones;//分的个位开始计数条件

wireend_m_ones;//分的个位结束计数条件

wireadd_m_tens;//分的十位开始计数条件

wireend_m_tens;//分的十位结束计数条件

wireadd_h_ones;//时的个位开始计数条件

wireend_h_ones;//时的个位结束计数条件

wireadd_h_tens;//时的十位开始计数条件

wireend_h_tens;//时的十位结束计数条件

wire end_h_ones_0;//时的十位为0个位为9时结束计数

wire end_h_ones_1;//时的十位为1个位为2时结束结束

wire end_h_tens_0;//在个位为9时,结束十位为0的状态

wire end_h_tens_1;//在个位为2十位为1时,结束十位为1的状态

wirepm_ding;//区分上午下午

2、秒钟代码块实现

//秒的个位

always @(posedge clk)

begin

if(reset)

s_ones <= 4'b0;

else if(add_s_ones)

begin

if(end_s_ones)

s_ones <= 4'b0;

else

s_ones <= s_ones + 4'b1;

end

end

assign add_s_ones=ena;

assign end_s_ones=add_s_ones&&(s_ones==4'd9);

//秒的十位

always@(posedge clk)

begin

if(reset)

s_tens<=4'b0;

else if(add_s_tens)

begin

if(end_s_tens)

s_tens<=4'd0;

else

s_tens<=s_tens+4'b1;

end

end

assign add_s_tens=end_s_ones;

assign end_s_tens=add_s_tens&&(s_tens==5);

3、分钟代码块实现

//分的个位

always @(posedge clk)

begin

if(reset)

m_ones <= 4'b0;

else if(add_m_ones)

begin

if(end_m_ones)

m_ones <= 4'b0;

else

m_ones <= m_ones + 4'b1;

end

end

assign add_m_ones = end_s_tens;

assign end_m_ones = add_m_ones && (m_ones == 4'd9);

//分的十位

always @(posedge clk)

begin

if(reset)

m_tens <= 4'b0;

else if(add_m_tens)

begin

if(end_m_tens)

m_tens <= 4'b0;

else

m_tens <= m_tens + 4'b1;

end

end

assign add_m_tens = end_m_ones;

assign end_m_tens = add_m_tens && (m_tens == 4'd5);

4、时钟的实现

//时钟个位的实现

always @(posedge clk)

begin

if(reset)

h_ones <= 4'd2;

else if(add_h_ones)

begin

if(end_h_ones_0)

h_ones <= 4'b0;//如果十位为0,则复位到0

else if(end_h_ones_1)

h_ones <= 4'b1;//如果十位为1,则复位到1,出现11:59:59

else

h_ones <= h_ones+4'b1;

end

end

assign add_h_ones=end_m_tens;

assign end_h_ones_0=add_h_ones&&(h_ones==4'd9);

assign end_h_ones_1=add_h_ones && ((h_ones == 4'd2) && (h_tens == 4'd1));

//时钟十位的实现

always @(posedge clk)

begin

if(reset)

h_tens <= 4'd1;

else if(add_h_tens)

begin

if(end_h_tens_0)

h_tens <= 4'b1;

else if(end_h_tens_1)

h_tens <= 4'b0;

end

end

assign add_h_tens = end_m_tens;

assign end_h_tens_1 = add_h_tens && end_h_ones_1;//在个位为2十位为1时,结束十位为1的状态

assign end_h_tens_0 =add_h_tens && end_h_ones_0;//在个位为9时,结束十位为0的状态

5、上午下午的区分

本部分参考另一位大佬的代码@日拱一卒_未来可期

//上午下午的区分

always@(posedge clk)

begin

if(reset)

pm_temp <= 1'b0;

else if(pm_ding)

pm_temp <= ~pm_temp;

end

assign pm_ding = h_tens == 4'd1 && h_ones == 4'd1 && end_m_tens;

6、输出的实现

always@(*)

begin

pm=pm_temp;

s={s_tens,s_ones};

m={m_tens,m_ones};

h={h_tens,h_ones};

end

7、完整代码

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] s_ones;//秒的个位

reg [3:0] s_tens;//秒的十位

reg [3:0] m_ones;//分的个位

reg [3:0] m_tens;//分的十位

reg [3:0] h_ones;//时的个位

reg [3:0] h_tens;//时的十位

wireadd_s_ones;//秒的个位开始计数条件

wireend_s_ones;//秒的个位结束计数条件

wireadd_s_tens;//秒的十位开始计数条件

wireend_s_tens;//秒的十位结束计数条件

wireadd_m_ones;//分的个位开始计数条件

wireend_m_ones;//分的个位结束计数条件

wireadd_m_tens;//分的十位开始计数条件

wireend_m_tens;//分的十位结束计数条件

wireadd_h_ones;//时的个位开始计数条件

wireend_h_ones;//时的个位结束计数条件

wireadd_h_tens;//时的十位开始计数条件

wireend_h_tens;//时的十位结束计数条件

wire end_h_ones_0;//时的十位为0个位为9时结束计数

wire end_h_ones_1;//时的十位为1个位为2时结束结束

wire end_h_tens_0;//在个位为9时,结束十位为0的状态

wire end_h_tens_1;//在个位为2十位为1时,结束十位为1的状态

wirepm_ding;//区分上午下午

//秒的个位

always @(posedge clk)

begin

if(reset)

s_ones <= 4'b0;

else if(add_s_ones)

begin

if(end_s_ones)

s_ones <= 4'b0;

else

s_ones <= s_ones + 4'b1;

end

end

assign add_s_ones=ena;

assign end_s_ones=add_s_ones&&(s_ones==4'd9);

//秒的十位

always@(posedge clk)

begin

if(reset)

s_tens<=4'b0;

else if(add_s_tens)

begin

if(end_s_tens)

s_tens<=4'd0;

else

s_tens<=s_tens+4'b1;

end

end

assign add_s_tens=end_s_ones;

assign end_s_tens=add_s_tens&&(s_tens==5);

//分的个位

always @(posedge clk)

begin

if(reset)

m_ones <= 4'b0;

else if(add_m_ones)

begin

if(end_m_ones)

m_ones <= 4'b0;

else

m_ones <= m_ones + 4'b1;

end

end

assign add_m_ones = end_s_tens;

assign end_m_ones = add_m_ones && (m_ones == 4'd9);

//分的十位

always @(posedge clk)

begin

if(reset)

m_tens <= 4'b0;

else if(add_m_tens)

begin

if(end_m_tens)

m_tens <= 4'b0;

else

m_tens <= m_tens + 4'b1;

end

end

assign add_m_tens = end_m_ones;

assign end_m_tens = add_m_tens && (m_tens == 4'd5);

//时钟个位的实现

always @(posedge clk)

begin

if(reset)

h_ones <= 4'd2;

else if(add_h_ones)

begin

if(end_h_ones_0)

h_ones <= 4'b0;//如果十位为0,则复位到0

else if(end_h_ones_1)

h_ones <= 4'b1;//如果十位为1,则复位到1,出现11:59:59

else

h_ones <= h_ones+4'b1;

end

end

assign add_h_ones=end_m_tens;

assign end_h_ones_0=add_h_ones&&(h_ones==4'd9);

assign end_h_ones_1=add_h_ones && ((h_ones == 4'd2) && (h_tens == 4'd1));

//时钟十位的实现

always @(posedge clk)

begin

if(reset)

h_tens <= 4'd1;

else if(add_h_tens)

begin

if(end_h_tens_0)

h_tens <= 4'b1;

else if(end_h_tens_1)

h_tens <= 4'b0;

end

end

assign add_h_tens = end_m_tens;

assign end_h_tens_1 = add_h_tens && end_h_ones_1;//在个位为2十位为1时,结束十位为1的状态

assign end_h_tens_0 =add_h_tens && end_h_ones_0;//在个位为9时,结束十位为0的状态

//上午下午的区分

always@(posedge clk)

begin

if(reset)

pm_temp <= 1'b0;

else if(pm_ding)

pm_temp <= ~pm_temp;

end

assign pm_ding = h_tens == 4'd1 && h_ones == 4'd1 && end_m_tens;

//输出

always@(*)

begin

pm=pm_temp;

ss={s_tens,s_ones};

mm={m_tens,m_ones};

hh={h_tens,h_ones};

end

endmodule

8、仿真波形图 复位和秒钟

分钟

时钟

###本文参考《明德杨大道至简的至简设计方法》,和@日拱一卒_未来可期的一篇博客,HDLBits答案(11)_Verilog计数器-CSDN博客。如有侵权,请联系删除。

相关知识

【fpga里Verilog语言的小知识点】
谈谈Verilog和SystemVerilog简史,FPGA设计是否需要学习SystemVerilog
实数比较指令示例
【免费】基于Javaweb的网上花店系统的设计与实现+jsp资源
用功能指令改变计数器C0的设定值,当X1、X0=00时设定值为10,当X1、X0
绿色医疗医学PPT模板.zip资源
彩灯控制电路设计
P=闭环系统稳定的充要条件
一种智能化成蚊密度监测设备的制作方法
δ的求法若f#(x,y)=M为常数

网址: 计数器的Verilog实现 https://m.huajiangbk.com/newsview893376.html

所属分类:花卉
上一篇: Mpg计算器
下一篇: Vmware中虚拟化Intel