基于FPGA的等精度频率计_fpga等精度频率计
基于FPGA的等精度频率计由刀豆文库小编整理,希望给你工作、学习、生活带来方便,猜你可能喜欢“fpga等精度频率计”。
光电与通信工程学院
课程设计报告书
课 设 名 称: 等精度频率计 年级专业及班级:
姓 名: 学 号:
一、课程设计目的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 IS PORT(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 IS SIGNAL 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);BEGIN
PROCESS(EN,TCLK)BEGIN IF RISING_EDGE(TCLK)THEN
EN2
IF EN2='1' THEN IF RISING_EDGE(TCLK)THEN
IF T_COUNT=X“FFFF_FFFF” THEN
T_COUNT'1');
ELSE T_COUNT
SAVE_T
END IF;ELSE NULL;END IF;IF FALLING_EDGE(TCLK)THEN
IF WIDE_TEST='0' THEN
WIDE_COUNT
WIDE_TEST
ELSE SAVE_WIDE
END IF;END IF;IF RISING_EDGE(BCLK)THEN
IF B_COUNT=X“FFFF_FFFF” THEN
B_COUNT'1');
ELSE B_COUNT
SAVE_B
END IF;ELSE NULL;END IF;ELSE--WHEN ENA=0,WE OUTPUT THE DATA AND RESET THE COUNTER.WIDE_COUNT'0');B_COUNT'0');T_COUNT'0');WIDE_TEST
IF EN2='0' THEN
--USE SOME CONSTANTS TO TEST
CASE ADDRESS IS
WHEN X“0”=>DATA_OUT
WHEN X“1”=>DATA_OUT
WHEN X“2”=>DATA_OUT
WHEN X“3”=>DATA_OUT
WHEN X“4”=>DATA_OUT
WHEN X“5”=>DATA_OUT
WHEN X“6”=>DATA_OUT
WHEN X“7”=>DATA_OUT
WHEN X“8”=>DATA_OUT
WHEN X“9”=>DATA_OUT
WHEN X“A”=>DATA_OUT
WHEN X“B”=>DATA_OUT
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){
} //数据载入
static void loadData(){
fre = getFre_Ex();wide = getWide_Ex();duty = getDuty_Ex();
communicationInit_Ex();while(1){
} mode = getMode_Ex();askForData_Ex();} disData();
//数据显示 loadData();
//确定选择的模式
//请求数据
//表示没有固定数据时,则载入数据 if(HOLD_DATA_MODE!= mode){ } /*************************************** 数据显示中:
wData(uchar)传入的参数意义 0 19 跟了点号的0-9 20 暗选
***************************************/ static void disDelay(){ //显示延时
} //数据显示--总控 static void disData(){
} /*static void disFre(){
} static void disWide(){
} static void disDuty(){
}*/ //数据显示--显示频率,单位Hz或MHz(双模式)
static void disFre(){
uchar data dataTemp[8],i;ulong data freTemp = fre;//为了显示1位小数,这里已经将频率扩大10倍 uchar data flag = 0;//消零标志位
if(1000000
disFre();disDelay();break;
disDelay();break;
disDuty();disDelay();break;case SHOW_WIDE_MODE: disWide();
uchar data x,y;for(x=250;x>0;x--)for(y=50;y>0;y--);
}
} freTemp /= 100000;//0.00MHz for(i=2;i
} dataTemp[4] += 10;//取2位小数,这里是加入小数点 dataTemp[1] = 21;//n dataTemp[0] = 22;//H dataTemp[i] =(uchar)(freTemp%10);freTemp /= 10;用于显示nH(即MHz)else{
} for(i=1;i
} dataTemp[2] += 10;dataTemp[0] = 22;//H } dataTemp[i] =(uchar)(freTemp%10);freTemp /= 10;for(i=0;i
if(0!= dataTemp[7-i]){ } if((0==dataTemp[7-i])&&(0==flag)){ } wData_Ex(dataTemp[7-i]);
//显示数据 dataTemp[7-i] = 20;flag = 1;//数据显示--显示脉宽,单位us,意味着最大只能测1MHz的频率 static void disWide(){
uchar data dataTemp[8],i;ulong data wideTemp = wide;uchar data flag = 0;for(i=0;i
} for(i=0;i
if(0!= dataTemp[7-i]){ } dataTemp[1]|=10;if((0==dataTemp[7-i])&&(0==flag)){ dataTemp[7-i] = 20;flag = 1;dataTemp[i] =(uchar)(wideTemp%10);wideTemp /= 10;
}
} } wData_Ex(dataTemp[7-i]);//数据显示--显示占空比 static void disDuty(){
} /* *.h文件,文件名:EqulaFre_SGMDisplay.h *SGM显示模块,用于显示由主程序传过来的数据
*硬件资源:
*/ #ifndef _EQUALFRE_SGMDISPLAY_H_H_ #define _EQUALFRE_SGMDISPLAY_H_H_ #include #include #define uchar unsigned char sbit sgm_clk=P3^1;//164时钟端 sbit sgm_data=P3^0;
};//接口函数
void wData_Ex(uchar);#endif /*
//在数码管上显示数据
//164数据端
static uchar code num[] = {//从低位到高位,高电平有效
0xfc,0x60,0xda,0xf2,0x66,0xb6,0xbe,0xe0,0xfe,0xf6,//数字0-9 0xfd,0x61,0xdb,0xf3,0x67,0xb7,0xbf,0xe1,0xff,0xf7,//带点号的0-9 0x00,0x2a,0x6e//暗选,n,h 164时钟端--P3.1 164数据端--P3.0 uchar data dataTemp[4],i;uint data dutyTemp = duty;for(i=0;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
void wData_Ex(uchar index){ uchar data i,byte;byte = num[index];for(i=0;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;while(0 == Key_Hold_Data);keyDelay();
//按下 Key_Hold_Data,即为P1^1时,数据保持不变
//*******************接口函数************** uchar getMode_Ex(void){
} /* *.h文件,文件名:equalFre.h *模式控制模块,通过键盘来控制模式的选择,并将所选模式传递给函数
*所使用的硬件资源:
频率显示、脉宽显示、占空比显示的切换建---P1.0
测试值保持键--P1^1 */ #ifndef _EQUALFRE_MODEFROMKEY_H_H_ #define _EQUALFRE_MODEFROMKEY_H_H_ #include #define SHOW_FRE_MODE 0 #define SHOW_WIDE_MODE 1 #define SHOW_DUTY_MODE 2 #define HOLD_DATA_MODE 3 #define uchar unsigned char sbit Key_Mode = P1^0;static uchar data mode;//内部函数
static void keyDelay();static void keyScan();//接口函数
uchar getMode_Ex(void);#endif /* *.h文件,文件名:EqulaFre_communication.h
//在数码管上显示数据
//按键检测延时
//按键扫描
//实现频率显示,脉宽显示,占空比显示的转化
sbit Key_Hold_Data = P1^1;
//将测得的数值定住 keyScan();return mode;
//返回mode,确定选择的模式 *通信模块,用于和FPGA通信,获取频率、脉宽、占空比的原始数据。
*并将处理好数据传给主程序
*所使用的硬件资源:
地址线0---P2.0
地址线1---P2.1
地址线2---P2.2
地址线3---P2.3
测频标志位---P2.4
数据线----P0
定时器T0 */ #ifndef _EQUALFRE_COMMUNICATION_H_H_ #define _EQUALFRE_COMMUNICATION_H_H_ #include #include #define uchar unsigned char #define ulong unsigned long #define uint unsigned int #define MY_TH0 0x5d//对于20Mhz晶振来说,25ms #define MY_TL0 0x3d #define FREE_TIME 80//空闲时间,即让FPGA测频率的时间,50ms*FREE_TIME #define DATA_IN P0 #define BASE_FRE 100000000 //FPGA的基准频率 sbit addre0 = P2^0;sbit addre1 = P2^1;sbit addre2 = P2^2;sbit addre3 = P2^3;sbit TEST_EN = P2^4;//当它为1表示测频结束 static ulong data fre,wide;static uint data duty;//内部函数
static ulong getSourceData(uchar);//接口函数
void communicationInit_Ex(void);void askForData_Ex(void);ulong getFre_Ex(void);ulong getWide_Ex(void);uint getDuty_Ex(void);
#endif /* *.c文件,文件名:EqualFre_communication.c */ #include “EqualFre_communication.h”
//请求数据
//计算频率值
//计算脉宽值
//计算占空比
//从FPGA中获得基准信号,被测信号的数据 //从FPGA那里获得频率、脉宽、占空比的原始值 static ulong getSourceData(uchar sourceKind){
addre3 = 0;addre2 = 1;addre1 = 1;addre0 = 1;_nop_();_nop_();_nop_();_nop_();//FPGA反应时间 byte3 = DATA_IN;break;addre3 = 1;addre2 = 0;addre1 = 0;addre0 = 0;_nop_();_nop_();_nop_();_nop_();//FPGA反应时间 byte0 = DATA_IN;
addre3 = 0;addre2 = 1;addre1 = 1;addre0 = 0;_nop_();_nop_();_nop_();_nop_();//FPGA反应时间 byte2 = DATA_IN;
addre3 = 0;addre2 = 1;addre1 = 0;addre0 = 1;_nop_();_nop_();_nop_();_nop_();//FPGA反应时间 byte1 = DATA_IN;
addre3 = 0;addre2 = 0;addre1 = 1;addre0 = 1;_nop_();_nop_();_nop_();_nop_();//FPGA反应时间 byte3 = DATA_IN;break;addre3 = 0;addre2 = 1;addre1 = 0;addre0 = 0;_nop_();_nop_();_nop_();_nop_();//FPGA反应时间 byte0 = DATA_IN;
addre3 = 0;addre2 = 0;addre1 = 1;addre0 = 0;_nop_();_nop_();_nop_();_nop_();//FPGA反应时间 byte2 = DATA_IN;uchar data byte0,byte1,byte2,byte3;ulong data temp = 0;byte0 = byte1 = byte2 = byte3 = 0;switch(sourceKind){ case 1://被测信号T值
addre3 = 0;addre2 = 0;addre1 = 0;addre0 = 0;_nop_();_nop_();_nop_();_nop_();//FPGA反应时间 byte0 = DATA_IN;
addre3 = 0;addre2 = 0;addre1 = 0;addre0 = 1;_nop_();_nop_();_nop_();_nop_();//FPGA反应时间 byte1 = DATA_IN;case 2://基准信号B值
case 3://脉宽W值
} //20MHz,25ms void t0()interrupt 1{
} /*********************************************接口函数********************** ****定义了传向主函数的频率、脉宽、占空比的值 ****接收来自主函数的请求 */ //通信模块初始化
void communicationInit_Ex(void){
IE |= 0x82;TMOD = 0x01;TH0 = MY_TH0;TL0 = MY_TL0;TR0 = 1;TEST_EN = 1;//允许测频 static uchar data count;TH0 = MY_TH0;TL0 = MY_TL0;count++;if(FREE_TIME == count){//测频时间 FREE_TIME *50ms } if(2*FREE_TIME == count){
} TEST_EN = 1;count = 0;TEST_EN = 0;
} temp = byte0 + byte1*256 + byte2*65536 + byte3*256*65536;//转化为十进制 return temp;addre3 = 1;addre2 = 0;addre1 = 1;addre0 = 1;_nop_();_nop_();_nop_();_nop_();//FPGA反应时间 byte3 = DATA_IN;break;
addre3 = 1;addre2 = 0;addre1 = 1;addre0 = 0;_nop_();_nop_();_nop_();_nop_();//FPGA反应时间 byte2 = DATA_IN;
addre3 = 1;addre2 = 0;addre1 = 0;addre0 = 1;_nop_();_nop_();_nop_();_nop_();//FPGA反应时间 byte1 = DATA_IN;default:break;} //数据请求
void askForData_Ex(void){ //
小数
fre = T;wide = B;duty =(uint)W;wide=W;/*tmp = BASE_FRE *(double)T;tmp=tmp/(double)B;fre =(long int)tmp;tmp =(double)W+(double)duty;ulong data B,T,W;double tmp;if(0 == TEST_EN){
T = getSourceData(1);B = getSourceData(2);W = getSourceData(3);if(0 == B)B = 1;fre=(ulong)(T/(0.1*B)*BASE_FRE);//频率先扩大10倍,即分母乘以0.1,以保留一wide=(ulong)(0.1*W);//脉宽单位us duty=(uint)(W*T/(0.0001*B));//占空比以百分数显示,并扩大100倍,以保留2位
//被测信号的周期数
//基准信号的周期数
//脉宽的周期数
位小数 ,单位hz
tmp =(double)W /tmp;
tmp = tmp*100;
duty=(long int)(tmp+0.5);
} ulong getFre_Ex(void){ } ulong getWide_Ex(void){ } uint getDuty_Ex(void){ } return duty;
//返回测量的占空比 return wide;
//返回测量的脉宽值 return fre;
//返回测量的频率值
} wide=W;tmp=B*(double)T;tmp=tmp/(double)B;fre=(long int)tmp;*/