1、简易频率特性测试仪的设计加在前面:术业有专攻。一般写一些东西我也不会在空间瞎发,弄的别人以为自己瞎显摆。不过我觉得我们电子设计的过程确实值得其他小组学习一下,比如说老葛焊板子那种芯片的布局,还有我们用 4 个按键解决所有数字的设置的思想。我希望大家看到文章的时候不是觉得怎么吊炸天,其实我们这种水平比我们吊炸天的多了去。我们之所以有敢厚着脸皮把这么次的设计思想分享出来,主要希望能把其中的某一些发光点分享给大家,同时希望他人给我们的更宝贵的意见和建议。 -end- 电子设计三中,仪器仪表组的第一个题目,是简易频率特性测试仪的设计。这个题目取自 2013 年的E 题:简易频率特性测试仪(E 题) 。
2、为了纪念近一个月的工作,特撰以此文纪念我们第七小组历经了的艰辛岁月。在此,感谢组长葛家瑾大神、还有范一华同学的辛勤付出,还有李煜及其他一些学长的帮助。特发上图,以作纪念。在本次完成题目的过程中,葛大神早早完成了公式推导、电路理论和原理的分析,并组织我们在工作上分工(虽然他好像对“被我和范一华排挤去焊电路板”很不满意私下抱怨并耿耿于怀,哈哈) 。下面我简单的回顾一下我们的这次设计:其中,有关硬件电路的部分是葛大神负责的,我只是略懂了原理,故仅仅略述。我主要承担的是 AD 采样部分的程序,还有就是通过操作液晶屏和按键实现的程序的总体逻辑控制程序。范一华同学主要完成的是 AD9854 部分的程序,正
3、弦波输出及其幅度补偿,还有扫频部分的程序。下面,我从入手这道题目的开始状态,来一步步回顾一下。下面,先把题目贴出来:/*=开始贴题目=*/【本科组】一、任务根据零中频正交解调原理,设计并制作一个双端口网络频率特性测试仪,包括幅频特性和相频特性,其示意图如图 1 所示。二、要求1基本要求制作一个正交扫频信号源。(1)频率范围为 1MHz40MHz,频率稳定度10-4;频率可设置,最小设置单位 100kHz。(2)正交信号相位差误差的绝对值5,幅度平衡误差的绝对值5%。(3)信号电压的峰峰值1V ,幅度平坦度5% 。(4)可扫频输出,扫频范围及频率步进值可设置,最小步进 100kHz;要求连续扫频
4、输出,一次扫频时间2s。2发挥部分(1)使用基本要求中完成的正交扫频信号源,制作频率特性测试仪。a. 输入阻抗为 50,输出阻抗为 50;b. 可进行点频测量;幅频测量误差的绝对值0.5dB,相频测量误差的绝对值5;数据显示的分辨率:电压增益 0.1dB,相移 0.1。(2)制作一个 RLC 串联谐振电路作为被测网络,如图 2 所示,其中 Ri 和 Ro 分别为频率特性测试仪的输入阻抗和输出阻抗;制作的频率特性测试仪可对其进行线性扫频测量。a. 要求被测网络通带中心频率为 20MHz,误差的绝对值5% ;有载品质因数为 4,误差的绝对值5%;有载最大电压增益 -1dB;b. 扫频测量制作的被测
5、网络,显示其中心频率和-3dB 带宽,频率数据显示的分辨率为 100kHz;c. 扫频测量并显示幅频特性曲线和相频特性曲线,要求具有电压增益、相移和频率坐标刻度。(3)其他。/*=贴题目结束=*/AD9854 实验板的程序,我们直接有学长找来的代码,我们需要做的工作只是移植。然而,源程序对应的 IO 口用到的均为位操作,而我们使用的 F020 单片机不能直接对 P6、P7 口直接进行位操作,所以需要将位操作均用“|=bitx”或者“KeyPort_Init();newLCDInit();/Welcome Pics.Clear();DrawcharS(“Our AD9854 sys“,1,0);
6、DrawcharS(“- to Be No.1“,2,4);while(0=KeyScan();/Go into Our System.initlcdsys();while(1)sysfuntion(KeyScan();上面是我们的 main 函数,我们主要就是进来初始化所有需要用到的外围电路,然后就进了一个sysfuntion(KeyScan();函数,这就是我们的 LCDsys。当然了,我们的 LCDsys.c 有 600+行,所以接下来关于这段程序的解读,我会直接在代码里面写。我个人认为我一个比较好的编程习惯就是注释写得非常详细,当然,和别的大牛比起来就很渣渣啦,不过通过注释让隔了一段时
7、间后自己还看得懂自己的程序是非常必要的。然后,我写此文时对程序的解读,我就用【】扩起来表示。Lcdsys.c 函数#include “lcdsys.h“#include “DataType.h“#include “math.h“#include “string.h“#include “lcd.h“ #include “key.h“ #include “ADDA.h“#include “AD9854.h“ #include “c8051F020.h“ /c8051f020 单片机头文件【上方都是头文件就没什么说的啦,当然,如果你经常在把别人的程序挪给自己用的时候出错,那么你就需要专门百度一下.c
8、 程序的头文件.h 需要怎么写了。 】 #define Vppadjust 0.819#define VppFangDaBeiShu 10.0#define VppPianZhiValue 1250.0#define GNDBuChang 13.0 【如果你有把不需要改变的值定义成变量的坏习惯,建议你定义他们为常量。这样你不会在程序中不小心的改变他们,更不会让 Keil 不智能的编译器不知为什么的就让你的程序跑飞。F020 单片机的存储单元在你写了一大串自己都不太记得什么用的变量和大量的借鉴了别人的代码后都不知道别人有什么变量的情况下存储空间的资源将会是十分极其以及相当的紧张的,所以你需要有这
9、个习惯】unsigned int f;/幅度(整型)给 AD9854 的时候*1000.0unsigned int a;/幅度(整型)给 AD9854 的时候*Vppadjust(即 0.819) unsigned int xdata tmp5;/记录采集出来的 ADC0 的 12 位数据bit JiaoZhunBit; float xdata ad0bc5;/补偿值数据 float xdata ad1bc5;/补偿值数据float xdata MaxValue;/最大相位或 K 取值 int xdata MaxPoint;/最大相位或 K 的频率点、/float xdata MinValue
10、;/最小相位或 K 取值/int xdata MinPoint;/最小相位或 K 的频率点、float xdata Value120;int xdata ThreeDb2;【给自己定义的变量注释清楚到底是用作什么用的】/*=对应关系=0- 5000k( 5M)1-10000k(10M)2-20000k(20M)3-30000k(30M)4-40000k(40M)=对应关系=*/unsigned int adtmp,adtmp0,adtmp1;/记录采集出来的 ADC0 的 12 位数据long double ad0,ad1,sinFi,Du,K;/将 12 位数据转化为实际电压值,保存为浮点数
11、据/cosFi 已经不用了unsigned char wei,count,incount;/LCDsys 用的:数据标志位、全局计数位、内嵌套计数位unsigned char cmd;/画图时候:1- 频率特性绘图,2-幅度特性曲线, 3-校准,4-退出/扫频时候:1-步进,2-起始频率,3-截止频率bit AorF;/用于标志:设置频率或者幅度、的标志位。unsigned int mo=1;/扫频使用 scan using.unsigned long Freq1=1000000.0;/扫频使用 scan using.unsigned int scanstep=1;/扫频使用 scan usi
12、ng. 扫频步进void initlcdsys()/LCDsys 初始化函数ADCcount=0;f=100;/ kHza=2000;/ mVwei=0;AorF=0;Clear();fun_ok();JiaoZhunBit=0;MaxValue=0;MaxPoint=0;/MinValue=0;/MinPoint=0; for(count=0;count1;start-)for(i=1;iai+1)a0=ai;ai=ai+1;ai+1=a0;return a3;【下面是一个将一位的整型转化成字符串的函数】/将 1 位的 int 型数据转换,返回字符的子函数char int2char(int
13、input)return 0x30+input;【在液晶屏上画无符号整型的函数】void drawint(unsigned int num,unsigned char row,unsigned char col)Drawchar(int2char(num/1)%10),row,col+4);Drawchar(int2char(num/10)%10),row,col+3);Drawchar(int2char(num/100)%10),row,col+2);Drawchar(int2char(num/1000)%10),row,col+1);Drawchar(int2char(num/10000)
14、%10),row,col+0);【在液晶屏上画有符号整型的函数】void drawsignedint(int input,unsigned char row,unsigned char col)int num; if(input“,cmd+1,0);DrawcharS(“scanStep=“,1,1);drawint(100*scanstep,1,10);DrawcharS(“k“,1,15);DrawcharS(“Start=“,2,1);drawint(adtmp0*100,2,7);DrawcharS(“kHz“,2,12);DrawcharS(“Stop=“,3,1);drawint(
15、adtmp1*100,3,6);DrawcharS(“kHz“,3,11);【下面是两路 ADC 的补偿函数,根据不同的频率,将电压分别在接直通网络自动校准的时候,分别校准位 1250mV 和 2500mV】/*=对应关系=0- 5000k( 5M)1-10000k(10M)2-20000k(20M)3-30000k(30M)4-40000k(40M)=对应关系=*/long double ad0BuChang(long double inputVpp,unsigned int inputf)/(相/ 频)度数补偿函数long double BuChangVpp,k;BuChangVpp=in
16、putVpp;if(1)/修改判断的值,以决定是否进行校正。if( 11)a-=1;break;case 3:if(a10)a-=10;break;case 2:if(a100)a-=100;break;case 1:if(a1000)a-=1000;break;/case 0:if(a1)a-=10000;break;default:break; fun_ok(); elseswitch(wei)case 4:if(f1)f-=1;break;case 3:if(f10)f-=10;break;case 2:if(f100)f-=100;break;case 1:if(f1000)f-=10
17、00;break;case 0:if(f10000)f-=10000;break;default:break;fun_ok(); break;【按键 3,4 控制的是下标表示位数的左移或右移】case 3: Clear();if(wei(0)wei-=1;fun_ok();break;case 4: Clear();if(wei4094)DrawcharS(“TooBig“,1,0); else /ad0=(0.591238914*adtmp-3.386186509);ad0=GNDBuChang+(0.591238914*adtmp-3.386186509);/这里因为接地电压不统一的缘故,
18、补偿 10mv。 /if(adtmp4094)ad0=2500; ad0=ad0BuChang(ad0,f);/*电压 *自动校准*/ drawsignedint(int)ad0,1,0); DrawcharS(“mV“,1,5);ad0=(ad0-VppPianZhiValue)/VppFangDaBeiShu);drawsignedint(int)ad0,2,0);DrawcharS(“mV“,2,5); /*AIN1 采集电压*/ADC0_Init(1,1);ADC0_Enable();count=0;while(count4094)DrawcharS(“TooBig“,1,8); el
19、se /ad1=(0.591238914*adtmp-3.386186509); ad1=GNDBuChang+(0.591238914*adtmp-3.386186509);/这里因为接地电压不统一的缘故,补偿 10mv。 /if(adtmp4094)ad1=2500; ad1=ad1BuChang(ad1,f);/*电压 *自动校准*/ drawsignedint(int)ad1,1,8); DrawcharS(“mV“,1,13);ad1=(ad1-VppPianZhiValue)/VppFangDaBeiShu);drawsignedint(int)ad1,2,8);DrawcharS
20、(“mV“,2,13); /*end*/if(0.0!=ad0 */sinFi=0.0-(ad1)/sqrt(ad0)*(ad0)+(ad1)*(ad1);/drawfloat2_2(acos(cosFi),3,8); /DrawcharS(“Hu“,3,13);/*Du=180*(acos(cosFi)/3.1415926;*/Du=180*(asin(sinFi)/3.1415926;/Du=DuBuChang(Du,f);/*drawfloat2_2(Du,3,8);*/*DrawcharS(“Du“,3,13); */drawsignedfloat2_2(Du,3,8);Drawcha
21、rS(“Du“,3,14);/* 显示参数 k */*K=(32.0*ad0*0.001/cosFi)/(a*0.001*a*0.001);*/K=0.0-(32.0*ad1*0.001/sinFi)/(a*0.001*a*0.001);K=10.0*log10(K);/drawint(int)K,3,0); drawsignedfloat2_2(K,3,0);DrawcharS(“dB“,3,6);elseDrawcharS(“Input Error!“,3,0); /* 按键退出 */while(1)if(7=KeyScan()|5=KeyScan()Clear();fun_ok();br
22、eak;break; case 8: AD9854_Init();【上图:】redodrawpic:Clear();/该按钮完成【画频率特性图】功能DrawcharS(“PicingOktoExit“,0,0);DrawcharS(“Up/6Fi(Du)“,1,0);DrawcharS(“Down/7K(dB)“,2,0);DrawcharS(“RightReSet“,3,0);cmd=4;【总共 6 个选项,1,6 键分别画 40K-400M 和 6M-30M 的相频曲线, 2,7 键分别画40K-400M 和 6M-30M 的幅频曲线,右键运行自动校准程序,5(ok)键退出】while(1
23、)/画图菜单选择if(5=KeyScan()cmd=5;Clear();fun_ok();break;else if(4=KeyScan()cmd=4;Clear();break;else if(1=KeyScan()Clear();DrawcharS(“Du“,2,14); for(count=0;count4094|adtmp14070)DrawcharS(“H“,0,14); else ad0=adtmp0;ad1=adtmp1; /*原本的补偿现在注释掉,因为有了现在自动校准的补偿* /if(adtmp04094)ad0=2500; /if(adtmp14094)ad1=2500;*/
24、 if(0.0!=ad0 ad0=ad0BuChang(ad0,f);/*电压 *自动校准*/ ad0=(ad0-VppPianZhiValue)/VppFangDaBeiShu); ad1=GNDBuChang+(0.591238914*adtmp1-3.386186509); ad1=ad1BuChang(ad1,f);/*电压 *自动校准*/ ad1=(ad1-VppPianZhiValue)/VppFangDaBeiShu); /*cosFi=(ad0)/sqrt(ad0)*(ad0)+(ad1)*(ad1);*/sinFi=0.0-(ad1)/sqrt(ad0)*(ad0)+(ad1)*(ad1);/* Drawing 相位 */ if(1=cmd)/*Du=180*(acos(cosFi)/3.1415926;*/Du=180.0*(asin(sinFi)/3.1415926;Valuecount=Du;if(MaxValue=Du)MinValue=Du;MinPoint=count;/DrawPoint(5+count,32);/横轴在中间,可能值为+90-