基于FPGA的计数器设计

描述

数电基础

关于时序逻辑设计的部分依然强烈推荐mooc上华科的数字电路与逻辑设计。

计数器可以分为同步和异步计数器,2进制、10进制和任意进制计数器,加法和减法计数器。同步和异步是指触发器是否都由同一个时钟信号控制。一个触发器能存储1位二进制数,所以由N个触发器构成N位寄存器。例如3个JK触发器可以存储000-111种状态。在数电的原理方面,mooc上讲解的很清晰,可以自行学习同步或异步的二进制寄存器、使用复位清零和反馈置数将M进制构成N进制(N

设计规划

本例将采用一个外部时钟信号,一个复位键和一个LED灯来实现1s内LED闪烁(亮0.5s灭0.5s)。这种计时的功能在FPGA中是通过计数器完成的: 经历一个时钟周期,计数器+1 ,我们只需要计算出计数截止的值,就可以完成计时。由于采用的50MHz时钟频率,也就是1s产生510e7个时钟。那么亮灭0.5s就是需要计2.510e7个数。计数器从0-24999999,2^24<24999999<2^25,因此需要25个触发器,即25位寄存器。这个计数过程是:复位键生效时计数器归零,释放后的第一个时钟上升沿开始计数,从0计到2499999时LED灯改变状态,计数器归零重新开始计数,到2499999时LED灯改变状态...

计数器

编写代码

module counter
#(
parameter CNT_MAX = 25'd24_999_999
 )
 (
 input wire sys_clk , //系统时钟50MHz
 input wire sys_rst_n , //全局复位
 output reg led_out 
 );


 reg [24:0] cnt; //经计算得需要25位宽的寄存器才够500ms


 //cnt:计数器计数,当计数到CNT_MAX的值时清零
 always@(posedge sys_clk or negedge sys_rst_n)
 if(sys_rst_n == 1'b0)
 cnt <= 25'b0;
 else if(cnt == CNT_MAX)
 cnt <= 25'b0;
 else
 cnt <= cnt + 1'b1;


 //led_out:输出控制一个LED灯,每当计数满标志信号有效时取反
 always@(posedge sys_clk or negedge sys_rst_n)
 if(sys_rst_n == 1'b0)
 led_out <= 1'b0;
 else if(cnt == CNT_MAX)
 led_out <= ~led_out;
 endmodule

代码注释:与#define 标识符 常量类似,这里使用参数的方式定义常量。在RTL代码中实例化该模块时,如果需要两个不同计数值的计数器,只需要修改常数值。使用testbench仿真时也需要实例化,0.5s才能看到led_out的变化,仿真时间过长。如果我们直接修改参数缩短时间就能看到效果。parameter定义的是局部参数,只在本模块中有效,不会影响实际值。

我们观察cnt和led_out的变化条件:计数器发生改变的条件有两个,一个是时钟上升沿,一个是复位有效(复位下降沿)。计数器发生的改变有两个,要么+1要么清零。清零条件有两个:复位和溢出。因此第一个always块中有三个判断条件:复位和溢出时清零,其他的时候+1。

led_out的变化条件:时钟上升沿和复位有效(复位下降沿)。LED灯状态的变化有两个,当复位时LED灯为低电平,溢出时取反。

计数器

编写testbench

`timescale 1ns/1ns
module tb_counter();


//reg define
reg sys_clk;
reg sys_rst_n;


//wire define
wire led_out;


 //初始化输入信号
 initial begin
 sys_clk = 1'b1;
 sys_rst_n <= 1'b0;
 #20
 sys_rst_n <= 1'b1;
 end


 //sys_clk:每10ns电平翻转一次,产生一个50MHz的时钟信号
 always #10 sys_clk = ~sys_clk;


 //---------------------flip_flop_inst----------------------
 counter
 #(
 .CNT_MAX (25'd24 ) 
 )
 counter_inst(
 .sys_clk (sys_clk ), 
 .sys_rst_n (sys_rst_n ), 
 .led_out (led_out ) 
 );


 endmodule

初始化:时钟高电平,复位低电平,20s延迟后复位高电平。

实例化:此处的参数只对该模块有效,想要改变这个模块里的参数数值,只需要在这里改变即可。这里设置成24是为了方便观察,节省时间。

对比波形

计数器

24个时钟脉冲输出就会取反,同理trl文件中24999999个脉冲(0.5s)之后LED灯会改变状态,实现1s内闪烁。

分配管脚

计数器

全编译后上板验证

计数器

计数器

LED灯在1s内闪烁,且S1一直按LED灯会一直亮(S1按下去为低电平,复位有效,led_out=0,LED灯亮,和预期一致。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分