矿石收音机论坛

 找回密码
 加入会员

QQ登录

只需一步,快速开始

搜索
查看: 80332|回复: 217

LCR表设计成功了!

  [复制链接]
     
发表于 2011-10-6 23:36:03 | 显示全部楼层 |阅读模式
本帖最后由 xjw01 于 2011-10-7 10:25 编辑

已设计好,并调试成功,精度良好。

DIY数字电桥说明

一、设计要点:
1、放大器的增益要控制好,开关切换到最低增益时,输入Zx短路时,所有运放不应过载。为了得到最佳分辨率,满载输入时,应使表头读数对应AD的满量程,但AD应留下10%的余量,防止信号源幅度漂移时表头溢出。
对于这个LCR表,表头满量程设计为1000字左右,约对应4.5V输入。OP07放大6倍,所以OP07的输入端对应的电压为4.5/6=0.75V;由于采用半波平均值检波,所以为了得到0.75V电压,输入需要0.75*3.14=2.36V峰值。TL084最大输出可达4V,所以不过载。中间两级TL084,最小增益为1,最大为30倍。
前级为5倍,所以要求前级V/I变换器最大输出达到2.36/5=0.472V。
本电路实际采用值比0.472V小了不少,是为了留下更多余量,电路工作更可靠稳定。
程序设计时,判断开关切换后的增益是否过大,应对Vx和Vy求模来判断,当模值大于950(接近满量程),说明增益过大。不能单单使用Vx或Vy来判断过载情况。因为,Vx或Vy其中的一个值可能非常小。
2、交流放大器由多级放大器构成,设计时,不论增益开关处于那个状态,应保证第n级运输出信号大于等于第n-1级放大器的输出信号。道理是:当不满足上述条件时,前级可能过载失真,而程序全然不知。在音响系统中,前级调音台过载,可以被电平指示灯显示,也可以被耳朵听出来,这时,我们就可以调大后级功放音量,调小前级调音台的增益,这样就不会失真了。但是,单片机程序没有金耳朵,所以中间级电路本身不得过载,以免造成单片机误判。运放的最大输出能力相同,所以最好的办法就是后级输出幅度大于等于前级输出,那么过载现象必然引起后级输出过大,进而毫伏表超量程,程序立刻知道电路过载了。
3、V/I变换器问题。
V/I变换器也存在过载问题,也要消除它,虽然人工切换量程时可以判断它是否过载,但对于没有经验的使用者来说,并不容易,因为,用眼睛看失真,不如耳朵听失真来得容易。
V/I变换器过载的原因有二,首先,那个运放的反馈回路接了500欧左右内阻的电子开关,它相当于输出衰减器;其次,TL082内部串接了300电阻,也是一个限流衰减。这样一来,100欧档为了得到0.472V,TL082内部电压将是0.472*(500+300+100)/100 = 4.25V,此时,内部有轻微过载。
为了解决过载问题,采用以下方法:考虑到信号源TL082也有过载问题,所以上臂限流电路与下臂电阻电路设计成对称的电路,那么只要信号源不过载,V/I变换器也不过载。
此外,V/I变换器的100欧档,采用了机械输助开关,那么相同电流下,更不容易过载的。
4、信号源
前述,V/I与限流器采用对称结构时,Zx短路,V/I变换器输出端的电压与信号源输出端是一样的。理想V/I输出的上限是0.472V,那么信号源也应是能够输出0.472V。本电路采用0.28V峰值(1kHz),100Hz时比该值大一些。它们都比0.472V小了不少。这样,DDS滤波器元件参数不同时,许可的幅度误差就比较大。
5、灵每度极限
a、可控增益放大器的可调范围。本电路最大与电小增益的关系是30倍,意味着最小分辨为1/30字。设下臂电压对应333字(100欧),那么每字对应0.3欧,1/30字对应10毫欧
约最小分辨到下臂电阻的1/10000
b、同理,上臂的最大量程,也是约为下臂的10000倍。
所以,量限约为10毫欧到1000兆欧
1pF电容在1kHz时的容抗是159兆欧,小于1000兆欧,所以pF级电容可以被本表准确测量。
二、使用要点:
菜单1:开机启动默认菜单
使用8键加1键切换到菜单1
使用8键加2键切换到菜单2
使用8键加3键切换到菜单3
……
1键:显示串联电抗X
2键:显示串联电阻R
3键:显示串联电感L
4键:显示串联电容C
5键:显示Q值
6键:频率切换,100Hz时,指示灯亮起,1kHz时不亮
7键:量程切换,4个指示灯轮跳
8键:菜单切换键
显示单位表示:
10的-12次方,显示为“P”
10的-9次方,显示为“n”
10的-6次方,显示为“u”
10的-3次方,显示为“大n”
10的0次方,显示为“小O”
10的3次方,显示为“三横”
10的6次方,显示为“d”
残余电抗。本表存在残余电抗。为此,测量pF级电容,先不接被测电容,测量出本底电容,我的LCR表本底是3.5pF,然后接上电容测量,若测得23.3pF,那么实际电容就是23.3-3.5=19.8pF,此法与Q表测得的电容比对,1字不差。
测小电阻时,切换到100欧档,按下机械开关,可以增加灵敏度数倍。测量后,弹出开关,以免影响其它档。
扩屏显示小数位:按下当前显示值对应的键,就会显示为四位模式,但“单位”不显示了。再按一下1至5任意键,退出四位模式。本LCR表达不到4位的精度,所以通常无需采用4位显示。有时显示1.xx的数值,觉得精度不够,可以按此法扩展一下位数。
  菜单2:
1键:显示并联电抗X
2键:显示并联电阻R
3键:显示并联电感L
4键:显示并联电容C
5键:显示Q值
6键:频率切换,100Hz时,指示灯亮起,1kHz时不亮
7键:量程切换,4个指示灯轮跳
8键:菜单切换键
单位显示同上
  菜单3:
这是调试菜单
1键:增益切换键,切换时,显示屏暂时跳出置位信号数秒钟,
3键:K3切换键,切换时,显示屏暂时跳出置位信号数秒钟
4键:相位旋转键,切换时,显示屏暂时跳出置位信号数秒钟,相位旋转的顺序是0度、180度、90度、270度
本菜单下,屏显内容是AD的读值。
在此菜单下,可以检测检波非线性。方法是:Zx接上一个10k电阻,切换到菜单3,用1键把增益置为0位,利用3键和4键,找一个读值为30以下的。接下来,1键更改增益,并记录读值。例如,得到27,87,297,897,理论增益关系是1、3、10、30,所以,以上显示值说明检波器线性度良好,但存在0点误差3字。以上数据统一加3字就正确了。我在程序中,已经做了加3处理。不同的CD4053的检波效果可能有所不同,所以建议实测零点误差,然后更改此语句
   if(c) c+=3;    //零点非线性改正
三、制作要点:
V/I变换器上的4个电阻要精确,最好优于0.5%
中间放大器,关系到1:3:10:30增益切换关系的4个电阻(2k、18k、1k、2k),比值关系要准确。请使用4位半的表筛选。
5倍放大器,上、下臂的热端关联的2k与10k电阻要准确,确保上下臂增益相同。冷曾端(虚地)的2k与10k电阻,不要求精度很高。
电源变压器使用8V*2或9V*2,其中7905与7805无需加散热器。接变压器的排针与接下载线的排针最好区别开,如果不区分,万一把9V电源插到下载线排针,单片机或电路有烧的可能,当然通不会烧的。
接线完成后,检查的关键是:每个IC电源和地线有没有接错。电源没接错,IC通常不会烧。
跳线多,不小心就会错,所以9V变压器使用小容量的,万一接错或碰电,由于变压器功率不足,反而会保护电路。
单片机的电压不可过高,如果高于5.5V,有危险。比如,不小心加入12V电压,单片机必烧。所以各个IC的供电是关键。

评分

5

查看全部评分

     
发表于 2018-3-9 09:23:43 | 显示全部楼层
许老师电桥不错,在X林电子买了台,体积小巧,用着舒服!
回复 支持 1 反对 0

使用道具 举报

     
 楼主| 发表于 2011-10-6 23:36:34 | 显示全部楼层
本帖最后由 xjw01 于 2011-10-7 07:13 编辑

myLCR.PNG
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2011-10-6 23:40:38 | 显示全部楼层
本帖最后由 xjw01 于 2011-10-6 23:42 编辑

制作工艺比较普通,按照音响前级板的工艺就足够了。
同时注意两个桥臂信号通路的对称性。
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2011-10-6 23:41:18 | 显示全部楼层
本帖最后由 xjw01 于 2011-10-7 15:53 编辑
  1. /*************************************
  2. LCR表驱动程序 V1.0
  3. xjw01 于莆田 2011.10
  4. **************************************/
  5. //====================================
  6. #define uchar unsigned char
  7. #define uint  unsigned int
  8. #define ulong  unsigned long
  9. #include <reg52.h>
  10. #include <math.h>

  11. void delay(uint loop) { uint i; for(i=0;i<loop;i++); } //延时函数
  12. void delay2(uint k){ for(;k>0;k--) delay(10000); } //长延时,k=100大约对应1秒

  13. //========================AD转换=============================
  14. sfr P1ASF = 0x9D; //将P1置为模拟口寄存器(使能),各位中为1的有效
  15. sfr ADC_CONTR = 0xBC; //A/D转换控制寄存器
  16. sfr ADC_res   = 0xBD; //A/D转换结果寄存器
  17. sfr ADC_resl  = 0xBE; //A/D转换结果寄存器

  18. void set_channel(char channel){
  19. P1ASF = 1<<channel;
  20. ADC_CONTR = channel+128; //最高位是电源开关,低3位通道选择
  21. delay(1); //首次打开电源应延迟,使输入稳定
  22. }
  23. uint get_AD2(){
  24. ADC_CONTR |= 0x08;             //00001000,置ADC_START=1启动A/D 转换
  25. while ( !(ADC_CONTR & 0x10) ); //等待A/D转换结束(ADC_FLAG==0)
  26. ADC_CONTR &= 0xE7;             //11100111,置ADC_FLAG=0清除结束标记, 置ADC_START=0关闭A/D 转换
  27. return ADC_res*4 + ADC_resl;
  28. }

  29. /*
  30. uchar get_AD(){
  31. ADC_CONTR |= 0x08;             //00001000,置ADC_START=1启动A/D 转换
  32. while( !(ADC_CONTR & 0x10) );  //等待A/D转换结束(ADC_FLAG==0)
  33. ADC_CONTR &= 0xE7;             //11100111,置ADC_FLAG=0清除结束标记, 置ADC_START=0关闭A/D 转换
  34. return ADC_res;
  35. }
  36. */
  37. //============================EEPROW偏程=========================
  38. sfr IAP_data  = 0xC2;
  39. sfr IAP_addrH = 0xC3;
  40. sfr IAP_addrL = 0xC4;
  41. sfr IAP_cmd   = 0xC5;
  42. sfr IAP_trig  = 0xC6;
  43. sfr IAP_contr = 0xC7;
  44. /********************
  45. 写字节时,可以将原有数据中的1改为0,无法将0改为1,只能使用擦除命令将0改为1
  46. 应注意,擦除命令会将整个扇区擦除
  47. *********************/
  48. uchar readEEP(uint k){ //读取
  49. IAP_addrL = k;    //设置读取地址的低字节,地址改变才需要设置
  50. IAP_addrH = k>>8; //设置读取地址的高字节,地址改变才需要设置
  51. IAP_contr = 0x81; //设置等待时间,1MHz以下取7,2M以下取6,3M取5,6M取4,12M取3,20M取2,24M取1,30M取0,前导1表示许档IAP
  52. IAP_cmd = 1;      //读取值1,写取2,擦除取3,擦除时按所在字节整个扇区撺除
  53. IAP_trig = 0x5A;  //先送5A
  54. IAP_trig = 0xA5;  //先送5A再送A5立即触发
  55. return IAP_data;
  56. }
  57. void writeEEP(uint k, uchar da){ //写入
  58. IAP_data = da;    //传入数据
  59. IAP_addrL = k;    //设置读取地址的低字节,地址改变才需要设置
  60. IAP_addrH = k>>8; //设置读取地址的高字节,地址改变才需要设置
  61. IAP_contr = 0x81; //设置等待时间,1MHz以下取7,2M以下取6,3M取5,6M取4,12M取3,20M取2,24M取1,30M取0,前导1表示许档IAP
  62. IAP_cmd = 2;      //读取值1,写取2,擦除取3,擦除时按所在字节整个扇区撺除
  63. IAP_trig = 0x5A;  //先送5A
  64. IAP_trig = 0xA5;  //先送5A再送A5立即触发
  65. }
  66. void eraseEEP(uint k){ //擦除
  67. IAP_addrL = k;    //设置读取地址的低字节,地址改变才需要设置
  68. IAP_addrH = k>>8; //设置读取地址的高字节,地址改变才需要设置
  69. IAP_contr = 0x81; //设置等待时间,1MHz以下取7,2M以下取6,3M取5,6M取4,12M取3,20M取2,24M取1,30M取0,前导1表示许档IAP
  70. IAP_cmd = 3;      //读取值1,写取2,擦除取3,擦除时按所在字节整个扇区撺除
  71. IAP_trig = 0x5A;  //先送5A
  72. IAP_trig = 0xA5;  //先送5A再送A5立即触发
  73. }

  74. xdata struct Ida{
  75. int bas;    //比值基数
  76. } cs;

  77. void cs_RW(char rw){
  78. uchar i,*p = &cs;
  79. if(rw){
  80.   eraseEEP(0);
  81.   for(i=0;i<sizeof(cs);i++) writeEEP(i,p[i]);
  82. }else{
  83.   for(i=0;i<sizeof(cs);i++) p[i]=readEEP(i);
  84. }
  85. }





  86. /**********
  87. 字形编码图
  88.    32
  89.    -
  90. 64| | 128
  91.    -  16
  92. 1| | 8
  93.    _. 4
  94.    2
  95. **********/
  96. uchar code zk[20]={235,136,179,186,216,122,123,168,251,250}; //字库
  97. uchar code zk2[7]={241,25,11,233,27,50,155};//p,n,u,m,0,k,M

  98. uchar disp[6]={168,251,250}; char cx=-1; //显示缓存,cx光标位置
  99. sfr P1M1=0x91; //P1端口设置寄存器
  100. sfr P1M0=0x92; //P1端口设置寄存器
  101. sfr P0M1=0x93; //P0端口设置寄存器
  102. sfr P0M0=0x94; //P0端口设置寄存器
  103. sfr P2M1=0x95; //P2端口设置寄存器
  104. sfr P2M0=0x96; //P2端口设置寄存器
  105. sfr P3M1=0xB1; //P3端口设置寄存器
  106. sfr P3M0=0xB2; //P3端口设置寄存器

  107. sbit ds3=P2^4; //数码管扫描口
  108. sbit ds2=P2^5; //数码管扫描口
  109. sbit ds1=P2^6; //数码管扫描口
  110. sbit ds0=P2^7; //数码管扫描口

  111. sbit spk=P2^3; //蜂鸣器
  112. sbit DDS2=P1^2;//移相方波输出口
  113. sbit K3=P1^7;
  114. sbit K4=P1^6;
  115. sbit K5=P1^5; //滤波器
  116. sbit K6=P1^4;
  117. sbit Ka=P2^2; //量程开关A
  118. sbit Kb=P2^1; //量程开关B
  119. sbit Kf=P2^0; //频率指示开关



  120. //功能程序开始

  121. xdata uchar menu=1,menuB=1;

  122. void cls(){ char i; for(i=0;i<6;i++) disp[i]=0; } //清屏
  123. void showDig(long f){ //显示数字
  124. uchar i;
  125. cls();
  126. for(i=0;i<6;i++) { disp[i]=zk[f%10], f/=10; if(!f) break; }
  127. }
  128. void showDig2(float f,char dw){ //显示浮点数
  129.   char i,b=0,b2=0,fh=0;
  130.   if(f<0) fh=1,f=-f;
  131.   for(i=0;i<2;i++){ if(f>=1000) f/=1000, b++;  }
  132.   for(i=0;i<4;i++){ if(f<1)     f*=1000, b--;  }
  133.   for(i=0;i<3;i++){ if(f<1000)  f*=10,   b2++; }
  134.   showDig(f);
  135.   disp[b2] += 4; //小数点
  136.   if(!dw) return;
  137.   disp[0] = zk2[b+4];  //显示单位
  138.   if(fh) disp[0] += 4; //显示符号
  139. }



  140. //==============低频信号DDS====================
  141. //PCA相关寄存器
  142. sfr CMOD = 0xD9;   //钟源选择控制等
  143. sfr CH = 0xF9;     //PCA的计数器
  144. sfr CL = 0xE9;     //PCA的计数器
  145. sfr CCON = 0xD8;   //PCA控制寄存器
  146. sfr CCPAM0 = 0xDA; //PCA模块0工作模式寄存器
  147. sfr CCPAM1 = 0xDB; //PCA模块1工作模式寄存器
  148. sfr CCAP0L = 0xEA; //模块0捕获寄存器低位
  149. sfr CCAP0H = 0xFA; //模块0捕获寄存器高位

  150. sbit PPCA  = IP^7;   //PCA的中断优先级设置
  151. sbit CCF0  = CCON^0; //PCA的模块0中断标志
  152. sbit CCF1  = CCON^1; //PCA的模块1中断标志
  153. sbit CR = CCON^6;    //PCA计数器使能

  154. void PWM_init(){ //把PCA置为PWM
  155.   CMOD = 2;   //0000 0010 计数源选择,钟源取fosc/2
  156.   CL = CH = 0;
  157.   CCAP0L = CCAP0H = 192; //占空比为25%
  158.   //CCPAM0=0x42;//0100 0010,PCA的模块0设置为PWM模式,无中断
  159.   CCPAM0=0x53;//0101 0011,PCA的模块0设置为PWM模式,有中断,下降沿中断
  160.   PPCA = 1;   //优先中断
  161.   //CR = 1;   //开始计数
  162.   EA = 1;     //开总中断
  163. }

  164. uint ph=0, phM=256,feq=1000; //相位,phM相位步进值
  165. uchar code sinB[256]={
  166. //查询表中不可装载零值,否则会造成无中断产生
  167. 255,255,255,255,255,255,254,254,253,252,252,251,250,249,248,247,246,245,243,242,240,239,237,236,234,232,230,229,227,225,222,220,
  168. 218,216,214,211,209,206,204,201,199,196,194,191,188,185,183,180,177,174,171,168,165,162,159,156,153,150,147,144,140,137,134,131,
  169. 128,125,122,119,116,112,109,106,103,100,97,94,91,88,85,82,79,76,73,71,68,65,62,60,57,55,52,50,47,45,42,40,
  170. 38,36,34,31,29,27,26,24,22,20,19,17,16,14,13,11,10,9,8,7,6,5,4,4,3,2,2,1,1,1,1,1,
  171. 1,1,1,1,1,1,2,2,3,4,4,5,6,7,8,9,10,11,13,14,16,17,19,20,22,24,26,27,29,31,34,36,
  172. 38,40,42,45,47,50,52,55,57,60,62,65,68,71,73,76,79,82,85,88,91,94,97,100,103,106,109,112,116,119,122,125,
  173. 128,131,134,137,140,144,147,150,153,156,159,162,165,168,171,174,177,180,183,185,188,191,194,196,199,201,204,206,209,211,214,216,
  174. 218,220,222,225,227,229,230,232,234,236,237,239,240,242,243,245,246,247,248,249,250,251,252,252,253,254,254,255,255,255,255,255
  175. };
  176. uchar xw0[4] = {0,0,1,1}; //0度
  177. uchar xw1[4] = {1,1,0,0}; //180度
  178. uchar xw2[4] = {0,1,1,0}; //90度
  179. uchar xw3[4] = {1,0,0,1}; //270度
  180. uchar *dds2=xw1; //方波DDS的ROM数据表指针
  181. void PCAinter(void) interrupt 7 {//PCA中断
  182.   uchar x;
  183.   CCF0=0; //清除中断请求,以免反复中断
  184.   x = ph>>8;
  185.   ph += phM; //相位累加
  186.   CCAP0H = sinB[x]; //取高8位
  187.   DDS2 = dds2[x>>6];
  188. }
  189. void setDDS(uint f){ //参考时钟是c=(fosc/2)/256=32000000/2/256=62500,频率f=c*phM/2^16
  190. feq = f;
  191. phM=f*65536.0/62500; //phM=f*2^16/62500
  192. if(!f) CR=0; else CR=1;
  193. }

  194. //相位控制函数
  195. xdata char xw=0; //相位
  196. void set90(char k){ //设置方波的相位差
  197.   k %= 4;
  198.   if(k<0) k += 4;
  199.   if(k==0) dds2=xw0;
  200.   if(k==1) dds2=xw1;
  201.   if(k==2) dds2=xw2;
  202.   if(k==3) dds2=xw3;
  203.   xw = k;
  204. }
  205. void set902() { set90(xw+1); }

  206. //量程控制函数
  207. xdata char rng=1; //量程
  208. void setRng(char k){//切换量程
  209. if(k==0) Ka=0,Kb=0; //100欧
  210. if(k==1) Ka=1,Kb=0; //1k欧
  211. if(k==2) Ka=0,Kb=1; //10k欧
  212. if(k==3) Ka=1,Kb=1; //100k欧
  213. rng = k;
  214. }
  215. void setRng2(){ setRng( (rng+1)%4); } //量程步进

  216. //增益控制函数
  217. float gain[4]={1,3,10,30};  //增益表
  218. char curGain=1; //当前增益索引号
  219. void setGain(char k){ //设置电路增益
  220.   if(k>3) k=3;
  221.   if(k<0) k=0;
  222.   if(k==0) K4=0,K6=0; //1倍
  223.   if(k==1) K4=0,K6=1; //3倍
  224.   if(k==2) K4=1,K6=0; //10倍
  225.   if(k==3) K4=1,K6=1; //30倍

  226.   curGain = k;
  227. }
  228. void setGain2(){ setGain((curGain+1)%4); }

  229. //设置频率
  230. uchar mT = 5; //测量速度
  231. void setF(char k){
  232.   if(k==0) { setDDS(100);  K5=0; Kf=1; mT=15; } //置为100Hz
  233.   if(k==1) { setDDS(1000); K5=1; Kf=0; mT=5;  } //置为1kHz
  234. }

  235. //LCR测量
  236. xdata int Vxy[4]={0,0,0,0};  //Vxy[Vx1,Vy1,Vx2,Vy2]
  237. xdata char Vga[4]={1,1,1,1}; //上下臂增益记录表
  238. xdata uchar tim=0,tims=0;
  239. xdata char pau=0; //暂停坐标自动旋转

  240. void timerInter1(void) interrupt 3 {//T1中断
  241.   char a,g; int c;
  242.   static int Ve0=0;
  243.   if(pau) return;
  244.   tims++;
  245.   if(tims>=mT){ //tim进位触发
  246.    tims = 0, tim++;
  247.    if(tim>=8) tim=0;
  248.    a = tim/2; //x1,y1,x2,y2指针
  249.    c = get_AD2(); //读取电压值
  250.    if(c) c+=3;    //零点非线性改正
  251.    if(tim%2){
  252.      if(Ve0>c) Vxy[a] = Ve0; //保存当前电压
  253.          else      Vxy[a] = -c;
  254.          Vga[a] = curGain; //保存当前增益
  255.    }else Ve0 = c;
  256.    if(tim==3||tim==7){ //上下臂切换
  257.          if(tim==3) K3=1, c = sqrt( 1.0*Vxy[2]*Vxy[2]+1.0*Vxy[3]*Vxy[3] ), g=Vga[2]; //切换到下臂
  258.          if(tim==7) K3=0, c = sqrt( 1.0*Vxy[0]*Vxy[0]+1.0*Vxy[1]*Vxy[1] ), g=Vga[0]; //切换到上臂
  259.          //切换后一定要设定一个g值,不论c为何值
  260.          setGain(g);
  261.      if(c>950) setGain(g-1);
  262.      if(c<250) setGain(g+1);
  263.      if(c<80)  setGain(g+2);
  264.      if(c<20)  setGain(g+3);
  265.    }
  266.    set90(tim+1); //相位旋转
  267.   }
  268. }

  269. char sfdw=1; //是否显示单位
  270. void showR(char xm){ //显示电阻
  271.   xdata float a,b,c,e;
  272.   xdata float x1 =  Vxy[0]/gain[Vga[0]];
  273.   xdata float y1 =  Vxy[1]/gain[Vga[1]];
  274.   xdata float x2 = -Vxy[2]/gain[Vga[2]];
  275.   xdata float y2 = -Vxy[3]/gain[Vga[3]];
  276.   xdata float bs;
  277.   if(rng==0) bs=100;
  278.   if(rng==1) bs=1000;
  279.   if(rng==2) bs=10000;
  280.   if(rng==3) bs=100000;

  281.   a = x2*x2+y2*y2;
  282.   b = x1*x2+y1*y2;
  283.   c = x2*y1-x1*y2;
  284.   if(!a) { cls(); disp[3]=115;disp[2]=disp[1]=97; return; }
  285.   if(xm==0){ showDig2(c/a*bs,sfdw); }//显示X值
  286.   if(xm==1){ showDig2(b/a*bs,sfdw); }//显示R值
  287.   if(xm==2){ showDig2(c/a*bs / 6.283/feq, sfdw); }//显示L值
  288.   if(xm==3){ showDig2(a/c/bs / 6.283/feq, sfdw); }//显示C值
  289.   if(xm==4||xm==9){ //显示Q值
  290.     if(!b) { showDig(9999); return; }
  291.         c = fabs(c/b);
  292.         if     (c>=1000) { showDig(999   ); }
  293.     else if(c>=100 ) { showDig(c     ); }
  294.     else if(c>=10  ) { showDig(c*10  );  disp[1] += 4; }
  295.     else if(c>=1   ) { showDig(c*100 );  disp[2] += 4; }
  296.     else             { showDig(c*1000);  disp[3] += 4; }
  297.   }
  298.   e = (b*b+c*c)/a;
  299.   if(xm==5){ showDig2(e/c*bs,sfdw); }//显示并联X值
  300.   if(xm==6){ showDig2(e/b*bs,sfdw); }//显示并联R值
  301.   if(xm==7){ showDig2(e/c*bs / 6.283/feq,sfdw); }//显示并联L值
  302.   if(xm==8){ showDig2(c/e/bs / 6.283/feq,sfdw); }//显示并联C值

  303. }
  304. //void timerInter(void) interrupt 1 {}//T0中断

  305. void showMsg(uchar a){ //临时跳出信息
  306.   P0 = ~a;
  307.   ds0=1, ds1=ds2=ds3=0;
  308.   delay2(50);
  309. }
  310. main(){
  311. uchar i=0,j=0,kn=0,key=0;
  312. uchar dispN=0; //显示扫描索引
  313. uchar spkN=0;  //蜂鸣器发声时长
  314. uchar nn=0;
  315. uchar XRQ=1;


  316. TCON=0, TMOD=0x12; //将T0置为自动重装定时器,T1置为定时器
  317. TH1 = 47, TL1 = 171; //20ms秒定时
  318. TR1=1;  //T1开始计数
  319. TR0=0;  //T0暂停计数
  320. ET1=1;  //T1开中断
  321. ET0=1;  //T1开中断
  322. EA=1;   //开总中断
  323. PT0=1;  //设置优先级


  324. set_channel(0); //设置AD转换通道
  325. P2M0 = 0xFF;    //P2.01234567置为推勉输出
  326. P1M0 = 0xFC;    //P1.234567置为推换口
  327. P1M1 = 0x01;    //P1.0置为高阻抗

  328. //请注意启动延时0.5秒方可读取cs_RW
  329. //cs_RW(0); //读取比值基数(调零时已做开机延时,确保电压上升到可读取EEPROW)

  330. PWM_init();//DDS初始化
  331. set90(2);  //初始设置相位
  332. setRng(1); //初始设置量程
  333. setGain(1); //初始设置增益
  334. setF(1);    //DDS初始设置为1kHz

  335. while(1){
  336.   //显示disp
  337.   nn++;
  338.   dispN=(++dispN)%4; //扫描器移动
  339.   ds0=ds1=ds2=ds3=0;
  340.   if(dispN==0) ds0=1;
  341.   if(dispN==1) ds1=1;
  342.   if(dispN==2) ds2=1;
  343.   if(dispN==3) ds3=1;
  344.   P0=~disp[dispN]; //显示
  345.   //扫描键盘
  346.   //键盘响应
  347.   //key = (~P3)&0xfc;
  348.   key = ~P3;
  349.   if(key&&kn<255) kn++; else kn=0;
  350.   for(i=0;key;i++) key/=2; key=i;
  351.   if(kn==20) spkN=50; else key=0;   //当按下一定时间后,key才有效,否则无效。spkN发声时长设置
  352.   if(spkN) spkN--, spk=0; else spk=1; //键盘发声
  353.   //菜单系统
  354.   if(key==8 && menu!=0) { menuB=menu, menu=0; key=0; } //菜单键
  355.   if(key==7) setRng2(); //量程步进
  356.   if(key==6) { //设置频率
  357.     if(feq==1000 ) { setF(0); showMsg(zk[0]); }
  358.     else           { setF(1); showMsg(zk[1]); }
  359.   }
  360.   if(menu==0){ //显示量程和菜单
  361.     showDig(menuB);
  362.         if(key==8) menu = menuB;
  363.         if(key>=1&&key<=7) menu = key;
  364.         key = 0;
  365.   }
  366.   if(menu==1){ //自动LCR测量(串联)
  367.     pau = 0;
  368.         if(key>=1&&key<=5){ //扩展一位显示
  369.           if(key-1==XRQ) { if(sfdw==0) sfdw = 1; else sfdw = 0; }
  370.           else sfdw = 1;
  371.           XRQ = key-1; //X,R,L,C,Q
  372.         }
  373.         if(key>=1&&key<=5) XRQ = key-1; //X,R,L,C,Q
  374.     showR(XRQ);
  375.   }
  376.   if(menu==2){ //自动LCR测量(并联)
  377.     pau = 0;
  378.         if(key>=1&&key<=5){ //扩展一位显示
  379.           if(key-1==XRQ) { if(sfdw==0) sfdw = 1; else sfdw = 0; }
  380.           else sfdw = 1;
  381.       XRQ = key+4; //X,R,L,C,Q
  382.         }
  383.     showR(XRQ);
  384.   }
  385.   if(menu==3){ //手动调试
  386.     pau = 1;
  387.         if(key==1) { setGain2(); showMsg( zk[curGain] );} //增益控制
  388.         if(key==2) { };
  389.     if(key==3) { K3=~K3;     showMsg(zk[K3]);       } //切换上下臂
  390.     if(key==4) { set902();   showMsg(zk[xw]);       } //相位旋转
  391.     if(nn%16==0) showDig(get_AD2());
  392.   }
  393.   delay(4000);
  394. }//while end
  395. }

复制代码
回复 支持 反对

使用道具 举报

     
发表于 2011-10-6 23:49:53 | 显示全部楼层
各档的量程有多宽?
回复 支持 反对

使用道具 举报

     
发表于 2011-10-6 23:59:40 | 显示全部楼层
LZ太厉害了。
有实物图么?
回复 支持 反对

使用道具 举报

发表于 2011-10-7 01:04:37 | 显示全部楼层
提示: 作者被禁止或删除 内容自动屏蔽
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2011-10-7 05:58:21 | 显示全部楼层
本帖最后由 xjw01 于 2011-10-7 06:32 编辑

回复 7# sinoidiot


    LCR测量的核心程序只有60行,并不多。

其它的300多行,是用于控制、定义“菜单系统、键盘及单片机的资源”。
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2011-10-7 06:11:47 | 显示全部楼层
本帖最后由 xjw01 于 2011-10-8 11:20 编辑

本表的残余是容抗显示,估计是信号源TL082与V/I的TL082共用造成的。
估计,信号源与V/I变换器在IC内部存在额外的信号耦合造成的。这种可能性比较大。建议用两个TL081代替TL082
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2011-10-7 06:26:55 | 显示全部楼层
本帖最后由 xjw01 于 2011-10-7 06:31 编辑

回复 5# 362647315


    量程比较大,非桥式的音频LC表要大很多。
以1kH档为例:
电阻档理论上可以分辨到10毫欧左右,或更小。
大电阻测量,可测到电导0.001微西
电容,可以测量到0.2pF分辨力,15000uF,当然,理论上,大于1000uF已不大准确,应换档100Hz档
电感可以分辨到0.5uH左右(未实测),实测2.99uH电感,得到2.64uH,测量35.5uH电感,得到35.4uH
最大可以测到几十享以上,更大几百倍的电感,理论上也可以测量,但大电感在1kHz时,受电感自身分布电容影响很大,测不准的,这时应使用100Hz档来测量。

桥式测法量,精度比万用表电感电容档的精度要高许多。
做为验证,也可以在手动档,利用VC9806+交流档测定上下桥臂的电压,人工计算结果,当上下臂阻值接近时,此法精度可以做得很高。上下臂偏移10倍时,VC9806+依然可以准确测定。
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2011-10-7 06:49:59 | 显示全部楼层
本帖最后由 xjw01 于 2011-10-7 09:37 编辑

本电路,与网络上提供的LCR电路比较,特点是:
1、利用单片机自带的AD,简化了程序设计,也简化了电路。缺点,AD分辨率低一些,约10bit。
2、利用四轴向旋转方波DDS,得到0度、90度、180度、270度,最后,正交信号转换为正电压检波输出,解决了单片机不能测量负电压问题。缺点是,测量速度减慢一倍。最后,1秒测量出一次结果。
3、增益控制,采用3倍关系步进,改善AD分辨率不足的问题。缺点,造成测量的上下极限分辨力减小3倍,增益变换范围是30倍。即最小5至10毫欧,如果采用两级10倍增益控制,变换范围是100倍,最小可分辨到5毫欧以下。
4、增加了一个带通滤波器,提高高阻测量的能力。高阻测量容易受干扰,有了带通,相当于提升了高阻测量的有效上限。有的LCR桥,好象没有设计滤波器
5、正弦信号发生器,采用正弦DDS,精度高,信号质量好。基于单片内部PWM的DA转换实现的。纯算法实现,无需另外硬件支持,所以看不到信号源发生器电路了,电路大大简化。移相方波,也采用DDS技术实现。它们的相位关系,可以精准控制。而且,信号质量,优于纯方波加4级二阶低通(相当于8阶)滤波器

本表的精度指标并不高。但优于普通非桥式的LCR
精度约1%,认真调试,可以达到0.5%
回复 支持 反对

使用道具 举报

     
发表于 2011-10-7 07:23:20 | 显示全部楼层
祝贺一下.
不知将来是否有打算将 LT2400与这个系统结合起来.
回复 支持 反对

使用道具 举报

     
发表于 2011-10-7 08:46:16 | 显示全部楼层
祝贺一下!
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2011-10-7 09:16:27 | 显示全部楼层
谢谢大家鼓励
回复 支持 反对

使用道具 举报

     
 楼主| 发表于 2011-10-7 09:17:27 | 显示全部楼层
电阻测试0.jpg
电阻测试4.jpg
电阻测试1.jpg
电阻测试2.jpg
电阻测试3.jpg
回复 支持 反对

使用道具 举报

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

本版积分规则

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

蒙公网安备 15040402000005号

GMT+8, 2024-5-7 16:38

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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