光电与通信工程学院课程设计报告书课设名称:等精度频率计年级专业及班级:姓名:学号:一、课程设计目的1、进一步熟悉 Quartus Ⅱ的软件使用方法,熟悉 keil 软件使用;2、熟悉单片机与可编程逻辑器件的开发流程及硬件测试方法;3、掌握等精度频率计设计的基本原理。
4、掌握独立系统设计及调试方法,提高系统设计能力。
实验设备EDA最小系统板一块(康芯)、PC机一台、示波器一台、信号发生器一台、万用表一个。
二、设计任务利用单片机与FPGA设计一款等精度频率计,待测脉冲的检测及计数部分由FPGA实现,FPGA的计数结果送由单片机进行计算,并将最终频率结果显示在数码管上。
要求该频率计具有较高的测量精度,且在整个频率区域能保持恒定的测试精度,具体指标如下:a)具有频率测试功能:测频范围 100Hz~5MHz。
测频精度:相对误差恒为基准频率的万分之一。
b)具有脉宽测试功能:测试范围 10μs~1s,测试精度:0.1μs。
c)具有占空比测试功能:测试精度1%~99%。
d)具有相位测试功能。
(注:任务a 为基本要求,任务 b、c、d 为提高要求)三、基本原理基于传统测频原理的频率计的测量精度将随被测信号频率的下降而降低,在实用中有较大的局限性,而等精度频率计不但具有较高的测量精度,而且在整个频率区域能保持恒定的测试精度。
3.1 等精度测频原理等精度频率计主控结构如图 1 所示预置门控信号 CL 选择为 0.1~1s 之间(通过测试实验得出结论:CL 在这个范围内选择时间宽度对测频精度几乎没有影响)。
BZH 和 TF 分别是 2 个高速计数器,BZH 对标准频率信号(频率为 Fs)进行计数,设计数结果为 Ns;TF 对被测信号(频率为Fx)进行计数,计数结果为 Nx,则有MUX64-8 模块并不是必须的,可根据实际设计进行取舍。
分析测频计测控时序,着重分析 START的作用,完成等精度频率计设计。
3.2 FPGA 模块FPGA模块所要完成的功能如图 1 所示,由于单片机的速度慢,不能直接测量高频信号,所以使用高速 FPGA 为测频核心。
100MHZ 的标准频率信号由FPGA 内部的 PLL 倍频实现,待测信号 TCLK 为方波,由信号发生器给出待测方波信号(注意:该方波信号带有直流偏置,没有负电压,幅值3.3V)。
预制门控信号 CL 由单片机发出,BRNA 和 ENA 分别是 BZH 与 TF 两个计数器的计数允许信号端。
FPGA 将允许计数时间内的 BZH、TF 的运行结果送入单片机进行最后的计算。
顶层文件如下:2以下是把20M 5倍频的设置,利用FPGA内部的PLL。
电路需要100M标准频率信号,FPGA提供20M的频率,所以需要建立PLL模块,使之五杯频,得到所需的100M信号。
功能仿真设置:下图是波形仿真的结果:3.3 单片机模块单片机模块完成对整个测频系统的控制,包括对FPGA的控制以及数码管的显示控制。
测频允许信号由单片机发出,并且单片机的P0 口负责循环读取FPGA 发送过来的测频结果数据(BZH、TF两个计数器的计数结果,每次传送8位数据),P2负责发送控制信号,单片机可以通过结束信号了解测频记数是否结束,以确定何时开始读取数据。
附上康芯原理图截图:四、实验现象占空比五、心得体会这周课程设计的题目是等精度频率计的设计,由于书本上有一段程序,所以一开始只是将书上的程序和显示波形研究了一下。
当到课程设计的时候,将书上程序敲入并实现效果后有点茫然的感觉。
于是,我又仔仔细细地分析了一遍设计原理,从新改变了输入的代码,加上自己的思路,并能自己添加预置控制信息CL模块。
原本我还想将测试频率显示在数码管上,但是最终没能实现,这应该是我的一个遗憾吧。
设计中,我感受到了硬件描述语言的强大,我可以几乎不用考虑硬件条件,将代码导入就可实现功能。
不要总想着去依靠书本上的原题或者是他人,自己思考的做出来的,才算是自己真正收获的。
本次实验最大的收获莫过于,独立系统的去完成一项任务。
在其中我查阅了大量的资料,尤其是数字电路、quartersⅡ软件使用说明、EDA设计等方面的资料。
通过本次学习使我对时序电路有了更深的理解,具体体现在复位、计数、锁存多环节的控制上。
同时,在这次实验中,我第一次联合单片机和EDA一起完成一个项目。
EDA充分的发挥其高频工作的特点,使得频率测量的上限很高。
单片机则在整个系统中充当控制及数据处理的作用设计的优点及缺点本频率计最大优点在于它的高精度。
信号频率的测量,不受闸门信号精度的影响。
在被测信号送入计数器之前,先通过D触发器,使闸门信号和被测信号同步,有效地避免了±1误差。
不仅如此,本频率计对100HZ至5MHZ的全域相对误差均小于百万之一。
当然,本频率计也存在缺点。
在频率计的设计中,乘法器为32位,除法器采用64位,资源占用率太大。
单片机处理32位数据的方式有待改进,要是它变得更优化六、系统设计步骤及程序,结果FPGA:LIBRARY IEEE;USE IEEE.STD_LOGIC_1164.ALL;USE IEEE.STD_LOGIC_UNSIGNED.ALL;ENTITY EQUALFRECOUNT ISPORT(BCLK,TCLK:IN STD_LOGIC;DATA_OUT:OUT STD_LOGIC_VECTOR(7 DOWNTO 0);EN:IN STD_LOGIC;ADDRESS:IN STD_LOGIC_VECTOR(3 DOWNTO 0));END EQUALFRECOUNT;ARCHITECTURE ARCH OF EQUALFRECOUNT ISSIGNAL EN2,WIDE_TEST:STD_LOGIC;SIGNAL WIDE_COUNT,B_COUNT,T_COUNT:STD_LOGIC_VECTOR(31 DOWNTO 0);SIGNAL SAVE_WIDE,SAVE_B,SAVE_T:STD_LOGIC_VECTOR(31 DOWNTO 0); BEGINPROCESS(EN,TCLK)BEGINIF RISING_EDGE(TCLK) THENEN2<=EN;ELSE NULL;END IF;END PROCESS;PROCESS(EN2,TCLK,BCLK)BEGINIF EN2='1' THENIF RISING_EDGE(TCLK) THENIF T_COUNT=X"FFFF_FFFF" THENT_COUNT<=(OTHERS=>'1');ELSE T_COUNT<=T_COUNT+1;SAVE_T<=T_COUNT+1;--SAVE T_COUNTEND IF;ELSE NULL;END IF;IF FALLING_EDGE(TCLK) THENIF WIDE_TEST='0' THENWIDE_COUNT<=B_COUNT;WIDE_TEST<='1';ELSE SAVE_WIDE<=WIDE_COUNT;--SAVE WIDE_COUNTEND IF;END IF;IF RISING_EDGE(BCLK) THENIF B_COUNT=X"FFFF_FFFF" THENB_COUNT<=(OTHERS=>'1');ELSE B_COUNT<=B_COUNT+1;SAVE_B<=B_COUNT+1;--SAVE B_COUNT IN SAVE_BEND IF;ELSE NULL;END IF;ELSE--WHEN ENA=0,WE OUTPUT THE DATA AND RESET THE COUNTER.WIDE_COUNT<=(OTHERS=>'0');B_COUNT<=(OTHERS=>'0');T_COUNT<=(OTHERS=>'0');WIDE_TEST<='0';END IF;END PROCESS;PROCESS(ADDRESS,EN2,SAVE_T,SAVE_B,SAVE_WIDE,BCLK)BEGINIF RISING_EDGE(BCLK) THENIF EN2='0' THEN--USE SOME CONSTANTS TO TESTCASE ADDRESS ISWHEN X"0"=>DATA_OUT<=SAVE_T(7 DOWNTO 0);WHEN X"1"=>DATA_OUT<=SAVE_T(15 DOWNTO 8);WHEN X"2"=>DATA_OUT<=SAVE_T(23 DOWNTO 16);WHEN X"3"=>DATA_OUT<=SAVE_T(31 DOWNTO 24);WHEN X"4"=>DATA_OUT<=SAVE_B(7 DOWNTO 0);WHEN X"5"=>DATA_OUT<=SAVE_B(15 DOWNTO 8);WHEN X"6"=>DATA_OUT<=SAVE_B(23 DOWNTO 16);WHEN X"7"=>DATA_OUT<=SAVE_B(31 DOWNTO 24);WHEN X"8"=>DATA_OUT<=SAVE_WIDE(7 DOWNTO 0);WHEN X"9"=>DATA_OUT<=SAVE_WIDE(15 DOWNTO 8);WHEN X"A"=>DATA_OUT<=SAVE_WIDE(23 DOWNTO 16);WHEN X"B"=>DATA_OUT<=SAVE_WIDE(31 DOWNTO 24);WHEN OTHERS=>NULL;END CASE;ELSE NULL;END IF;ELSE NULL;END IF;END PROCESS;END ARCH;单片机:/* *.c文件,文件名:EqualFre_main.c*各模块的流程控制*/#include "EqualFre_main.h"int main(void){communicationInit_Ex();while(1){mode = getMode_Ex(); //确定选择的模式askForData_Ex(); //请求数据if(HOLD_DATA_MODE != mode){ //表示没有固定数据时,则载入数据loadData();}disData(); //数据显示}}//数据载入static void loadData(){fre = getFre_Ex();wide = getWide_Ex();duty = getDuty_Ex();}/***************************************数据显示中:wData(uchar) 传入的参数意义0 - 9 数字0-910 - 19 跟了点号的0-920 暗选***************************************/static void disDelay(){ //显示延时uchar data x,y;for(x=250;x>0;x--)for(y=50;y>0;y--);}//数据显示--总控static void disData(){switch(mode){case SHOW_FRE_MODE: disFre(); disDelay(); break;case SHOW_WIDE_MODE: disWide(); disDelay();break;case SHOW_DUTY_MODE: disDuty(); disDelay(); break;default:break;}}/*static void disFre(){uchar data i;for(i=0;i<8;i++)wData_Ex(1);}static void disWide(){uchar data i;for(i=0;i<8;i++)wData_Ex(2);}static void disDuty(){uchar data i;for(i=0;i<8;i++)wData_Ex(3);}*///数据显示--显示频率,单位Hz或MHz(双模式)static void disFre(){uchar data dataTemp[8],i;ulong data freTemp = fre;//为了显示1位小数,这里已经将频率扩大10倍uchar data flag = 0;//消零标志位if(1000000 <= freTemp){//当频率值大于1M时,使用兆显示模式freTemp /= 100000;//0.00MHzfor(i=2;i<8;i++){//数据从低位到高位装入数据暂存器dataTemp,这里保留2位,用于显示nH(即MHz)dataTemp[i] = (uchar)(freTemp%10);freTemp /= 10;}dataTemp[4] += 10;//取2位小数,这里是加入小数点dataTemp[1] = 21;//ndataTemp[0] = 22;//H}else{for(i=1;i<8;i++){dataTemp[i] = (uchar)(freTemp%10);freTemp /= 10;}dataTemp[2] += 10;dataTemp[0] = 22;//H}for(i=0;i<8;i++){//数据从高位到低位显示,并进行高位消零操作if(0 != dataTemp[7-i]){flag = 1;}if((0==dataTemp[7-i])&&(0==flag)){dataTemp[7-i] = 20;}wData_Ex(dataTemp[7-i]); //显示数据}}//数据显示--显示脉宽,单位us,意味着最大只能测1MHz的频率static void disWide(){uchar data dataTemp[8],i;ulong data wideTemp = wide;uchar data flag = 0;for(i=0;i<8;i++){dataTemp[i] = (uchar)(wideTemp%10);wideTemp /= 10;}for(i=0;i<8;i++){//数据从高位到低位显示,并进行高位消零操作if(0 != dataTemp[7-i]){flag = 1;}dataTemp[1]|=10;if((0==dataTemp[7-i])&&(0==flag)){dataTemp[7-i] = 20;}wData_Ex(dataTemp[7-i]);}}//数据显示--显示占空比static void disDuty(){uchar data dataTemp[4],i;uint data dutyTemp = duty;for(i=0;i<4;i++){dataTemp[i] = (uchar)(dutyTemp%10);dutyTemp /= 10;}dataTemp[2] += 10;wData_Ex(20);//补4个暗选wData_Ex(20);wData_Ex(20);wData_Ex(20);for(i=0;i<4;i++){wData_Ex(dataTemp[3-i]);}}/**.h文件,文件名:EqulaFre_SGMDisplay.h*SGM显示模块,用于显示由主程序传过来的数据*硬件资源:164时钟端--P3.1164数据端--P3.0*/#ifndef _EQUALFRE_SGMDISPLAY_H_H_#define _EQUALFRE_SGMDISPLAY_H_H_#include<reg52.h>#include<intrins.h>#define uchar unsigned charsbit sgm_clk=P3^1; //164时钟端sbit sgm_data=P3^0; //164数据端static uchar code num[] = {//从低位到高位,高电平有效0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6,//数字0-90xfd,0x61,0xdb,0xf3,0x67,0xb7,0xbf,0xe1,0xff,0xf7,//带点号的0-90x00,0x2a,0x6e//暗选,n,h};//接口函数void wData_Ex(uchar ); //在数码管上显示数据#endif/**.c文件,文件名:EqualFre_SGMDisplay.c*/#include "EqualFre_SGMDisplay.h"//接口函数void wData_Ex(uchar index){uchar data i,byte;byte = num[index];for(i=0;i<8;i++){sgm_clk = 0;sgm_data = (bit)((byte>>i)&0x01);_nop_();sgm_clk = 1;_nop_();}}/**.c文件,文件名:EqualFre_modeFromKey.c*/#include "EqualFre_modeFromKey.h"//**************内部函数************//按键检测延时static void keyDelay(){uchar data x,y;for(x=100;x>0;x--);for(y=200;y>0;y--) ;}//按键扫描static void keyScan(){ //选择模式if(0 == Key_Mode){keyDelay();if(1 == Key_Mode) return ;switch(mode){case SHOW_FRE_MODE: //测频率mode = SHOW_WIDE_MODE; //下一次测的是脉宽break;case SHOW_WIDE_MODE: //测脉宽mode = SHOW_DUTY_MODE; //下一次测的是占空比break;case SHOW_DUTY_MODE: //测占空比mode = SHOW_FRE_MODE; //下一次测的是频率break;default:mode = SHOW_FRE_MODE;break;}while(0 == Key_Mode) ;keyDelay();}if(0 == Key_Hold_Data){keyDelay();if(1 == Key_Hold_Data) return ;mode = HOLD_DATA_MODE; //按下Key_Hold_Data,即为P1^1时,数据保持不变while(0 == Key_Hold_Data);keyDelay();}}//*******************接口函数**************uchar getMode_Ex(void){ //返回mode,确定选择的模式keyScan();return mode;}/**.h文件,文件名:equalFre.h*模式控制模块,通过键盘来控制模式的选择,并将所选模式传递给函数*所使用的硬件资源:频率显示、脉宽显示、占空比显示的切换建---P1.0测试值保持键-- P1^1*/#ifndef _EQUALFRE_MODEFROMKEY_H_H_#define _EQUALFRE_MODEFROMKEY_H_H_#include<reg52.h>#define SHOW_FRE_MODE 0#define SHOW_WIDE_MODE 1#define SHOW_DUTY_MODE 2#define HOLD_DATA_MODE 3#define uchar unsigned charsbit Key_Mode = P1^0; //实现频率显示,脉宽显示,占空比显示的转化sbit Key_Hold_Data = P1^1; //将测得的数值定住static uchar data mode;//内部函数static void keyDelay(); //按键检测延时static void keyScan(); //按键扫描//接口函数uchar getMode_Ex(void); //在数码管上显示数据#endif/**.h文件,文件名:EqulaFre_communication.h*通信模块,用于和FPGA通信,获取频率、脉宽、占空比的原始数据。