xjw01 发表于 2012-10-11 22:13:16

大小通吃的电感表,精度还很好

本帖最后由 qg2007 于 2012-11-2 15:04 编辑


             大小通吃的电感表,精度还很好

                                    ----许剑伟 莆田十中



1、制作
先是试制了网上流行的LM311电路。因手上没有LM311,用LM393代换。虽然只有几个元件,但也焊接了几个小时。
原电路出现以下问题:
1、频率稳定性不好,跳得比较历害
2、测量大电感误差非常大,可达20%
3、测量更大的电感,如10H以上的电感,很多无法测量,不起振。
解决方法:
用示波器观察,谐振器上面的波形非常差,说明电路Q值太低。
原电路使用33k电阻反馈(就是那3个100k电阻的并联值),测大电感时,频率低,阻抗大比33k电阻还大, Q值严重下降,造成电路不起振,就算起振了,测值误差也大得惊人。所以改用1兆欧高阻耦合。
改了之后,可以测到1000H以上的大电感,而且很准。
2、性能
为了与电桥比对,所以上限频率只做到200kHz,辅助电感是220uH
零点缓慢漂移,得经常清零,比较讨厌。这是谐振元件温漂害的。
不过,秒一级的稳定性比较好,读数不会乱跳,因为频率只会跳1个计数值(1计数对应2Hz,计数时间采用0.5秒),所以清零后,及时测量,还是可以准确测量0.x uH电感的。
从几uH到1H之间实测来看,误差小于1%,1H到几百H,误差可以5%左右估算,一般是偏大。因为本电路测量大电感的电压比较高,不易与电桥比对。铁芯电感的电感量随测量电压升高,电感量略有增加。
3、校准
通过修改程序中的这一句校准:
c0 = 3.12e-9 * c2c(f);
其中3.12e-9表示谐振电容在1kHz频率下是3.12nF。
实测700uH空芯线圈,根据误差大小,调整3.12的值,重新下载,使得测量准确。
本表测量的结果实际上是等效并联电感。
4、电容容量修正
•谐振器的极限谐振频率是200kHz。
•涤纶电容随频率变大而变小,所以程序内建修正表,改正电容的容量误差。
以下是3.12nF电容的真值修正表,其中b数组是容量的修正系数
code float a={100,   1000,10000, 100000, 200000 }; //频率
code float b={1.004, 1.000, 0.992, 0.975,0.973}; //修正量(涤纶原真修正表)
•修正值改进
那个1M欧的耦合电阻,在超声波范围内并不是存阻的。当频率较高时,电阻两端的分布电容及LM393内的信号耦合是不可以忽略的。虽然是电容耦合量很小,但在密勒效应的作用下,会被成百上升倍放大,有效谐振电容变小。频率比较高时,谐振器的阻抗很小,所以反馈系数非常弱,这就造成密勒效应的影响严重,可影响2%以上,为此高频率下,有效谐振电容仅修正系数仅为0.973是不够的。
此外,LM393的延迟也会造成振荡频率变小,引起测值变大。如果谐振器高Q,则影响小。整个回路的Q值只有20左右,所以频率高时,这个影响也是不能忽略的。用排除法证明:表笔接20R电阻测量电路中的那个功率电感,结果输电感量变大了2%,并联串联关系的转换远没有2%变化,谐振电压的变化也远不足以造成2%的变化,而接电阻后谐振阻抗变低,密勒效应更大,应造成电感量测值变小才对。显然,这2%的增加是LM393引起的。
以上因素,结合起来,修正表变为
code float a={100,   1000,10000, 100000, 150000 };//频率
code float b={1.004, 1.000, 0.992, 0.960,0.950};//修正量(综合修正表)
•测量100uH以下的电感的改正
测量这种电感,频率大约在150kHz至200kHz
这个范围内频率变化,产生如下效果:
功率电感约有0.5uH的变化,电感量随频率变大而变小,引起电感测值变小。
涤纶电容随频率增加,容量变小,引起电感测值变大。
以及其它方面因素影响,相互补偿,最后结果150kHz以后的电容修正值与200kHz的修正值是一样的。所以电容修正表上限只要做到150kHz即可,大于150kHz的使用150kH的修正值。//==========================================================================
//LC表驱动程序 V1.0
//许剑伟 于莆田 2012.10
//==========================================================================
//==========================================================================
#define uchar unsigned char
#define uintunsigned int
#define ulongunsigned long
#include <reg52.h>

//==========================================================================
// 项目:LCD1602 四线驱动程序
// 设计要点:
//   LCD1602 的运行速度慢,而单片机运行的速度快,因此容易因为速度不
//   匹配造成调试失败。因此,调试之前应准确测试lcd_delay() 延时函数
//   准确的延时量,如果不能满足注释中的要求,则应调整循次数。每步操
//   作所需的延时量,按照数据手册指标指行,同时留下足够的时间余量。
// 硬件连接:
//   至少需要9条线,电源线2条,7条信号线。信号线详见程序中的接口定义。
//   清注意对LCD1602比对的调节,否则无显示。
// 设计:许剑伟,于莆田,2010.12
//==========================================================================
sbit lcd_RS = P0^1; //数据命令控制位,0命令1数据
sbit lcd_RW = P0^2; //读写位,0写1读
sbit lcd_EN = P0^3; //使能位,下降沿触发
sbit lcd_D4 = P0^7; //数据端口D4
sbit lcd_D5 = P0^6; //数据端口D5
sbit lcd_D6 = P0^5; //数据端口D6
sbit lcd_D7 = P0^4; //数据端口D7
//==========================================================================
void lcd_delay(int n){ //LCD专用延时函数
//32MHz钟频下,约循环3000次延迟1毫秒
int i,j;
if(n<0)    { for(i=0;i< 20;i++); return; } //10us
if(n== 0){ for(i=0;i<100;i++); return; } //50us
for(;n;n--){ for(j=0;j<2000;j++);      } //n毫秒
}
//==========================================================================
void lcd_B(char f, uchar c, char t){ //控制四线式接口LCD的7个脚
//f=0写命令字, f=1写RAM数据, f=2读地址(或读忙), f=3读RAM数据
lcd_EN = 0;
lcd_RS = f%2;
lcd_RW = f/2%2;
//移入高四位
lcd_D4 = c & 16;
lcd_D5 = c & 32;
lcd_D6 = c & 64;
lcd_D7 = c & 128;
lcd_EN = 1;lcd_delay(-1);lcd_EN = 0; //使能脉冲
if(f==4) { lcd_delay(t); return; }
//移入低四位
lcd_D4 = c & 1;
lcd_D5 = c & 2;
lcd_D6 = c & 4;
lcd_D7 = c & 8;
lcd_EN = 1;lcd_delay(-1);lcd_EN = 0; //使能脉冲
lcd_delay(t);//不同的命令,响应时间不同,清零命令需要2ms
}
//==========================================================================
void lcd_init(){ //LCD1602 初始化
//启动四线模式须势行9个步骤,初始化所须耗时较长,约65ms,时限不可减
lcd_delay(20); //启动lcd之前须延时大于15ms,直到VDD大于4.5V
lcd_B(4, 0x30, 9); //置8线模式,须延时大于4.1ms
lcd_B(4, 0x30, 5); //置8线模式,须延时大于100us
lcd_B(4, 0x30, 5); //置8线模式,手册中未指定延时
lcd_B(4, 0x20, 5); //进入四线模式
lcd_B(0, 0x28, 5); //四线模式双行显示
lcd_B(0, 0x0C, 5); //打开显示器
lcd_B(0, 0x80, 5); //RAM指针定位
lcd_B(0, 0x01, 5); //启动清屏命初始化LCD
}
//==========================================================================
//=========================几个功能常用函数=================================
void lcd_cls()         { lcd_B(0, 0x01+0, 2);} //清屏
void lcd_cur0()      { lcd_B(0, 0x0C+0, 0);} //隐藏光标
void lcd_goto1(uchar x){ lcd_B(0, 0x80+x, 0);} //设置DDRAM地址,第1行x位
void lcd_goto2(uchar x){ lcd_B(0, 0xC0+x, 0);} //设置DDRAM地址,第2行x位
void lcd_putc(uchar d) { lcd_B(1, 0x00+d, 0);} //字符输出
void lcd_puts(uchar *s){ for(; *s; s++) lcd_B(1,*s,0); } //字串输出
//==============字符显示函数====================
#define digW 4 //数字显示位数宏
void lcd_puti(long a,char w){ //定宽显示正整数
char i=0, s={32,32,32,32,32,32,32,32,32,32};
if(a<0) { a=-a; lcd_puts("-"); }
else    lcd_puts(" ");
do{
   s = a%10+48;
   a /= 10;
}while(a);
for(;w;w--) lcd_putc(s);
}
void lcd_putf(float a,char n,char w){ //浮点输出,n是保留小数的位数,w是数字宽度
char i,g,fi=0;
long b,c=1;
if(a<0) { lcd_putc('-'); a = -a; }
else    { lcd_putc(' '); }
for(i=0;i<n;i++) a *= 10;
for(i=1;i<w;i++) c *= 10;
b = a;
for(i=0;i<w;i++){
g = b/c;
b -= g*c;
c /= 10;
if(g>9||g<0) g='*'-48;
if(i == w-n ) lcd_putc('.');
if(!g && !fi && i<w-n-1) { lcd_putc(' '); continue; }
lcd_putc(g+48);
fi = 1;
}
if(!n) lcd_putc(' '); //无小数点的补足显示宽度
}

//==========================================================================
//===============================延时函数===================================
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秒


//==========================================================================
//==================================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
应注意,擦除命令会将整个扇区擦除
*********************/
int eepEn = 0;
void saEEP(){ //触发并EEP保护
if(eepEn==12345) IAP_trig = 0x5A;//先送5A
if(eepEn==12345) IAP_trig = 0xA5;//先送5A再送A5立即触发
IAP_cmd = 0;      //关闭令,保护
IAP_contr = 0;    //关EEPROM,保护
IAP_trig = 0;
IAP_addrL = 255; //设置读取地址的低字节,地址改变才需要设置
IAP_addrH = 255; //设置读取地址的高字节,地址改变才需要设置
}
uchar readEEP(uint k){ //读取
IAP_addrL = k;    //设置读取地址的低字节,地址改变才需要设置
IAP_addrH = k>>8; //设置读取地址的高字节,地址改变才需要设置
IAP_contr = 0x82; //设置等待时间,1MHz以下取7,2M以下取6,3M取5,6M取4,12M取3,20M取2,24M取1,30M取0,前导1表示许档IAP
IAP_cmd = 1;      //读取值1,写取2,擦除取3,擦除时按所在字节整个扇区撺除
saEEP(); //触发并保护
return IAP_data;
}
void writeEEP(uint k, uchar da){ //写入
IAP_data = da;    //传入数据
IAP_addrL = k;    //设置读取地址的低字节,地址改变才需要设置
IAP_addrH = k>>8; //设置读取地址的高字节,地址改变才需要设置
IAP_contr = 0x82; //设置等待时间,1MHz以下取7,2M以下取6,3M取5,6M取4,12M取3,20M取2,24M取1,30M取0,前导1表示许档IAP
IAP_cmd = 2;      //读取值1,写取2,擦除取3,擦除时按所在字节整个扇区撺除
saEEP(); //触发并保护
}
void eraseEEP(uint k){ //擦除
IAP_addrL = k;    //设置读取地址的低字节,地址改变才需要设置
IAP_addrH = k>>8; //设置读取地址的高字节,地址改变才需要设置
IAP_contr = 0x82; //设置等待时间,1MHz以下取7,2M以下取6,3M取5,6M取4,12M取3,20M取2,24M取1,30M取0,前导1表示许档IAP
IAP_cmd = 3;      //读取值1,写取2,擦除取3,擦除时按所在字节整个扇区撺除
saEEP(); //触发并保护
}


xdata struct Ida{
float L0;
float C0;
} cs;

void cs_RW(char rw){
uchar i,*p = &cs;
const int offs=512;
if(rw){
eraseEEP(offs);
for(i=0;i<sizeof(cs);i++) writeEEP(i+offs,p);
}else{
for(i=0;i<sizeof(cs);i++) p=readEEP(i+offs);
}
}


//==========================================================================
//================================电感表主程序==============================
//==========================================================================
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端口设置寄存器
sfr WAKE_CLKO = 0x8F;
sfr AUXR = 0x8E;
sfr BRT = 0x9C;


sbit K1=P3^7;//清零键

long feq=0;
char Tk=0,Tkm=12,fa=0;
void timerInter1(void) interrupt 3 {//T1中断
fa++;
}
void timerInter0(void) interrupt 1 {//T0中断
uchar a,b,c;
if(++Tk>=Tkm){ //读取计数值
        Tk = 0;
    TR1 = 0; //暂停计数
        a = fa, b = TH1, c = TL1;
        fa = TH1 = TL1 = 0;
        TR1 = 1;
        feq = (a*256L*256L + b*256L+c) * (24/Tkm);
    if(feq<=5) feq = 0;; //去除本频率(通常有1Hz)
    if(feq<300&&feq>10) Tkm = 24; //低频(小于10视为不起振)
        else                Tkm = 12; //频率较高时,闸门时间减小一些,加快测量速度
}
}
void putLx(float L){
if(L<1e-4) { L*=1e6; lcd_putf(L,2,4); lcd_puts(" uH"); return; }
if(L<1e-3) { L*=1e6; lcd_putf(L,1,4); lcd_puts(" uH"); return; }
if(L<1e-2) { L*=1e3; lcd_putf(L,3,4); lcd_puts(" mH"); return; }
if(L<1e-1) { L*=1e3; lcd_putf(L,2,4); lcd_puts(" mH"); return; }
if(L<1e+0) { L*=1e3; lcd_putf(L,1,4); lcd_puts(" mH"); return; }
if(L<1e+1) {         lcd_putf(L,3,4); lcd_puts("H"); return; }
if(L<1e+2) {         lcd_putf(L,1,4); lcd_puts("H"); return; }
if(L<1e+5) {         lcd_puti(L,5);   lcd_puts("H"); return; }
lcd_puts("Overflow.");
}
float c2c(float f){ //针对涤纶电容修正
code float a={100,   1000,10000, 100000, 150000 };//频率
code float b={1.004, 1.000, 0.992, 0.960,0.950};//修正量(综合修正表)
//code float a={100,   1000,10000, 100000, 200000 }; //频率
//code float b={1.004, 1.000, 0.992, 0.975,0.973}; //修正量(涤纶原真修正表)
char i;
if(f<a) return b;
if(f>a) return b;
for(i=0;i<4;i++){
if( f>=a && f<a) return b + (b-b) * (f-a) / (a-a);
}
}
float Lx=0;
void calcL(){ //电感计算
float f,w,c0;
f = feq/1.024;
c0 = 3.12e-9 * c2c(f);
w = 2*3.1415926*f;
if(w) Lx = 1/(w*w*c0);
elseLx = 1e20;
lcd_goto1(0); putLx(Lx-cs.L0);
lcd_goto2(0); lcd_puts("F="); lcd_puti(f,6); lcd_puts("Hz");
}

main(){
uchar kn=0;
eepEn = 12345;
//端口初始化
P3M0 = 0x00;    //00000000
P3M1 = 0x20;    //00100000 P3.5置为高阻口

delay2(5);    //等待升压电源电压上升
lcd_init();   //初始化LCD
lcd_cur0();   lcd_puts("LC 1.0");   //隐藏光标并显示片本
lcd_goto2(0); lcd_puts("XJW Putian,2012"); //显示作者
delay2(200);lcd_cls(); //启动延时
eepEn = 12345;
cs_RW(0);   //读EEPROM

AUXR |= 0x40;
TMOD =0x51;//T1置为16位计数器,T2置为16位定时器
TR0 = TR1 = 1; //起动计数
ET0 = ET1 = 1; //开定时器中断
EA = 1;      //开总中断

while(1){
calcL();
if(!K1 && kn <255) kn++;
if(K1) kn=0;
if(kn==3){ //键按下
    lcd_cls();
    if(!feq) { cs.L0 = 0; lcd_puts("Removed."); }
        else   { cs.L0 = Lx; lcd_puts("Cleared."); }
        cs_RW(1);
        delay2(50);
}

delay(20000);
}

}
//==========================================================================

xjw01 发表于 2012-10-24 23:27:29

本帖最后由 xjw01 于 2012-10-24 23:35 编辑

玩的高兴 发表于 2012-10-24 21:35 static/image/common/back.gif
谢许老师回复 。唉!再报名预定吧!到时请吱短信吧。年岁大了,600度老光,只会动烙铁,其它的力不从心啦。 ...

表面上看只有几个元件,其实做套件,细节也很多的。PCB设计的每个细节,要考虑PCB与元件是否匹配;买元件时,得多家淘宝店才能买齐。M3圆头螺丝、铜柱子、排针找一家,单片机等电子元件找一家,云母电容找一家,PCB找一家,电阻找一家。为了找到合适的220uH电感并比对,还另找一家买个几款220uH几款电感。

因为买的时候不知道220uH电感质量,所以只能每种买10个,共买了5种。经电桥测试,确定了最好的那种电感,但只有10个,所以只能装10台。
STC及1602,虽然只买10套(是2012年批号的),不过,我原选还有很多备件,单片机还有2009年和2011批号的40片,是好片子,AD高线性,用于制作LCR效果很好。

优化组合之后,才得到可行的购买方案。

前几天,有位坛友非要我装入几个Rd测量的电阻电容。其实,我是真的没有那些阻容。
淘宝上买东西,一次性买过多东西并不合适,因为不知道对方卖的是什么货。确定没问题,才会多买一些。

我出这几套,主要是给我的老师的。他们都曾帮助过我。也没想要全部焊接的,只想帮他们把单片机程序下载进去即可,他们都是高手,焊得比我好多了。:lol

lyq7015 发表于 2018-5-13 07:57:14

量产吧!我想要一套!要成品!:)

qg2007 发表于 2012-11-22 11:46:32

本帖最后由 qg2007 于 2012-11-22 11:56 编辑

G4-AAA 发表于 2012-11-22 11:24 static/image/common/back.gif
谢谢回复。最新版的电路和PCB能发个上来吗?

PCB还一样,调换了几个元件的数值。谐振电感换为25微亨,R4换 3.3K ,R5换10K,R6换300K,第一批没有装的电源测试51K、100电阻装上,程序是新的。





R4是清零键上边LM393片左边第一个电阻。


xjw01 发表于 2012-10-11 22:15:39


收听者 发表于 2012-10-11 22:22:24

上次买的做Q表的单片机集成块还没有用,可以用上面的程序吗?能不改成LED数码管的。

xjw01 发表于 2012-10-11 22:33:10

Q表那个是3V的单片机,这个是5V的,不一样。
可以改成LED,但程序也得改动。

L.D.XIONG 发表于 2012-10-12 06:52:46

:victory::victory:

flyfish19730518 发表于 2012-10-12 07:33:07

比英文还难懂!超厉害的楼主

et23v 发表于 2012-10-12 08:06:30

其待推出套件。:victory:

66718 发表于 2012-10-12 08:16:56

期待出套件。

临风听雪 发表于 2012-10-12 08:50:33

很好玩的DD,谁有直流电压电流、功率、内阻4用表件,玩腻了的给我一套玩玩:victory:

老家伙 发表于 2012-10-12 09:08:15

成本几何(含人力成本)?

收听者 发表于 2012-10-12 12:32:44

xjw01 发表于 2012-10-11 22:33 static/image/common/back.gif
Q表那个是3V的单片机,这个是5V的,不一样。
可以改成LED,但程序也得改动。

是STC12C5A60S2是几伏工作电压,程序能直接用吗。

园丁 发表于 2012-10-13 16:52:53

很好的电感表作品,楼主辛苦了。:handshake

xjw01 发表于 2012-10-13 23:11:21

图中清零按键画错了。
正确的应接到P3.7

qg2007 发表于 2012-10-13 23:24:57

xjw01 发表于 2012-10-13 23:11 static/image/common/back.gif
图中清零按键画错了。
正确的应接到P3.7

是这样?

xlxyasd 发表于 2012-10-14 02:32:39

楼主期待出套件
页: [1] 2 3 4 5 6 7 8 9 10
查看完整版本: 大小通吃的电感表,精度还很好