找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 6593|回复: 1
收起左侧

VHDL语言数字式频率计的设计过程,源代码,和仿真图型(Word文档)

[复制链接]
ID:468708 发表于 2019-1-22 16:16 | 显示全部楼层 |阅读模式
本文介绍了使用VHDL开发FPGA的一般流程,重点介绍了频率计的基本原理和相应的测量方案,最终采用了一种基于FPGA的数字频率的实现方法。该设计采用硬件描述语言VHDL,在软件开发平台ISE上完成,可以在较高速时钟频率(100MHz)下正常工作。该设计的频率计能准确的测量频率在1Hz到100MHz之间的信号。使用ModelSim仿真软件对VHDL程序做了仿真,并完成了综合布局布线,最终下载到芯片Spartan-II上取得良好测试效果。


原理框图
测试结果
参考文献
计数器级联程序
锁存器源程序
顶层原理图
计数器的级联图
外文资料原文
翻译文稿

第一章  引言

第二章  基于FPGA的VHDL设计流程

2.1  概述
2.2  VHDL语言介绍
2.2.1  VHDL的特点
2.2.2  基于VHDL的自顶向下设计方法
2.3  FPGA开发介绍
2.3.1  FPGA简介
2.3.2  FPGA设计流程
2.3.3  Spartan-II芯片简介
第三章  数字频率计的软件开发环境

3.1  开发环境
3.2  ModelSim介绍
3.2.1  ISE环境中ModelSim的使用
3.3  ISE介绍
3.3.1  建立项目工程
3.3.2  行为仿真
3.3.3  建立顶层原理图
3.3.4  综合
3.3.5  布局布线
3.3.6  下载及硬件仿真
第四章  数字频率计的设计与实现

4.1  任务要求
4.2  测量原理
4.2.1  频率或时间的原始基准
4.2.2  电子计数器测频方法
4.2.3  误差分析
4.2.4  测量周期的必要性和基本原理
4.2.5  等精度测量
4.3  原理框图
4.4  各模块的功能及实现
4.4.1  分频器
4.4.2  闸门选择器
4.4.3  测频控制器
4.4.4  频率计数器
4.4.5  锁存器
4.4.6  扫描显示控制译码系统
4.5  顶层原理图
4.6  分配引脚和下载实现
4.7  测试结果
第五章  结论

参考文献

致  谢

附  录

附录1.  计数器级联程序
附录2.  锁存器源程序
附录3.  顶层原理图
附录4.  计数器的级联图
外文资料原文

翻译文稿


在电子技术领域内,频率是一个最基本的参数,频率与其它许多电参量的测量方案、测量结果都有十分密切的关系。如时间,速度等都涉及到或本身可转化为频率的测量。因此,频率的测量就显得更为重要。而且,目前在电子测量中,频率的测量精确度是最高的.现在市场上有各种多功能,高精度,高频率的数字频率计,但价格不菲。而在实际工程中,不是对所有信号的频率测量都要求达到非常高的精度。因此,本文提出了一种能满足一般测量精度要求,但成本低廉的数字频率计的设计方案。
本文主要任务是针对设计的要求,基于FPGA利用硬件描述语言VHDL完成数字频率计的设计,通过仿真,分析,综合并最终下载到FPGA里面去实现。除被测信号的整形部分、键输入部分以外,其余全部在一片FPGA芯片上实现,整个系统非常精简,而且具有灵活的现场可更改性。在不更改硬件电路的基础上,对系统进行各种改进还可以进一步提高系统的性能。该数字频率计具有高速、精确、可靠、抗干扰性强和现场可编程等优点。经实验表明,其测量精度基本能达到,且系统成本非常低廉,可作为学生数字逻辑设计综合实验或自制数字频率计的备选方案。

第二章  基于FPGA的VHDL设计流程2.1  概述
数字频率计是数字电路中的一个典型应用,实际的硬件设计用到的器件较多,连线比较复杂,而且会产生比较大的延时,造成测量误差、可靠性差。频率计的设计有传统方法和现代方法,传统的设计方法耗时耗功,设计强度大,且容易出错,设计的质量不一定是最好的。自然我们考虑到现代方法,即二十世纪八十年代兴起的电子设计自动化技术,英文为Electronic Design Auto,缩写为EDA。在EDA设计工具中,用的最广泛的是VHDL和VERILOG,当然还有其它的。比较VHDL和VERILOG,在顶层设计方面VHDL优于VERILOG,在门级电路设计方面VERILOG优于VHDL。随着复杂可编程逻辑器件(CPLD)的广泛应用,以EDA工具作为开发手段,运用VHDL语言,将使整个系统大大简化,提高整体的性能和可靠性。本次的频率计设计主要是顶层设计,目的是设计6位十进制频率计,学习常用的数字系统设计方法。采用VDHL编程设计实现的数字频率计,除被测信号的整形部分、键输入部分以外,其余全部在一片FPGA芯片上实现,整个系统非常精简,而且具有灵活的现场可更改性。在不更改硬件电路的基础上,对系统进行各种改进还可以进一步提高系统的性能。该数字频率计具有高速、精确、可靠、抗干扰性强和现场可编程等优点。
2.2  VHDL语言介绍
VHDL(Very-high-speed Integrated Circuit Hardware Description Language)诞生于1982年。1987年底,VHDL被IEEE(The Institute of Electrical and Electronics Engineers)和美国国防部确认为标准硬件描述语言。自IEEE公布了VHDL的标准版本(IEEE-1076)之后,各EDA公司相继推出了自己的VHDL设计环境,并宣布自己的设计工具可以和VHDL接口。此后VHDL在电子设计领域得到了广泛的接受,并逐步取代了原有的非标准硬件描述语言。1993年,IEEE对VHDL进行了修订,从更高的抽象层次和系统描述能力上扩展VHDL的内容,公布了新版本的VHDL,即IEEE标准的1076-1993版本。现在,VHDL和VERILOG作为IEEE的工业标准硬件描述语言,又得到众多EDA公司的支持,在电子工程领域,已成为事实上的通用硬件描述语言。有专家认为,在新的世纪中,VHDL和VERILOG语言将承担起­­几乎全部的数字系统设计任务。
2.2.1  VHDL的特点
VHDL主要用于描述数字系统的结构、行为、功能和接口。除了含有许多具有硬件特征的语句外,VHDL的语言形式,描述风格以及句法十分类似于一般的计算机高级语言。VHDL的程序结构特点是将一项工程设计,或称为设计实体(可以是一个元件、一个电路模块或一个系统)分成外部(又称为可视部分,即端口)和内部(又称为不可视部分),即设计实体的内部功能和算法完成部分。在对一个设计实体定义了外部界面后,一旦其内部开发完成后,其它的设计就可以直接调用这个实体。这种将设计实体分成内外部分的概念是VHDL系统设计的基本点。应用VHDL进行工程设计的优点是多方面的,具体如下:
1、与其它的硬件描述语言相比,VHDL具有更强的行为描述能力,从而决定了它成为系统设计领域最佳的硬件描述语言。强大的行为描述能力是避开具体的器件结构,从逻辑行为上描述和设计大规模电子系统的重要保证。就目前流行的EDA工具和VHDL综合器而言,将基于抽象的行为描述风格的VHDL程序综合成为具体的FPGA和CPLD等目标器件的网表文件已不成问题,只是在综合与优化效率上略有差异。
2、VHDL最初是作为一种仿真标准格式出现的,因此VHDL既是一种硬件电路描述和设计语言,也是一种标准的网表格式,还是一种仿真语言。其丰富的仿真语句和库函数,使得在任何大系统的设计早期(即尚未完成),就能用于查验设计系统的功能可行性,随时可对设计进行仿真模拟。即在远离门级的高层次上进行模拟,使设计者对整个工程设计的结构和功能的可行性做出决策。
3、VHDL语句的行为描述能力和程序结构决定了它具有支持大规模设计的分解和已有设计的再利用功能,符合市场所需求的,大规模系统高效、高速的完成必须由多人甚至多个开发组共同并行工作才能实现的特点。VHDL中设计实体的概念、程序包的概念、设计库的概念为设计的分解和并行工作提供了有力的支持。
4、对于用VHDL完成的一个确定的设计,可以利用EDA工具进行逻辑综合和优化,并自动地把VHDL描述设计转变成为门级网表。这种方式突破了门级电路设计的瓶颈,极大地减少了电路设计的时间和可能发生的错误,降低了开发成本。应用EDA工具的逻辑优化功能,可以自动地把一个综合后的设计变成一个更高效、更高速的电路系统。反过来,设计者还可以容易地从综合和优化后的电路获得设计信息,返回去更新修改VHDL设计描述,使之更为完善。
5、VHDL对设计的描述具有相对独立性,设计者可以不懂硬件的结构,也不必管最终设计实现的目标器件是什么,而进行独立的设计。正因为VHDL硬件描述与具体的工艺技术和硬件结构无关,VHDL设计程序的硬件实现目标器件有广阔的选择范围,其中包括各系列的CPLD、FPGA及各种门阵列实现目标。
6、由于VHDL具有类属描述语句和子程序调用等功能,对于已完成的设计,在不改变源程序的条件下,只需要改变端口类属参量或函数,就能轻易地改变设计的规模和结构。
2.2.2  基于VHDL的自顶向下设计方2.2.2.1  自顶向下设计的步骤
1、设计说明:用自然语言表达系统项目的功能特点和技术参数等。
2、建立VHDL行为模型,即将设计说明已转化为VHDL行为模型。建立模型是为了通过VHDL仿真器对整个系统进行系统行为仿真和性能评估。
3、VHDL行为仿真。这一阶段可以利用VHDL仿真器对顶层系统的行为模型进行仿真测试,检查模拟结果,继而进行修改和完善。
4、VHDL-RTL级建模。即将VHDL的行为模型表达为VHDL行为代码。
5、前端功能仿真。即对VHDL-RTL级模型进行仿真,简称功能仿真。
6、逻辑综合。使用逻辑综合工具将VHDL行为代码描述转化为结构化的门级电路。
7、测试向量生成。
8、功能仿真。
9、结构综合。
10、门级时序仿真。
11、硬件测试。
2.2.2.2  Top-down设计方法的优点
1、完全符合设计人员的设计思路;从功能描述开始,到最后的物理实现。
2、功能设计可完全独立于物理实现;采用Top-Down设计方法,功能输入采用国际标准的HDL输入方法,HDL可不含有任何器件的物理信息,因此工程师可以有更多的空间去集中精力进行功能描述。设计师可以在设计过程的最后阶段任意选择或更改物理器件,不会在设计一开始就受到最终所采用器件的约束。
3、设计可再利用;设计结果完全可以以一种知识产权(IP-Intellectual Property)的方式作为设计师或设计单位的设计成果,应用于不同的产品设计中,做到成果的再利用。
4、易于设计的更改;设计工程师可在极短的时间内修改设计,对各种FPGA/CPLD结构进行设计结果规模(门消耗)和速度(时序)的比较,选择最优方案。
5、设计和处理大规模复杂电路;目前的FPGA/CPLD器件正向高集成度、深亚微米工艺发展。为设计系统的小型化,低功耗、高可靠性等提供了集成的手段。
6、设计周期缩短,生产率大大提高,产品上市时间提前,性能明显提高,产品竞争力加强。据统计,采用Top-Down设计方法的生产率可达到传统设计方法2到4倍。
2.3  FPGA发介绍2.3.1  FPGA简介
现场可编程门阵列(FPGA)器件是八十年代中期出现的新产品,它的应用大大地方便了IC的设计,因而随着数字技术日益广泛的应用,以FPGA为代表的ASIC器件得到了迅速的普及和发展,器件集成度和速度都在高速增长。
传统的电路设计过程是:先画原理图、把原理图绘制成印制电路板图、再制版、安装、调试。有了FPGA,我们只需要在计算机上绘出原理图,再运行相应的软件,就可把所设计的逻辑电路在FPGA中实现。所有步骤均可自动完成。电子设计工程师自己设计专用集成电路成为了一件很容易的事情。
FPGA作为专用集成电路(ASIC)概念上的一个新型范畴和门类,以其高度灵活的用户现场编程方式,现场定义高容量数字单片系统的能力,能够重复定义、反复改写的新颖功能,为复杂数字系统设计、研制以及产品开发提供了有效的技术手段。电子应用设计工程师应用FPGA技术不仅可避免通常ASIC单片系统设计周期长,前期投资风险大的弱点,而且克服了过去板级通用数字电路应用设计的落后,繁琐和不可靠性。
目前FPGA的两个重要发展与突破是,大多数厂商在其高端器件上都提供了片上的处理器(如CPU、DSP)等硬核(Hard Core)或固化核(Fixed Core)。比如Xilinx的Virtex II Pro芯片可以提供Power PC,而Altera的Stratix、Excalibur等系列芯片可以提供Nios、DSP和Arm等模块。在FPGA上集成微处理器,使SOPC设计更加便利与强大。另一个发展是在不同器件商推出的高端芯片上大都集成了高速串行收发器,一般能够达到3Gb/s以上的数据处理能力,在Xilinx、Altera、Lattice都有相应的器件型号提供该功能。这些新功能使FPGA的数据吞吐能力大幅度增强。
2.3.2  FPGA设计流程
对于目标器件为FPGA和CPLD的HDL设计,其工程设计的基本流程如图 2-1所示。现具体说明如下。
图 2-1 EDA设计流程
1、文本编辑
用任何文本编辑器都可以进行,通常VHDL文件保存为vhd文件,Verilog文件保存为v文件。
2、使用编译工具编译源文件
HDL的编译器有很多,ACTIVE公司,MODELSIM公司,SYNPLICITY公司,SYNOPSYS公司,VERIBEST公司等都有自己的编译器。
3、逻辑综合
将源文件调入逻辑综合软件进行综合。综合的目的是在于将设计的源文件由语言转换为实际的电路。但是此时还没有在芯片中形成真正的电路。这一步的最终目的是生成门电路级的网表(Netlist)。
4、布局、布线
将第3步生成的网表文件调入PLD厂家提供的软件中进行布线,即把设计好的逻辑安放到CPLD/FPGA内。这一步的目的是生成用于下载(编程Programming)的编程文件。在这一步,将用到第3步生成的网表,并根据CPLD/FPGA厂商的器件容量,结构等进行布局、布线。这就好像在设计PCB时的布局布线一样。先将各个设计中的门根据网表的内容和器件的结构放在器件的特定部位。然后,在根据网表中提供的各门的连接,把各个门的输入输出连接起来。最后,生成一个供编程的文件。这一步同时还会加一些时序信息(Timing)到你的设计项目中去,以便于你做后仿真。
5、后仿真
利用在布局布线中获得的精确参数,用仿真软件验证电路的时序。(也叫布局布线仿真或时序仿真)。这一步主要是为了确定你的设计在经过布局布线之后,是不是还满足你的设计要求。
6、编程,下载
如果前几步都没有发生错误,并且符合设计要求,这一步就可以将由适配器等产生的配置或下载文件通过编程器或下载电缆下载到目标芯片中。
7、硬件测试
硬件测试的目的是为了在更真实的环境中检验HDL设计的运行情况,特别是对于HDL程序设计上不是十分规范,语义上含有一定歧义的程序。
2.3.3  SPARTAN-II芯片简介
本设计用到的FPGA芯片是XILINX公司生产的SPARNTAN-II系列中的xc2s100-6。下面将对该系列做简单的介绍。
2.3.3.1  Spartan-II系列的特点
进入ASSP的领域FPGA正在极力将ASSP从电路板上挤出去,并使其失去设计人员的宠爱。但是任何旧式的FPGA器件都无法恰当地替代专用器件。只有Spartan-II FPGA可以做到这一点。Spartan-II系列为设计人员提供了完整的封装。在密度、功能和性能以及运行速度方面都差不多。但是,Spartan-II为解决方案所提供的可编程能力有着巨大的价值,从而使其与ASSP/ASIC器件相比具有了很大的优势。
1、现场升级的灵活性
Spartan-II FPGA的可编程能力为设计人员带来很大优势。采用的FPGA是标准器件后,您可更快地将产品标准化。因为Spartan器件可进行现场升级,升级就像下载软件一样简单。
2、拥有丰富的逻辑门资源
Spartan-II系列有六款器件,密度高达20万门。丰富的逻辑门资源能让设计者更大限度的发挥。
3、告别ASIC和FPGA间的性能和功能差距
在性能和功能方面,大多数设计人员都会想到ASIC和FPGA间的巨大差距。但是SPARTAN-II消除了这一差距。
4、拥有最多的存储器
片上带存储器是必须的,如果还具有很好的灵活性的话,那么就更为有用了。分布式存储器和块RAM可高效地实现最适合您要求的配置,现时还可采用与片上存储器一样快的外部存储器。
5、方便的时钟管理
如果您面临时钟管理问题,Spartan-II系列的四个高度灵活的DLL可解决您的问题。设计人员可在片上对输入时钟进行倍频或分频,还可驱动板上的多个时钟。
6、提供高性能
今天的数字世界里有许多新的I/O标准要求很苛刻。通过Select I/O技术,Spartan-II器件支持所有这些新I/O标准。I/O速度超过200 MHz。Spartan-II系列丰富的功能、以及高性能和低成本,使其成为多种数据网络应用HDLC控制器解决方案中的首选。Spartan-II也非常适于实现控制和接口逻辑,比如用于将CPU同QDR SRAM连接在一起。
7、器件密度扩展至20万门
随着大量产品的设计变得越来越复杂,对更高密度、更大存储器资源以及更多I/O数量的需求也在增长。对于此类设计,Spartan-II系列的XC2S200非常适合,该器件能提供20多万个门、14个RAM块以及284个I/O,并有三种不同的低成本适合大批量生产的封装PQ208、FG256和FG456可供选择。利用XC2S200,可获得比XC2S150多36%的逻辑单元,而且其密度是Spartan或Spartan-XL最大器件密度的五倍。XC2S200包括了支持Spartan-II解决方案获得成功的所有特性。
2.3.3.2  Spartan-II的结构特点
1、结构框图
Spartan-II系列FPGA采用了常规的灵活可编程构架,包括可配置逻辑块(CLB)和环绕在CLB四周的可编程输入/输出模块(IOB),并通过多用途布线资源形成强大的互连体系。
图2-2 Spartan-ii 的结构框图
2、输入/输出模块
Spartan-II的IOB的输入和输出支持16种I/O信号标准,包括LVCMOS、HSTL、SSTL和GTL。这些高速输入和输出可支持各种先进的存储器和总线接口。三个IOB寄存器可作为边沿触发D型触发器或作为电平敏感的锁存器。
图2-3 Spartan-ii 的输入输出模块
3、逻辑单元
Spartan-II CLB的基本构造单元是逻辑单元(LC)。一个LC包括一个四输入的函数发生器、一个进位逻辑和一个存储单元。每个LC中函数发生器的输出同时驱动CLB输出端和触发器的D输入端。每个Spartan-II CLB包含四个LC,两两组合成两个同样的Slice。除了四个基本LC外,Spartan-II CLB还包含一些逻辑电路,结合函数发生器可提供五个或六个输入的函数功能。因此当预计给定器件所能提供的系统门数量时,每个CLB可当作4.5个逻辑单元来计算。
Spartan-II函数发生器采用4输入查找表(LUT)的方式来实现。除了作为函数发生器以外,每个LUT还可作为一个16*1位的同步RAM来使用。Spartan-II LUT还可作为一个16位移位寄存器使用,而且对于捕捉高速或猝发数据非常理想。这一模式还可在诸如数字信号处理等应用中用于数据的存储。Spartan-II逻辑片中的存储单元可通过配置成为边沿触发型D型触发器或电平敏感锁存器。



图2-4 Spartan-ii的逻辑单元
4.块RAM
Spartan-II FPGA集成了几块大型的4K位容量Select RAM+ 存储器块。这与在CLB中能够实现浅RAM结构的分布式Select RAM+资源互为补充。每个存储器块可配置为4K x 1 和256 x 16之间的多种不同配置。
图2-5 Spartan-ii的块RAM
5.延迟锁相环
与每个全局时钟输入缓冲器相连的是一个完全数字的延迟锁相环(DLL),它可消除时钟输入焊盘和器件内部时钟输入引脚间的畸变。每个DLL可驱动两个全局时钟网络。首先监视输入的时钟信号,然后是分布式时钟信号,并自动地调整时钟延迟单元。通过引入额外的延迟来保证时钟边沿严格地在到达时钟输入端一个时钟周期后到达内部触发器。通过保证到达内部触发器的时钟边沿与到达时钟输入端的时钟边沿严格同步,这一闭环系统有效地消除了时钟传输延迟。

第三章  数字频率计的软件开发环境
本章主要介绍项目中将要用到了一系列软件,包括用于VHDL语言编写和编译的ISE软件和用于程序仿真的仿真软件ModelSim。
3.1  开发环境
随着可编程器件纷纷超越百万门级,设计者面临的产品性能与设计效率的挑战也越来越大。设计者必须合理选择各EDA厂家提供的加速设计的工具软件,这样才能在较短的时间内设计出高效稳定的产品。在本次设计中,由于选择的FPGA芯片是由Xilinx公司生产的,所以我们主要使用ModelSim和ISE软件进行仿真和综合。
3.2  ModelSim介绍
ModelSim支持PC和UNIX平台,是单一内核支持VHDL和Verilog混合仿真的HDL语言仿真器。ModelSim不仅可以完成设计的功能验证,也可实现逻辑综合后的门级仿真以及布局布线后的功能与时序验证。
ModelSim完全支持VHDL和Verilog标准;采用直接编辑技术,大大提高HDL编译和仿真速度。还可以利用ModelSim调用设计文件进行仿真分析。在调试环境中,设计者可以通过ModelSim的快速调试步骤以及对各种信号的监控功能(无论信号处于VHDL层,还是处于混合语言层)使仿真的执行过程形象直观化,帮助设计者及时发现漏洞,缩短设计周期。
ModelSim最大的特点是其强大的调试功能:先进的数据流窗口,可以迅速追踪到生产不定或者错误状态的原因;性能分析工具帮助分析性能瓶颈,加速仿真;代码覆盖率检查确保测试的完备;多种模式的波形比较功能;先进的 SignalSpy功能,可以方便地访问VHDL或者VHDL和Verilog混合设计中的底层信号;支持加密IP;可以实现与Matlab的Simulink的联合仿真。
3.2.1  ISE环境中ModelSim的使用
ModelSim是一个独立的仿真工具,它在工作的时候并不需要其他软件的协助,在Xilinx公司的ISE集成开发环境中给ModelSim仿真软件预留了接口,通过这个接口可以从ISE集成环境中直接启动ModelSim工具进行仿真。这个过程通常会给初学者一个错觉,以为ISE集成环境和ModelSim工具是联合工作的,其实ISE并没有集成ModelSim工具,只是预留了软件接口。为了说明ModelSim的用户接口,将使用从ISE集成开发环境中直接启动ModelSim仿真工具的方法。使用此种方法启动ModelSim工具需要具备3个条件:第一,启动ISE集成开发环境并建立了一个FPGA/CPLD的工程项目;第二,添加设计源代码并且编译通过;第三,使用ISE中的TestFixture或者TestBenchWaveform工具为当前的设计提供一个测试模板(Testbench),并且在测试模板中添加设计激励。只有上述条件具备之后才可以从ISE的当前资源操作窗中直接启动ModelSim工具并运行仿真,以下使用ISE自带的一个例子加以说明。
在ISE中直接启动ModelSim
1、在Windows操作系统中选择[开始]/[程序]/[Xilinx ISE 6]/[Project Navigator]命令,启动ISE集成开发环境。
2、在ISE主窗口中选择[File]/[Open Example]命令,弹出[Open Example]对话框,如图所示,然后在[Select an Example Project]栏目中选择“goldcode-ver-217”,在[Destination Directory]中选择项目存放的目录,单击OK按钮打开例子程序。
图3-1 打开例子程序
3、在资源管理窗口(Source in Project)中的模块视图(Model View)中选中的测试文件“testbench.tf”,在相应的当前资源操作窗口(Process for Current Source)中将会出现与Modelsim仿真器相关的行为仿真(Simulate Behavioral Verilog Model),翻译后仿真(Simulate Post-Map Verilog Model)和布局布线后仿真(Simulate Post-Place & Route Verilog Model)等4个不同的操作选项,如图所示:
图 3-2 Modelsim 仿真
4、双击[Simulate Behavioral Model]操作选项,将启动Modelsim仿真器。
5、在Modelsim主窗口中选择[View]/[All]命令,将显示所有的窗口。
在当前资源操作窗口中选择任意一个操作选项都可以启动相应阶段的仿真操作,如果相应阶段的仿真文件不存在,那么集成环境将自动生成仿真文件。例如,当双击资源操作窗口中的[Simulate Post-Place & Route Verilog Model]操作选项时将启动时序仿真,而这一仿真过程所需要的布局布线后仿真文件以及时序标注文件都还没有产生,那么ISE集成开发环境将自动开始对这个工程进行编译,综合,翻译,映射和布局布线等操作,得到布局布线后仿真文件以及时序标注文件,然后再启动ModelSim仿真器进行时序仿真。
3.3  ISE介绍
本节主要介绍在XILINX的ISE集成软件环境中,如何用VHDL和原理图的方式进行设计输入,如何用ModelSim仿真工具对设计进行功能仿真和时序仿真,如何实现设计。
3.3.1  建立项目工程
建立新的项目工程,选择【File】,再选择【New Project】,如图就可以了。
图 3-3 ISE建立新工程
选择使用的可编程器件类型device family-器件族名device-器件型号package-封装speed grade-速度top-level module type-顶层文件类型synthesis tool-综合工具simulator-仿真工具generated simulation language-生成的仿真模型语言。
图 3-4 选择器件
然后一路NEXT,最后点击完成。刚生成的工程是没有类型的,需要自己加入。方法是在 sources in project中右击,选择add sources,选择你写的文件加入即可。如果要新写程序,用同样的方法,选择new sources即可,会弹出如下对话框,让你选择New Sources的类型。
图 3-5 选择New Sources的类型
选择vhdl module,写上文件名,在下一页可以写上输入输出口,也可以不写。一路NEXT到完成就可以。这样就可以开始写代码或继续下一步综合了。要打开或编辑新建的文件,直接在sources in project窗口中双击该文件即可。
3.3.2  行为仿真
1、在工程项窗口Project Window的源文件中选中计数器(counter.vhd)。
2、选择Project/New Source。
3、在新的对话框中选择新文件类型为Test Bench Waveform。
4、键入文件名为counter_tbw。
5、点击Next,在其他工程项中你可以将你的testbench波形与其他源文件关联。
6、一直Next直到Finish,此时HDL Bencher 程序自动启动并等候你输入所需的时序需求,你现在可以指定仿真所需的时间参数、时钟高电平时间和时钟低电平时间一起定义了设计操作必须达到的时钟周期,输入建立时间定义了输入在什么时候必须有效,输出有效延时,定义了有效时钟沿到达后多久必须输出有效数据。
默认的初始化时间设置如下:
时钟高电平时间:  Clock high time: 50 ns 。
时钟低电平时间:  Clock low time: 50 ns 。
输入建立时间:   Input setup time: 10 ns 。
输出有效时间:  Output valid delay: 10 ns 。
7、点击OK,接受默认的时间设定。Testbench waveform窗口如下。
图 3-6 Testbench Waveform
在HDL Bencher 的波形中,初始化计数器输入如下:
在每个单元的蓝色区域输入激励。
a、在CLK第1周期下点击RESET单元直到该单元变为。
b、在CLK第2周期下点击RESET单元直到该单元变为低。
c、在CLK第3周期下点击CE单元直到该单元变为高。
d、在CLK第2周期下点击DIR单元直到该单元变为高。
图 3-7 激励输入
e、将你的testbench文件存盘,选择File/Save Waveform或点击工具栏的存盘图标,接下来HDL Bencher会提示你设置你希望仿真的时钟周期数。
f、在End the testbench __ cycles after the last input assignment对话框中输入8,默认值为1。
g、点击OK.退出HDL Bencher新的testbench波形源文件counter_tbw.tbw自动加入到该工程项中。
8、生成预期的输出响应:
我们进行行为仿真以验证计数器模块的功能。
a、在Sources in Project窗口中选择counter_tbw.tbw文件。
b、在Processes for Current Source窗口中点击 + 符号展开ModelSim仿真器的层次结构找到并双击Simulate Behavioral VHDL Model,此时ModelSim仿真器自动启动。
c、对于第一次运行ModelSim的用户会显示一个对话框需要在其中做以下处理:选中Do not show this dialog again选项,点击Run ModelSim此对话框在你重新安装或重新配置ModelSim之前将不再显示你的仿真结果现在显示在ModelSim的波形窗口(wave window)。
d、点击Zoom / Zoom Full;点击Zoom / Zoom in。
e、拖动波形窗口下端的滚动条至窗口的最左端。
图 3-8 仿真图
3.3.3  建立顶层原理图3.3.3.1 生成原理图符号
1、在Sources in Project窗口中选中计数器模块counter.vhd。
2、在Processes for Current Source窗口中,点击设计输入实用程序(Design Entry Utilities)之前的“+”符号然后双击创建原理图符号(CreateSchematic Symbol)经过以上步骤,名称为“counter”的图形化元件被放入到工程项库中。
3.3.3.2 创建顶层原理图
1、在工程项导航器(Project Navigator)菜单中,选择Project/New Source。
2、选择原理图(Schematic)为源类型。
3、输入原理图名为“top”。
4、先点击“Next”再点击“Finish”,此时原理图编辑器(ECS)自动启动并在其原理图窗口中打开一张空图。
3.3.3.3 例化VHDL模块
1、在菜单中选择Add / Symbol或者在工具栏中点击(Add Symbol)图标。
2、从元件符号列表(在屏幕右侧)中选择计数器counter,注意不要在类别(Categories)窗口中作任何选择。
3、点击左键可将计数器counter放置在光标所在的位置出现。
4、按ESC键退出添加符号(Add Symbol)模式。
图 3-9 例化VHDL模块
3.3.3.4 原理图连线
1、首先激活划线功能通过在菜单中选择Add/Wire或者在工具栏中点击 (Add Wire)图标。
2、添加一根悬空线和延展连线,在计数器模块的某一管脚单击鼠标,然后将连线拉伸到需要的长度。再在连线端点处双击鼠标,给计数器模块的每一管脚添加连线。
3、添加两个元件符号之间的连线,在一个计数器模块的管脚处单击鼠标,在另一个计数器模块的对应管脚处双击鼠标。连接好线后按ESC键退出添加连线(Add/Wire)模式。
图 3-10 原理图连线
3.3.3.5 添加输入输出管脚标记
1、在菜单中选择Add/ (I/O Marker)或在工具栏中点击(Add I/O Marker)图标,连接好的图如下。
图 3-11 添加输入输出管脚
2、连接步骤:首先为clock,reset,ce,load,dir1和dir2添加输入标记,同时为总线din1(3:0)和din2(3:0)添加输入标记。在工具栏右边的参数单选框中选择输入(Input);将鼠标移动到输入信号线的端点,此时光标处显示出输入标记的图形;点击鼠标左键,输入标记会将网络名或总线名包含在标记图形的内部。
3、按如下步骤为count总线添加双向信号标记。在工具栏右边的参数单选框中选择双向(Bidirectional);将鼠标移动到输出信号线的端点,此时光标处显示出双向信号标记的图形;点击鼠标左键。
4、在菜单中选择File/Save,保存原理图,退出原理图编辑器(ECS)。
3.3.4  综合3.3.4.1 Synthesize综合
当你编写程序后,并把顶层原理图连接好以后,就可以综合了。选中你的顶层文件,双击Synthesize-Synplify Pro。
图 3-12 综合
如果出现上图的小勾,表示综合没有问题。你可以双击View RTL Schematic来查看综合后的RTL原理图。
3.3.4.2 定义输入输出管脚约束
选中顶层文件,双击下图中的Assign Package Pins,该操作会提示系统将生成一个.ucf文件,选择是,系统将自动启动Xilinx Pace。
图 3-13 分配引脚
图 3-14 Xilinx Pace
现在就可以在LOC栏写上管脚名,定义I/O电平类型,输出电流大小等,需要注意的是一些I/O是有特殊用处的,不能胡乱分配。定义完后保存退出。
3.3.5  布局布线
双击Implement Design,会依次执行Translate,Map,Place&Route。
图 3-15 设计实现
3.3.6  下载及硬件仿真
选中顶层文件,双击运行Generate Programming File,运行后生成相应的(.Bit)下载文件。该文件将下载到芯片中实现设计。
图 3-16 生成下载文件
再双击上图Configure Device。运行后跳出下载界面,选择主从下载文式(Slave Serial Mode),点击完成。
图 3-17 下载方式
右键点击元件,点击Program,选择相应的BIT文件开始下载。
图 3-18 下载位文件
成功下载后就可以在FPGA板子上运行和测试了。

第四章  数字频率计的设计与实现4.1  任务要求
本课题核心任务是完成基于FPGA利用VHDL语言设计一个数字频率计的设计,仿真,下载实现并实际测量效果,同时要熟悉和掌握Spartan-II这块板子的各种性能。考虑到是首次接触VHDL描述语言,并且以前没有过基于FPGA设计的经验,所以在完成课题的同时,也不断的加深对VHDL描述语言的掌握,以及不断总结由软件来实现硬件的特点,为以后的工作和更进一步的学习学习打好基础。除此以外,利用课余时间学习数字频率计的硬件实现方法,即用MultiSim仿真,PROTEL作原理图以及PCB板等。数字频率计的相关技术指标如下:
1、位数:测量频率通过LED数码管为六位十进制数显示。
2、测试频率范围为:1Hz~1MHz。扩展1MHz~100MHz。
3、量程分为三档:
第一档:最小量程档,闸门时间为1S时,最大读数为999.999KHz。
第二档:闸门时间为0.1S时,最大读数为9999.99KHz。
第三档:闸门时间为0.01S时,最大读数为99999.9KHz。
以上三档,实际测得的频率是1Hz~99999.9KHz。显然完全涵盖了1Hz~100MHz的范围。
4、显示工作方式:
a、用BCD七段共阳极数码管显示读数,只有在读数不发生跳变时才是正确的结果。
b、采用记忆显示方法,即在一次测试结束时,显示测试结果,此显示值一直保留到下次测量显示数到来,才将上次显示冲刷更新。用第二次测试结果,更新显示值。
c、实现对高位无意义零的消隐。
5、要求被测输入信号应是符合数字电路要求的脉冲波或正弦波。
4.2  测量原理
在电子技术领域内,频率是一个最基本的参数,频率与其它许多电参量的测量方案、测量结果都有十分密切的关系。因此,频率的测量就显得更为重要.而且,目前在电子测量中,频率的测量精确度是最高的。
4.2.1  频率或时间的原始基准
时间是某一时刻与另一时刻之间的时间长度,这里指的时刻是连续流逝的时间中的一个时点。为了使大家能够确定出同一时刻,就需要使用共同的时刻标尺来衡量,用这个时刻标尺上的标度来客观地认识时刻。要计量时间需要有固定不变的时间单位,用秒作为时间的基本单位。如果一秒内的振动数即频率为已知,则可由此振动数的倒数得到秒的间隔,这就是说单位秒和标准频率数是互相依存的事物。时刻和时间发展的历史,集中反映在秒的定义在不断变迁,秒的准确度不断提高。
采用天文观测方法,求得的太阳出现于天顶的平均周期为平均太阳日。将太阳日分为24×60×60份,得到的秒为零类世界时(记作),其准确度在量级。地球自转受到极运动(极移引起的经度变化)的影响,校正了这个偏差而得到的地球自转的周期,称为第一世界时(记作)。再把地球自转的季度性、年度性的变化(最大可达0.03秒)校正,就引出了第二世界时(记作)。世界时经过五十年的观测,发现其稳定度为。这样,以为标准其计时准确度很难优于
为了得到更准确的均匀不变的时间标准,人们以1.900回归年的31 556 925 9747分之一作为历书时的秒(记作ET),其准确度可达左右。、ET为宏观计时标准,它需要精密的天文观测,手续烦杂,准确度有限。
近年来引进了微观计时标准,这就是利用原子或分子内部能级跃迁所辐射或吸收的电磁波的频率作为基准来计量时间。采用()原子基态的两个超精细能级之间跃迁所对应的9 192 631 770个周期的持续时间为一秒,以此为标准定出的时间标准称为原子时(记作AT),其准确度可达
目前,国际上已经应用经过原子标准修正过的时间来发送时间标准,用原子时来对天文时(、ET)进行修正。另外,由于频率是时间的倒数,因此,有了时间标准也就有了频率标准。
由于数字电路的飞速发展和数字集成电路的普及,电子计数器的应用已十分普及,利用电子计数器测量频率具有精确度高、使用方便、测量迅速,以及便于实现测量过程自动化等一系列突出优点,故已发展成为近代频率测量的重要手段。
4.2.2  电子计数器测频方法
目前,绝大多数实验室用电子计数器都具有测量频率(测频)和测量周期(测周)等两种以上的测量功能,故统称“通用计数器".各种测量功能可利用《功能选择》开关加以选择。
4.2.2.1  电子计数器的测频原理
所谓“频率”,就是周期性信号在单位时间(一秒)内变化的次数。若在一定时间内计得这个周期信号变化的次数为N,则其频率可表达:
                             (4-1)
电子计数器可以严格按照公式(4-1)所表达的频率的定义进行测频,其原理方框图如图 4-1 示:
图 4-1 测频原理图
首先,把被测信号①(以正弦波为例)通过脉冲形成电路转变成脉冲②(实际上变成方波即可)其重复频率等于被测频率,然后将它加到闸门的一个输入端。闸门出门控信号④来控制开、闭时间,只有在闸门开通时间T内,被计数的脉冲⑤才能通过闸门,被送到十进制电子计数器进行计数。门控信号的作用时间T是非常准确的,以它作为时间基准(时基),它由时基发生器提供。时基信号发生一个高稳定的石英振荡器和一系列数字分频器组成,由它输出的标准时间脉冲(时标)去控制门控电路形成门控信号。比如,时标信号的重复周期为1S,则加到闸门的门控信号作用时间T即闸门时间亦准确地等于1s,即闸门开通时间为1s,这时若计得10 000个数,则按式(4-1),被测频率=10.000Hz,若计数器上单位显示为“kHz”,则显示10.000kHz,即小数点定位在第三位。不难设想,若闸门时间改为T=0.1s,则计数值为1 000,这个数乘以10就等于1s的计数值,即Hz。实际上,当改变闸门时间T时,显示器上的小数点也随着往右移一位(自动定位),即显示10.000kHz。
从以上讨论可知,电子计数器的测频原理实质上以比较法为基础,它将和时基信号频率相比,两个频率相比的结果以数字的形式显示出来。
4.2.3  误差分析
下面我们来分析计数器测频的测量误差。从公式(4-1)可知,上述测频方法的测量误差,一方面决定于闸门时间T准不准,另一方面决定于计数器计得的数准不准。根据误差合成方法,从公式(4-1)可得:
                             (4-2)
公式(4-2)中第一项是数字化仪器所特有的误差,而第二项是闸门时间的相对误差,这项误差决定于石英振荡器所提供的标准频率的准确度。现分述如下。
4.2.3.1  ±1误差
在测频时,主门的开启时刻与计数脉冲之间的时间关系是不相关的,所以它们在时间轴上的相对位置是随机的。这样,在相同的主门开启时间内,计数器所计得的数却不一定相同,当主门开启时间T接近甚至等于被测信号周期的整数倍N倍时,此项误差为最大,图 4-2 画出的就是这种情况。
图 4-2 正负1误差
若主门开启时刻为,而第1个计数脉冲出现在,图 4-2 (a)中示出了>>0的情况(),这时计数器计得N个数(图中N=6);现在再来看图 4-2 (b)情况,即趋近于0,这就有两种可能的计数结果:若第1个计数脉冲和第7个计数脉冲都能通过主门,则可计得N+1=7个数;也可能这两个脉冲都没有能进入主门,则只能计得N-1=5个数。由此可知,最大的计数误差为个数。所以考虑到公式(4-1),可写成
                               (4-3)
式中T为闸门时间,为被测频率。从公式(4-3)可知,不管计数值N多少,其最大误差总是±1个计数单位,故称“±1个字误差”,简称“±1误差”。而且一定时,增大闸门时间T,可减小±1误差对测频误差的影响。当T选定后,越低,则由±1误差产生的测频误差越大。
4.2.3.2  标准频率误差
闸门时间T准不准,主要决定于由石英振荡器提供的标准频率的准确度,若石英振荡器的频率为,分频系数为k,则
所以
                         (4-4)
可见,闸门时间的准确度在数值上等于标准频率的准确度,式中负号表示由引起的闸门时间的误差为
通常,对标准频率准确度的要求是根据所要求的测频准确度提出来的,例如,当测量方案的最小计数单位为1Hz,而=Hz,在T=1s时的测量准确度为(只考虑误差),为了使标准频率误差不对测量结果表明产生影响,石英振荡器的输出频率准确度应优于,即比误差引起的测频误差小一个量级。
4.2.3.3  结论
综上所述,可得如下结论:
1、计数器直接测频的误差主要有两项:即误差和标准频率误差。一般,总误差可采用分项误差绝对值合成,即
                         (4-5)
可把公式(4-5)画成图 4-3 所示的曲线,即与T,以及的关系曲线。
图 4-3 误差曲线
从图可知,一定时,闸门时间T选得越长,测量准确度就越高。而当T选定后,越高,则由于误差对测量结果的影响越小,测量准确度就越高。但是,随着误差的减小,标准频率误差将对测量结果产生影响,并以(图中以为例)为极限,即测量准确度不可能优于
2、测量低频时,由于误差产生的测频误差大得惊人,例如,为10Hz,T=1s,则由误差引起的测频误差可达到10%,所以,测量低频时不宜采用直接测频方法。
4.2.4  测量周期的必要性和基本原理4.2.4.1 测量周期的必要性
正如前述,当较低时,利用计数测器直接测频,由误差所引起的测频误差将会大到不可允许的程度。所以,为了提高测量低频时的准确度,即减小误差的影响,可改成先测量周期,然后计算因为越低,则越大,计数器计得的数N也越大,误差对测量结果的影响自然减小。
4.2.4.2 测量周期的基本原理
计数器测量周期的原理方框图如图 4-4 所示。
图 4-4 测周原理图
被测信号(正弦)从B输入端输入,经脉冲形成电路变成方波,加到门控电路,比如=10ms则主门打开10ms,在此期间时标脉冲通过主门计数,若选择时标为则计数器计得的脉冲数等于/=10000个,如以ms为单位,则从计数器显示上可读得10.000(ms)。
从以上讨论可知,计数器测周的基本原理刚好与测频相反,即由被测信号控制主门开门,而用时标脉冲进行计数,所以实质上也是一种比较测量方法。
4.2.4.3 误差分析
与分析电子计数器测频时的误差类似,根据误差传递公式,并结合图 4-4可得:
                         (4-6)
根据图 4-4 测周原理
=
所以,公式(4-6)可写成
             (4-7)
从公式(4-7)可见,测量周期时的误差表达式与测频的表达式形式相似,很明显愈大(即被测频率愈低),误差对测周精确度的影响就愈小。
图 4-5 示出了测周时的误差曲线,图中三条曲线,其中10和100两条线是采用多周期测量(详后)时的误差曲线。
图 4-5 测周时的误差曲线
4.2.4.4 倒数计数器
测量低频时,首选测量周期,然后求倒数得到被测频率值,这是减小由误差产生频率误差的一种有效方法。但是,这种方法不能直接读出频率值,而需要通过1/求倒数才得到频率值。
众所周知,数字电路也可以完成数字运算,所谓倒数计数器,就是这种计数器:首先测量周期,然后自动计算并显示被测频率。图 4-6 示出了一种倒数计数器的简化方框图。
图 4-6 倒数计数器
主门I和计数器I工作在测周模式,即输入频率经触发器加工,形成门控信号,在时间内主门开启,时钟通过主门I计数,计得(被测信号的周期,而为时钟周期)。N作为定标器的预置值,即将定标器预置到。定标器实质上起分频作用,时钟通过门Ⅲ由定标器计数,当计完N个时钟后,计数器溢出并输出一个进位脉冲,即每计完N个时钟输出一个脉冲,故定标器输出频率为或周期为,后者通过主门Ⅱ计数,主门Ⅱ的闸门时间为,计数器计得的数为
                     (4-8)
测周模式计得的数为
                             (4-9)
从公式(4-8)和公式(4-9)可见,计数器II计得的数正比于N的倒数,从而完成了倒数的运算,也就是说,可从计数器II上直接读被测频率,其显示的位数由分频系数而定。将公式(4-9)代入公式(4-8)可得
                             (4-10)
从公式(4-10)可见,主门II和计数器II实际上工作在测频模式,其输入频率就是(注意:由于测周期模式计得的数N本身存在误差,故严格来讲输入频率并非准确地等于),且工作在同步计数方式,即加到主门II的同步。由于同步计数不会产生误差,所以,倒数计数器的误差与测周模式误差相同。
4.2.5  等精度测量
目前,有三种常用的数字频率的测量方法:直接测频法(以下简称M法),直接测周法(以下简称T法)和综合测量法(即相结合的方法,以下简称为M/T法)。前两种测量法的原理,在上面的实验原理里面已经详细的讨论了,不再累述。这两种方法由误差分析可知,其精度都与被测信号的有关,因而它们是非等精度测量法。而M/T法它通过测量被测信号数个周期的时间,然后换算得出被测信号的频率,克服了测量精度对被测信号的依赖性。
M/T法的核心思想是通过闸门信号与被测信号同步,将闸门时间τ控制为被测信号周期长度的整数倍。测量时,先打开预置闸门,当检测到被测信号脉冲沿到达时,标准信号时钟开始计数。预置闸门关闭时,标准信号并不立即停止计数,而是等检测到被测信号脉冲沿到达时才停止,完成被测信号整数个周期的测量。测量的实际闸门时间可能会与预置闸门时间不完全相同,但最大差值不会超过被测信号的一个周期。M/T法测量原理如下图所示。
图 4-7 同步计数
不如令实际闸门时间为τ,被测信号周期数为,标准信号频率为,计数值为,则被测信号的频率值为:
                            (4-11)
由于实际闸门时间τ是由被测信号同步过的,因此在此期间测得的被测信号周期的整数倍是准确的,不存在误差。而标准信号的计数值则存在误差。用来表则标准信号计数的真实值为+。由此可知被测信号的频率真实值为:
                        (4-12)
若不计标准信号时钟的误差,则测量的相对误差为:
                (4-15)
可以看出,在M/T法中,相对误差与被测信号本身的频率特性无关,即对整个测量域而言,测量精度相等,因而称之为“等精度测量”。标准信号的计数值越大则测量相对误差越小,即提高门限时间τ和标准信号频率可以提高测量精度。在精度不变的情况下,提高标准信号频率可以缩短门限时间,提高测量速度。原理图如下:
图 4-8 同等度测量的原理图
计数控制器将标准信号分频为预置信号,预置闸门信号与被测信号作用同步之后输出实际闸门信号,作为周期计数器和脉冲计数器的计数使能信号。同时在实际闸门信号关断的时间里,计数控制器产生一个清数脉冲,用以清除计数器内的计数值,以备下一次计数,该清零脉冲同时还作为一次计数结束后,将计数值进行计算,译码显示的锁存信号,不然,数码管的显示将因为数值的不停跳动而无法看清楚。
运算器则通过不停地做除法运算实现被测信号频率值的计算,显示译码器在收到被测信号频率值后,将该值转换为七段码数据显示的形式,并按照动态扫描方式依次定时先通各个显示管,将显示数值送出,由于人眼的暂留效应,就可以看到稳定的输出值了。
4.3  原理框图
图 4-9 原理框图
4.4  各模块的功能及实现4.4.1  分频器
分频器的功能是提供标准闸门时间控制信号以精确控制计数器的开闭。由于闸门时间只有1S,0.1S,0.01S三档,由于本设计将下载到Spartan-II上,其提供的标准时间是32MHz,为此,我们想到了计数器。对一个两位的二进制计数器,当输入两个脉冲时,其输出进位脉冲为1个,即入/出之比为2比1。如此下推,对输出为2位、3位、4位、5位的二进制计数则其输入/输出为1﹕4,1﹕8,1﹕16,1﹕32……。但十进制例外,输出虽为四位,但输入/输出比为1﹕10。这是因为在此,计数器到9时,但产生了进位。
如果我们采用一个32进制的计数器和六个十进制计数器串行连接,那么,我们在最后的三级上,可分别获得100Hz,10Hz、1Hz、其闸门时间分别为0.01s、0.1s、1s的控制信号。生成的分频器模块如下图所示:
图 4-10 分频器模块
程序中使用了隶属函数generic, Generic ( rate : integer :=10  );定义了一个整形变量rate,通过修改这个整形变量rate的值,可以实现分频器分频数的改变。这样做可以实现程序的调用,只需要修改少量的地方就可以实现不同的分频需要。
源程序如下:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity fdiv is
   Generic (  rate : integer :=10  );
   Port    (  f_in : In  std_logic;
                   f_out : Out std_logic );
end;
architecture behavioral of fdiv is
   signal cnt : integer range 0 to rate := 0;
   signal clk : std_logic:='0';
begin
   process (f_in)
   begin
      if f_in'event and f_in = '1' then
              if cnt /= rate then
                  cnt <= cnt + 1;
              else
                  cnt <= 1;
                  clk<=not clk;
              end if;
      end if;
   end process;
f_out <= clk;
end behavioral;
仿真图如下所示:
图 4-11 分频器模块仿真图
运用component函数对上面程序的调用,即可很轻松的实现几个分频器,而不用再写类似的程序。生成的模块如图所示:
图 4-12 多输出的分频器
这个模块即实现了把32MHz的时基信号分成了我们需要的四个信号1Hz,10Hz,100Hz,1KHz。其源程序如下:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity Fdiv3 is
    Port ( clkin : in std_logic;
           clkout1 : out std_logic;
           clkout10 : out std_logic;
           clkout100 : out std_logic;
                            clkout1k              :   out std_logic);
end Fdiv3;
architecture structure of Fdiv3 is
   component fdiv is
    Generic (  rate : integer :=10  );
   Port    (  f_in : In  std_logic;
                   f_out : Out std_logic );
    end component fdiv;
                  signal carry1,carry2,carry3:std_logic;
begin
   U1:fdiv generic map(rate=>16000) port map (f_in=>clkin,f_out=>carry1);
   U2:fdiv generic map(rate=>5) port map (f_in=>carry1,f_out=>carry2);
   U3:fdiv generic map(rate=>5) port map (f_in=>carry2,f_out=>carry3);
   U4:fdiv generic map(rate=>5) port map (f_in=>carry3,f_out=>clkout1);
   clkout1K <= carry1;
   clkout100 <= carry2;
   clkout10<=carry3;
end structure;
4.4.2  闸门选择器
该模块的功能是实现对输入的几个闸门信号的手动选择,并输出被选中的闸门信号以及小数点的控制信号DP1,DP2,DP3。生成的模块如下图所示:
图 4-13 闸门选择器
该模块有六个输入端口,其中se1,se10,se100为选择使能端,f1hz,f10hz,f100hz为被选时基信号输入端。当se1为1时,f1hz的输入时基信号被选中,被赋值给输出端口fref输出,此时DP1有效,DP2和DP3无效,点亮DP1连接的小数点;当se1为0,se10为1时,f10hz时基信号被选中,DP2有效,DP1和DP3无效,点亮由DP2连接的小数点;最后当se1和se10都无效时,即都为0时,se100为1时,f100hz端口的输入信号被选中作为输出,DP3有效,DP1和DP2无效,点亮由DP3连接的小数点。
本模块的源程序如下:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity sele is
      port(se1,se10,se100:              in              std_logic;
                    f1hz,f10hz,f100hz:              in              std_logic;
                            fref:                                          out              std_logic;
                            dp1,dp2,dp3:                            out              std_logic);
end sele;
architecture Behavioral of sele is
begin
  process (se1,se10,se100,f1hz,f10hz,f100hz)
   begin
      fref <= '0'; dp1 <= '0';dp2 <= '0';dp3 <= '0';
      if se1 = '1' then
              fref <= f1hz;
              dp1<= '1';
      elsif se10 = '1' then
              fref <= f10hz;
              dp2 <= '1';
      elsif se100 = '1' then
              fref <= f100hz;
              dp3 <='1';
      end if;
   end process;
end Behavioral;
1


第四章  数字频率计的设计与实现
仿真图如下所示:
图 4-14 闸门选择器仿真图
4.4.3  测频控制器
测频控制器是控制整个频率计各模块进行时序工作的控制装置,它对输入的标准时钟信号进行变换,产生我们所需要的三个信号闸门信号GATE,锁存信号LATCH以及清零信号CLEAR。如使用一个低触发器处理1Hz的时钟信号,其Q端输出,即是脉宽1S计数器使能端的控制信号,而输出即为脉宽1S的锁存器使能信号。计数清零信号也由测频控制器变换后输出,控制整个电路。其生成的元件符号如下图所示:
图 4-15 测频控制器
测频控制信号发生器设计要求:频率测量的基本原理是计算每秒钟内待测信号的脉冲个数。这就要求Control的计数使能信号Gate能产生一个周期信号,并对频率计的每一计数器Counter6的Carry_in使能端进行同步控制。当Gate为高电平时,允许计数,为低电平时停止计数,并保持其所计的脉冲数。在停止计数期间,首先需要一个锁存信号latch的上跳沿将计数器在前1秒钟的计数值锁存进24位锁存器Latch中,并由外部的7段译码器译出,并稳定显示。设置锁存器的好处是,显示的数据稳定,不会由于周期性的清零信号而不断闪烁。锁存信号之后,必须有一清零信号Reset对计数器进行清零,为下1秒钟的计数操作准备。源程序如下:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity control is
    Port ( Bsignal : in std_logic;
           Gate : out std_logic;
           Reset : out std_logic;
           latch : out std_logic);
end control;
architecture Behavioral of control is
                signal G1,G2: std_logic:='0';
begin
process(Bsignal,G1)
                begin
                            if rising_edge(Bsignal) then
                                 G1<=not G1;
                            end if;
                            if falling_edge(bsignal) then
                                          G2<=not G1;
                            end if;            
end process;
                            gate<=G1;
                            latch<=G2;
                            reset<=(not bsignal)and(not G1)and (G2);
end Behavioral;
测频控制信号发生器的仿真工作时序如图所示。
图 4-16 测频控制器的仿真图
如果闸门信号Gate的频率取1Hz,那么信号Gate的脉宽恰好为1S,可以用作计数闸门信号。然后根据测频的时序要求,可得出信号latch和Reset的逻辑描述。由图可见,在计数完成后,即计数使能信号Gate在1S的高电平后,利用其反相值产生一个锁存信号latch,由于反相器的器件延时,锁存信号的上升沿是在计数使能信号即闸门信号Gate的下降沿之后,即是计数完了才锁存的,符合我们的设计要求。而清零信号Reset的上升沿的产生是在下一个Gate信号上升沿来临之前,也就是说是清了零才开始计数的,不是计了一会儿数再被清零了继续计数,这也是与我们的设计要求相符合的。高质量的测频控制信号发生器的设计十分重要,设计中要对其进行仔细的实时仿真,防止可能产生的毛刺。
4.4.4  频率计数器
由于要求频率计的显示为十进制六位,所示我们设计的是使能端的十进制计数器,所生成的模块如图所示:其中RST是清零端,CLK是计数信号输入端,Carry_in是计数保持端,即为高电平时计数,低电平时停止计数保持计数不变。Count_out是计数结果输出,carry_out是进位信号。
图形 4-17 单个计数器模块
其源程序为:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity counter is
port (rst,clk : in std_logic;
      carry_in  : in std_logic;
      carry_out : out std_logic;
      count_out     : out std_logic_vector(3 downto 0));
end counter;
architecture Behavioral of counter is
                 signal count: std_logic_vector(3 downto 0):="0000";
begin
              process(rst,clk)
                  begin
                            if rst='1' then
                                count <= "0000";
                            elsif clk'event and clk= '1' then
                                          if carry_in = '1' then
                                                        if  count < "1001" then
                                                            count <= count+1;
                                                        else
                                                            count <= "0000";
                                                        end if;
                                              else
                                          null;
                                          end if;
                            end if;            
                end process;
      count_out<=count;
              carry_out <= '1' when carry_in = '1' and count = "1001" else '0';
end Behavioral;
仿真图如下图所示:
图 4-18 单个计数器的仿真图
由仿真图可以看出,程序的综合出来的这个计数器的确实现我们预定的要求。有清零端和保持端,通过对计数器的级联就可以实现十进制六位数的计数。
被测信号接至此计数器的Csignal。清零端clear和保持端count_en分别与测频控制器Reset端和闸门信号Gate相对接。计数器输出端与锁存器输入端对接,而进位输出端则依次接到下一位计数器的保持端cout_en,惟第六位即最高位的进位输出作为溢出标志用over来表示,用以显示计数器计数是否溢出,溢出了就更换大一级的档位。这样的级联形成了同步计数,是一种计数较快的级联方式,生成的原理模块如下:
图 4-19 级联后的计数器
计数器模块级联的程序跟频率计级联程序雷同,这里不再贴出,有兴趣的朋友可以参考附录。级联成六位计数器的仿真图如下:
图 4-20 六位计数器的仿真图
4.4.5  锁存器
如果计数器输出直接与译码器相连接,那么在计数过程中输出端则随输入脉冲数的增加而不断跳变,那么显示数码管则也会不断闪烁跳变,让人不能看到稳定的输出,设锁存器后,则不再跳变,便可清晰读出计数结果。由control控制模块产生的latch信号来提供锁存脉冲。其生成的功能模块如图所示:
图 4-21 锁存器模块
这模块实现了对六位计数结果和溢出信号over的锁存功能。程序很简单,即锁存信号的上升沿来时送数,其它时候则保持不变。具体程序参考附录。
4.4.6  扫描显示控制译码系统
本模块通过用一个频率1KHz的信号来扫描一个多路选择器,实现对六位已经锁存的计数结果的扫描输出,由于1KHz相对了人眼的暂留效应已经很高了,所以显示结果不会让人感觉到闪烁。这样就可以用一个译码器来实现对六个4位二进制数的译码。译码结果再连接到一个多路选择器的输入端,同样由1KHz的信号来同步扫描选通。同时本模块还实现了无意义零的消隐。最出的输出全部通过下载前的固定引脚连接到LED显示管上。实现最终结果的数字显示。输入端包括扫描信号1KHz,由前面产生在本模块起控制作用的溢出信号Q_over,小数点指示信号Dp1,Dp2以及锁存器的输出结果。

其生成模块如下:
图 4-22 显示译码控制模块
其源程序如下:
  1. library IEEE;
  2. use IEEE.STD_LOGIC_1164.ALL;
  3. use IEEE.STD_LOGIC_ARITH.ALL;
  4. use IEEE.STD_LOGIC_UNSIGNED.ALL;
  5. entity multi is
  6.        port(f1khz,q_over              :              in              std_logic;
  7.                                 dp1,dp2              :              in              std_logic;            
  8.                     freq_value0,freq_value1              :              in              std_logic_vector(3 downto 0);
  9.                             freq_value2,freq_value3              :              in              std_logic_vector(3 downto 0);
  10.                             freq_value4,freq_value5              :              in              std_logic_vector(3 downto 0);
  11.                             out0,out1,out2,out3,out4,out5:              out               std_logic_vector(6 downto 0));
  12. end multi;
  13. architecture Behavioral of multi is
  14.               signal               sel                            :              std_logic_vector(2 downto 0):="000";
  15.               signal               hide                            :              std_logic;
  16.               signal               data                            :              std_logic_vector(3 downto 0);
  17.               signal              led                            :              std_logic_vector(6 downto 0);            
  18. begin
  19.               scan : process (f1khz)
  20.                                begin
  21.                                   if rising_edge(f1khz) then
  22.                                                         if sel  = "101" then
  23.                                                             sel <= "000";
  24.                                                         else
  25.                                                             sel <= sel + 1;
  26.                                                         end if;
  27.                                   end if;
  28.                                end process;
  29.               mux:process(sel,freq_value0,freq_value1,freq_value2,freq_value3,freq_value4,freq_value5)
  30.                                begin
  31.                     case sel is
  32.                                           when "000" =>              data <= freq_value0;
  33.                                           when "001" =>              data <= freq_value1;
  34.                                           when "010" =>              data <= freq_value2;
  35.                                           when "011" =>              data <= freq_value3;
  36.                                           when "100" =>              data <= freq_value4;
  37.                                           when others =>              data <= freq_value5;
  38.                     end case;
  39.                                end process;
  40.               bcd2led : process (hide,data)
  41.                                begin
  42.                     led <= "1111111";
  43.                     if hide /= '1' then
  44.                                           case data is
  45.                                               when "0000" =>  led <= "0000001";            
  46.                                               when "0001" =>  led <= "1001111";            
  47.                                               when "0010" =>  led <= "0010010";            
  48.                                               when "0011" =>  led <= "0000110";            
  49.                                               when "0100" =>  led <= "1001100";            
  50.                                               when "0101" =>  led <= "0100100";            
  51.                                               when "0110" =>  led <= "0100000";            
  52.                                               when "0111" =>  led <= "0001111";            
  53.                                               when "1000" =>  led <= "0000000";
  54.                                               when "1001" =>  led <= "0000100";
  55.                                               when others =>  null;
  56.                                           end case;
  57.                     end if;
  58.                                end process;
  59.               fenpei:process(sel,led)
  60.                                           begin
  61.                                           out0<="1111111";
  62.                                  out1<="1111111";
  63.                                  out2<="1111111";
  64.                                  out3<="1111111";
  65.                                  out4<="1111111";
  66.                                  out5<="1111111";            
  67.                                                         case sel is
  68.                                                                       when "000" => out0 <= led;
  69.                                                                       when "001" => out1 <= led;
  70.                                                                       when "010" => out2 <= led;
  71.                                                                       when "011" => out3 <= led;
  72.                                                                       when "100" => out4 <= led;
  73.                                                                       when "101" => out5 <= led;
  74.                                                                       when others => null;
  75.                                                         end case;
  76.                             end process;            
  77.                  hide_zero:process (sel,q_over,dp1,dp2,freq_value5,freq_value4,freq_value3,freq_value2)
  78.                                begin
  79.                     hide <= '0';
  80.                     case sel is
  81.                             when "101" =>
  82.                                               if q_over = '0' and freq_value5 = "0000"
  83.                                                  then hide <= '1';
  84.                                               end if;
  85.                             when "100" =>
  86.                                               if q_over = '0' and freq_value5 = "0000"
  87.                                                         and freq_value4 = "0000"
  88.                                                  then hide <= '1';
  89.                                               end if;
  90.                             when "011" =>
  91.                                               if q_over = '0' and freq_value5 = "0000"
  92.                                                             and freq_value4 = "0000"
  93.                                                             and freq_value3 = "0000"
  94.                                                             and dp1 /= '1'
  95.                                    then hide <= '1';
  96.                                               end if;
  97.                             when "010" =>
  98.                                               if q_over = '0' and freq_value5 = "0000"
  99.                                                             and freq_value4 = "0000"
  100.                                                             and freq_value3 = "0000"
  101.                                                             and freq_value2 = "0000"
  102.                                                             and dp1 /= '1'
  103.                                                             and dp2 /= '1'
  104.                                    then hide <= '1';
  105.                                               end if;
  106.                             when others =>
  107.                                               null;
  108.                     end case;
  109.                                end process;
  110. end Behavioral;
复制代码


仿真结果如下:
图 4-23 显示译码控制模块的仿真图
4.5  顶层原理图
将各程序生成的模块按我们的要求连接就形成了顶层原理图。再定义好输入输出引脚,就可以做最后的综合和设计实现了。原理图过大,可参考附录。
以下是最后的仿真,第一个是局部的放大,第二个仿真结果的整体。在仿真图上可以看出程序的综合的确达到了我们的要求。能清零,小数点随着闸门的变化而变化,正确显示是否溢出,以及成功的计数和译码显示。
图 4-24 顶层原理图仿真的局部放大
图 4-25 顶层原理图仿真图整体
4.6  分配引脚和下载实现
全部仿真通过后,就运行ISE的设计实现,然后再打开XILINX PACE,在里面分配引脚,即实现设计的输入输出端口与实际芯片的输入输出端口的对应连接。比如七段LED管的控制信号就连接到实际电路的七个引脚。需要注意的是一些端口是固定的,不能胡乱的连接。比如时基信号即石英振荡器所提供的信号就只能由P181输入。同时还要考虑内部的可配制逻辑块CLB的数量是否够满足程序的综合要求。一切都准备就绪后就可以运行Configure Device,选择要下载的位文件(.bit)便可开始下载了。
4.7  测试结果
在成功下载并运行后,为评估该设计系统的实际测量效果,做了一次对比实验,选用频率可调的函数发生器SP1641B,同时用示波器TDS210 Tektronix做同步的跟踪。测得的数据很精确,跟函数发生器以及示波器的显示全吻合。最低频率可以测到1Hz,不过要求输入信号很稳定且为方波,因为芯片输入端口自带的整形电路能力毕竟有限。在做高频的对比测量时,波形发生器换成了Agilent公司生产的4410做信号源。结果表明该设计的确能测量到100MHz,测量结果表明该设计达到了最初的提出的所有设计要求。

第五章  结论
本文主要介绍了利用VHDL语言完成基于FPGA的数字频率计的设计与实现。详细介绍了测量原理,设计方案以及各模块的设计过程及其实现的功能,并对设计中遇到的问题作了分析和处理;利用ISE和ModelSim对设计进行了仿真,分析,综合,并最终下载到Spartan-II系列芯片中,实现了对频率的测量。
传统数字频率计由于在高频段受基准时钟频率的限制,其测频精度受到很大的限制.本设计应用EDA技术,很好的解决了这一问题.在设计完成后,为评估系统的实际测量效果,做了一次对比实验,测量结果表明测量精度基本能达到,可满足一般测量精度的要求。但当被测信号频率较低时,测试精度较低,误差变大。究其原因,除了数字测量本身的正负误差和标准信号引起的误差外,还发现低频信号的上升沿和下降沿的变化较缓慢,影响了计数器的计数值,造成了测量精度的下降。
这是第一次利用HDL语言来实现基于FPGA的实际工程项目,所以在实践过程中不可避免的遇到了很多问题以及设计中一些不足的地方。理论和实践没有有机的联系起来,理论没有起到应有的指导作用。如本来可以实现测量档位的自动切换。同时受到FPGA板子本身的限制(小数点不受控于芯片I/O的输出信号),小数点的变化只能由另外的LED来体现。

附录1.  计数器级联程序
  1. library IEEE;
  2. use IEEE.STD_LOGIC_1164.ALL;
  3. use IEEE.STD_LOGIC_ARITH.ALL;
  4. use IEEE.STD_LOGIC_UNSIGNED.ALL;
  5. entity counter6 is
  6.    port(Csignal              :              in               std_logic;
  7.                  clear                            :              in              std_logic;
  8.                  count_en              :              in              std_logic;
  9.                  over                            :              out              std_logic;
  10.                  result1              :              out               std_logic_vector(3 downto 0);
  11.                  result2              :              out               std_logic_vector(3 downto 0);
  12.                  result3              :              out               std_logic_vector(3 downto 0);
  13.                  result4              :              out               std_logic_vector(3 downto 0);
  14.                  result5              :              out               std_logic_vector(3 downto 0);
  15.                  result6              :              out               std_logic_vector(3 downto 0));
  16. end counter6;
  17. architecture structure of counter6 is
  18.               component counter is
  19.                    port(rst,clk                 :               in               std_logic;
  20.                                   carry_in                :               in               std_logic;
  21.                                   carry_out               :               out               std_logic;
  22.                                   count_out               :               out               std_logic_vector(3 downto 0));
  23.               end component counter;
  24.             
  25.               signal              carry1,carry2,carry3,carry4,carry5,carry6:              std_logic;
  26.               signal              over1              :std_logic;                           
  27. begin
  28.                             U1 : counter Port map (     rst => clear,
  29.                                                               clk => Csignal,
  30.                                                         carry_in => count_en,
  31.                                                         carry_out => carry1,
  32.                                                             count_out => result1   );
  33.                             U2 : counter Port map (     rst => clear,
  34.                                                               clk => Csignal,
  35.                                                         carry_in => carry1,
  36.                                                         carry_out => carry2,
  37.                                                             count_out => result2   );
  38.                             U3 : counter Port map (     rst => clear,
  39.                                                               clk => Csignal,
  40.                                                         carry_in => carry2,
  41.                                                         carry_out => carry3,
  42.                                                             count_out => result3   );
  43.                             U4 : counter Port map (     rst => clear,
  44.                                                               clk => Csignal,
  45.                                                         carry_in => carry3,
  46.                                                         carry_out => carry4,
  47.                                                             count_out => result4   );
  48.                             U5 : counter Port map (     rst => clear,
  49.                                                               clk => Csignal,
  50.                                                         carry_in => carry4,
  51.                                                         carry_out => carry5,
  52.                                                             count_out => result5   );
  53.                             U6 : counter Port map (     rst => clear,
  54.                                                               clk => Csignal,
  55.                                                         carry_in => carry5,
  56.                                                         carry_out => carry6,
  57.                                                         count_out => result6   );
  58. process (clear,csignal)
  59.    begin
  60.       if clear = '1' then
  61.               over1<= '0';
  62.       elsif rising_edge(csignal) then
  63.       over1 <= carry6 or over1;
  64.       end if;
  65.    end process;
  66.    over<=over1;
  67. end structure;
复制代码

附录2.  锁存器源程序
  1. library IEEE;
  2. use IEEE.STD_LOGIC_1164.ALL;
  3. use IEEE.STD_LOGIC_ARITH.ALL;
  4. use IEEE.STD_LOGIC_UNSIGNED.ALL;
  5. entity latch is
  6.   port ( latchin              :              in std_logic;
  7.          overin              :              in std_logic;
  8.                      numin1              :              in std_logic_vector(3 downto 0);
  9.                   numin2              :              in std_logic_vector(3 downto 0);
  10.                   numin3              :              in std_logic_vector(3 downto 0);
  11.                   numin4              :              in std_logic_vector(3 downto 0);
  12.                   numin5              :              in std_logic_vector(3 downto 0);
  13.                   numin6              :              in std_logic_vector(3 downto 0);
  14.                   overout              :              out std_logic;
  15.                   numout1              :              out std_logic_vector(3 downto 0);
  16.                   numout2              :              out std_logic_vector(3 downto 0);
  17.                   numout3              :              out std_logic_vector(3 downto 0);
  18.                   numout4              :              out std_logic_vector(3 downto 0);
  19.                   numout5              :              out std_logic_vector(3 downto 0);
  20.                   numout6              :              out std_logic_vector(3 downto 0));                                                      
  21. end latch;
  22. rchitecture Behavioral of latch is
  23. begin
  24.   process(latchin)
  25.     begin
  26.    if rising_edge(latchin) then
  27.    overout<=overin;
  28.    numout1<=numin1;
  29.    numout2<=numin2;
  30.    numout3<=numin3;
  31.    numout4<=numin4;
  32.    numout5<=numin5;
  33.    numout6<=numin6;
  34.     end if;
  35.   end process;
  36. end Behavioral;
复制代码


附录3.  顶层原理图

附录4.  计数器的级联图



完整的Word格式文档51黑下载地址:
数字式频率计的设计过程,其中包含了所用到的VHDl语言的源代码,和仿真图型.rar (1.77 MB, 下载次数: 39)
回复

使用道具 举报

ID:1 发表于 2019-1-25 01:44 | 显示全部楼层
好资料,51黑有你更精彩!!!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表