最新要闻

广告

手机

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

iphone11大小尺寸是多少?苹果iPhone11和iPhone13的区别是什么?

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

警方通报辅警执法直播中被撞飞:犯罪嫌疑人已投案

家电

11-计数器

来源:博客园


(相关资料图)

1.计数器

FPGA中一切与时间有关的电路都会使用到计数器计数是一种最简单的基本运算,计数器就是实现这种运算的逻辑电路,计数器在数字系统中主要是对脉冲的个数进行计数,以实现测量\计数和控制的功能,同时兼有分频功能.计数器在数字系统中应用广泛,如电子计算机的控制器中对指令地址进行计数,以便顺序取出下一条指令,在运算器中做乘法,除法运算时记下加法\减法次数;有如在数字仪器中对脉冲的计数等计数器在FPGA最常用的时序逻辑电路,通过计数器可以知道各个信号之间的关系计数器一般从0开始计数,计满清0或者是计到一定次数清0

2. FPGA实现

  • 前0.5s处于点亮状态,后0.5s处于熄灭状态

2.1 计数器设计关键

计数器关键:什么时候开始计数,什么时候清零

  • 计数器在复位信号撤销之后,时钟沿到来就可以立即进行计数
  • 计数器清0:计满或者计到需要的值,哪一个值是需要计到的值?比如需要计数1s,就需要知道计数器计多少个数(50M时钟)
  • f = 50MHz = 50000KHz = 50000_000(十进制)Hz,单位时间内信号进行周期性变化的次数,50000_000Hz表示单位时间内进行了50000_000次周期性变化,每次变化所用的时间为t
  • t = 1/f = (1/50000_000) = 20ns -- 时钟周期,计数器每一次计数经过的时间为20ns
  • 计数器需要计数的个数M:M = 1s/20ns = 5*10^7
  • 计数器的最大值是:M-1(从0开始计数)

2.2 模块框图和波形图

  • 计数器是对时钟信号进行计数,所以要有时钟信号,复位信号
  • 引出一路输出信号到LED灯波形图绘制非常重要,按照时钟,复位信号,输入,输出的顺序画波形图
  • 设置一个中间变量进行计数,复位信号下赋予初值,复位信号撤销且在上升沿开始计数优化
  • 计数到M/2-1之后进行清零,再计数到M/2-1之后再次清0,也可以实现上述前0.5s灯亮,后0.5s灯灭,且每次计数都是M/2
  • 第一种条件下计数到M-1(4999999),转化为二进制需要26bit,优化之后计数到M/2-1(2499999)需要使用25bit,节省资源量

2.3 RTL

module counter#(  parameter  CNT_MAX = 25"d24_999_999  // 例化模块的参数传递接口,参数之间加,)(  input wire sys_clk,  input wire sys_rst_n,    output reg led_out);  // 声明计数器变量,位宽25bit  reg [24:0] cnt;    // 参数定义  // 计数器的计数最大值  // parameter可以用与模块内部,也可以用于参数例化模块的参数传递  parameter  CNT_MAX = 25"d24_999_999; // 普通模块参数定义  // localparam CNT_MAX = 25"d24_999_999; // 只用于模块内部    counter   #(    .CNT_MAX (100);  // 实例化的时候参数也写在这个位置,并且可以修改参数  )  counter_inst1      // 带有参数的模块实例化的模块名称写在参数列表之后  (    .sys_clk  (sys_clk),    .sys_rst_n (sys_rst_n),        .led_out (led_out)  );    counter   #(    .CNT_MAX (100);  // 实例化的时候参数也写在这个位置,并且可以修改参数  )                  // 多个模块实例化可以传递不同的参数  counter_inst1  (    .sys_clk  (sys_clk),    .sys_rst_n (sys_rst_n),        .led_out (led_out)  );endmodule
module counter#(  parameter  CNT_MAX = 25"d24_999_999;  // 例化模块的参数传递接口)(  input wire sys_clk,  input wire sys_rst_n,    output reg led_out);  // 声明计数器变量,位宽25bit  reg [24:0] cnt;   // 计数器变量赋值     always @ (posedge sys_clk or negedge sys_rst_n)  begin    if(sys_rst_n == 1"b0)      begin        cnt <= 25"d0;      end    else if(cnt = CNT_MAX)      begin        cnt <= 25"b0;      end    else      cnt <= cnt + 25"d1;  end    // 输出信号赋值  always@(posedge sys_clk pr negedge sys_clk_n) begin    if(sys_rst_n == 1"b0)      led_out <= 1"b0;    else if(cnt == CNT_MAX)      led_out <= ~led_out;    else      led_out <= led_out;  endendmodule
  • 编译代码

2.4 Testbench

`timescale 1ns/1nsmodule tb_counter();  reg sys_clk;  reg sys_rst_n;    wire led_out;    initial begin    sys_clk = 1"b1;    sys_rst_n <= 1"b0;    #20;    sys_rst_n <= 1"b1;  end  always #10 sys_clk = ~sys_clk;    counter  #(    .CNT_MAX (25"d24)  )  counter_inst  (    .sys_clk (sys_clk),    .sys_rst_n (sys_rst_n),    .led_out (led_out)  );endmodule

2.5 上板验证

2.6 其他方式实现

  • 当计数器计满之后,添加一个cnt_reg变量,给这个变量的信号产生一个周期的脉冲(拉高一个周期),然后拉低
  • cnt信号正常
  • led_out信号在检测到cnt_flag信号为高电平的时候,会进行一次翻转
  • 使用脉冲标志信号cnt_flag,当计数器计数到M/2-2的时候,在下一个周期(M/2-1)周期上升沿产生一个脉冲,同样在cnt_flag信号拉高的时候led_out进行翻转,这样就能实现led_out和计数信号同步,没有延迟周期引入脉冲标志信号cnt_flag,可以简化if中的条件语句,在进行复杂设计的时候可以节省资源
module counter#(  parameter  CNT_MAX = 25"d24_999_999;  // 例化模块的参数传递接口)(  input wire sys_clk,  input wire sys_rst_n,    output reg led_out);  // 声明计数器变量,位宽25bit  reg [24:0] cnt;  reg        cnt_flag;   // 计数器变量赋值     always @ (posedge sys_clk or negedge sys_rst_n)  begin    if(sys_rst_n == 1"b0)      begin        cnt <= 25"d0;      end    else if(cnt = CNT_MAX)      begin        cnt <= 25"b0;      end    else      cnt <= cnt + 25"d1;  end    // 计数器标志位赋值  always @ (posedge sys_clk or negedge sys_rst_n)    if(sys_rst_n == 1"b0)      cnt_flag <= 1"b0;    else if(cnt ==(CNT_MAX - 25"d1))      cnt_flag <= 1"b1;    else       cnt_flag <= 1"b0;        // 输出信号赋值  always@(posedge sys_clk pr negedge sys_clk_n) begin    if(sys_rst_n == 1"b0)      led_out <= 1"b0;    else if(cnt_flag == 1"b1)      led_out <= ~led_out;    else      led_out <= led_out;  endendmodule

关键词: