#include "reg52.h"
#include "intrins.h"
//-------宏定义---------
#define u8 unsigned char
#define u16 unsigned int
#define u32 unsigned long
#define Cref 2200 //基准电容值(单位pF)
#define LCD_DATA P0 //LCD数据口(8位)
//-------I/O定义--------
sbit LCD_BUSY = P0^7; //LCD忙信号
sbit LCD_RS = P1^0; //数据/命令选择(数据=1,命令=0)
sbit LCD_RW = P1^1; //读/写选择(写=0,读=1)
sbit LCD_EN = P1^2; //使能信号
sbit K1_F_LC = P1^3; //F/LC测量选择按钮(自锁),([抬起]=0测LC,[按下]=1测F)
sbit K2_L_C = P1^4; //L/C测量选择按钮(自锁)([抬起]=0测C,[按下]=1测L)
sbit K3_Eb_Es = P1^6; //电解量程选择按钮(自锁),([抬起]=0低量程,[按下]=1高量程)
sbit K4_FLC_EC = P3^6; //FLC或EC(电解电容)测量选择按钮(无锁)(每按一次,翻转一次)
sbit K5_Calib = P3^7; //手工校正(清零)按钮(无锁)(消除寄生电容值)
sbit Dischg = P1^5; //测量电解电容时的充放电控制端口(=0放电,=1充电)
//-------全局变量定义--------
bit FLC_EC_Flag; //测量标志(=0测FLC,=1测电解电容)
u8 Measure_Flag; //测量标志(=1测电容,=2测电感,=3测频率,=4测小电解,=5测大电解)
u8 Lref; //基准电感值(单位uH)(原作没有)
u16 T0_times; //T0中断计数预设值(每50ms一次),测F=20次(1s),测LC=10次(0.5s)
u16 Timer0_Num; //T0计数
u16 Timer1_Num; //T1计数
u32 Frequency0; //频率0(未接被测元件时的频率)
u32 Frequency1; //频率1(接入被测元件时的频率)
u32 Cx; //被测电容
u32 Lx; //被测电感
u32 ECx_H; //被测电解电容(大)
u32 ECx_L; //被测电解电容(小)
//------x的n次方------------
u32 power(u8 x,u8 n)
{
u8 i;
u32 j = 1;
if(n == 0)
{
return 1;
}
else
{
for(i=0; i<n; i++)
{
j *= x;
}
return j;
}
}
//----延时n毫秒(12M晶振,12T模式,一个指令周期=1us)---
//----1ms=(跳转等3个指令周期+两个空指令)*200----
void Delay_ms(u8 n)
{
u8 i,j;
for(i=0; i<n; i++)
{
for(j=0; j<200; j++)
{
_nop_();
_nop_();
}
}
}
//------LCD1602读忙标志位------
void Check_busy(void)
{
do
{
LCD_EN=0;
LCD_RS=0;
LCD_RW=1;
LCD_DATA=0xFF;
LCD_EN=1;
}
while(LCD_BUSY==1);
LCD_EN=0;
}
//------LCD1602写指令------
void Write_Command(u8 cmd)
{
Check_busy();
LCD_RS=0;
LCD_RW=0;
LCD_DATA=cmd;
LCD_EN=0;
LCD_EN=1;
LCD_EN=0;
}
//------LCD1602写数据------
void Write_Data(u8 dat)
{
Check_busy();
LCD_RS=1;
LCD_RW=0;
LCD_DATA=dat;
LCD_EN=0; //机器周期小于1us时,须加延时
LCD_EN=1;
LCD_EN=0;
}
//-----LCD1602写字符串------
//---x=列(0~15); y=行(0,1)
//---从指定的位置开始写,直到超出屏幕显示
void LCD_Write_String(u8 y,u8 x,u8 *Data)
{
if(y==0) //第一行
{
if(x<16)
{
Write_Command(0x80+x); //0x80 + 第一行起始地址
for(; x<16&&*Data!='\0'; x++) //'\0'字符串结束标志
{
Write_Data(*(Data++));
}
}
}
if(y==1) //第二行
{
if(x<16)
{
Write_Command(0xc0+x); //0xc0 + 第二行起始地址
for(; x<16&&*Data!='\0'; x++) //'\0'字符串结束标志
{
Write_Data(*(Data++));
}
}
}
}
//------LCD1602写长整型数据------
//x=列(0~15); y=行(0,1);截取长整型后length个数字显示在指定位置(全显示length=10)
//注意此函数不支持换行,起始列+length>15时后面的显示不出来,仅能单行显示
void LCD_Write_Long(u8 y,u8 x,u8 length,u32 Data)
{
u8 i,k;
if(length>10)
{
length = 10;
}
if(length<10)
{
Data = Data%power(10,length);
}
if(y==0) //第一行
{
Write_Command(0x80+x); //0x80 + 第一行起始地址
for(i=0; i<length; i++)
{
k = (u8)(Data/power(10,length-1-i));
Data = Data%power(10,length-1-i);
Write_Data(k+0x30);
}
}
if(y==1) //第二行
{
Write_Command(0xc0+x); //0xc0 + 第二行起始地址
for(i=0; i<length; i++)
{
k = (u8)(Data/power(10,length-1-i));
Data = Data%power(10,length-1-i);
Write_Data(k+0x30);
}
}
}
//------LCD1602写长整型数据,可以指定小数点后位数-------
//x=列(0~15); y=行(0,1);截取长整型后length个数字显示在指定位置(全显示length=10)
//注意此函数不支持换行,起始列+length>15时后面的显示不出来,仅能单行显示
//pot:小数点后显示几个数字 例:1234567 pot=2时显示为12345.67
void LCD_Write_LongPoint(u8 y,u8 x,u8 length,u8 pot,u32 Data)
{
u8 i,j,k;
if(length>10)
{
length = 10;
}
if(length<10)
{
Data = Data%power(10,length);
}
if(y==0) //第一行
{
j=0;
Write_Command(0x80+x); //0x80 + 第一行起始地址
for(i=0; i<=length; i++)
{
if(i==(length-pot))
{
Write_Data(0x2e); //小数点
Write_Command(0x80+x+i+1);
}
else
{
k = (u8)(Data/power(10,length-1-j));
Data = Data%power(10,length-1-j);
Write_Data(k+0x30);
j++;
}
}
}
if(y==1) //第二行
{
j=0;
Write_Command(0xc0+x); //0xc0 + 第二行起始地址
for(i=0; i<=length; i++)
{
if(i==(length-pot))
{
Write_Data(0x2e); //小数点
Write_Command(0xc0+x+i+1);
}
else
{
k = (u8)(Data/power(10,length-1-j));
Data = Data%power(10,length-1-j);
Write_Data(k+0x30);
j++;
}
}
}
}
//------LCD1602清屏---------
void LCD_Clear(void)
{
Write_Command(0x01);
}
//------LCD1602初始化-----
void LCD1602_Init(void)
{
Delay_ms(15);
Write_Command(0x38); //16x2显示,8位数据
Write_Command(0x0c); //开显示
Write_Command(0x06); //AC自动加1,字符依次向后写
LCD_Clear();
}
//------判断测量类型-------
void Get_Measure_Flag(void)
{
if(FLC_EC_Flag==0) //测FLC按键选择标志位
{
if(K1_F_LC==1)
{
Measure_Flag = 3; //测频率
T0_times = 20; //T0定时1s
}
else
{
if(K2_L_C==0)
{
Measure_Flag = 1; //测电容
}
else
{
Measure_Flag = 2;
}
T0_times = 10; //T0定时0.5s
}
}
else
{
TR0 = 0; //关闭测频率(含LC)功能
ET0 = 0;
if(K3_Eb_Es==0)
{
Measure_Flag = 4; //测小电解
}
else
{
Measure_Flag = 5; //测大电解
}
}
}
//------测试(F/L/C)初始化(T0,T1初始化)------
void MeasureFLC_init(void)
{
Timer0_Num = 0;
Timer1_Num = 0;
TMOD = 0x51; //T0作定时器,T1作计数器
TH0 = 0x3c; //T0初值高8位(定时50ms)
TL0 = 0xb0; //T0初值低8位
TH1 = 0x3c; //T1初值高8位(计数50000次)
TL1 = 0xb0; //T1初值低8位
TR0 = 1; //T0开
TR1 = 1; //T1开
ET0 = 1; //T0中断开
ET1 = 1; //T1中断开
EA = 1; //总中断开
}
//--------计算L/C值--------
void LC_Calculate(void)
{
float mes;
mes = (float)Frequency0/(float)Frequency1; //频率比
mes *= mes; //平方值
if(mes < 1) //取绝对值
{
mes = 1 - mes;
}
else
{
mes -= 1;
}
Cx = 100 * mes * Cref; //计算被测电容值(精确到0.1pF)
if((Cx%10) >= 5) //四舍五入
{
Cx = Cx/10 + 1;
}
else
{
Cx = Cx/10;
}
Lx = mes * Lref * 1000; //计算被测电感值(精确到0.01uH)
if((Lx%10) >= 5) //四舍五入
{
Lx = Lx/10 + 1;
}
else
{
Lx = Lx/10;
}
if(Frequency1<50) //防止不接入电感时显示溢出值
{
Lx = 0;
}
}
//----自动校正(清除寄生电容值)-------
void Auto_Calib(void)
{
u8 i;
if((K1_F_LC != 0) || (K2_L_C != 0)) //判断K1,K2的初始位置
{
LCD_Clear();
LCD_Write_String(0,0,"Auto Calib fail!");
if((K1_F_LC == 1) && (K2_L_C == 1))
{
LCD_Write_String(1,0,"Need up K1 & K2 ");
}
else
{
if(K1_F_LC == 1)
{
LCD_Write_String(1,0," Need up K1 ");
}
else
{
LCD_Write_String(1,0," Need up K2 ");
}
}
while((K1_F_LC == 1) || (K2_L_C == 1)); //等待K1,K2的准确初始位置
for(i=0; i<20; i++)
{
Delay_ms(75); //延时1.5秒,消抖.
}
}
LC_Calculate();
Delay_ms(150);
Lref = (Cx/Cref + 1) * 100; //计算基准电感值(单位uH)
Frequency0 = Frequency1;
}
//-------按键读取--------
void Get_Key(void)
{
if(K4_FLC_EC == 0) //如果=0(按钮按下)
{
Delay_ms(50);
if(K4_FLC_EC == 0)
{
FLC_EC_Flag = ~FLC_EC_Flag; //测量标志取反
if(FLC_EC_Flag == 0) //如果=0,是测FLC
{
EX0 = 0; //关闭测电解电容的功能(外部中断0关)
MeasureFLC_init(); //测试(F/L/C)初始化(T0,T1初始化)
}
else //否则,是测量电解电容.
{
TR0 = 0; //T0关
ET0 = 0; //T0中断关
}
}
}
if(K5_Calib == 0) //如果=0(按钮按下)(手工校正)
{
Delay_ms(50); //延时50sm,消抖
if(K5_Calib == 0)
{
if((K1_F_LC == 0) && (K2_L_C == 0)) //如果K1,K2处于测量电容位置
{
Frequency0 = Frequency1;
}
}
}
}
//-------测试电解电容初始化(T0,T1及外部中断初始化)-------
void MeasureElec_init(void)
{
u8 i;
ECx_H = 0;
ECx_L = 0;
TR1 = 0;
ET1 = 0;
EX0 = 0; //关外部中断
Dischg = 0; //放电
Delay_ms(180);
Delay_ms(200);
Dischg = 1; //充电
Timer1_Num = 0;
TMOD = 0x11; //T0,T1都作定时器
TH1 = 0x3c; //T1初值高8位(定时50ms)
TL1 = 0xb0; //T1初值低8位
TR1 = 1; //T1开
ET1 = 1; //T1中断开
IT0 = 1; //下降沿触发
EX0 = 1; //外部中断开
EA = 1; //总中断开
for(i=0; i<65; i++) //延时1.3s,等待测量
{
Delay_ms(20);
if(K4_FLC_EC == 0) //如果测量期间K4键按下
{
Delay_ms(20);
if(K4_FLC_EC == 0)
{
break; //中止
}
}
}
EX0 = 0; //外部中断关
Dischg = 0; //放电
}
//--------定时器0中断处理---------
void Timer0_interrupt(void) interrupt 1
{
TH0 = 0x3c; //重装载T0初值高8位(定时50ms)
TL0 = 0xb0; //重装载T0初值低8位
Timer0_Num++; //T0计次累加
if(Timer0_Num >= T0_times) //如果T0计次数=T0预设值(测F=20(1s),测LC=10(0.5s))
{
TR0 = 0; //T0关
TF0 = 0; //T0溢出标志清零
TR1 = 0; //T1关
TF1 = 0; //T1溢出标志清零
Frequency1 = 50000*Timer1_Num + ((u16)((TH1<<8)+TL1)-0x3cb0);
//计算频率值(Frequency1)
Timer0_Num = 0; //T0计次清零
Timer1_Num = 0; //T1计次清零
TH0 = 0x3c; //重装载T0初值高8位(定时50ms)
TL0 = 0xb0; //重装载T0初值低8位
TH1 = 0x3c; //重装载T1初值高8位(计数50000次)
TL1 = 0xb0; //重装载T1初值低8位
TR0 = 1; //T0开
TR1 = 1; //T1开
}
}
//------定时器1中断处理-------
void Timer1_interrupt(void) interrupt 3
{
TH1 = 0x3c; //重装载T1初值高8位(定时50ms,或计数50000次)
TL1 = 0xb0; //重装载T1初值低8位
Timer1_Num++; //T1计次累加
}
//-------外部INT0中断处理--------
void INT0_Interrupt(void) interrupt 0
{
if(Measure_Flag==4)
{
ECx_L = (50000*Timer1_Num + ((u16)((TH1<<8)+TL1)-0x3cb0))*100/2000;
//计算低容量电解电容值(精确到0.01uF)
if((ECx_L-2)>=0)
{
ECx_L -= 2; //修正误差
}
}
if(Measure_Flag==5)
{
ECx_H = (50000*Timer1_Num + ((u16)((TH1<<8)+TL1)-0x3cb0))*10/100;
//计算高容量电解电容值(精确到0.1uF)
if((ECx_H-4)>=0)
{
ECx_H -= 4; //修正误差
}
}
}
//-----------
void Main(void)
{
u8 i;
u8 clear; //清屏标志位,如果功能转换则需要清屏
Measure_Flag = 0;
FLC_EC_Flag = 0; //开机默认测FLC
T0_times = 10;
Timer0_Num = 0;
Timer1_Num = 0;
Frequency0 = 169500;
//基准频率的一半(基准频率是:当L=100uH,C=2200pF时的频率,=339000Hz)
Frequency1 = 0;
LCD1602_Init();
MeasureFLC_init();
LCD_Write_String(0,0," L.C.F Meter ");
LCD_Write_String(1,0," 2015-08-01 ");
for(i=0; i<20; i++)
{
Delay_ms(150); //开机画面显示3秒
}
Auto_Calib();
while(1)
{
Get_Key(); //按键扫描
Delay_ms(70); //该延时使按键切换稳定
clear = Measure_Flag; //读测量类型标志及清屏
Get_Measure_Flag(); //获取测量类型标志
if(clear != Measure_Flag)
{
LCD_Clear();
}
switch(Measure_Flag) //根据测量标志计算并显示
{
case 1: //测电容
{
LC_Calculate();
LCD_Write_String(0,0,"Cx= ");
LCD_Write_LongPoint(0,4,8,1,Cx);
LCD_Write_String(0,13," pF");
LCD_Write_String(1,0,"freq= ");
LCD_Write_Long(1,6,6,Frequency1*2);
LCD_Write_String(1,13," Hz");
break;
}
case 2: //测电感
{
LC_Calculate();
LCD_Write_String(0,0,"Lx= ");
LCD_Write_LongPoint(0,4,8,2,Lx);
LCD_Write_String(0,13," uH");
LCD_Write_String(1,0,"freq= ");
LCD_Write_Long(1,6,6,Frequency1*2);
LCD_Write_String(1,13," Hz");
break;
}
case 3: //测频率
{
LCD_Write_String(0,0," Meas_Freq ");
LCD_Write_String(1,0,"Freq= ");
if(Frequency1<40) //如果被测频率小于40Hz
{
Frequency1=0; //显示零
}
LCD_Write_Long(1,6,6,Frequency1);
LCD_Write_String(1,13," Hz");
break;
}
case 4: //测小电解
{
LCD_Write_String(0,0,"0.47uF<CEx<600uF");
LCD_Write_String(1,0,"CEx= ");
LCD_Write_String(1,14,"uF");
LCD_Write_LongPoint(1,6,5,2,ECx_L);
MeasureElec_init();
break;
}
case 5: //测大电解
{
LCD_Write_String(0,0,"220uF< CEx <12mF");
LCD_Write_String(1,0,"CEx= ");
LCD_Write_String(1,14,"uF");
LCD_Write_LongPoint(1,6,6,1,ECx_H);
MeasureElec_init();
break;
}
default:
break;
}
}
}
请分析上述代码中的电感电容计算原理
最新发布