关于数字频率计系统设计的时间参数的测量的报告
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
等精度频率测量的设计报告
学生姓名:小兮兮指导老师:刘学校
摘要:本设计报告先对于频率测量的原理进行了分析,然后通过对于相应的频率测量的实现方案进行了误差分析、比较和论证,确定可采用相关计数法来进行等精度的频率的测量,并且最终在基于单片机MCS51系统的平台上,分别基于计数芯片8254-2和复杂可编程逻辑芯片(CPLD)来实现这种等精度频率测量,在0.1Hz 到16MHz的频率范围的中,根据设计所得到的两个不同的系统都可以实现最终的等精度频率测量。
关键词:等精度频率测量,相关计数法,CPLD,8254-2
目录
错误!未找到引用源。
第1章频率测量的原理和误差分析
1.1 频率测量的原理
实现时间参数的数字化测量的仪器是电子计数器。
对于电子计数器而言,测量频率的实质就是通过计数器记录待测信号的周期变化的次数,然后通过频率的定义计算出待测信号的频率。
已知频率的测量表达式为:
/
(1.1)
f N T
从其测量原理和频率的数学表达式中不难看出,计数器测频必须具备以下三个条件:
(1)测量是一个比较的过程,被测信号要和基准信号作比较,必须有一个标准的单位时间。
(2)为实现在单位时间内对于被控信号的振动次数的记录,必须有一个控制电路。
(3)被测信号采样后的量化由电子计数器完成,以获得量化值N。
对应于电子计数器测量频率的原理图如下:
图1.1 电子测频的原理框图
可知电子计数法测频主要由3个部分组成:
(1)时间基准T产生电路。
时间基准产生电路的作用是用来产生计数器所使用的标准频率。
(2)计数脉冲形成电路
计数脉冲形成电路的作用是将被测的周期信号转换成可计数的窄脉冲。
(3)计数显示电路
计数显示电路的作用是对主门输出的脉冲进行计数,其结果显示在数码管上。
1.2频率测量的误差分析
对于电子计数器而言,直接测频的误差主要由两项组成,即1量化误差和标准频率误差。
一般地,总误差可采用分项误差绝对值合成,即:
1(||)x c x x c
f f f f T f ∆∆=±+
(1.2)
式中,等号右边括号内第一项为1量化误差,第二项为标准频率误差。
(1)量化误差
用电子计数器测量频率,实际上就是一个量化的过程,量化的最小单位是数码的一个字或者一个脉冲。
在测频时候,由于主门开启时刻与计数脉冲之间的时间关系是不相关的,它们在时间轴上的相对位置是随机的,门控信号很难精确的是被测信号的整数倍所以量化会带来误差,可知对于计数误差最大为1个数,所以计数器计数的最大的相对误差为:
11x N N N f T
∆=±=±
(1.3) 式中,x f 是被测频率;T 是闸门时间。
该表达式表明被测频率越高,闸门时间越宽,相对误差就越小。
(2)标准频率误差
标准频率误差又称为闸门时间误差,它是由晶振信号本身通过分频输出的信号频率不稳定性导致的闸门时间的不稳定,而造成测频误差。
由误差合成原理可知:
c c f T T f ∆∆=-
(1.4)
式中,晶振频率为c f 。
该表达式表明闸门相对误差在数值上等于晶振频率的相对误差。
所以,在设计中要求晶振达到的精度要比系统所要达到的精度高一个数量级。
第2章 系统的设计任务的理论分析及方案的论证
2.1 设计任务的分析及方案的论证
本设计是一个基于单片机平台的时间参数(频率)测量系统。
由于本次系统设计的测频范围很宽(0.1Hz~10MHz )、精度高(测量误差0.001%),因此精确的控制闸门的开启和关闭,追求计数器较高的频率和较大的计数容量,保持系统在整个测量频段内的测量精度不变及实现频标信号的高稳定度和高精确度成为了评价系统设计优劣的关键。
而对于电子计数器的测量误差有了深刻的讨论。
下面对于不同的方案进行了比较。
(1)直接测频法(闸门时间计数法)
直接测频法就是在确定的闸门时间内,通过计数器记录待测信号的周期变化次数,并根据频率的定义来计算待测信号的频率。
由于测量的起始时刻和结束时刻相对于信号而言是随机的,将会有一个脉冲周期的量化误差,也就是对于不同的闸门时间会产生同样的计数值N 。
如图中闸门1和闸门2时间长度不一样,但是计数值相同。
图2.1 直接测频法示意图
当测量时间为T 时,测量的准确度=T/x f ,其中x f 为待测信号,可知对于测量频
高时,测量准确度越高。
但是低频达不到所要达到的要求。
(2)间接测周法
间接测周法就是在一个信号周期内记录下基准脉冲的个数。
原理恰好与直接测 频法相对应,当测量的信号周期越长,即其频率越低,测量的精度就越高,但对于高 频信号就不能适用。
(3)分段法
分段法就是采用直接测频和间接测周相结合的方法,在高频段采用直接测频,在 低频段采用间接测周,但是中间频率难以确定,要实现全频段的等精度测量,且达到 设计的要求,系统的设计复杂度很高。
(4)相关计数测频法
相关计数测频法采用多周期同步测量原理,测量输入信号的整数个周期值而求得 频率的一种测量方法。
由于被测信号与门控信号之间采用同步锁定的方式,使得主门 的开启时刻计数脉冲之间的时间关系是相关的,这样便可以实现在测频范围内频率的 等精度测量。
其实,等精度测量并非严格意义上的等精度,闸门信号在测量中的开启和关闭受 控于被测信号的上升沿或下降沿。
其测量的精度就有赖于频标信号的稳定度和精度。
若系统要求测量精度为6
10-,那么基准源的开机稳定度和温度稳定度应该较高,其综 合性能应优于710-。
综上所述,对于测频方案的选择,直接测频法和间接测周法的原理很简单,电路实 现容易,但是它们都不能满足全频段范围内的信号的测量,分段法在理论上可以保证 等精度测量,其中界频率的确定也比较容易,但是随着系统测量精度的提高,测试盲区 可能会出现。
而相关计数法虽同时对于未知待测信号和基准信号两路信号进行计数, 且对于闸门控制和频标信号的稳定度有很高的要求,却可以满足在整个测量频段的等 精度测量。
2.2 等精度测量技术的理论分析
相关计数法测频原理如下图2.2所示,同步闸门是由预置开门脉冲0P 经x f 同步后 得到的,因而闸门时间W T 可以准确地等于x f 的整周期倍数,所以没有1量化误差, 但由于同步闸门与0f 并不同步,因而0N 存在1的量化误差,可得到下式:
0000()x x f N f f N f ∆∆∆=±+ (2.1)
式中,00
f f ∆为0f 的频率准确度。
由于所用的晶体振荡器有较高的稳定度,误差很小,可以忽略,因而最大的相对误差
x x f f ∆取决于00N N ∆,所以当0f =1MHz ,则在W T =1s 的同步闸门时间内,0N 可达6
10量级,恩能够满足设计指标。
图2.2 相关计数法测频原理框图
第3章 基于8254-2的系统的具体设计和实现
3.1 基于8254-2的系统整体设计
测频模块的设计框图如图3.1
所示:
图3.1 测频模块设计框图
3.2 系统的硬件设计
3.2.1 闸门开启和关闭的控制电路
N不出现量化误差,要求根据等精度测频法的原理,为了确保对被测信号的计数值
x
f周期的整数倍。
相关门控实现电路的原理框图如图3.2所闸门时间准确地等于待测信号
x
示。
图3.2 相关门控实现电路原理图
图中D触发器A起门控同步作用,P1.2是两触发器的复位信号。
P1.3是预置门启闭信号,其中P1.2和P1.3分别是单片机P1.2和P1.3引脚。
D触发器A的Q端输出的逻辑电平为精确门信号,配合两个与门分别控制待测信号和频标信号的通过。
精确门的开启和关闭由预置门和待测信号的上升沿决定。
D触发器B产生计数完成中断信号。
即在门控时间T 之后,计数完成则向单片机MCS51发出一种中断信号IR3,请求单片机读出计数值,进行相应的处理和计算。
此时触发器A的精确门控信号Q关闭,Q产生一个下升沿,Q则产生一个上升沿,给下一个D触发器中的时钟端,它的Q端产生一个正脉冲中断信号给82C59.
3.2.2 8254-2的级联设计
8254-2的计数频率为10MHz,最高频率高达20MHz,可以满足全频段范围内的频率测量。
而对于8254-2的16位计数器而言,不能满足高频的测量,所以必须对其进行级联,使其为32位的宽位计数器。
8254-2有6种工作方式,根据芯片资料可知,在计数时,使其工作在方式2.但是在8254-2正常工作之前,CPU需要送一组控制字给8254-2,将其设置为预定的工作模式,而对于8254-2,初始化时初值和控制字只赋值给计数器初值寄存器,装入减1计数器要靠外部信号CLK触发。
所以,clk的信号只有完成一次上升沿和下降沿,初值才得以装入,减1
计数器准备就绪,显然,这对计数事件言,自然丢失了一个事件。
这样的结果在低阶只产生l的误差,而在高阶却要引起极大的计数误差。
针对8254这一设计上的不足,本设计中提出了一种合理的解决方法(如图3.3所示)。
其设计思想是,利用8254写入不同的控制方式会在OUT端出现不同电乎的特点,用软件编程的简单方法人为模拟1个正向脉冲,以解决高阶计数器计数初值的装入。
具体方法为:
(1) 设置高阶16位计数器的工作方式及其初值;
(2)设置低阶16俺计数器为方式0,此时OUT0端的电平在写完控制字后马上变低;
(3)设置低阶16位计数器为方式l,此时OUT0端的电乎在写完控制字后马上变高;
(4)设置低阶16位计数器为方式O,此时OUTO端的电平在写完控制字后马上变低;
(5)设置低阶16位计数器的工作方式及其初值。
上述步骤1和5是设置高低阶计数器正常的工作方式和初值。
步骤2、3、4是为了把高阶计数器的初值装入而在cLKl端人为模拟一个正向脉冲。
这样就解决了高阶初值的装入问题,但低阶的l误差仍然存在。
这可以在单片机软件编程中加以修正来解决。
图3.3 8254-2内部计数器的级联图
3.2.3.高稳定度的基准源产生电路
采用高精度的晶振作为振荡源并配合如下的外围电路,便可以使得输出的频标信号具有很高的精确度和稳定度。
图3.4 高稳定度的将基准源产生电路
3.3 系统软件设计
(1)系统软件设计流程图
图3.5 程序的流程图
(2)软件设计中的关键环节
利用8254读回功能读取计数值时,32位计数值需要分别4次读入,为了确保计数值的正确读入,先利用读回功能将3个计数器都锁存,然后分4次读出。
同时在读取计数值高低位时候,由于时序不兼容,对于相应位的读取要延时,这样才能保证读数的准确。
其详细的软件代码见附录一。
第4章基于CPLD的系统的具体设计和实现
4.1 基于CPLD的系统整体设计
由以上基于8254-2的等精度频率计可知,8254-2本身存在很多缺陷,它本身的计数速度也限制测频范围的进一步提高,且对于数据的采集和处理复杂,且硬件电路要考虑的错误很多,不好调试。
由于CPLD生成的计数器不会出现8254出现的计数问题,而且计数器不需要写入相应的控制字和初值,而且它与单片机的接口只需要片选信号和地址信号A0、A1即可,且移植性强。
本章将阐述利用CPLD来实现等精度数字频率计(如下图所示),以此与上一个系统作比较。
图 4.1 基于CPLD的测频系统电路框图4.2 CPLD的顶层模块设计
图4.2 CPLD测频模块顶层电路图
基于CPLD的等精度频率计24位计数器的verilog代码和整个系统的代码见附录2.
第5章系统的测试结果与误差分析
5.1 系统的检验操作过程和测试结果
通过设置AFG信号发生器,输出满足TTL电平的频率信号,从0.1Hz到1Hz之间以0.01Hz的长度步进,从1Hz到10Hz以0.1Hz的长度步进,从10Hz到100Hz的以1Hz的长度步进,从100hz到1KHz以10Hz的长度步进,依次类推,一直到16MHz。
通过比较显示的数据和真实数据,来计算两个系统的测量精度。
基于8254-2的系统测试统计数据如下:
待测信号的频率范围(Hz) 该频段所测频率与待测信号最大频差的绝对值(Hz)
0.1~10 0.01
10~1000 0.002 1000~10000 0.02 10000~100000 0.56 100000~1000000 3.3
1000000~10000000 28.0 10000000~16000000 45.0 表1 基于8254-2的系统的误差分析表基于CPLD的系统的测试统计数据如下:
待测信号的频率范围
(Hz) 该频段所测频率与待测信号最大频差的绝对值(Hz)
0.1~10 0.01
10~1000 0.002
1000~10000 0.01
10000~100000 0.12
100000~1000000 0.51
1000000~10000000 9.0
10000000~16000000 28.0
表2 基于CPLD的系统的误差分析表
5.2 基于8254-2和CPLD的系统的比较和分析
从上述的统计数据可以看出,两种系统都达到了设计所要求的精度(测试误差小于),由于所得到的精度很大程度上受到了所用的晶振的本身稳定度和精确度的影响,达不到设计的理想的要求。
同时可以看出CPLD的系统的精确度要明显高于8254-2系统的精度,可见CPLD这种高密度器件与分立器件组成的电路相比,除了系统模型的可移植性要好、复杂度越低之外,它的电路实现的可靠性和测量指标都要比分立器件要好得多,这也是为什么像CPLD这种高密度器件会成为现在的主流趋势。
附录一
基于8254-2的等精度频率测量系统的整体代码#include<reg51.h>
#include <math.h>
#include <stdio.h>
#include <absacc.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define con_8254_1 XBYTE [0xd003]
#define a_8254_1 XBYTE [0xd000]
#define b_8254_1 XBYTE [0xd001]
#define c_8254_1 XBYTE [0xd002]
#define con_8254_2 XBYTE [0xe003]
#define a_8254_2 XBYTE [0xe000]
#define b_8254_2 XBYTE [0xe001]
#define c_8254_2 XBYTE [0xe002]
#define even_8259 XBYTE [0xc000]
#define odd_8259 XBYTE [0xc001]
#define con_8279 XBYTE [0xb001]
#define data_8279 XBYTE [0xb000]
sbit P1_3=P1^3; /*闸门开启信号*/
sbit P1_1=P1^1; /*后或门控制开启的信号*/
sbit P1_2=P1^2; /*闸门清零信号*/
sbit clrflag=ACC^7;/*显示清零标志*/
bit interxl_flag; /*外部中断1标志位*/
bit interx0_flag;/*外部中断0标志位*/
bit tf;/*定时中断标志位*/
bit xiaoshudian;/*小数点显示的标志位*/
bit w;/*测量周期的标志位*/
bit s;
bit z;/*闸门时间的标志位*/
bit stop;
/**********函数声明****************/
void delay(ulong timer);/*不定时延时程序*/
void delay1(uchar t);/*中断定时器0程序*/
void display(float xx1);/*显示所测的频率以及所测的周期程序*/
void init_system(void);/*初始化程序*/
void ce_pin(void);/*测频程序*/
void duqu(void);
/*************全局变量定义******************/
uint xdata a1,b1,c1;/*第一片8254的计数器0的计数值,第一片8254的计数器1的计数值,第一片8254的计数器2的计数值*/
uint xdata a2,b2,c2;/*第2片8254的计数器0的计数值,第2片8254的计数器1的计数值,第2片8254的计数器2的计数值*/
float xdata jishuzhi[2];/*对应于组成的三个32位的计数器的计数器*/
uchar idata t1,choose;/*定时器参数,键盘选择,8254的6个计数器的状态*/
uchar code table[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};/*数字对应的段码*/
/**************主要程序*************/
void main()
{
init_system();
delay(100);
while(1)
{
ce_pin();
}
}
/*******初始化程序*******/
void init_system()
{
uchar i;
uchar xdata s3,s4,s5,s6,s7,s8,s9,s10;
uchar code hello[8]={0x3f,0x38,0x38,0x79,0x76,0x00,0x00,0x00};
xiaoshudian=0; /*显示小数点的标志位为零*/
w=0;/*显示的标志位为0*/
s=0;
interxl_flag=0;
interx0_flag=0;/*外部中断0和1的初始化为0*/
choose=0;
tf=0;t1=0;/*给定时器t0赋初值*/
even_8259=0x16;/*设定8259的工作方式*/
odd_8259=0x00;/*设定8259的外部中断向量的高8位地址*/
odd_8259=0xf7;/*允许8259的IR3发生中断*/
con_8279=0x34;/*8279时钟指令*/
con_8279=0x00;/*8279键盘显示方式*/
con_8279=0xd3;/*清显示*/
do
{
ACC=con_8279;
}
while(clrflag==1);
for(i=0;i<8;i++)
{
con_8279=0x90+i;
data_8279=hello[i]; /*数码管显示hello*/
}
con_8254_1=0x38; /*计数器0的控制字,低阶16位计数器应用于方式4*/
con_8254_1=0x74;/*第一片8254的计数器1的控制字,高阶16位计数器应用于方式2*/
b_8254_1=0xff;
b_8254_1=0xff;/*计数器1初值为65535*/
con_8254_1=0x30; /*计数器0的控制字,低阶16位计数器应用于方式0*/
con_8254_1=0x38;
con_8254_1=0x34;/*计数器0的控制字,低阶16位计数器工作于方式2*/
a_8254_1=0xff;
a_8254_1=0xff;/*计数器0初值为65535*/
con_8254_2=0x38; /*计数器0的控制字,低阶16位计数器应用于方式4*/
con_8254_2=0x74;/*第二片8254的计数器1的控制字,高阶16位计数器应用于方式2*/
b_8254_2=0xff;
b_8254_2=0xff;/*计数器1初值为65535*/
con_8254_2=0x30; /*计数器0的控制字,低阶16位计数器应用于方式0*/
con_8254_2=0x38;
con_8254_2=0x34;/*计数器0的控制字,低阶16位计数器工作于方式2*/
a_8254_2=0xff;
a_8254_2=0xff;/*计数器0初值为65536*/
P1_2=0; /*使得d触发器清零*/
P1_3=0;/*闸门关闭*/
P1_1=0;
P1_1=1;
P1_1=0;
P1_1=1;
TMOD=0x11;/*定时器0工作于方式1*/
TR0=0;
TH0=0x3c;
TL0=0xb0;/*产生50ms的单位时间*/
EX1=1;
IT1=0;
EX0=1; /*外部中断0的中断开放*/
ET0=1; /*定时器中断0的中断开放*/
IT0=0; /*外部中断0为电平触发*/
EA=1;/*开总中断*/
}
/************估计定时程序**************/
void delay(ulong timer)
{
while(timer--);
}
/***********定时器t0延时程序****************/ void delay1(uchar t)
{
TR0=1;
TH0=0x3c;
TL0=0xb0;
t1=t;
do{}
while(tf==0);
tf=0;
TR0=0;/*产生50ms*t的延时*/
}
/*************定时器t0中断服务程序**************/
void timer0(void) interrupt 1 using 1
{
t1--;
TH0=0x3c;
TL0=0xb0;
TR0=1;
if(t1==0)
tf=1;
}
/***************外部中断1服务程序*******************/
void inter_key(void) interrupt 2 using 2
{
uchar key_value;/*键值*/
EA=0;
interxl_flag=1;
key_value=data_8279;
switch(key_value)
{
case 0x30:choose=1;break;
case 0x20:choose=2;break;
case 0x10:choose=3;break;
case 0x00:choose=4;break;
default:break;
}
EA=1;
}
/*****************外部中断0服务程序**************************/
void inter_key1(void) interrupt 0 using 1
{
uchar s0,s1,s2;
s0=even_8259;
s1=even_8259; /*读中断矢量的低地址*/
s2=even_8259; /*读中断矢量的高地址*/
interx0_flag=1;
P1_2=0;
P1_2=1;
even_8259=0x20;
}
/*******************频率测试****************************/
void ce_pin()
{
uchar i;
float k;/*待测信号的频率值*/
uchar code cepin[8]={0x37,0x06,0x73,0x79,0x39,0x00,0x00,0x00}; s=0; /*小数点的位置的显示的标志位*/
do{}
while(choose==0);
for(i=0;i<8;i++)
{
con_8279=0x90+i;
data_8279=cepin[i]; /*数码管显示cepin*/
}
xiaoshudian=0;/*显示小数点的标志位复位*/
P1_2=1;
if(choose==1)
{
P1_1=0;
P1_3=1;/*闸门开启*/
delay1(20);/*延时1s*/
P1_3=0;/*闸门关闭,设置预置门为1s*/
do{}
while(interx0_flag==0);
interx0_flag=0;/*中断向量的标志复位为0*/
duqu();
if(k>8.0)
{
k=(1000000.0*jishuzhi[1])/jishuzhi[0];/*读出计数值的频率值*/ }
else
{
k=(1000022.0*jishuzhi[1])/jishuzhi[0];
}
if((k>0.1)&&(k<=9999.999))
{
k=k*1000.0;
xiaoshudian=1; /*显示小数点*/
s=0;
}
else if((k>9999.999)&&(k<999999.99))
{
k=k*100.0;
xiaoshudian=1; /*显示小数点*/
s=1;
}
else
{
xiaoshudian=0; /*不显示小数点*/
}
display(k);/*显示所测的频率*/
xiaoshudian=0;/*显示小数点的标志位复位*/
}
else if(choose==2)
{
P1_1=0;
P1_3=1; /*闸门开启*/
delay1(200);/*闸门时间为10s*/
P1_3=0;/*闸门关断*/
do{}
while(interx0_flag==0);/*等待中断结束*/
interx0_flag=0;/*中断向量的标志复位为0*/
duqu();
k=1000029.0*jishuzhi[1]/jishuzhi[0];
if(k<0.400)
{
k=k*1000.0+1;/*小数点后两位表示成整数*/
}
else
{
k=k*1000.0;
}
display(k);/*显示所测的频率*/
}
choose=0;
}
/*********************显示程序***************************/ void display(float xx1)/*显示所测的频率*/
{
ulong zheng;
uchar i;
uchar dis[8],xx[8];
zheng=(ulong)xx1;
xx[0]=(zheng%100000000)/10000000;
xx[1]=(zheng%10000000)/1000000;
xx[2]=(zheng%1000000)/100000;
xx[3]=(zheng%100000)/10000;
xx[4]=(zheng%10000)/1000;
xx[5]=(zheng%1000)/100;
xx[6]=(zheng%100)/10;
xx[7]=zheng%10; /*获得每一位的对应的整数数值*/ for(i=0;i<8;i++)
{
dis[i]=table[xx[7-i]];
}
if(choose==1)
{
if(xiaoshudian==1)
{
if(s==0)
{
dis[3]=dis[3]+0x80;/*加上小数点*/
}
else if(s==1)
{
dis[2]=dis[2]+0x80;
}
}
if(xx[0]==0)
{
dis[7]=0x00;
if(xx[1]==0)
{
dis[6]=0x00;
if(xx[2]==0)
{
dis[5]=0x00;
if(xx[3]==0)
{
dis[4]=0x00;
if(xx[4]==0&&(xiaoshudian==0))
{
dis[3]=0x00;
if((xx[5]==0))
{
dis[2]=0x00;
if(xx[6]==0)
{
dis[1]=0x00;
}
}
}
}
}
}
} /*对于所传得数值的每一位的判断*/ }
else if(choose==2)
{
for(i=7;i>3;i--)
{
dis[i]=0x00;
}
dis[3]=dis[3]+0x80;/*加上小数点*/
}
for(i=0;i<8;i++)
{
con_8279=0x90+i;
data_8279=dis[i]; /*以8位数显示出来*/ }
}
/***读取函数*/
void duqu()
{
uchar xdata a3,a4,a5,a6,b3,b4,b5,b6;
uchar xdata s1,s2,s3,s4,s5,s6,s7,s8,s9,s10; con_8254_1=0xcd;
con_8254_1=0xcd;
a3=a_8254_1;
delay(2000);
a4=a_8254_1;
b3=b_8254_1;
delay(2000);
b4=b_8254_1;
con_8254_2=0xcd;
con_8254_2=0xcd;
a5=a_8254_2;
a6=a_8254_2;
delay(2000);
b5=b_8254_2;
b6=b_8254_2;
if(a6==a5)
{
a6=a_8254_2;
}
if(b6==b5)
{
s1=b_8254_2;
s2=b_8254_2;
if(s1!=b5)
{
b6=s1;
b5=s2;
}
else
{
b5=s1;
b6=s2;
}
}
b1=b4*256+b3;/*第一片8254计数器1的计数值*/ a1=a3+a4*256;
b2=b6*256+b5;/*第二片8254计数器1的计数值*/ a2=a6*256+a5;/*第二片8254计数器0的计数值*/ if(b1<0xfe80)
{
b1=0xff*256+b3;
}
if(b2<0xfe80)
{
b2=0xff*256+b5;
}
if(choose==1)
{
jishuzhi[1]=(0xffff-b2)*65536+0xffff-a2-4;
}
else
{
jishuzhi[1]=(0xffff-b2)*65536+0xffff-a2;
}
jishuzhi[0]=(0xffff-b1)*65536+0xffff-a1+1;
con_8254_1=0x38; /*计数器0的控制字,低阶16位计数器应用于方式4*/
con_8254_1=0x74;/*第一片8254的计数器1的控制字,高阶16位计数器用方式2*/ b_8254_1=0xff;
b_8254_1=0xff;/*计数器1初值为65535*/
con_8254_1=0x30; /*计数器0的控制字,低阶16位计数器应用于方式0*/
con_8254_1=0x38;
con_8254_1=0x34;/*计数器0的控制字,低阶16位计数器工作于方式2*/
a_8254_1=0xff;
a_8254_1=0xff;/*计数器0初值为65535*/
con_8254_2=0x38; /*计数器0的控制字,低阶16位计数器应用于方式4*/
con_8254_2=0x74;/*第二片8254的计数器1的控制字,高阶16位计数器应用于方式2*/
b_8254_2=0xff;
b_8254_2=0xff;/*计数器1初值为65535*/
con_8254_2=0x30; /*计数器0的控制字,低阶16位计数器应用于方式0*/
con_8254_2=0x38;
con_8254_2=0x34;
a_8254_2=0xff;
a_8254_2=0xff;/*计数器0初值为65536*/
P1_2=0;
P1_3=0;
P1_1=0;
P1_1=1;
P1_1=0;
P1_1=1; }/*产生一个完整脉冲将初值赋给8254-2*/
附录2
1.基于CPLD的等精度测频系统中的24位计数器的verilog代码module counter24(clk,clr,cs,a1,a0,q,out);
output [7:0] q ;
input clk,clr,cs,a0,a1;
reg [7:0]q;
reg [1:0]sel;
output reg [23:0]out;
always@(posedge clk or negedge clr)
begin
if(!clr)
out<=2'b00;
else
out<=out+1;
end
always@(cs)
begin
sel={a1,a0};
if(cs==0)
begin
case(sel)
2'b00:q<=out[7:0];
2'b01:q<=out[15:8];
2'b10:q<=out[23:16];
default:q<=8'b0;
endcase
end
else
q<=8'bzzzzzzzz;
end
endmodule
2.基于CPLD的等精度测频系统中的整体系统的代码#include<reg51.h>
#include <math.h>
#include <stdio.h>
#include <absacc.h>
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#define a_counter24_1 XBYTE [0xd000]
#define b_counter24_1 XBYTE [0xd001]
#define c_counter24_1 XBYTE [0xd002]
#define a_counter24_2 XBYTE [0xe000]
#define b_counter24_2 XBYTE [0xe001]
#define c_counter24_2 XBYTE [0xe002]
#define even_8259 XBYTE [0xc000]
#define odd_8259 XBYTE [0xc001]
#define con_8279 XBYTE [0xb001]
#define data_8279 XBYTE [0xb000]
sbit P1_3=P1^3; /*闸门开启信号*/
sbit P1_2=P1^2; /*闸门清零信号*/
sbit clrflag=ACC^7;/*显示清零标志*/
bit interxl_flag; /*外部中断1标志位*/
bit interx0_flag;/*外部中断0标志位*/
bit tf;/*定时中断标志位*/
bit xiaoshudian;/*小数点显示的标志位*/
bit w;/*测量周期的标志位*/
bit s;
bit z;/*闸门时间的标志位*/
/**********函数声明****************/
void delay(ulong timer);/*不定时延时程序*/
void delay1(uchar t);/*中断定时器0程序*/
void display(float xx1);/*显示所测的频率以及所测的周期程序*/
void init_system(void);/*初始化程序*/
void ce_pin(void);/*测频程序*/
void duqu(void);
/*************全局变量定义******************/
float xdata jishuzhi[2];/*对应于组成的三个32位的计数器的计数器*/
uchar idata t1,choose;/*定时器参数,键盘选择,8254的6个计数器的状态*/
uchar code table[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};/*数字对应的段码*/
/**************主要程序*************/
void main()
{
init_system();
while(1)
{
ce_pin();
}
}
/*******初始化程序*******/
void init_system()
{
uchar i;
uchar code hello[8]={0x3f,0x38,0x38,0x79,0x76,0x00,0x00,0x00};
xiaoshudian=0; /*显示小数点的标志位为零*/
w=0;/*显示的标志位为0*/
s=0;
interxl_flag=0;
interx0_flag=0;/*外部中断0和1的初始化为0*/
choose=0;
tf=0;t1=0;/*给定时器t0赋初值*/
even_8259=0x16;/*设定8259的工作方式*/
odd_8259=0x00;/*设定8259的外部中断向量的高8位地址*/
odd_8259=0xf7;/*允许8259的IR3发生中断*/
con_8279=0x34;/*8279时钟指令*/
con_8279=0x00;/*8279键盘显示方式*/
con_8279=0xd3;/*清显示*/
do
{
ACC=con_8279;
}
while(clrflag==1);
for(i=0;i<8;i++)
{
con_8279=0x90+i;
data_8279=hello[i]; /*数码管显示hello*/
}
P1_2=0; /*使得d触发器清零*/
P1_3=0;/*闸门关闭*/
TMOD=0x11;/*定时器0工作于方式1*/
TR0=0;
TH0=0x3c;
TL0=0xb0;/*产生50ms的单位时间*/
EX1=1;
IT1=0;
EX0=1; /*外部中断0的中断开放*/
ET0=1; /*定时器中断0的中断开放*/
IT0=0; /*外部中断0为电平触发*/
EA=1;/*开总中断*/
}
/************估计定时程序**************/
void delay(ulong timer)
{
while(timer--);
}
/***********定时器t0延时程序****************/
void delay1(uchar t)
{
TR0=1;
TH0=0x3c;
TL0=0xb0;
t1=t;
do{}
while(tf==0);
tf=0;
TR0=0;/*产生50ms*t的延时*/
}
/*************定时器t0中断服务程序**************/
void timer0(void) interrupt 1 using 1
{
t1--;
TH0=0x3c;
TL0=0xb0;
TR0=1;
if(t1==0)
tf=1;
}
/***************外部中断1服务程序*******************/
void inter_key(void) interrupt 2 using 2
{
uchar key_value;/*键值*/
EA=0;
interxl_flag=1;
key_value=data_8279;
switch(key_value)
{
case 0x30:choose=1;break;
case 0x20:choose=2;break;
case 0x10:choose=3;break;
case 0x00:choose=4;break;
default:break;
}
EA=1;
}
/*****************外部中断0服务程序**************************/ void inter_key1(void) interrupt 0 using 1
{
uchar s0,s1,s2;
s0=even_8259;
s1=even_8259; /*读中断矢量的低地址*/
s2=even_8259; /*读中断矢量的高地址*/
interx0_flag=1;
even_8259=0x20;
}
/*******************频率测试****************************/
void ce_pin()
{
uchar i;
float k;/*待测信号的频率值*/
uchar code cepin[8]={0x37,0x06,0x73,0x79,0x39,0x00,0x00,0x00}; s=0; /*小数点的位置的显示的标志位*/
z=0;
do{}
while(choose!=1);
for(i=0;i<8;i++)
{
con_8279=0x90+i;
data_8279=cepin[i]; /*数码管显示cepin*/
}
xiaoshudian=0;/*显示小数点的标志位复位*/
P1_2=1;
P1_3=1;/*闸门开启*/
delay1(13);/*延时1s*/
P1_3=0;/*闸门关闭,设置预置门为1s*/
delay1(13);
if(interx0_flag==1)
{
interx0_flag=0;
z=1;
}
else
{
z=0;
P1_2=0;
goto hh;
}
if(z==1)
{
P1_2=0;
P1_2=1;
P1_3=1;/*闸门开启*/
delay1(20);/*延时1s*/
P1_3=0;/*闸门关闭,设置预置门为1s*/
do{}
while(interx0_flag==0);
interx0_flag=0;/*中断向量的标志复位为0*/ duqu();
k=(1000060.0*jishuzhi[1])/jishuzhi[0];
if((k>0.1)&&(k<=9999.999))
{
k=k*1000.0;
xiaoshudian=1; /*显示小数点*/
s=0;
}
else if((k>9999.999)&&(k<999999.99))
{
k=k*100.0;
xiaoshudian=1; /*显示小数点*/
s=1;
}
else
{
xiaoshudian=0; /*不显示小数点*/
}
display(k);/*显示所测的频率*/
xiaoshudian=0;/*显示小数点的标志位复位*/
}
hh: if(z==0)
{
P1_2=1;
P1_3=1; /*闸门开启*/
delay1(200);/*闸门时间为10s*/
P1_3=0;/*闸门关断*/
do{}
while(interx0_flag==0);/*等待中断结束*/
interx0_flag=0;/*中断向量的标志复位为0*/
duqu();
k=1000000.0*jishuzhi[1]/jishuzhi[0];
k=k*1000.0;
display(k);/*显示所测的频率*/
}
choose=0;
}
/*********************显示程序***************************/ void display(float xx1)/*显示所测的频率*/
{
ulong zheng;
uchar i;
uchar dis[8],xx[8];
zheng=(ulong)xx1;
xx[0]=(zheng%100000000)/10000000;
xx[1]=(zheng%10000000)/1000000;
xx[2]=(zheng%1000000)/100000;
xx[3]=(zheng%100000)/10000;
xx[4]=(zheng%10000)/1000;
xx[5]=(zheng%1000)/100;
xx[6]=(zheng%100)/10;
xx[7]=zheng%10; /*获得每一位的对应的整数数值*/ for(i=0;i<8;i++)
{
dis[i]=table[xx[7-i]];
}
if(z==1)
{
if(xiaoshudian==1)
{
if(s==0)
{
dis[3]=dis[3]+0x80;/*加上小数点*/
}
else if(s==1)
{
dis[2]=dis[2]+0x80;
}
}
if(xx[0]==0)
{
dis[7]=0x00;
if(xx[1]==0)
{
dis[6]=0x00;
if(xx[2]==0)
{
dis[5]=0x00;
if(xx[3]==0)
{
dis[4]=0x00;
if(xx[4]==0&&(xiaoshudian==0))
{
dis[3]=0x00;
if((xx[5]==0))
{
dis[2]=0x00;
if(xx[6]==0)
{
dis[1]=0x00;
}
}
}
}
}
}
} /*对于所传得数值的每一位的判断*/ }
else if(z==0)
{
for(i=7;i>3;i--)
{
dis[i]=0x00;
}
dis[3]=dis[3]+0x80;/*加上小数点*/
}
for(i=0;i<8;i++)
{
con_8279=0x90+i;
data_8279=dis[i]; /*以8位数显示出来*/ }
}
/***读取函数*/
void duqu()
{
uchar xdata a3,a4,a5,b3,b4,b5;
a3=a_counter24_1;
a4=b_counter24_1;
a5=c_counter24_1;
b3=a_counter24_2;
b4=b_counter24_2;
b5=c_counter24_2;
jishuzhi[0]=a3+256*a4+65536*a5;
jishuzhi[1]=b3+256*b4+65536*b5-1;
P1_2=0;
P1_3=0;
}
结束语
本次设计实验,我本以为很快就可以做完,但是实际上花费了整整一个月,说明现在做事情还是有些眼高手低,同时也深刻地了解到,虽然对于由分立器件组成的系统模型调试起来很复杂,但是却能够更加透彻地理解系统的模型,因而在高密度器件上也能够很快地实现系统的响应。
同时也非常感谢老师对我的提醒和帮助,正是这些东西使得我能在最低潮的时候能够一如既往地做下去。
参考文献
[1]刘克刚,复杂电子系统设计与实践,电子工业出版社,2010.6
[2]徐江丰等,相关计数法频率计的研究和实现,电子技术,2003.4
39。