zoukankan      html  css  js  c++  java
  • 以秒为单位的计数器

     学习的文章:https://mp.weixin.qq.com/s/hfrnaK4QJRN7JE_Eieuu7Q

    仅作个人学习记录,侵权即删。

    原理:

    具体要求:以clk为基准,设计一个秒计数器,在指定的计数值产生中断,实时输出当前的秒数计数值。已知clk的频率32.768kHz,rst_n低电平有效,收到start后,秒计数器sec_cnt从零开始以秒为单位来计数,计数到alarm[7:0]指定的数值后,产生一个脉冲int,然后秒数计数器回零并停止。

    解决:意思是通过clk分频一个周期为1s的时钟,拿这个时钟来检测alarm的数值,比如alarm是3,那么就是有3秒。

    clk=32768Hz=215Hz,那么1s就需要计数(1/(1/clk))=215次。

    还有一个这里的计数到32768,就意味着从0计数到32767,那么就是15'b111_1111_1111_1111,如果计数到这个值就会占用很多资源,所以改成了&cnt_1s==1'b1。


     代码:

    综合代码:

    module sec_cnt
    #(
    parameter cnt_1s_width=4'd14
    )
    (
    input clk,
    input rst_n,
    input start,
    input [7:0]alarm,
    output reg int,
    output reg [31:0]sec_cnt   //计数计算到第sec_cnt个1s
    );
    reg cnt_en;               //将start寄存到一个寄存器,这样可以控制它的状态
    reg [cnt_1s_0]cnt_1s;    //计数到1s所用的时间
    
    always @(posedge clk or negedge rst_n)
    if(!rst_n)
    cnt_en<=1'b0;
    else if(start)
    cnt_en<=1'b1;
    else if(sec_cnt==alarm && &cnt_1s==1'b1)
    cnt_en<=1'b0;
    
    always @(posedge clk or negedge rst_n)
    if(!rst_n)
    cnt_1s<=15'd0;
    else if(cnt_en)
    cnt_1s<=cnt_1s+1'b1;
    else
    cnt_1s<=15'd0;
    
    always @(posedge clk or negedge rst_n)
    if(!rst_n)
    sec_cnt<=32'd0;
    else if(sec_cnt==alarm && &cnt_1s==1'b1)   //这两个不能换过来
    sec_cnt<=32'd0;
    else if(&cnt_1s==1'b1 && cnt_en==1'b1)     //这两个不能换过来
    sec_cnt<=sec_cnt+1'b1;
    
    always @(posedge clk or negedge rst_n)
    if(!rst_n)
    int<=1'b0;
    else if(sec_cnt==alarm && &cnt_1s==1'b1)
    int<=1'b1;
    else
    int<=1'b0;
    endmodule 

    仿真代码:仿真这里按照着原理,把宽度parameter从14换成2,省略了很多计数,只是数值计算就变成了7,所以&cnt_1s==1'b1就是cnt_1s==3'b111。

    `timescale 1ns/1ns
    module sec_cnt_tb;
    reg clk;
    reg rst_n;
    reg start;
    reg [7:0]alarm;
    wire int;
    wire [31:0]sec_cnt;
    initial begin
    clk<=1'b1;
    rst_n<=1'b0;
    start<=1'b0;
    alarm<=8'd0;
    #10 rst_n<=1'b1;
    end
    always #10 clk<=~clk;
    
    initial begin
    #40
    start<=1'b1;
    alarm<=8'd3;
    #20 
    start<=1'b0;
    #1000
    start<=1'b1;
    alarm<=8'd4;
    #20
    start<=1'b0;
    end
    
    sec_cnt 
    #(
    .cnt_1s_width(4'd2)  //这里就是把宽度parameter值由15变成2,所以计数&cnt_1s==1'b1就是3'b111
    )
    u_sec_cnt(
    .clk (clk),
    .rst_n (rst_n),
    .start (start),
    .alarm (alarm),
    .int (int),
    .sec_cnt (sec_cnt)
    );
    endmodule

    仿真效果:

    部分放大一点:

  • 相关阅读:
    DLL导出类避免地狱问题的完美解决方案
    WorldWind源码剖析系列:影像图层类ImageLayer
    WorldWind源码剖析系列:插件类Plugin、插件信息类PluginInfo和插件编译器类PluginCompiler
    多线程中的锁系统(一)-基础用法
    [转]分布式计算框架综述
    C#自定义控件开发
    GDI+编程小结
    C#自定义控件
    WorldWind源码剖析系列:窗口定制控件类WorldWindow
    WorldWind源码剖析系列:四叉树瓦片集合类QuadTileSet
  • 原文地址:https://www.cnblogs.com/FPGAer/p/13828325.html
Copyright © 2011-2022 走看看