前言
之前一直说整理点FPGA控制器应用的内容,今天就从计数器这个在时序逻辑中比较重要的内容开始总结一下,主要通过还是通过让一个LED闪烁这个简单例子来理解。
寄存器
了解计数器之前先来认识一下寄存器。寄存器是时序逻辑设计的基础。时序逻辑能够避免组合逻辑存在的竞争和冒险问题,使电路系统更加稳定。而寄存器的基础是D触发器。
- D触发器:
在一个脉冲信号的变化沿(上升或下降沿),将信号从输入端送到输出端。且若脉冲的边沿一直没有出现,即使输入信号变化,输出信号也一直不变。同时寄存器拥有复位与清零功能。 - 下面以使用FPGA通过寄存器“点亮一个LED灯”的信号变化为例说明:首先理解一下几个概念同步复位,异步复位,延一拍
同步复位:
所谓同步,就是和工作时钟同步进行,如下图的蓝色框里面,当复位信号(rst_n)拉低后,输出信号(led_out)只有在工作时钟信号(clk)的上升沿时来回拉低复位。
异步复位:
和同步复位略有不同,异步复位不关注工作时钟是否到达变化沿(上升或者下降)。如下图蓝色框框中,当复位信号(rst_n)被拉低,输出信号(led_out)立刻被拉低,而不同于上面的还要等待工作时钟的上升沿到来后再变化。
延一拍
如下图蓝色框框里面,输入信号(key_in)在复位后第一个时钟的上升沿到来时拉高,但是此时输出信号(led_out)并没有跟着变化。在组合逻辑中,这种变化时是同步的。这就涉及到一个叫“延一拍”的术语。
首先理解下两个“时间”:
建立时间(Tsu):触发器的时钟信号上升沿到来之前,数据稳定不变的最小时间。
保持时间(Th):触发器的时钟信号上升沿到来之后,数据稳定不变的最小时间。
在进行时序逻辑仿真时,如果时钟和数据是对齐的,默认当前时钟采集到的数据为在该时钟上升沿前一时刻的值。也可以理解为仿真寄存器按照建立时间最大(一个时钟周期),保持时间最小(0)来进行。(在进行组合逻辑仿真时,数据变化大部分时候都是和时钟直接对齐的)。
- FPGA通过D触发器实现“点亮LED灯”:
软件平台:Quartus II开发软件
硬件平台:EP4CE10F17C8征途Mini FPGA开发板
编写同步触发器代码和仿真代码后得到以下仿真结果。可以观察到:复位信号变为高电平和时钟上升沿是对齐的。由于“延一拍”,此时采集到的复位信号时上升沿前一时刻的低电平值(0),寄存器处于复位状态,输出led_out保持低电平。
在下一个时钟上升沿到来之前,复位信号变为了高电平(1),输入为高电平,输出为高电平。通过打印文件也可以看出:输出信号(led_out)和输入信号(key_in)存在着“延一拍”的关系。输入数据在前一个时钟的上升沿变化,输出数据不变,而在下一刻时钟的上升沿变化。
计数器
- 作用
对脉冲的个数进行计数,通过计数器的计数值精确计算各种信号之间的时间关系,通过计数器精确控制各个信号的变化和持续时间等。 - 实例
使用计数器让LED每隔1s闪烁一次(亮0.5s,熄灭0.5s):
设计思路:
核心:什么时候开始计数,什么时候清零。(开始计数可以默认没有什么条件,只要复位撤销,时钟沿来到即可。清零:以50Mhz时钟为例,一个周期为20ns,也就是1s时间内计50000000个数,从0开始计数,也就是0-49999999。)
提炼出来也就是1s内让电平翻转一次,也就是计数到一半的时候(24999999)电平翻转一次。可以据此来绘制波形变化图:
其中N=24999999,复位信号(rst_n)一直有效时,计数器(cnt)计到N就清零,同时输出信号(led_out)取反。实现LED闪烁的效果。
仿真波形:
不知道为啥计数没显示出来。
上面是不带标志信号的计数器,还有一个带有标志信号的计数器,波形图如下图所示:
相较于上面那个波形,这里多了一个标志信号(cnt_flag),这个脉冲信号指示计数器计数到N-1,当计数到N-1的时候,输出信号先不翻转,一个时钟周期,输出信号再取反。这里这个标志信号计数到N或者N-1时候都行,但计数到N-1更精准,在参考书中说这里给出的脉冲标志信号的作用是节约逻辑资源,同时也能够让代码更加清晰简洁。
编写RTL代码,仿真,全编译后上板测试
LED闪烁效果:
FPGA编译与上板验证流程:
设计波形
新建工程
编写RTL代码
查看RTL视图
编写仿真文件
仿真设置
Modelsim仿真观察
添加引脚约束
全编译
JTAG下载网表到开发板(切忌带电插拔JTAG接口)
程序固化
小结
今天主要是参考野火的这块Mini FPGA开发板的一些资料对时序逻辑设计中的这个计数器进行了一些梳理与总结。计数器的核心思想自己总结其实就是将时间顺序量化后再发挥其作用。因为自己后面还需要用FPGA来实现好几个还比较复杂的大工程,所以这个系列慢慢也会写一些文章。文中用到的一些代码并没有贴出来。可以参考野火这块板子官方提供的一些资料。