找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 4081|回复: 9
收起左侧

51单片机制作电容电感测表源程序

  [复制链接]
ID:399789 发表于 2020-9-14 21:54 | 显示全部楼层 |阅读模式
51单片机制作电容电感测表,附件下载
1581565765776147.jpg

单片机源程序如下:
  1. #include "reg52.h"
  2. #include "intrins.h"
  3. //-------宏定义---------
  4. #define u8 unsigned char
  5. #define u16 unsigned int
  6. #define u32 unsigned long
  7. #define Cref 2200      //基准电容值(单位pF)
  8. #define LCD_DATA P0    //LCD数据口(8位)
  9. //-------I/O定义--------
  10. sbit LCD_BUSY = P0^7; //LCD忙信号
  11. sbit LCD_RS   = P1^0; //数据/命令选择(数据=1,命令=0)
  12. sbit LCD_RW   = P1^1; //读/写选择(写=0,读=1)
  13. sbit LCD_EN   = P1^2; //使能信号
  14. sbit K1_F_LC   = P1^3; //F/LC测量选择按钮(自锁),([抬起]=0测LC,[按下]=1测F)
  15. sbit K2_L_C    = P1^4; //L/C测量选择按钮(自锁)([抬起]=0测C,[按下]=1测L)
  16. sbit K3_Eb_Es  = P1^6; //电解量程选择按钮(自锁),([抬起]=0低量程,[按下]=1高量程)
  17. sbit K4_FLC_EC = P3^6; //FLC或EC(电解电容)测量选择按钮(无锁)(每按一次,翻转一次)
  18. sbit K5_Calib  = P3^7; //手工校正(清零)按钮(无锁)(消除寄生电容值)
  19. sbit Dischg    = P1^5; //测量电解电容时的充放电控制端口(=0放电,=1充电)
  20. //-------全局变量定义--------
  21. bit  FLC_EC_Flag;  //测量标志(=0测FLC,=1测电解电容)
  22. u8   Measure_Flag; //测量标志(=1测电容,=2测电感,=3测频率,=4测小电解,=5测大电解)
  23. u8   Lref;         //基准电感值(单位uH)(原作没有)
  24. u16  T0_times;     //T0中断计数预设值(每50ms一次),测F=20次(1s),测LC=10次(0.5s)
  25. u16  Timer0_Num;   //T0计数
  26. u16  Timer1_Num;   //T1计数
  27. u32  Frequency0;   //频率0(未接被测元件时的频率)
  28. u32  Frequency1;   //频率1(接入被测元件时的频率)
  29. u32  Cx;           //被测电容
  30. u32  Lx;           //被测电感
  31. u32  ECx_H;        //被测电解电容(大)
  32. u32  ECx_L;        //被测电解电容(小)
  33. //------x的n次方------------
  34. u32 power(u8 x,u8 n)
  35. {
  36.     u8 i;
  37.     u32 j = 1;
  38.     if(n == 0)
  39.     {
  40.         return 1;
  41.     }
  42.     else
  43.     {
  44.         for(i=0; i<n; i++)
  45.         {
  46.             j *= x;
  47.         }
  48.         return j;
  49.     }
  50. }
  51. //----延时n毫秒(12M晶振,12T模式,一个指令周期=1us)---
  52. //----1ms=(跳转等3个指令周期+两个空指令)*200----
  53. void Delay_ms(u8 n)
  54. {
  55.     u8 i,j;
  56.     for(i=0; i<n; i++)
  57.     {
  58.         for(j=0; j<200; j++)
  59.         {
  60.             _nop_();
  61.             _nop_();
  62.         }
  63.     }
  64. }
  65. //------LCD1602读忙标志位------
  66. void Check_busy(void)
  67. {
  68.     do
  69.     {
  70.         LCD_EN=0;
  71.         LCD_RS=0;
  72.         LCD_RW=1;
  73.         LCD_DATA=0xFF;
  74.         LCD_EN=1;
  75.     }
  76.     while(LCD_BUSY==1);
  77.     LCD_EN=0;
  78. }
  79. //------LCD1602写指令------
  80. void Write_Command(u8 cmd)
  81. {
  82.     Check_busy();
  83.     LCD_RS=0;
  84.     LCD_RW=0;
  85.     LCD_DATA=cmd;
  86.     LCD_EN=0;
  87.     LCD_EN=1;
  88.     LCD_EN=0;
  89. }
  90. //------LCD1602写数据------
  91. void Write_Data(u8 dat)
  92. {
  93.     Check_busy();
  94.     LCD_RS=1;
  95.     LCD_RW=0;
  96.     LCD_DATA=dat;
  97.     LCD_EN=0;  //机器周期小于1us时,须加延时
  98.     LCD_EN=1;
  99.     LCD_EN=0;
  100. }
  101. //-----LCD1602写字符串------
  102. //---x=列(0~15); y=行(0,1)
  103. //---从指定的位置开始写,直到超出屏幕显示
  104. void LCD_Write_String(u8 y,u8 x,u8 *Data)
  105. {
  106.     if(y==0)      //第一行
  107.     {
  108.         if(x<16)
  109.         {
  110.             Write_Command(0x80+x);  //0x80 + 第一行起始地址
  111.             for(; x<16&&*Data!='\0'; x++)   //'\0'字符串结束标志
  112.             {
  113.                 Write_Data(*(Data++));
  114.             }
  115.         }
  116.     }
  117.     if(y==1)      //第二行
  118.     {
  119.         if(x<16)
  120.         {
  121.             Write_Command(0xc0+x);          //0xc0 + 第二行起始地址
  122.             for(; x<16&&*Data!='\0'; x++)   //'\0'字符串结束标志
  123.             {
  124.                 Write_Data(*(Data++));
  125.             }
  126.         }
  127.     }
  128. }
  129. //------LCD1602写长整型数据------
  130. //x=列(0~15); y=行(0,1);截取长整型后length个数字显示在指定位置(全显示length=10)
  131. //注意此函数不支持换行,起始列+length>15时后面的显示不出来,仅能单行显示
  132. void LCD_Write_Long(u8 y,u8 x,u8 length,u32 Data)
  133. {
  134.     u8 i,k;
  135.     if(length>10)
  136.     {
  137.         length = 10;
  138.     }
  139.     if(length<10)
  140.     {
  141.         Data = Data%power(10,length);
  142.     }
  143.     if(y==0)     //第一行
  144.     {
  145.         Write_Command(0x80+x);      //0x80 + 第一行起始地址
  146.         for(i=0; i<length; i++)
  147.         {
  148.             k = (u8)(Data/power(10,length-1-i));
  149.             Data = Data%power(10,length-1-i);
  150.             Write_Data(k+0x30);
  151.         }
  152.     }
  153.     if(y==1)     //第二行
  154.     {
  155.         Write_Command(0xc0+x);      //0xc0 + 第二行起始地址
  156.         for(i=0; i<length; i++)
  157.         {
  158.             k = (u8)(Data/power(10,length-1-i));
  159.             Data = Data%power(10,length-1-i);
  160.             Write_Data(k+0x30);
  161.         }
  162.     }
  163. }
  164. //------LCD1602写长整型数据,可以指定小数点后位数-------
  165. //x=列(0~15); y=行(0,1);截取长整型后length个数字显示在指定位置(全显示length=10)
  166. //注意此函数不支持换行,起始列+length>15时后面的显示不出来,仅能单行显示
  167. //pot:小数点后显示几个数字 例:1234567 pot=2时显示为12345.67
  168. void LCD_Write_LongPoint(u8 y,u8 x,u8 length,u8 pot,u32 Data)
  169. {
  170.     u8 i,j,k;
  171.     if(length>10)
  172.     {
  173.         length = 10;
  174.     }
  175.     if(length<10)
  176.     {
  177.         Data = Data%power(10,length);
  178.     }
  179.     if(y==0)    //第一行
  180.     {
  181.         j=0;
  182.         Write_Command(0x80+x);      //0x80 + 第一行起始地址
  183.         for(i=0; i<=length; i++)
  184.         {
  185.             if(i==(length-pot))
  186.             {
  187.                 Write_Data(0x2e);   //小数点
  188.                 Write_Command(0x80+x+i+1);
  189.             }
  190.             else
  191.             {
  192.                 k = (u8)(Data/power(10,length-1-j));
  193.                 Data = Data%power(10,length-1-j);
  194.                 Write_Data(k+0x30);
  195.                 j++;
  196.             }
  197.         }
  198.     }
  199.     if(y==1)    //第二行
  200.     {
  201.         j=0;
  202.         Write_Command(0xc0+x);      //0xc0 + 第二行起始地址
  203.         for(i=0; i<=length; i++)
  204.         {
  205.             if(i==(length-pot))
  206.             {
  207.                 Write_Data(0x2e);   //小数点
  208.                 Write_Command(0xc0+x+i+1);
  209.             }
  210.             else
  211.             {
  212.                 k = (u8)(Data/power(10,length-1-j));
  213.                 Data = Data%power(10,length-1-j);
  214.                 Write_Data(k+0x30);
  215.                 j++;
  216.             }
  217.         }
  218.     }
  219. }
  220. //------LCD1602清屏---------
  221. void LCD_Clear(void)
  222. {
  223.     Write_Command(0x01);
  224. }
  225. //------LCD1602初始化-----
  226. void LCD1602_Init(void)
  227. {
  228.     Delay_ms(15);
  229.     Write_Command(0x38);   //16x2显示,8位数据
  230.     Write_Command(0x0c);   //开显示
  231.     Write_Command(0x06);   //AC自动加1,字符依次向后写
  232.     LCD_Clear();
  233. }
  234. //------判断测量类型-------
  235. void Get_Measure_Flag(void)
  236. {
  237.     if(FLC_EC_Flag==0)    //测FLC按键选择标志位
  238.     {
  239.         if(K1_F_LC==1)
  240.         {
  241.             Measure_Flag = 3;   //测频率
  242.             T0_times = 20;  //T0定时1s
  243.         }
  244.         else
  245.         {
  246.             if(K2_L_C==0)
  247.             {
  248.                 Measure_Flag = 1; //测电容
  249.             }
  250.             else
  251.             {
  252.                 Measure_Flag = 2;
  253.             }
  254.             T0_times = 10;  //T0定时0.5s
  255.         }
  256.     }
  257.     else
  258.     {
  259.         TR0 = 0;        //关闭测频率(含LC)功能
  260.         ET0 = 0;
  261.         if(K3_Eb_Es==0)
  262.         {
  263.             Measure_Flag = 4;  //测小电解
  264.         }
  265.         else
  266.         {
  267.             Measure_Flag = 5;  //测大电解
  268.         }
  269.     }
  270. }
  271. //------测试(F/L/C)初始化(T0,T1初始化)------
  272. void MeasureFLC_init(void)
  273. {
  274.     Timer0_Num = 0;
  275.     Timer1_Num = 0;
  276.     TMOD = 0x51;  //T0作定时器,T1作计数器
  277.     TH0  = 0x3c;  //T0初值高8位(定时50ms)
  278.     TL0  = 0xb0;  //T0初值低8位
  279.     TH1  = 0x3c;  //T1初值高8位(计数50000次)
  280.     TL1  = 0xb0;  //T1初值低8位
  281.     TR0  = 1;  //T0开
  282.     TR1  = 1;  //T1开
  283.     ET0  = 1;  //T0中断开
  284.     ET1  = 1;  //T1中断开
  285.     EA = 1;    //总中断开
  286. }
  287. //--------计算L/C值--------
  288. void LC_Calculate(void)
  289. {
  290.     float mes;
  291.     mes = (float)Frequency0/(float)Frequency1;  //频率比
  292.     mes *= mes;  //平方值
  293.     if(mes < 1)  //取绝对值
  294.     {
  295.         mes = 1 - mes;
  296.     }
  297.     else
  298.     {
  299.         mes -= 1;
  300.     }
  301.     Cx = 100 * mes * Cref;   //计算被测电容值(精确到0.1pF)
  302.     if((Cx%10) >= 5)  //四舍五入
  303.     {
  304.         Cx = Cx/10 + 1;
  305.     }
  306.     else
  307.     {
  308.         Cx = Cx/10;
  309.     }
  310.     Lx = mes * Lref * 1000;  //计算被测电感值(精确到0.01uH)
  311.     if((Lx%10) >= 5)  //四舍五入
  312.     {
  313.         Lx = Lx/10 + 1;
  314.     }
  315.     else
  316.     {
  317.         Lx = Lx/10;
  318.     }
  319.     if(Frequency1<50)    //防止不接入电感时显示溢出值
  320.     {
  321.         Lx = 0;
  322.     }
  323. }
  324. //----自动校正(清除寄生电容值)-------
  325. void Auto_Calib(void)
  326. {
  327.     u8 i;
  328.     if((K1_F_LC != 0) || (K2_L_C != 0))  //判断K1,K2的初始位置
  329.     {
  330.         LCD_Clear();
  331.         LCD_Write_String(0,0,"Auto Calib fail!");
  332.         if((K1_F_LC == 1) && (K2_L_C == 1))
  333.         {
  334.             LCD_Write_String(1,0,"Need up K1 & K2 ");
  335.         }
  336.         else
  337.         {
  338.             if(K1_F_LC == 1)
  339.             {
  340.                 LCD_Write_String(1,0,"   Need up K1   ");
  341.             }
  342.             else
  343.             {
  344.                 LCD_Write_String(1,0,"   Need up K2   ");
  345.             }
  346.         }
  347.         while((K1_F_LC == 1) || (K2_L_C == 1));  //等待K1,K2的准确初始位置
  348.         for(i=0; i<20; i++)
  349.         {
  350.             Delay_ms(75);  //延时1.5秒,消抖.
  351.         }
  352.     }
  353.     LC_Calculate();
  354.         Delay_ms(150);
  355.     Lref = (Cx/Cref + 1) * 100;  //计算基准电感值(单位uH)
  356.     Frequency0 = Frequency1;
  357. }
  358. //-------按键读取--------
  359. void Get_Key(void)
  360. {
  361.     if(K4_FLC_EC == 0)  //如果=0(按钮按下)
  362.     {
  363.         Delay_ms(50);
  364.         if(K4_FLC_EC == 0)
  365.         {
  366.             FLC_EC_Flag = ~FLC_EC_Flag; //测量标志取反
  367.             if(FLC_EC_Flag == 0)  //如果=0,是测FLC
  368.             {
  369.                 EX0 = 0;        //关闭测电解电容的功能(外部中断0关)
  370.                 MeasureFLC_init();  //测试(F/L/C)初始化(T0,T1初始化)
  371.             }
  372.             else  //否则,是测量电解电容.
  373.             {
  374.                 TR0 = 0;  //T0关
  375.                 ET0 = 0;  //T0中断关
  376.             }
  377.         }
  378.     }
  379.     if(K5_Calib == 0)  //如果=0(按钮按下)(手工校正)
  380.     {
  381.         Delay_ms(50);  //延时50sm,消抖
  382.         if(K5_Calib == 0)
  383.         {
  384.             if((K1_F_LC == 0) && (K2_L_C == 0))  //如果K1,K2处于测量电容位置
  385.             {
  386.                 Frequency0 = Frequency1;
  387.             }
  388.         }
  389.     }
  390. }
  391. //-------测试电解电容初始化(T0,T1及外部中断初始化)-------
  392. void MeasureElec_init(void)
  393. {
  394.     u8 i;
  395.     ECx_H = 0;
  396.     ECx_L = 0;
  397.     TR1 = 0;
  398.     ET1 = 0;
  399.     EX0 = 0;  //关外部中断
  400.     Dischg = 0;  //放电
  401.     Delay_ms(180);
  402.     Delay_ms(200);
  403.     Dischg = 1;  //充电
  404.     Timer1_Num = 0;
  405.     TMOD = 0x11;  //T0,T1都作定时器
  406.     TH1  = 0x3c;  //T1初值高8位(定时50ms)
  407.     TL1  = 0xb0;  //T1初值低8位
  408.     TR1  = 1;  //T1开
  409.     ET1  = 1;  //T1中断开
  410.     IT0  = 1;  //下降沿触发
  411.     EX0  = 1;  //外部中断开
  412.     EA   = 1;  //总中断开
  413.     for(i=0; i<65; i++)  //延时1.3s,等待测量
  414.     {
  415.         Delay_ms(20);
  416.         if(K4_FLC_EC == 0)  //如果测量期间K4键按下
  417.         {
  418.             Delay_ms(20);
  419.             if(K4_FLC_EC == 0)
  420.             {
  421.                 break;  //中止
  422.             }
  423.         }
  424.     }
  425.     EX0    =    0;    //外部中断关
  426.     Dischg =    0;    //放电
  427. }
  428. //--------定时器0中断处理---------
  429. void Timer0_interrupt(void) interrupt 1
  430. {
  431.     TH0  = 0x3c;  //重装载T0初值高8位(定时50ms)
  432.     TL0  = 0xb0;  //重装载T0初值低8位
  433.     Timer0_Num++; //T0计次累加
  434.     if(Timer0_Num >= T0_times)  //如果T0计次数=T0预设值(测F=20(1s),测LC=10(0.5s))
  435.     {
  436.         TR0 = 0;  //T0关
  437.         TF0 = 0;  //T0溢出标志清零
  438.         TR1 = 0;  //T1关
  439.         TF1 = 0;  //T1溢出标志清零
  440.         Frequency1 = 50000*Timer1_Num + ((u16)((TH1<<8)+TL1)-0x3cb0);
  441.         //计算频率值(Frequency1)
  442.         Timer0_Num = 0;  //T0计次清零
  443.         Timer1_Num = 0;  //T1计次清零
  444.         TH0  = 0x3c;  //重装载T0初值高8位(定时50ms)
  445.         TL0  = 0xb0;  //重装载T0初值低8位
  446.         TH1  = 0x3c;  //重装载T1初值高8位(计数50000次)
  447.         TL1  = 0xb0;  //重装载T1初值低8位
  448.         TR0  = 1;  //T0开
  449.         TR1  = 1;  //T1开
  450.     }
  451. }
  452. //------定时器1中断处理-------
  453. void Timer1_interrupt(void) interrupt 3
  454. {
  455.     TH1  = 0x3c;  //重装载T1初值高8位(定时50ms,或计数50000次)
  456.     TL1  = 0xb0;  //重装载T1初值低8位
  457.     Timer1_Num++; //T1计次累加
  458. }
  459. //-------外部INT0中断处理--------
  460. void INT0_Interrupt(void) interrupt 0
  461. {
  462.     if(Measure_Flag==4)
  463.     {
  464.         ECx_L = (50000*Timer1_Num + ((u16)((TH1<<8)+TL1)-0x3cb0))*100/2000;
  465.         //计算低容量电解电容值(精确到0.01uF)
  466.         if((ECx_L-2)>=0)
  467.         {
  468.             ECx_L -= 2;  //修正误差
  469.         }
  470.     }
  471.     if(Measure_Flag==5)
  472.     {
  473.         ECx_H = (50000*Timer1_Num + ((u16)((TH1<<8)+TL1)-0x3cb0))*10/100;
  474.         //计算高容量电解电容值(精确到0.1uF)
  475.         if((ECx_H-4)>=0)
  476.         {
  477.             ECx_H -= 4;   //修正误差
  478.         }
  479.     }
  480. }
  481. //-----------
  482. void Main(void)
  483. {
  484.     u8 i;
  485.     u8 clear;           //清屏标志位,如果功能转换则需要清屏
  486.     Measure_Flag = 0;
  487.     FLC_EC_Flag  = 0;   //开机默认测FLC
  488.     T0_times     = 10;
  489.     Timer0_Num   = 0;
  490.     Timer1_Num   = 0;
  491.     Frequency0   = 169500;
  492.         //基准频率的一半(基准频率是:当L=100uH,C=2200pF时的频率,=339000Hz)
  493.     Frequency1   = 0;
  494.     LCD1602_Init();
  495.     MeasureFLC_init();
  496.     LCD_Write_String(0,0,"  L.C.F  Meter   ");
  497.     LCD_Write_String(1,0,"   2015-08-01  ");
  498.     for(i=0; i<20; i++)
  499.     {
  500.         Delay_ms(150);  //开机画面显示3秒
  501.     }
  502.     Auto_Calib();
  503.     while(1)
  504.     {
  505.         Get_Key();               //按键扫描
  506.         Delay_ms(70);            //该延时使按键切换稳定
  507.         clear = Measure_Flag;    //读测量类型标志及清屏
  508.         Get_Measure_Flag();      //获取测量类型标志
  509.         if(clear != Measure_Flag)
  510.         {
  511.             LCD_Clear();
  512.         }
  513.         switch(Measure_Flag)    //根据测量标志计算并显示
  514.         {
  515.         case    1:              //测电容
  516.         {
  517.             LC_Calculate();
  518.             LCD_Write_String(0,0,"Cx= ");
  519.             LCD_Write_LongPoint(0,4,8,1,Cx);
  520.             LCD_Write_String(0,13," pF");
  521.             LCD_Write_String(1,0,"freq=  ");
  522.             LCD_Write_Long(1,6,6,Frequency1*2);
  523.             LCD_Write_String(1,13," Hz");
  524.             break;
  525.         }
  526.         case    2:              //测电感
  527.         {
  528.             LC_Calculate();
  529.             LCD_Write_String(0,0,"Lx= ");
  530.             LCD_Write_LongPoint(0,4,8,2,Lx);
  531.             LCD_Write_String(0,13," uH");
  532.             LCD_Write_String(1,0,"freq= ");
  533.             LCD_Write_Long(1,6,6,Frequency1*2);
  534.             LCD_Write_String(1,13," Hz");
  535.             break;
  536.         }
  537.         case    3:              //测频率
  538.         {
  539.             LCD_Write_String(0,0,"   Meas_Freq   ");
  540.             LCD_Write_String(1,0,"Freq= ");
  541.             if(Frequency1<40)  //如果被测频率小于40Hz
  542.             {
  543.                 Frequency1=0;  //显示零
  544.             }
  545.             LCD_Write_Long(1,6,6,Frequency1);
  546.             LCD_Write_String(1,13," Hz");
  547.             break;
  548.         }
  549.         case    4:              //测小电解
  550.         {
  551.             LCD_Write_String(0,0,"0.47uF<CEx<600uF");
  552.             LCD_Write_String(1,0,"CEx=  ");
  553.             LCD_Write_String(1,14,"uF");
  554.             LCD_Write_LongPoint(1,6,5,2,ECx_L);
  555.             MeasureElec_init();
  556.             break;
  557.         }
  558.         case    5:              //测大电解
  559.         {
  560.             LCD_Write_String(0,0,"220uF< CEx <12mF");
  561.             LCD_Write_String(1,0,"CEx=  ");
  562.             LCD_Write_String(1,14,"uF");
  563.             LCD_Write_LongPoint(1,6,6,1,ECx_H);
  564.             MeasureElec_init();
  565.             break;
  566.         }
  567.         default:
  568.             break;
  569.         }
  570.     }
  571. }
复制代码

所有资料51hei提供下载:
电容电感表.rar (178.18 KB, 下载次数: 108)
回复

使用道具 举报

ID:251816 发表于 2020-9-16 09:47 | 显示全部楼层
源程序有明白的注释,赞一个。
回复

使用道具 举报

ID:567636 发表于 2020-9-16 10:54 | 显示全部楼层
有人试了吗?
回复

使用道具 举报

ID:371895 发表于 2020-9-17 07:35 来自手机 | 显示全部楼层
早知道就不买现成的电容电感表了
回复

使用道具 举报

ID:147329 发表于 2021-3-5 07:15 来自手机 | 显示全部楼层
程序很规范呀,学习了
回复

使用道具 举报

ID:876099 发表于 2021-10-30 13:34 | 显示全部楼层
有人做过实物吗,我仿真没办法测量,只能测频率
回复

使用道具 举报

ID:34149 发表于 2021-10-30 18:56 | 显示全部楼层
这是个大工程!为楼主点赞。辛苦了
回复

使用道具 举报

ID:138707 发表于 2022-3-4 18:10 | 显示全部楼层
这是个大工程!为楼主点赞。辛苦了
回复

使用道具 举报

ID:852236 发表于 2022-3-5 08:59 | 显示全部楼层
大工程 点千赞!!!
回复

使用道具 举报

ID:744744 发表于 2022-4-24 06:47 来自手机 | 显示全部楼层
学习了,正要做电感电容表,参考一下楼主程序。十分感谢!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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