引言
在电子测量领域中,频率测量的精确度是最高的,可达10至10
数量级。因此,在生产过程中许多物理量,例如温度、压力、流量、液位、PH值、振动、位移、速度、加速度,乃至各种气体的百分比成分等均用传感器转换成信号频率,然后用数字频率计来测量,以提高精确度。
国际上数字频率计的分类很多。按功能分类,因计数式频率计的测量功能很多,用途很广。所以根据仪器具有的功能,电子计数器有通用和专用之分。一、通用型计数器:通用型计数器是一种具有多种测量功能、多种用途的万能计数器。它可测量频率、周期、多周期平均值、时间间隔、累加计数、计时等;若配上相应插件,就可测相位、电压、电流、功率、电阻等电量;配上适当的传感器,还可进行长度、重量、压力、温度、速度等非电量的测量。二、专用计数器:专用计数器指专门用来测量某种单一功能的计数器。如频率计数器,只能专门用来测量高频和微波频率;时间计数器,是以测量时间为基础的计数器,其测时分辨力和准确度很高,可达ns数量级;特种计数器,它具有特种功能,如可逆计数器、阈值计数器、差值计数器、倒数计数器等,用于工业和自控技术等方面。数字频率计按频段分类:①低速计数器:最高计数频率<10MHz;②中速计数器:最高计数频率10—100MHz;③高速计数器:最高计数频率>100MHz;④微波频率计数器:测频范围1—80GHz或更高。
由于大规模和超大规模数字集成电路技术、数据通信技术与单片机技术的结合,数字频率计发展进入了智能化和微型化的新阶段。其功能进一步扩大,除了测量频率、频率比、周期、时间、相位、相位差等基本功能外,还具有自捡、自校、自诊断、数理统计、计算方均根值、数据存储和数据通信等功能。可见,频率计是很有工业价值的。本作品即为一个基于单片机的数字频率计,它通过74HC390芯片进行分频,克服了单片机难以处理高频信号的困难,并使用LCD1602液晶显示进行输出,精确度为20万分之一。
1 电路功能、硬件与原理
此次智能电子设计与制作实训本小组的题目为“数字频率计的设计”,在仔细研究了题目要求并通过小组内部积极细致的讨论之后,决定作品采用的功能方案如下:①能测出正弦波、三角波或方波等波形的频率。②频率的测量范围为1Hz—20MHz,且能检测幅度最小值为1Vpp的信号;③通过LCD1602液晶显示屏显示检测到的即时频率数值(最多8位数,单位为Hz)。值得一提的是,当输入频率大于20KHz的信号时,由于采用了100分频采样,显示结果稍有误差,如输入最大测量频率20MHz的信号时,LCD1602液晶显示屏上显示的测量结果为19998900HZ,误差不超过十万分之一,在可接受范围之内。
以下将以待测输入信号走向为顺序介绍电路中各个功能模块。
1.1电路主要模块
1.1.1信号采集模块
图1.1 基于三极管共射放大电路的信号采集模块
为了有效防止因信号过小而造成的检测障碍,在信号输入处采用了三极管共射放大电路,如图1.1所示。实际工作中,我们必须解决放大电路与信号源及放大电路与负载之间的耦合问题。一方面要求耦合电路能够传输交流的输入和输出信号,传输过程中的信号损耗尽可能小;另一方面又要求信号源,放大电路、负载之间的直流工作状态互补影响,即有“隔直”作用,电路的C1、C7就很好的解决了这个问题即固定偏置共射极放大器。集电极电压通过基极偏置电阻R2使晶体管Je正偏;同时拖过R3使Jc反偏,从而实现信号源放大。
1.1.2脉冲产生模块
图1.2 74HC14管脚图和功能图
脉冲产生模块采用74HC14实现了三次施密特触发并反相,从图1.2可以看出,来自信号采集模块的经过放大的信号从74HC14的1脚进入,经过1A→1Y、2A→2Y和3A→3Y三次施密特触发并反相最终将缓慢变化的输入信号转换成清晰、无抖动的信号从6脚输出。
具体到每一个施密特触发反相器来说,其转移特性和输入输出波形关系如图1.3所示。
图1.3 74HC14单个施密特触发器转移特性和输入输出波形
通过Proteus,可以同时观察到有信号输入时74HC14的1脚、2脚、4脚和6脚上的波形仿真。
图1.4 输入信号通过74HC14转换为脉冲
1.1.3分频模块
图1.5 基于双4位十进制波纹计数器74HC390的分频模块
74HC390具有有八个主从触发器和附加门以构成两个独立的4位计数器,其中每个计数器皆包含两个部分:“除2计数部分”和“除5计数部分”,每个计数器又有一个清除输入和一个时钟输入。它可以实现等于2 分频、5 分频乃至100 分频的任何累加倍数的周期长度,且可以连成十进制计数器或二-五进制计数器以分别实现两种进制的数值输出。由于每个计数级都有并行输出,所以系统定时信号可以获得输入计数频率的任何因子。
74HC390具有以下特点:
①A和B触发器都有独立的时钟
②每个计数器都有直接清除
③有效提高系统密度
④缓冲输出减小集电极转换的可能性
图1.6 74HC390单个计数器功能图
从74HC390的单个计数器功能图中可以看出,若从nCP0输入频率为f的时钟信号,则会在nQ0得到频率为f/2的信号;若从nCP1输入时钟信号,则会在nQ1、nQ2、nQ3得到按表1变化的组合信号。
表1 时钟信号从nCP1输入时Q2:Q1:Q0真值表
由此展开设想:由于单片机可操作频率有限,若输入信号频率过大则单片机无法成功实现脉冲计数,因此需要使用74HC390进行分频,以100分频为宜(具体为200KHz以上信号采取100分频后再检测,200KHz或以下信号则检测未经100分频的原始信号)。采取的方法为:从表1中可以看出,若从nCP1输入频率为f的时钟信号,则会在nQ2处输出频率为f/5的脉冲信号,因此可进行如图1.5所示的连线方法,1CP1--1Q2→2CP1--2Q2→1CP0--1Q0→2CP0--2Q0,其中“→”代表芯片外部电气连接,“--”代表芯片内部功能连接,从而得到5×5×2×2=100分频,即若从1CP1输入一个频率为f的信号,则会从2Q0输出一个频率为f/100的分频信号。
1.1.4主芯片
图1.7 主芯片89S52
对于89S52单片机的功能作用本文无需赘言,在此只说明与本作品有关的部分:未经100分频的待测信号接入单片机的定时/计数器0(P3.4),100分频后的待测信号接入单片机的定时/计数器1(P3.5),单片机的P1.0、P1.1、P1.2分别接1602LCD液晶显示模块的片选控制、读写控制和使能控制,而P0.0-P0.7则控制1602芯片的数据引脚D0-D7。另外值得一提的是,此为52单片机,其定时器2具有16位自动重装载中断功能,即为“interrupt 5”中断方式。
1.1.5液晶显示输出模块
图1.8 1602液晶实物图
图1.9 1602液晶引脚排列和引脚功能说明
限于篇幅,本文针对1602液晶显示芯片的功能描述仅限于与本作品相关部分。
首先说明1602液晶显示芯片在本作品上需完成的功能:①没有信号输入时液晶显示“fre= Hz”②有信号输入时液晶显示单片机RAM中的全局变量“fre”的即时数值(最多显示8位,不显示无效的“0”,如若fre=123,则液晶显示“fre=123Hz”)。
以下将结合具体程序来描述1602液晶显示模块在本作品中实现的功能:
①程序头文件
unsigned long int fre;
unsigned char time;
unsigned int count;
unsigned int count1;
sbit LCD_RS=P1^0; //片选信号
sbit LCD_RW=P1^1; //读写信号
sbit LCD_E=P1^2; //使能信号
#define LCD_DB P0 //数据信号
unsigned char character[10]={0};//在屏幕上显示的字符串
unsigned char character_1[]={"fre= Hz"};
unsigned char FLAG = 0;
void LCD_init(void);//初始化函数
void LCD_write_command(unsigned char command);//写指令函数
void LCD_write_data(unsigned char dat);//写数据函数
void LCD_disp_char(unsigned char x,unsigned char y,unsigned char dat);//在某个屏幕位置上显示一个字符,X(0-15),y(1-2)
void delay_n40us(unsigned int n);//延时函数
void timer_init(); //中断初始化函数
②函数设定
void LCD_write_command(unsigned char dat) //写命令函数
{
LCD_DB=dat;
LCD_RS=0;//指令
LCD_RW=0;//写入
LCD_E=1; //使能
LCD_E=0;
delay_n40us(1);//写命令延时
}
void LCD_write_data(unsigned char dat) //写数据函数
{
LCD_DB=dat;
LCD_RS=1;//数据
LCD_RW=0;//写入
LCD_E=1;//使能
LCD_E=0;
delay_n40us(1); //写数据延时
}
1602芯片的4号引脚为RS(数据/命令选择端,1数据寄存器,0指令寄存器),5号引脚为RW(读写选择端,1读,0写),6号引脚为EN(使能端,1允许读写,0禁止读写),因此调用LCD_write_command函数时,变量dat将作为指令信号输入而控制1602芯片,调用LCD_write_data函数时,变量dat将作为数据信号输入1602芯片。
void LCD_init(void) //液晶初始化函数
{
LCD_write_command(0x38);//设置8位格式,2行,5x7
LCD_write_command(0x38);//设置8位格式,2行,5x7
LCD_write_command(0x38);//设置8位格式,2行,5x7
LCD_write_command(0x0c);//整体显示,关光标,不闪烁
LCD_write_command(0x06);//设定输入方式,增量不移位
LCD_write_command(0x01);//清除屏幕显示
delay_n40us(100);//清屏延时
}
首先需要说明的是,执行三次LCD_write_command(0x38)的目的是让所有1602芯片都兼容。
进行功能设定时,指令格式如下:001 DL N F 00;DL=1时,数据长度为8位,DL=0时,数据长度为4位;N=1时显示双列字,N=0时显示单列字;F=1时显示5×10字形,F=0时显示5×7字形。本作品中采用8位数据格式,2行显示,5x7字符显示,故执行0011 1000B(0x38)指令。
进行显示器开关设定时,指令格式如下:0000 1DCB;D=1时,整体显示;C=1时,开启光标;B=1时,光标所在位置光标闪烁。本作品中采用关闭显示,关光标,不闪烁,故执行0000 1100B(0x0c)指令。
进行进入模式设定时,指令格式如下:0000 01 I/D S;I/D=1时,递增, I/D=0时,递减;S=1时,开启显示屏且整个屏移动;S=0时,屏幕不移动。本作品中采用增量不移位,故执行0000 0110B(0x06)指令。
清屏指令为0000 0001B(0x01)。
void LCD_disp_char(unsigned char x,unsigned char y,unsigned char dat)//显示一个字符
{
unsigned char address;
if(y==1)
address=0x80+x; //显示在第一排的时候的x的地址
else
address=0xc0+x; //显示在第二排的时候的x的地址
LCD_write_command(address); //输入地址
LCD_write_data(dat); //输入数据
}
void LCD_disp_num(unsigned char x,unsigned char y,unsigned char dat)//显示一个数字
{
unsigned char address;
if(y==1)
address=0x80+x; //显示在第一排的时候的x的地址
else
address=0xc0+x; //显示在第二排的时候的x的地址
LCD_write_command(address); //输入地址
LCD_write_data(dat+48); //输入数据
}
表2 1602液晶显示地址(16列×02行)
根据表2可以了解到1602液晶第一行第一列显示位的地址为0x80,第二行第一列显示位的地址为0xC0,因此LCD_disp_char和LCD_disp_num中的参数y为1时输入的字符或数字将显示在第一行,参数y为0时输入的字符或数字将显示在第二行,出现在哪一列则由参数x决定。
图1.10 1602液晶标准字符库
如图1.10所示,1602液晶可显示的每一个字符都有一个唯一的代码,其中“A”处于0100 0001B(十进制65)位置,“a”处于0110 0001B(十进制97)位置,“0”处于0011 0000B(十进制48)位置,我们知道“A”、“a”和 “0”的ASCII码分别为65、97和48,因此只要在参数dat处直接输入字母或数字的ASCII码即可,字母的ASCII码即为字母本身,数字的ASCII码则为48+数字。
void dis_num(void)
{
unsigned char i=0,j=0,k=0;
LCD_write_command(0x01);//清除屏幕显示
character[0] = fre/10000000;
character[1] = fre/1000000%10;
character[2] = fre/100000%10;
character[3] = fre/10000%10;
character[4] = fre/1000%10;
character[5] = fre/100%10;
character[6] = fre/10%10;
character[7] = fre%10;
character[8] = 'H';
character[9] = 'z';
for(i = 0;i<4;i++) //显示fre=
{
LCD_disp_char(i+0,1,character_1[ i]);
}
for(i = 0;i<10;i++) //判断第一个不为0的数
{
if(character[ i]!=0)
break;
}
k = 8-i;
for(j = 0;j<k;j++) 显示所有的数字[="" align] for(i = 5;i<7;i++) //显示Hz
{
LCD_disp_char(j+4,1,character_1[ i]);
j++;
}
}
此为实现上文提到的1602液晶芯片在本作品中要发挥的功能②的函数。首先使用一个常规编程手法将全局变量fre中的8位数字分别赋值给数组character[0]- character[7],character[8]:character[9]则固定为“Hz”。在将数组character_1[]中的字符串“fre=”显示在1602液晶第一行的前四列的同时,作为虚拟光标的局部变量i的值变为3,接下来,通过逐位检查排除将i定位在fre的第一个不为零的数位上,此时8-i的数值即为fre的有效数字个数,有效数字即要显示在1602液晶上的数字,则从字符“=”的下一位即Ox84开始逐位将以上有效数字显示在液晶上,最后补上字符串“Hz”。
图1.21 LCD1602液晶显示芯片
最后附上1602液晶显示芯片的接线原理图,需要说明的是,可通过调节电位器R6调整1602液晶显示的对比度。
1.2整体电路原理
图1.22 电路原理图
原理说明如下:
①待测信号从P1(正):P4(负)输入。
②通过2SC3355三极管进行信号放大。
③使用74HC14施密特触发反相器进行多种波形向脉冲波形的转换,并优化。
④脉冲波形进入74HC390波纹计数器进行100分频。
⑤未分频脉冲和100分频脉冲分别进入单片机的两个定时/计数器,经过软件算法处理,产生待测信号频率数值。
⑥将此数值通过LCD1602液晶显示模块进行输出。
2 软件算法实现
上文已作说明的电路原理中,“未分频脉冲和100分频脉冲分别进入单片机的两个定时/计数器,经过软件算法处理,产生待测信号频率数值”毫无疑问是最关键的环节,在此将作详细说明。
①定时器初始化函数
void timer_init(void) //定时/计数器初始化
{
TMOD=0x66; //计数器0和计数器1工作工作方式2,自动重装初值
TH0=0; //计数器初值为0
TL0=0;
TR0=1; //计数器开始计数
ET0=1; //打开计数器0中断
TH1=0; //计数器初值为0
TL1=0;
TR1=1; //计数器开始计数
ET1=1; //打开计数器1中断
RCAP2H=(65536-62500)/256; //在程序初始化的时候给RCAP2L和RCAP2H赋值,
RCAP2L=(65536-62500)%256; //TH2和TL2将会在中断产生时自动使TH2=RCAP2H,TL2=RCAP2L。
TH2=RCAP2H; //12M晶振下每次中断62.5ms(1s=1000ms=62.5ms×16)
TL2=RCAP2L;
ET2=1; //打开定时器2中断
TR2=1; //定时器2开始计时
EA=1; //开总中断
}
表3 TMOD寄存器
由表3可知,TMOD=0x66=0110 0110B表明TR0(计数器0)和TR1(计数器1)工作工作在方式2,即可自动重装8位初值。
另外,52单片机具有定时器2,它的功能比定时/计数器0和定时/计数器1要强大很多。它具有自动重装16位初值的功能,初值存储在16 位计数存储器RCAP2H (高8位)和RCAP2L(低8位)中,只要程序初始化的时候给RCAP2H和RCAP2L赋值,在中断产生时将会自动执行TH2=RCAP2H,TL2=RCAP2L。这个中断操作在C语言中被编排为52单片机特有的方式5,即“interrupt 5”。
通过计算得到若要在晶振为12MHz的条件下每62.5ms进行一次计时中断需要在RCAP2H: RCAP2L装载初值62500。选择62.5ms的原因是62.5ms×16=1000ms=1s,这样既可通过准确测量计算16个计时中断周期内在TR0和TR1上捕获了几个脉冲信息,即待测信号的频率值。
②中断函数
void timer2(void) interrupt 5 //定时器2中断(62.5ms)
{
time++;
TF2=0; //定时器2的中断标志位TF2不能够由硬件清零,所以要在中断服务程序中将其清零
if (time==16) //定时1s时间到
{
time=0; //计时清0
EA=0; //关中断
fre=(long)count1*256+TL1; //count*256强制转换成long型,否则将不产生进位 先判断分频后(计数器1)
FLAG = 0;
if(fre<2000)//如果不到200KHz则读取分频前(计数器0)频率(200K÷100=2000)
{
fre = (long)count*256+TL0;
FLAG = 1;
}
if(!FLAG)
{
fre = fre *100;//100分频
}
TL0=0; //清零计数器0计数
TH0=0;
TL1=0;
TH1=0;
count=0; //清零计数器0计数
count1=0;
EA=1; //开中断
}
}
//----------------------------------------------------------------
void timer0(void) interrupt 1 //计数器0中断(100分频前)
{
count++;
}
//----------------------------------------------------------------
void timer1(void) interrupt 3 //计数器1中断(100分频后)
{
count1++;
}
依照上文的方案,通过变量time控制定时器2每16个62.5ms,即1s进行一次中断。进入中断后,考察来自TR1的脉冲计数值,“fre = (long)count*256+TL1;”的含义是:count为1s计时到时时TL1在此周期内重装初值的次数,即TR1的中断次数,将此值乘以256再加上定时器2中断瞬间TL1的值即为此周期内TR1捕获的脉冲的准确数量,需要注意的是,fre是long类型变量,故需将count强制临时转换成long类型,否则与256相乘后仍是8位的字节变量,造成错误。
若经过上述考察后发现fre的数值不到200KHz的100分频值即2000Hz,则根据尽量规避分频造成误差的原则,在单片机能处理的频率范围内进行操作,即使用TR0上捕获的1s内未分频原始脉冲信号到达的数量对fre进行赋值,方法及注意事项同上。
最后,清零一切TR0、TR1计数值并重新打开总中断,等待潜在的频率数值变化的出现。
③主函数
void main()
{
unsigned char i;
LCD_init();
timer_init(); //定时/计数器初始化
for(i = 0;i<4;i++)
{
LCD_disp_char(i+0,1,character_1[ i]);
}
while(1)
{
dis_num(); //显示
delay_1s();
}
}
主函数的主要任务就是进行各种初始化并开启无限循环检测输入信号频率值的变化并通过改变fre的值在LCD1602上表现出来(在无信号输入的情况下,初始化函数将LCD1602上显示的字符固定为“fre= Hz”)。
3 结论
实训的最终目的是全面提高学生的职业素质,最终达到学生满意就业、企业满意用人的目的。合理的实训教育本应该是大学教育的一个重要组成部分。这次的实训与以往不同,是以小组为单位而进行的,以往都是一个人在努力,而今有了组员的帮助,事情变得有条理了不少,大大的锻炼了我们组员之间的协作能力,提高了个人的团队合作意识,让我们以后面对一个企业的氛围时不至于埋头苦干。
这次实训我们使用的是单片机系统,对于当前智能电子仪器已经在当今生活中无处不在的情况下,尤其活跃于计算机领域中,我们更需要对单片机进行进一步的了解和掌握,以顺应时代的潮流,而目前祖国也需要大量的技术型人才,而我们这些二十一世纪的大学生将为以后对国家进行更大的贡献。
回顾这次的实训,我们感慨万千,的确,从选题到制作,从调试到论文,每一个环节都留下我们努力的汗水,尤其是现在是大四这个关键的时期,我们组员也各有自己的事情要忙,考研的考研,找工作的找工作,难得有聚在一起的机会。但是毫无疑问,我们仍顺利的完成了任务,并从中学到不少理论上和为人处世上的知识,为我们以后的发展留下了宝贵的经验。通过这次实训,我们明白了团队的重要性,再一次让理论溶于实践之中,更加提高了实践能力和动手能力。
谢 辞
实训临近结束了,在短暂的实训过程中得到了老师和很多同学的帮助。首先衷心感谢王守华、归发弟和邓艳容三位老师的悉心指导和热情帮助,在我们小组完成过程中给以大力的帮助,让我们学到了许多实践的知识,开阔了眼界,增强了我们的实践动手能力,以及我们的团队合作精神。同时,还要感谢全班同学对我们小组的大力帮助,让我们在冬日的寒风中天天都充满了干劲,如果没有他们,我们不能够完成得这么顺利。除此之外,我们小组的组员各有分工,通力合作,彼此互相协作,不懂的地方大家一起讨论,碰到困难时大家一起解决,正是有了这种小组的氛围,我们才能够最终恪尽职守的完成这一个实训任务。不过由于我们时间和水平有限,本作品仍然有很多缺憾和不足的地方,恳请老师和同学批评指出。
参考文献
[1] 金峰. 智能仪器设计基础. 清华大学出版社,2005.
[2] 程德福,林君. 智能仪器(第二版). 机械工业出版社,2009.
[3] 王贤勇,赵传申. 单片机原理与接口技术应用教程. 清华大学出版社,2010.
[4] 谭浩强. C语言程序设计(第三版). 清华大学出版社,2005.
[5] 刘海涛. 8051单片机C语言程序设计与实例解析. 清华大学出版社,2009.
附 录1
以下为本电路的PCB(Printed Circuit Board,印制电路板):
图.附录PCB

本课设论文对应的所有设计资料下载(包含仿真工程文件 源码等):
http://www.51hei.com/bbs/dpj-77186-1.html