|

楼主 |
发表于 2019-1-3 11:40:43
|
显示全部楼层
//==========================================================================
// LCR表驱动程序 V2.0
// 许剑伟 于莆田 2012.01
//==========================================================================
//==========================================================================
#define uchar unsigned char
#define uint unsigned int
#define ulong unsigned long
#include <reg52.h>
#include <math.h>
void lcd_putp(float a,float b,char bo,char n, float qmin){ //带单位显示复数,n是单位下限,qmin是最小位权值(用于限定有效数字)
code uchar dwB[] = {'p','n','u','m','o','k','M','G'}; //单位表
char i,j, c=0, h=digW-1, fh[2]={' ','+'};
long d,q,Q=1; //D最高位权
float f,g=1;
if(a<0) fh[0] = '-', a = -a;
if(b<0) fh[1] = '-', b = -b;
if(a>b) f = a; else f = b;
第091行:-------------------------------------------------------|
if(qmin) { |
a += qmin/2, a -= fmod(a,qmin)-qmin/1000; |
b += qmin/2; b -= fmod(b,qmin)-qmin/1000; |
}-------------------------------------------------------------
for(i=1;i<digW;i++) Q *= 10;
for(i=0;i<3;i++){ if(f*g >= 1000) g/=1000, c++; } //以3位为单位移动小数点,右移
for(i=0;i<n;i++){ if(f*g < 1) g*=1000, c--; } //以3位为单位移动小数点,左移
for(i=1;i<digW && f*g<Q;i++) g*=10,h--; //继续移动小数点,使之满字
for(i=0;i<2;i++){
if(i) d = b*g+0.5; //取出实部
else d = a*g+0.5; //取出虚部
q = Q;
lcd_putc(fh[i]); //显示符号
for(j=0; j<digW; j++){ //数字输出
lcd_putc(d/q+48); //数字
if(j==h) lcd_putc('.');//小数点
d %= q, q /= 10;
}
if(!bo) break; //不显示虚部
}
lcd_putc(dwB[c+4]); //单位
}
void lcd_putf(float a, char n, float qmin) //带单位显示浮点数,n是单位下限
{ lcd_putp(a,0,0,n,qmin); }
void lcd_int(int a,char w){ //定宽显示正整数
char i=0, s[5] = {' ',' ',' ',' ',' '};
if(a<0) { a=-a; lcd_puts("-"); }
else lcd_puts(" ");
do{
s[i++] = a%10+48;
a /= 10;
}while(a);
for(;w;w--) lcd_putc(s[w-1]);
}
}
}
//==========================================================================
//==================================LCR主程序===============================
//==========================================================================
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 spk=P2^3; //蜂鸣器
sbit Kb=P2^1; //量程开关B
sbit Ka=P2^2; //量程开关A
sbit DDS2=P1^2;//移相方波输出口
sbit K3=P1^7;
sbit K4=P1^6;
sbit K5=P1^5; //7.8kHz滤波开关
sbit K6=P1^4;
sbit K8=P2^0; //100Hz滤波开关
sbit K32=P1^1; //32kHz发生器
xdata uchar menu=1,menu2=0; //菜单变量
EA = 1; //开总中断
}
//==============LCR测量====================
code float ga[4] = { 1, 3, 9, 27 }; //增益表
code float dwR[4] = { 20, 1e3, 1e4, 1e5 }; //各档电阻表
xdata int Vxy[6]={0,0,0,0,1,1}; //Vxy[Vx1,Vy1,Vx2,Vy2,g1,g2]
xdata char Sxw[4]={0,1,0,1}; //保存正确相位
xdata int Vz[12]; //LCR测量结果队
xdata uchar tim=0,tims=0;
xdata char pau=0; //暂停坐标自动旋转
#define Vfull 9600
#define gad (9600/30)
uchar mT = 6; //测量速度,mT取值为6或12或24时,可以消除数字噪声,尾数不动,但不利于于取平均
//==============设置频率====================
xdata char feqK=1; //频率索引号
void setF(char k){
if(k==-1) k = (feqK+1)%3; //步进
feqK = k;
if(k==0) { setDDS(100); K5=0; K8=1; mT=12; } //置为100Hz
if(k==1) { setDDS(977); K5=0; K8=0; mT=6; } //置为1kHz
if(k==2) { setDDS(7813); K5=1; K8=0; mT=6; } //置为7.8125kHz
TH1 = 150, TL1 = 171; //置为20ms
tims = 0;
tim = 0;
ph = 0;
}
int absMax(int a,int b){ //取两个数绝对值最大者
if(a<0) a = -a;
if(b<0) b = -b;
if(b>a) a = b;
return a;
}
char yc1=0,yc2=0; //溢出标识
void timerInter1(void) interrupt 3 {//T1中断,LCR数据采集
char g,i; int c=0;
tims++;
if(tims>=mT) tims = 0, tim++, c = 1;
if(tim>=4) tim=0;
if(pau) return;
if(c){ //tim进位触发
c = getAD10b(); //读取电压值
c -= cs.zo[feqK];
Vxy[tim] = xw<2 ? c : -c; //保存当前电压
Vxy[tim/2+4] = curGain; //保存当前增益
Sxw[tim] = ( Sxw[tim]+(c<0 ? 2 : 0) )%4; //相位翻转(预测下次的相位采用值)
if(tim==1||tim==3){ //上下臂切换
if(tim==1) { K3=1, c = absMax(Vxy[2],Vxy[3]), g=Vxy[5]; yc2 = c>Vfull ? 1:0; }//切换到下臂
if(tim==3) { K3=0, c = absMax(Vxy[0],Vxy[1]), g=Vxy[4]; yc1 = c>Vfull ? 1:0; }//切换到上臂
if(c>Vfull) g--;
else if(c<gad*1 ) g += 3; //增加27倍
else if(c<gad*3 ) g += 2; //增加9倍
else if(c<gad*9) g++; //增加3倍
setGain(g);
}
set90( Sxw[ (tim+1)%4 ] ); //相位旋转
if(tim==3){ for(i=0;i<6;i++) Vz[i+6]=Vz[i], Vz[i]=Vxy[i]; }
}
}
xdata char isQ=0;
void showR(char binLian){ //显示LCR
xdata float a=0,b=0,c=0,e,w,L,C;
xdata int gr=cs.R[rng], g1=cs.g1, g2=cs.g2;
xdata int g12 = g1 + g2; //增益最大补偿
xdata int j12 = (int)cs.j1+cs.j2; //相位最大补偿
xdata float JD = 0, G = 0, cJD; //补偿变量
xdata int v[4];
//LCR计算
if(feqK<0||feqK>2) return;
if(rng==3){
if(yc1) { lcd_cls(); lcd_puts("Overflow,high"); return; } //未知高阻
if(yc2) { lcd_cls(); lcd_puts("Overflow,low"); return; } //未知低阻
}
v[0] = Vz[0]+Vz[6];
v[1] = Vz[1]+Vz[7];
v[2] = Vz[2]+Vz[8];
v[3] = Vz[3]+Vz[9];
a = +( 1.0*v[2]*v[2] + 1.0*v[3]*v[3] );
第461行:-----------------------------------|
b = -( 1.0*v[0]*v[2] + 1.0*v[1]*v[3] ); | 为什么要加负号????
c = -( 1.0*v[2]*v[1] - 1.0*v[0]*v[3] ); |
------------------------------------------|
a *= ga[Vz[4]] / ga[Vz[5]];
if(feq==7813&&rng==3) gr += cs.R4b; //7.8kHz时下臂修正量
a /= dwR[rng]*(1+gr/10000.0); //除以下臂电阻阻值
//可控增益单元的增益修正、相位补偿量
if(feq==7813) g2 += cs.G2b; //7.8kHz时9倍档修正量
if(Vz[4] == 1) JD += cs.j1, G += g1;
if(Vz[4] == 2) JD += cs.j2, G += g2;
if(Vz[4] == 3) JD += j12, G += g12;
if(Vz[5] == 1) JD -= cs.j1, G -= g1;
if(Vz[5] == 2) JD -= cs.j2, G -= g2;
if(Vz[5] == 3) JD -= j12, G -= g12;
JD = (JD - cs.J[rng]) * feqX/7813/2000;
if(feq==977) JD -= cs.phx/2000.0;
cJD = 1 - JD*JD/2;
e = b;
a = a+a*G/10000; //增益补偿
b = e*cJD - c*JD; //相位补偿
c = e*JD + c*cJD; //相位补偿
if(binLian==20){ //测量开路残余值
if(rng==3){
a = (b*b+c*c)/a;
cs.QRo[feqK] = b/a, cs.QXo[feqK] = c/a; //开路残余导抗
cs_RW(1); setF(feqK); //保存
lcd_cls(); lcd_puts("Open zero. OK.."); delay2(100);
}
if(rng==0){
cs.QRs[feqK] = b/a, cs.QXs[feqK] = c/a; //短路残余阻抗
cs_RW(1); setF(feqK); //保存
lcd_cls(); lcd_puts("Short zero. OK.."); delay2(100);
}
return;
}
if(binLian==21){ //是否应用清零
isQ = (isQ+1)%2;
return;
}
if(isQ){ //清零
b -= cs.QRs[feqK]*a, c -= cs.QXs[feqK]*a;//短路清零
a = (b*b+c*c)/a;
b -= cs.QRo[feqK]*a, c -= cs.QXo[feqK]*a; //开路清零
a = (b*b+c*c)/a;
}
//电学量显示 if(!a) { lcd_cls(); lcd_puts("DIV 0"); return; }
w = 2*3.1415926*feqX;
lcd_goto2(0); //显示频率
if(feq==100) lcd_putc('A');
if(feq==977) lcd_putc('B');
if(feq==7813) lcd_putc('C');
lcd_putc(rng+49); //显示量程
if(binLian){ //并联
e = (b*b+c*c)/a;
lcd_goto1(0);
if(isQ) lcd_puts("Zp");
else lcd_puts("Hp");
lcd_putf(e/b, 1, 1e-4); //显示并联复阻抗,显示到毫欧
lcd_putf(e/c, 1, 1e-4); //显示并联复阻抗,显示到毫欧
lcd_goto2(2);
C = -c/e/w;
L = +e/c/w;
if(C>-2e-12) { lcd_putf(C, 4, 1e-14); lcd_putc('F'); } //显示并联C值,显示到pF
else { lcd_putf(L, 2, 5e-9 ); lcd_putc('H'); } //显示并联L值,显示到uH
}else{ //串联
e = a;
lcd_goto1(0);
if(isQ) lcd_puts("Zs");
else lcd_puts("Hs");
lcd_putp(b/e, c/e, 1, 1, 1e-4); lcd_putc(244); //显示串联复阻抗,显示到毫欧
lcd_goto2(2);
C = -e/c/w;
L = +c/e/w;
if(L<-2e-8) { lcd_putf(C, 4, 1e-14); lcd_putc('F'); } //显示C值,显示到pF
else { lcd_putf(L, 2, 5e-9 ); lcd_putc('H'); } //显示L值,显示到uH
}
if(b){ c = fabs(c/b); if(c>999) c=999; } //计算Q
else c = 999;
lcd_putf(c,0,0); //显示Q
}
//void timerInter(void) interrupt 1 {}//T0中断
main(){
uchar i=0,kn=0,key=0;
uchar dispN=0; //显示扫描索引
uchar spkN=0; //蜂鸣器发声时长
uint nn=0;
char binLian=0;
char mo=0; //编辑显示开关
lcd_init(); //初始化LCD
lcd_cur0(); //隐藏光标
lcd_puts("LCR 2.0");
lcd_goto2(0);
lcd_puts("XJW Putian,2011");
delay2(500); //启动延时
eepEn= 12345;
cs_RW(0); //读EEPROM
TCON=0, TMOD=0x12; //将T0置为自动重装定时器,T1置为定时器
TH1 = 0, TL1 = 0;
TR1=1; //T1开始计数
TR0=0; //T0暂停计数
ET1=1; //T1开中断
ET0=1; //T1开中断
EA=1; //开总中断
PT0=1; //设置优先级
set_channel(0); //设置AD转换通道
P2M0 = 0xFF; //P2.01234567置为推勉输出
P1M0 = 0xFE; //P1.1234567置为推换口
P1M1 = 0x01; //P1.0置为高阻抗
P2 = 0x0F;
PWM_init(); //DDS初始化
set90(2); //初始设置相位
setRng(1); //初始设置量程
setGain(1); //初始设置增益
setF(1); //DDS初始设置为1kHz
while(1){
//显示disp
nn++;
//扫描键盘
key = ~P3;
if(key&&kn<255) kn++; else kn=0;
for(i=0;key;i++) key/=2; key=i;
if(kn==4) spkN=10; else key=0; //当按下一定时间后key才有效。spkN发声时长设置
//菜单系统
if(key==8){//菜单键
lcd_cls(); lcd_puts("M:1 LCR 3 Test");
lcd_goto2(0); lcd_puts("6 setF,7 Set");
menu=0; key=0; mo=0; pau=0;
}
if(menu>=1 && menu<=3){
if(key==7) setRng2(); //量程步进
if(key==6) setF(-1); //设置频率
}
if(menu==0){ //显示量程和菜单
if(key) lcd_cls();
if(key>=1 && key<=7) menu = key, menu2 = 0;
key = 0;
}
if(menu==1){ //LCR测量(串联)
if(key==1) binLian = (binLian+1)%2; //串并联切换
if(key==3) showR(21); //取消清零
if(key==4) showR(20); //开路清零
showR(binLian);
}
if(menu==2){
lcd_goto1(0);
lcd_puts("up:"); lcd_putc(Vxy[4]+48);
lcd_puts(" dw:"); lcd_putc(Vxy[5]+48);
}
if(menu==3){ //手动调试
pau = 1;
if(key==1) setGain2();//增益控制
if(key==2) { };
if(key==3) K3=~K3; //切换上下臂
if(key==4) set902(); //相位旋转
lcd_goto1(0);
lcd_puts(" xw="); lcd_putc(xw+48); //相位索引号
lcd_puts(" K3="); lcd_putc(K3?49:48); //K3状态
lcd_puts(" Ga="); lcd_putc(curGain+48); //增益索引号
lcd_goto2(0);
if(nn%32==0) lcd_int(getAD10(),5);
}
if(menu==6){ //频率修正
if(key==1) cs.feq += 1; //X键增
if(key==2) cs.feq -= 1; //R键减
if(key==3) { cs_RW(1); setF(feqK); } //L键保存
lcd_cls();
lcd_goto1(0); lcd_puts("Feq correct");
lcd_goto2(0); lcd_putf(cs.feq,0,0);
}
if(menu==7){ //校准
code char *csR[19] = {
"Z0 : 20", "Z1 : 20", "Z2 : 20",
"R1 : 20", "R1X: 20",
"ak : 25",
"R2 : 1k", "R2X: 1k",
"R3 :10k", "R3X:10k",
"R4 :.1M", "R4b:.1M", "R4X:.1M",
"G1 :3k3", "G1X:3k3",
"G2 : 9k", "G2b: 9k", "G2X: 9k",
"phX: 1k"
};
char *p,bc=1, feqD=1,rngD=1;
static char kc=0;
if(key==4) *p = 0; //C键清除
if(key==5) { if(menu2==0) menu2=18; else menu2--; mo=0; }
if(key==6) { if(menu2==18)menu2=0; else menu2++; mo=0; }
if(key==7) mo = (mo+1)%2;
if(key==4){ //恢复到默认值
if(++kc==5){
kc = 0;
cs.j1 = 36, cs.j2 = 34;
cs.g1 = 0, cs.g2 = 0;
cs.zo[0] = 76;
cs.zo[1] = 76;
cs.zo[2] = 70;
cs.J[0] = cs.J[1] = 0, cs.J[2] = 4, cs.J[3] = 48;
cs.R[0] = cs.R[1] = cs.R[2] = cs.R[3] = 0;
cs.R4b = cs.G2b = cs.phx = cs.feq = 0;
cs.ak = 0;
for(i=0;i<3;i++) cs.QRs[i] = cs.QXs[i] = cs.QRo[i] = cs.QXo[i] = 0;
}
}
else { if(key) kc=0; }
//显示
if(mo){
if(feqD!=feqK) setF(feqD);
if(rngD!=rng) setRng(rngD);
if(menu2>=3&&menu2<=7) showR(0);
else showR(1);
}else{
lcd_cls();
lcd_goto1(0);
lcd_puts(csR[menu2]); //输出参数名称
lcd_goto2(0);
lcd_putf(*p,0,0);
lcd_puts("X:+ R:-");
}
}
if(spkN) spkN--, spk=0; else spk=1; //键盘发声
delay(20000);
}//while end
}
//==========================================================================
|
|