/************************************* LCR表驱动程序 V1.0 xjw01 于莆田 2011.10 **************************************/ //==================================== #define uchar unsigned char #define uint unsigned int #define ulong unsigned long #include #include void delay(uint loop) { uint i; for(i=0;i0;k--) delay(10000); } //长延时,k=100大约对应1秒 //========================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<>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立即触发 saEEP(); //保护 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立即触发 saEEP(); //保护 } 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立即触发 saEEP(); //保护 } xdata struct Ida{ char zo[3];//三个频率下的零点改正值 char j1; //相位补偿(3倍档) char j2; //相位补偿(10倍档) char J[4]; //相位补偿(V/I变换器) char R[4]; //下臂电阻修正(20,1k,10k,100k) char g1; //增益修正(3倍档) char g2; //增益修正(10倍档) } cs; void cs_RW(char rw){ uchar i,*p = &cs; if(rw){ eraseEEP(0); for(i=0;i=1000) f/=1000, b++; } //以3位为单位移动小数点,把大数转粉0至999,小数点在末字 for(i=0;i> 8; //截断正弦相位累加器,取高8位 y = x + chuX; //方波相位 CCAP0H = sinB[x];//正弦DDS输出 DDS2 = fbB[y]; //方波DDS输出 ph += phM; //相位累加 } void setDDS(uint f){ //参考时钟是c=(fosc/2)/256=32000000/2/256=62500,频率f=c*phM/2^16 feq = f; phM=f*65536.0/62500; //phM=f*2^16/62500 feqX = 62500.0*phM/65536; //实际输出频率 ph = 0; //高频时,使波形对称 if(!f) CR=0; else CR=1; } //相位控制函数 xdata char xw=0; //相位 void set90(char k){ //设置方波的相位差 k %= 4; if(k<0) k += 4; if(k==0) chuX=0; //移相0度 if(k==1) chuX=64; //移相90度 if(k==2) chuX=128; //移相180度 if(k==3) chuX=192; //移相270度 xw = k; } void set902() { set90(xw+1); } //相位步进 //==============量程控制函数==================== xdata char rng=1; //量程 void setRng(char k){//切换量程 if(k==0) Ka=0,Kb=0; //100欧 if(k==1) Ka=0,Kb=1; //1k欧 if(k==2) Ka=1,Kb=0; //10k欧 if(k==3) Ka=1,Kb=1; //100k欧 rng = k; } void setRng2(){ setRng( (rng+1)%4); } //量程步进 //==============增益控制函数==================== char curGain=1; //当前增益索引号 void setGain(char k){ //设置电路增益 if(k>3) k=3; if(k<0) k=0; if(k==0) K4=0,K6=0; //1倍 if(k==1) K4=0,K6=1; //3倍 if(k==2) K4=1,K6=0; //10倍 if(k==3) K4=1,K6=1; //30倍 curGain = k; } void setGain2(){ setGain((curGain+1)%4); } //==============LCR测量==================== xdata int Vxy[4]={0,0,0,0}; //Vxy[Vx1,Vy1,Vx2,Vy2] xdata char Sxw[4]={0,1,0,1}; //保存正确相位 xdata char Vga[4]={1,1,1,1}; //上下臂增益记录表 xdata uchar tim=0,tims=0; xdata char pau=0; //暂停坐标自动旋转 #define Vfull 9600 #define gad (9600/30) uchar mT = 6; //测量速度 //==============设置频率==================== xdata char feqK=1; //频率索引号 void setF(char k){ if(k==-1){ //步进 k = 0; if(feq==100) k=1; if(feq==1000) k=2; if(feq==7813) k=0; } if(k==0) { setDDS(100); K5=0; K8=1; mT=15; } //置为100Hz if(k==1) { setDDS(1000); K5=0; K8=0; mT=6; } //置为1kHz if(k==2) { setDDS(7813); K5=1; K8=0; mT=6; } //置为7.8125kHz feqK=k; TH1 = 47, 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; } #define avn 4 //求平无个数 xdata float vq[3][avn]; //数据缓存,用于求平均 void LCRcalc(int *v,char *g){ //LCR计算 code float ga[4] = { 1, 3, 9, 27 }; //增益表 code float dwR[4] = { 20, 1e3, 1e4, 1e5 }; //各档电阻表 xdata int g12 = (int)cs.g1+cs.g2; //增益最大补偿 xdata int j12 = (int)cs.j1+cs.j2; //相位最大补偿 xdata float JD = 0,cJD, G = 0; //补偿变量 xdata float a,b,c,e; char i; a = +( 1.0*v[2]*v[2] + 1.0*v[3]*v[3] ); 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[g[0]] / ga[g[2]]; a /= dwR[rng]*(1+cs.R[rng]/10000.0); //除以下臂电阻阻值 //可控增益单元的增益修正、相位补偿量 if(g[0] == 1) JD += cs.j1, G += cs.g1; if(g[0] == 2) JD += cs.j2, G += cs.g2; if(g[0] == 3) JD += j12, G += g12; if(g[2] == 1) JD -= cs.j1, G -= cs.g1; if(g[2] == 2) JD -= cs.j2, G -= cs.g2; if(g[2] == 3) JD -= j12, G -= g12; JD -= cs.J[rng]; JD *= feqX/7813/1000; cJD = 1 - JD*JD/2; a *= 1+G/10000; //增益补偿 e = b*cJD - c*JD; //相位补偿 c = b*JD + c*cJD; //相位补偿 b = e; //入队 for(i=1;i=mT){ //tim进位触发 tims = 0, tim++; if(tim>=4) tim=0; c = getAD10(); //读取电压值 c -= cs.zo[feqK]; Vxy[tim] = xw<2 ? c : -c; //保存当前电压 Vga[tim] = curGain; //保存当前增益 Sxw[tim] += c<0 ? 2 : 0; //相位翻转(预测下次的相位采用值) Sxw[tim] %= 4; if(tim==1||tim==3){ //上下臂切换 //电压模值才能反应运放的输出幅度,所以增益切换判断得用模值 if(tim==1) K3=1, c = absMax(Vxy[2],Vxy[3]), g=Vga[2]; //切换到下臂 if(tim==3) K3=0, c = absMax(Vxy[0],Vxy[1]), g=Vga[0]; //切换到上臂 if(c>Vfull) g--; else if(c=1000) { showDig(999 ); } else if(c>=100 ) { showDig(c ); } else if(c>=10 ) { showDig(c*10 ); disp[1] += 4; } else if(c>=1 ) { showDig(c*100 ); disp[2] += 4; } else { showDig(c*1000); disp[3] += 4; } } } //void timerInter(void) interrupt 1 {}//T0中断 void showMsg(uchar a){ //临时跳出信息 P0 = ~a; ds0=1, ds1=ds2=ds3=0; delay2(50); } main(){ uchar i=0,kn=0,key=0; uchar dispN=0; //显示扫描索引 uchar spkN=0; //蜂鸣器发声时长 uint nn=0; uchar XRQ=1; char binLian=0; //并联1,串联0 delay2(80); //启动延时 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 = 0xFC; //P1.234567置为推换口 P1M1 = 0x03; //P1.0置为高阻抗 //请注意启动延时0.5秒方可读取cs_RW //cs_RW(0); //读取比值基数(调零时已做开机延时,确保电压上升到可读取EEPROW) PWM_init();//DDS初始化 set90(2); //初始设置相位 setRng(1); //初始设置量程 setGain(1); //初始设置增益 setF(1); //DDS初始设置为1kHz while(1){ //显示disp nn++; 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; P0=~disp[dispN]; //显示 //扫描键盘 //键盘响应 //key = (~P3)&0xfc; key = ~P3; if(key&&kn<255) kn++; else kn=0; for(i=0;key;i++) key/=2; key=i; if(kn==20) spkN=50; else key=0; //当按下一定时间后,key才有效,否则无效。spkN发声时长设置 if(spkN) spkN--, spk=0; else spk=1; //键盘发声 //菜单系统 if(key==8) { menu=0; key=0; XRQ=-1;} //菜单键 if(menu>=1&&menu<=4){ if(key==7) setRng2(); //量程步进 if(key==6) setF(-1); //设置频率 } if(menu==0){ //显示量程和菜单 showDig(10000); if(key>=1 && key<=7) menu = key, menu2 = 0; key = 0; } if(menu==1){ //自动LCR测量(串联) pau = 0; if(XRQ==-1) XRQ=1, sfdw=1; if(key==4) { //串并联切换 if(binLian) { binLian=0; showMsg(122); } //转为串联 else { binLian=1; showMsg(241); } //转为并联 } if(key==1) { if(XRQ==0) sfdw++; else sfdw=1; XRQ = 0; } if(key==2) { if(XRQ==1) sfdw++; else sfdw=1; XRQ = 1; } if(key==3) { if(XRQ==2) sfdw++; else sfdw=1; XRQ = 2; } if(key==5) XRQ = 3; sfdw %= 2; showR(XRQ,binLian); if(binLian && nn%512<50) { for(i=0;i<4;i++) disp[i] |= 4; } } if(menu==2){ //显示增益档位 showDig(Vga[0]*100+Vga[2]+10000); disp[1]=disp[3]=0; } if(menu==3){ //手动调试 pau = 1; if(key==1) { setGain2(); showMsg( zk[curGain] );} //增益控制 if(key==2) { }; if(key==3) { K3=~K3; showMsg(zk[K3]); } //切换上下臂 if(key==4) { set902(); showMsg(zk[xw]); } //相位旋转 if(nn%64==0) { showDig( getAD10()); disp[1]+=4; } } if(menu==7){ //设置零点偏移数 char *p,bc=1, feqD=1,rngD=1; static char kc=0, mo=0; if(menu2==0) p = cs.zo+0, feqD=0, rngD=2; //100Hz零点校准,接入10欧电阻 if(menu2==1) p = cs.zo+1, feqD=1, rngD=2; //1kHz零点校准,接入10欧电阻 if(menu2==2) p = cs.zo+2, feqD=2, rngD=2; //7.8kHz零点校准,接入10欧电阻 if(menu2==3) p = cs.J+0, feqD=2, rngD=0; //VI变换器相位校准,接入20电阻 if(menu2==4) p = cs.J+1, feqD=2, rngD=1; //VI变换器相位校准,接入1k电阻 if(menu2==5) p = cs.J+2, feqD=2, rngD=2; //VI变换器相位校准,接入10k电阻 if(menu2==6) p = cs.J+3, feqD=2, rngD=3; //VI变换器相位校准,接入100k电阻 if(menu2==7) p = &cs.j1, feqD=2, rngD=1; //运放3倍档相位校准,接入3.3k电阻 if(menu2==8) p = &cs.j2, feqD=2, rngD=1; //运放10倍档相位校准,接入10k电阻 if(menu2==9) p = cs.R+0, bc=2, feqD=1, rngD=0; //VI变换器模值校准,接入20欧 if(menu2==10) p = cs.R+1, bc=2, feqD=1, rngD=1; //VI变换器模值校准,接入1k欧 if(menu2==11) p = cs.R+2, bc=2, feqD=1, rngD=2; //VI变换器模值校准,接入10k欧 if(menu2==12) p = cs.R+3, bc=2, feqD=1, rngD=3; //VI变换器模值校准,接入100k欧 if(menu2==13) p = &cs.g1, bc=2, feqD=1, rngD=1; //运放3倍增益校准,接入2k欧电阻 if(menu2==14) p = &cs.g2, bc=2, feqD=1, rngD=1; //运放10倍增益校准,接入10k欧电阻 if(key==1) *p += bc; //X键增 if(key==2) *p -= bc; //R键减 if(key==3) { cs_RW(1); setF(feqK); } //L键保存 if(key==4) *p = 0; //C键清除 if(key==5) { if(menu2==0) menu2=14; else menu2--; mo=0; showMsg(menu2<9?zk[menu2]:zk[menu2-6]+4); } if(key==6) { if(menu2==14)menu2=0; else menu2++; mo=0; showMsg(menu2<9?zk[menu2]:zk[menu2-6]+4); } if(key==7) mo = (mo+1)%2; if(key==4){ //恢复到默认值 if(++kc==5){ kc = 0; cs.j1 = 16, cs.j2 = 18; cs.g1 = 0, cs.g2 = 0; cs.zo[0] = 15; cs.zo[1] = 17; cs.zo[2] = 15; cs.J[0] = cs.J[1] = cs.J[2] = 0, cs.J[3] = 20; cs.R[0] = cs.R[1] = cs.R[2] = cs.R[3] = 0; } } else { if(key) kc=0; } if(mo){ if(feqD!=feqK) setF(feqD); if(rngD!=rng) setRng(rngD); if(menu2>=3 && menu2<=8) showR(3,1); //显示Q else showR(1,1); //显示电阻 }else{ sfdw = 0; showDig(abs(*p)); if(*p<0) disp[3] = 16; } } delay(4000); }//while end }