|
发表于 2024-4-17 09:02:00
|
显示全部楼层
//综合10楼,19楼,33楼,可编译的代码
/*************************************
Q表驱动程序 V3.1
xjw01 于莆田 2010.10
**************************************/
//====================================
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#include <reg52.h>
void delay(uint loop) { uint i; for(i=0;i<loop;i++); } //延时函数
void delay2(uint k){ for(;k>0;k--) delay(10000); } //长延时,k=100大约对应1秒
uchar key_T[16]={
15,13,14,12,
1,2,3,10,
4,5,6,0,
7,8,9,11
};
//========================AD转换=============================
sfr P1ASF = 0x9D; //将P1置为模拟口寄存器(使能),各位中为1的有效
sfr ADC_CONTR = 0xBC; //A/D转换控制寄存器
sfr ADC_res = 0xBD; //A/D转换结果寄存器
sfr ADC_resl = 0xBE; //A/D转换结果寄存器
void set_channel(char channel){
P1ASF = 1<<channel;
ADC_CONTR = channel+128; //最高位是电源开关,低3位通道选择
delay(1); //首次打开电源应延迟,使输入稳定
}
uint get_AD2(){
ADC_CONTR |= 0x08; //00001000,置ADC_START=1启动A/D 转换
while ( !(ADC_CONTR & 0x10) ); //等待A/D转换结束(ADC_FLAG==0)
ADC_CONTR &= 0xE7; //11100111,置ADC_FLAG=0清除结束标记, 置ADC_START=0关闭A/D 转换
return ADC_res*4 + ADC_resl;
}
/*
uchar get_AD(){
ADC_CONTR |= 0x08; //00001000,置ADC_START=1启动A/D 转换
while( !(ADC_CONTR & 0x10) ); //等待A/D转换结束(ADC_FLAG==0)
ADC_CONTR &= 0xE7; //11100111,置ADC_FLAG=0清除结束标记, 置ADC_START=0关闭A/D 转换
return ADC_res;
}
*/
//============================EEPROW偏程=========================
sfr IAP_data = 0xC2;
sfr IAP_addrH = 0xC3;
sfr IAP_addrL = 0xC4;
sfr IAP_cmd = 0xC5;
sfr IAP_trig = 0xC6;
sfr IAP_contr = 0xC7;
/********************
写字节时,可以将原有数据中的1改为0,无法将0改为1,只能使用擦除命令将0改为1
应注意,擦除命令会将整个扇区擦除
*********************/
uchar readEEP(uint k){ //读取
IAP_addrL = k; //设置读取地址的低字节,地址改变才需要设置
IAP_addrH = k>>8; //设置读取地址的高字节,地址改变才需要设置
IAP_contr = 0x81; //设置等待时间,1MHz以下取7,2M以下取6,3M取5,6M取4,12M取3,20M取2,24M取1,30M取0,前导1表示许档IAP
IAP_cmd = 1; //读取值1,写取2,擦除取3,擦除时按所在字节整个扇区撺除
IAP_trig = 0x5A; //先送5A
IAP_trig = 0xA5; //先送5A再送A5立即触发
return IAP_data;
}
void writeEEP(uint k, uchar da){ //写入
IAP_data = da; //传入数据
IAP_addrL = k; //设置读取地址的低字节,地址改变才需要设置
IAP_addrH = k>>8; //设置读取地址的高字节,地址改变才需要设置
IAP_contr = 0x81; //设置等待时间,1MHz以下取7,2M以下取6,3M取5,6M取4,12M取3,20M取2,24M取1,30M取0,前导1表示许档IAP
IAP_cmd = 2; //读取值1,写取2,擦除取3,擦除时按所在字节整个扇区撺除
IAP_trig = 0x5A; //先送5A
IAP_trig = 0xA5; //先送5A再送A5立即触发
}
void eraseEEP(uint k){ //擦除
IAP_addrL = k; //设置读取地址的低字节,地址改变才需要设置
IAP_addrH = k>>8; //设置读取地址的高字节,地址改变才需要设置
IAP_contr = 0x81; //设置等待时间,1MHz以下取7,2M以下取6,3M取5,6M取4,12M取3,20M取2,24M取1,30M取0,前导1表示许档IAP
IAP_cmd = 3; //读取值1,写取2,擦除取3,擦除时按所在字节整个扇区撺除
IAP_trig = 0x5A; //先送5A
IAP_trig = 0xA5; //先送5A再送A5立即触发
}
#define Nda 23
xdata struct Ida{
int bas; //比值基数
int z[Nda]; //激励电压表
int C,C2; //主调电容的电大值与最小值,单位0.1pF
int jz[14]; //125等分非线性改正表,jz[0]存放初始温度下的零点电压(初次非线性桥正时的零点电压)而不存0值
} cs;
void cs_RW(char rw){
uchar i,*p = &cs;
if(rw){
eraseEEP(0);
for(i=0;i<sizeof(cs);i++) writeEEP(i,p[i]);
}else{
for(i=0;i<sizeof(cs);i++) p[i]=readEEP(i);
}
}
//=============================DDS部分========================
#define fMax 12500000
xdata ulong feq=600000;
xdata uchar fstep=100;
sbit FSYNC=P2^1; //DDS使能
sbit SCLK=P2^2; //DDS串行时钟
sbit SDATA=P2^3; //DDS串行数据
void DDS_W16(uint d){ //写32比特数据到DDS
uchar i;
SCLK = SDATA = FSYNC=1; delay(3000);
FSYNC=0; //使能(或同步)打开,数据开始传送
delay(5);
for(i=0;i<16;i++){
SDATA = d>>15; delay(1);
SCLK = 0; delay(1);
SCLK = 1; delay(1);
d<<=1;
}
FSYNC=1; delay(1);
SCLK=0; delay(1);
}
void DDS_init(void){
DDS_W16(0x2100); //B28=1(28位连续写频置位),选择频率0相位0,RESET=1
//DDS_W16(0x2500); //B28=1(28位连续写频置位),选择频率0相位1,RESET=1
//DDS_W16(0x2900); //B28=1(28位连续写频置位),选择频率1相位0,RESET=1
//DDS_W16(0x2D00); //B28=1(28位连续写频置位),选择频率1相位1,RESET=1
//当RESET置位后,开始初始化频率和相位
DDS_W16(0x4000); //写频率0寄存器的低字节LSB
DDS_W16(0x4000); //写频率0寄存器的高字节MSB
DDS_W16(0x8000); //写频率1寄存器的低字节LSB
DDS_W16(0x8000); //写频率1寄存器的高字节MSB
DDS_W16(0xC000); //写相位0
DDS_W16(0xF000); //写相位1
DDS_W16(0x2000); //28位连续,选择频率0,相位0,RESET=0
}
void DDS_f(){ //设置频率
ulong m;
uint mL,mH;
if( feq > fMax ) feq = fMax;
m = feq*10 + feq*11/16 + feq*12/256 + feq*12/256/16 + feq*6/65536; // f* 268435456/ 25000000
mL = m, mH = m>>14; //分离出低字节和高字节(各14bit有效)
mL = (mL & 0x3FFF) + 0x4000; //补上前导01
mH = (mH & 0x3FFF) + 0x4000; //补上前导01
DDS_W16(0x2000); DDS_W16(mL); DDS_W16(mH); //连续28bit写频,RESET=0时所设频率被应用
}
/**********
字形编码图
32
-
64| | 128
- 16
1| | 8
_. 4
2
**********/
uchar code zk[20]={235,136,179,186,216,122,123,168,251,250}; //字库
uchar disp[6]={168,251,250}; char cx=-1; //显示缓存,cx光标位置
sfr P1M1=0x91; //P1端口设置寄存器
sfr P1M0=0x92; //P1端口设置寄存器
sfr P0M1=0x93; //P0端口设置寄存器
sfr P0M0=0x94; //P0端口设置寄存器
sfr P2M1=0x95; //P2端口设置寄存器
sfr P2M0=0x96; //P2端口设置寄存器
sfr P3M1=0xB1; //P3端口设置寄存器
sfr P3M0=0xB2; //P3端口设置寄存器
sbit ds3=P2^4; //数码管扫描口
sbit ds2=P2^5; //数码管扫描口
sbit ds1=P2^6; //数码管扫描口
sbit ds0=P2^7; //数码管扫描口
sbit kx0=P3^4; //键盘扫描口
sbit kx1=P3^5; //键盘扫描口
sbit kx2=P3^6; //键盘扫描口
sbit kx3=P3^7; //键盘扫描口
sbit K0=P3^3; //调零开关端口(输出)
sbit KP=P3^2; //电源管理
sbit spk=P2^0; //蜂鸣器
//功能程序开始
xdata uchar menu=1,menuF=0,menu2=0;
void cls(){ char i; for(i=0;i<6;i++) disp[i]=0; } //清屏
void showDig(long f){ //显示数字
uchar i;
cls();
for(i=0;i<6;i++) { disp[i]=zk[f%10], f/=10; if(!f) break; }
}
uchar tms=0,ts=0,tm=0,th=0; ////tms为5ms计数器
uchar tmX=0; //无操作时间(自动关机使用)
void timerInter1(void) interrupt 3 {//T1中断
TH1=0xa8; TL1+=0x11;
tms++;
if(tms==100){
tms = 0, ts++; //秒跳变
if(ts==60){
ts=0, tm++,tmX++; //分钟跳变
if(tm==60) tm=0, th++;
if(th==24) th=0;
if(tmX==8) KP = 0; //自动关机
}
}
}
void timerInter(void) interrupt 1 {//T0中断
}
xdata int V0=0,V1=0,V10=0; //V0调零电压,V1检波电压
int code lineV[14]={0,1,2,3,4,5,10,15,20,25,50,75,100,125}; //娇正输出表(线性表)
int jiaozheng(long v){ //输入已调零的电压值
char i,b;
int a;
if(v<=0) return 0;
for(i=1;i<14;i++) if(v<cs.jz[i]) break;
if(i==14) i=13;
//温漂改正
b = (V0-cs.jz[0])*7/10; //零点漂移量的70%
if(v<170) v += v*b/170;
else v += b;
//矫正
if(i) a = cs.jz[i-1]; else a = 0;
return lineV[i-1]*10 + (lineV[i]-lineV[i-1])*10*(v-cs.jz[i-1])/(cs.jz[i]-cs.jz[i-1]);
}
uint Qlc(int f, ulong v){ //Q值计算,f单位千赫,非线性v矫正后的电压
xdata int a = cs.z[Nda-1];
xdata char i;
i = f/500, f%=500;
if(i<Nda-1) a = cs.z[i] + f*(cs.z[i+1]-cs.z[i])/500;
return (v*cs.bas + a/2)/a;
}
void showQ(){ //显示Q
if(V1>=1023) { disp[0]=disp[1]=disp[2]=disp[3]=128; return; }
showDig( Qlc(feq/1000,jiaozheng(V1-V0)) );
disp[1] += 4;
}
void showF(){ //显示频率
if(ts%4==0){
showDig(feq%10000);
disp[3] = 115;
if(!disp[1]) disp[1]=zk[0];
if(!disp[2]) disp[2]=zk[0];
}else{
showDig(feq/1000);
if(feq>=10000000) disp[3]+=4;
}
}
void zeroOff(){ //读取调零值
spk=1; //关闭蜂鸣器,防音频干扰
K0=1; delay2(50); //调零开关置位
V0=get_AD2(); //读取调零电压
K0=0; delay2(50); //调零开关复位
}
xdata ulong fm=0; //中心谐振点
int Q3db=0,C0=0; //3dB Q值,C0分布电容
long Lx = 10000,Cz=5000; //Lx被电感的电感量(单位0.01uH),Cz主调电容值(单位0.1pF)
int readV(ulong f){ feq=f; DDS_f(); delay(60000); return jiaozheng(get_AD2()-V0); } //置频率并读取谐振电压,返回矫正后的电压
void autoF(int maxQ,char N){ //自动查找谐振点,N扫频点数(实扫频2N+1点),通常N=50足够,N<maxQ/2
char i,k; //循环变量
xdata long bc=feq/maxQ; //扫描步长,建议maxQ=5000设计
char im=0,an=0; int vm=0,qm; //极点变量
xdata int va,vb,v3db; //偏频计算的变量
xdata long pf,pf1,pf2; //偏频计算的变量
spk=1; //关闭蜂鸣器,防音频干扰
delay2(100);//等待1秒
//开始扫频,查找极点
fm = feq;
for(k=0;k<2;k++){ //分两次查找,第一次粗调,第二次细调
an=0, vm=0; //an溢出计数器
for(i=-N;i<=N;i++){
feq=fm+i*bc; DDS_f(); //设置频率
delay(4000); V1=get_AD2(); //读电压
if(vm<V1) im=i,vm=V1; //记录最大值
if(V1>=1023) an++;
}
im += an/2, fm+=im*bc; //极值位置
N=10, bc/=N;
}
vm=jiaozheng(vm-V0), v3db = vm*17/24, qm=Qlc(fm/1000,vm);
//已找到谐振点,下面进一频做3dB分析
pf = fm*5/qm; //带通半宽度
va = readV(fm+pf/2); if(va<v3db) qm*=5,pf/=5; //量程判断
pf1 = pf, pf2 = -pf;
va = readV(fm+pf); //右频偏1
vb = readV(fm+pf*9/10); //右频偏2
if(vb!=va) pf1 -= (pf/10)*(v3db-va)/(vb-va); //精确右偏频点
va = readV(fm-pf); //左频偏1
vb = readV(fm-pf*9/10); //左频偏2
if(vb!=va) pf2 += (pf/10)*(v3db-va)/(vb-va); //精确左偏频点
//谐振点及3dB
fm = fm+(pf2+pf1)/2; //谐振频率
if(pf1>pf2) Q3db = fm*10/(pf1-pf2); else Q3db=0; //计算3dB Q值
if(!Lx) Lx = 2.53303e19/fm/fm/cs.C; //电感量计算,单位0.01uH
Cz = 2.53303e19/fm/fm/Lx; //谐振总电容,单位0.1pF
if(Q3db>qm) C0 = Cz*(Q3db-qm)/Q3db; else C0=0; //1l是1的长整型
feq = fm; DDS_f();
}
main(){
uchar i=0,j=0,kn=0,key=0,act=1;
uchar dispN=0; //显示扫描索引
uchar spkN=0; //蜂鸣器发声时长
//定时器T0设置,用于信号发生器
TCON=0, TMOD=0x12; //将T0置为自动重装定时器,T1置为定时器
TH1=0xA8, TL1=0x11;
TR1=1; //T1开始计数
TR0=0; //T0暂停计数
ET1=1; //T1开中断
ET0=1; //T1开中断
EA=1; //开总中断
PT0=1; //设置优先级
set_channel(0); //设置AD转换通道
P2M0 = 0xF0; //P2.4567置为推勉输出
P1M1 = 0x03; //P1.01置为高阻抗
P3M0 = 0x0C; //P3.23置为推勉输出口
delay2(50); //等待电路的电压平稳
zeroOff(); //调零
DDS_init(); DDS_f(); //DDS初始化
cs_RW(0); //读取比值基数(调零时已做开机延时,确保电压上升到可读取EEPROW)
while(1){
V10-=(V10+5)/10; V10+=get_AD2(); V1=(V10+5)/10; //取检波电压(数字滤波)
//显示disp
dispN=(++dispN)%4; //扫描器移动
ds0=ds1=ds2=ds3=0;
if(dispN==0) ds0=1;
if(dispN==1) ds1=1;
if(dispN==2) ds2=1;
if(dispN==3) ds3=1;
if(dispN==cx && tms>100) P0=255; //光标闪烁
else P0=~disp[dispN]; //显示
//扫描键盘
for(i=0,key=255;i<16;i++){
kx0=kx1=kx2=kx3=1;
switch(i%4){ //X线置0
case 0: kx0=0; break;
case 1: kx1=0; break;
case 2: kx2=0; break;
case 3: kx3=0;
}
// if(!(P1 & 1<<i/4+4 )) { key=i; if(kn<255) kn++; break; } //有键按下
if(!(P1 & 1<<i/4+4 )) { key=key_T[i]; if(kn<255) kn++; break; } //有键按下
}
if(i==16) kn=0; //无键按下
//键盘响应
if(kn==20) spkN=50,tmX=0; else key=255; //当按下一定时间后,key才有效,否则无效。spkN发声时长设置
if(spkN) spkN--, spk=0; else spk=1; //键盘发声
//菜单系统
if(key==15) menu=0,menu2=0;
if(key==12) { if(menuF) menu=menuF, menuF=0; else menuF=menu, menu=255; key=255; } //频率显示键
if(menuF){ //编辑频率
if(key<10 ) feq = feq*10+key; //设置频率,有数字键按下则进入编辑状态
if(key==10) feq = 0; //清除
if(key==11) feq *= 1000; //整千赫输入
if(key<15) DDS_f();
showF(); //显示
}
if(menu==0){ //显示菜单
int Vbat;
set_channel(1); //设置AD转换通道
delay(20); Vbat = get_AD2(); //读取电池电压
set_channel(0); //设置AD转换通道
Vbat = Vbat*14/29;
showDig(Vbat);
disp[2]+=4;
disp[3]=2;
if(key<15) { menu=key; continue; }
}
if(menu==1){ //显示Q
if(key<=4) menu2 = key;
if(key==13) { feq += fstep; DDS_f(); } //频率微调
if(key==14) { feq -= fstep; DDS_f(); } //频率微调
if(key==5) { feq = 1000000; DDS_f(); } //设置频率为中波段频率的中心
if(key==6) { feq = 3000000; DDS_f(); } //设置频率为3MHz频率
if(key==7) { autoF(200,100); } //宽范围自动粗调谐
if(key==8) { fstep=20; }
if(key==9) { fstep=100; }
if(key==11) { autoF(5000,50); } //窄范围自动细调谐
if(key==10) { zeroOff(); } //调零
if(menu2==0) { if(tms%10==0) showQ(); } //显示Q
if(menu2==1) { showDig(Q3db); disp[1]+=4; } //显示3dB法Q值
if(menu2==2) { showDig(Cz); disp[1]+=4; } //显示主调电容
if(menu2==3) { showDig(C0); disp[1]+=4; } //显示分布电容
if(menu2==4) { //显示电感量
if(Lx<9999) { showDig(Lx); disp[2]+=4; }
else if(Lx<99999) { showDig(Lx/10); disp[1]+=4; }
else { showDig(Lx/100); }
}
}
if(menu==14){ Lx=0; autoF(5000,50); menu=1; key=255; } //电感量测量
if(menu==2){ //显压显示
if(key>=0&&key<10) menu2=key;
if(key==10) zeroOff(); //强制调零
if(menu2==0) { if(tms%10==0) showDig(jiaozheng(V1-V0)); } //显示矫正后的电压
if(menu2==1) { if(tms%10==0) showDig(V0); } //显示调零电压
if(menu2==2) { if(tms%10==0) showDig(V1); } //显示检波电压
}
if(menu==3){ //编辑比值基数
if(key==14) menu2=0;
if(key==13) menu2=1;
if(menu2==0){ //设置变压器的比值(例如比值为56,应输入560)
if(key<10) cs.bas = cs.bas*10+key; //修改
if(key==10) cs.bas = 0; //清零
if(key==11) cs_RW(1); //保存
showDig(cs.bas);
}
if(menu2==1){ //设置主调电容的最大容量
if(key<10) cs.C = cs.C*10+key; //修改
if(key==10) cs.C = 0; //清零
if(key==11) cs_RW(1); //保存
showDig(cs.C);
}
}
if(menu==4){ //编辑激励电压
//频点选择
if(key==14&&menu2>0) menu2--;
if(key==13&&menu2<Nda-1) menu2++;
//手动修改
if(key<10) cs.z[menu2] = cs.z[menu2]*10+key; //手动修改
if(key==10) cs.z[menu2] = 0; //清零
if(key==0 && cs.z[menu2]==0){ //已清零再输入0则全部清0
for(i=0;i<Nda;i++) cs.z[i]=0;
}
if(key==11){ //保存
spk=1; //关闭蜂鸣器,防音频干扰
for(i=0;i<Nda;i++){ //自动检查,如果数据为空则自动测量
if(cs.z[i]>0&&cs.z[i]<255) continue;
if(i==0) feq = 300; else feq = i*500;
feq*=1000; DDS_f();
delay2(5); V1=get_AD2(); //读电压
cs.z[i] = jiaozheng(V1-V0);
}
cs_RW(1);
}
showDig(cs.z[menu2]*10+(menu2/2)%10);
disp[1]+=4; if(menu2%2) disp[0]+=4;
}
if(menu==5){ //非线性校正数据编辑
//插值点选择
if(key==14&&menu2>0) menu2--;
if(key==13&&menu2<13) menu2++;
if(key<10) cs.jz[menu2] = cs.jz[menu2]*10+key; //编辑
if(key==10) cs.jz[menu2] = 0; //清零
if(key==11) cs_RW(1); //保存
if(ts%2) { showDig(lineV[menu2]); disp[3]=207; }//显示等分定标电压值
else showDig(cs.jz[menu2]); //显示未桥正的电压值(已调零)
}
delay(4000);
}//while end
} |
打赏
-
查看全部打赏
|