之前每次创建完一个新的文件,文件最上方总会显示一行timescale。当初觉得没什么作用,删了之后依旧没有任何问题便没把它当回事,直到后来做频率计数器的时候我才决定一探究竟。那么这篇文章也就一并谈一下这个问题。
References:
电子文献:
https://blog.csdn.net/m0_37652453/article/details/90301902
https://blog.csdn.net/ciscomonkey/article/details/83661395
https://blog.csdn.net/qq_16923717/article/details/81099833
基本原理
一个简易的频率计数器主要由分频器和计数器构成,其基本原理就是记录由分频器得到的一段时间内被测信号上升沿的个数,从而求得被测信号的频率。
控制信号转换模块
1 |
|
计数模块
1 |
|
寄存模块
1 |
|
顶层文件
1 |
|
仿真文件
1 |
|
仿真结果
以100Hz(T1)为例,输出的仿真结果如下。
其中CLK是固定的1Hz基准时钟信号;RST是系统需求的复位按键,当按下复位即RST为下降沿时,可以看到计数器Cnt被清零同时第一排译码输出的BCD码也被清零;Signal为输入的信号,这里我使用的是100Hz的,由我自己设定,由于频率较快,可以看到波形图非常密集;Cnt_EN是计数使能信号,可见在它为高电平时,Cnt随着输入信号一样快速计数;Cnt_CR是清零信号,在每次计数使能的上升沿或者复位的下降沿到来时Cnt_CR置零,也就是对Cnt清零操作;此外,当时钟信号到来时,假如系统不在计数(Cnt_EN=0),那么Latch_Sig将置1,也就是把记录数值存入锁存器。
实际上,这种设计方案会存在±1的计数误差,应为输入信号不一定与分频器同周期,即有可能每次测量的起始位置出于输入信号一个周期内的不同状态。
timescale
timescale是Verilog中的预编译指令,指定位于它后边的module的时间单位和时间精度,直到遇到新的timescale指令或者resetall指令。它的语法如下:
1 |
假如我们延时x个time_unit,那延时的总时间time = x * time_unit,但最后真正延时的时间是根据time_precision对time进行四舍五入后的结果。
注意:
- time_unit和time_precision只能是1、10和100这三种整数,单位有s、ms、us、ns、ps和fs。
- time_precision必须小于等于time_unit。
- timescale的时间精度设置是会影响仿真时间的,1ps精度可能是1ns精度仿真时间的一倍还多,并且占用更多的内存,所以如果没有必要,应尽量将时间精度设置得更大一些。
仿真时间
之前进行仿真时,我往往是让它自动运行至系统默认时间然后停止,这就会造成出现好几次重复循环的情况。
在Vivado中,窗口上方有三个类似播放器中的按钮,从左往右依次是:复位、不停运行、按指定时长(在后面的栏中设定)运行。
此外,如果计算不准时间,可以直接在仿真文件末尾或者想要结束的地方使用$stop
或者$finifsh
来终止仿真。