矿石收音机论坛

 找回密码
 加入会员

QQ登录

只需一步,快速开始

搜索
查看: 6097|回复: 15

请问有对XJW01的LCR电桥程序感兴趣的朋友吗?

[复制链接]
     
发表于 2019-1-2 18:10:03 | 显示全部楼层 |阅读模式
    最近闲的很,翻出以前xjw01老师的LCR电桥程序学习.想弄懂程序,不仅是要懂单片机C语言编程,还要弄懂电路的原理,LCR电桥的测量原理等,可不是件很容易的事情.现就程序里的部分语句向坛里对此感兴趣的朋友讨教!
  (一)程序第091行(keil u3打开后有行号,我加了框,很好找的.)我的理解是对a四舍五入按设定的精度来保存的.但不知为什么有一个-qmin/1000;的尾巴.假如精度
qmin=1e-3,那么-qmin/1000就相当于在a的后面加上(对,是加上!)一个0.000001,本来按精度来截取数据的,反而加了尾巴,是何道理呢?
(二)程序第461行b=- (1.0*v[0]*v[2]+1.0*v[1]*v[3]) ;  测量到的V[ 0]--V[3]都是有正有负的,这里的负号是程序中另加的.为什么要变号呢?经过和安捷伦的
电桥手册求Zx的式子对照,不加负号一致,加了负号倒相反了.而462行的c加负号才一致.我感到不解.您若能提示哪怕是一句,我都感谢之极!
     
发表于 2019-1-2 20:53:32 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 1 反对 0

使用道具 举报

     
发表于 2019-1-2 19:37:08 | 显示全部楼层
顶一下,等待高手解答。
回复 支持 反对

使用道具 举报

     
发表于 2019-1-3 08:33:49 | 显示全部楼层
没有程序,没法帮你!
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 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
}
//==========================================================================

回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2019-1-3 11:45:24 | 显示全部楼层
因为原来的程序超过矿坛允许的长度,不得已删掉一些.第091行和第461行在内.前后语句未删.
回复 支持 反对

使用道具 举报

     
发表于 2019-1-3 19:00:35 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

     
发表于 2019-1-3 19:08:08 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2019-1-4 10:11:10 | 显示全部楼层
谢谢楼上朋友的回复! 关于461行和462行,经过查找资料和演算,得到答案了:原来程序是按照求导纳的方法计算复阻抗的.如果直接计算阻抗,那么开路清零跟短路清零的残余阻抗无法简单地从测量值里减去.以导纳形式就可以直接从测量值里扣除了.另外,根据电路图,上臂测得的值跟信号源同相位,而下臂测得的Vr
跟信号源反相,所以代公式Vr要用 -Vr代入.演算结果,程序里的b相当于公式里电导的分子,程序里的c相当于公式里电纳的分子.由于输入公式比较麻烦,我把演算草稿用照片附上,请朋友们指教.谢谢!发照片显示sever io  error 什么意思?
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2019-1-4 10:17:37 | 显示全部楼层
照片大小已经压缩到符合要求了.再发发看?还是说sever io error.
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2019-1-17 16:38:36 | 显示全部楼层
  全部程序里没有找到auxr或大写的AUXR.关于t0x12,宏晶公司的STC12C5A60S2芯片说明文献里明确说其复位值是00000000,但是百度一下,基本上都是说,STC12C5A60S2芯片默认是1T的而不是12T的.要它是12T才需在AUXR里设置.这就是说,宏晶公司的说明书也有错误?!
程序里用的STC12C5A60S2定时器T0,T1肯定是1T模式的,因为在void setDDS(uint f)函数里选择PCA计数器的时钟源为sysclk/2时,明确注释fosc为32MHZ,这样PCA的PWM脉冲频率为32000000/2/256=62500HZ.
那么,在void setF(char k)函数里,TH1=150,TL1=171;   原注释是"置为20ms,T1定时",请你试试看16位定时器T1预置这样的数,能是20ms吗?12T都不行的.怎样解释呢?谢谢关注!
回复 支持 反对

使用道具 举报

     
发表于 2019-1-28 09:49:05 来自手机 | 显示全部楼层
许老师在坛里,可以私信提醒他来解答。他很热心。
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2019-1-28 13:29:48 | 显示全部楼层
  谢谢楼上的朋友!我试试看能不能联系上许老师.
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2019-1-28 13:57:53 | 显示全部楼层
请问bobjams老师:是否知道XJW01老师的联系方法,比如手机号码,微信什么的?坛里发消息他不在线,最后一次还是2018年在线的.
回复 支持 反对

使用道具 举报

     
发表于 2019-1-28 14:18:28 来自手机 | 显示全部楼层
我也不知道……
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 加入会员

本版积分规则

小黑屋|手机版|矿石收音机 ( 蒙ICP备05000029号-1 )

蒙公网安备 15040402000005号

GMT+8, 2025-4-29 16:58

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表