风筝
发表于: 2022-9-1 11:09:13 | 显示全部楼层

在设计或调试电子设备时,了解电路板上使用的组件的值非常重要。使用万用表可以轻松测量和识别大多数组件,但大多数普通万用表没有测量电感和电容的功能,因为这很少需要。但是,没有电容,实际上就没有电路,而复杂的电路中可能包含电感。 LCR(电感-电容-电阻)测量仪可用于确定上述组件,但通常此类仪表非常昂贵。

image-20.png


在本文中我们将分享一种可以在一定程度上准确测量电感和电容的方法。为此,我们可以使用常见的8位微控制器。我用过PIC18F452。当然,只要保持计算和程序,任何其他微控制器都同样适用于该目的。我们还需要一个基于LM393双模拟比较器的小型外部模拟电路。该电路是一个简单的哈特莱振荡器(Hartley)。这个想法是测量振荡器的频率或时间周期。当将诸如电感之类的新组件引入振荡器时,其频率和时间周期都会发生变化。然后我们可以反算组件值。


PIC18F452是一款8位PIC18F系列单片机。在硬件方面比流行的PIC16F877A或PIC16F887要强大得多。但是,除了捕获比较模块 (CCP) 和定时器之外,我们不需要任何其他硬件。使用PIC18F的主要原因是其工作时钟速度为40MHz。


电路原理图

以下是电感电容测量仪的原理图:

image-1.png


所需的组件

我们将需要电路图中所示的所有组件。组件L2到L6和C4到C8是测试组件。旋转开关SW1和SW2仅在仿真原理图中使用,实际上不存在。 2×16字母数字LCD用于显示信息。连接到引脚C0的按钮用于模式选择。


代码

  1. #include <18F452.h>  
  2.   
  3. #device *=16  
  4.                                                                         
  5. #fuses NOWDT, PUT, H4, BROWNOUT, BORV42
  6. #fuses NOLVP, NODEBUG, NOCPB, STVREN, CPD
  7. #fuses PROTECT, NOWRT, NOWRTB, NOWRTC
  8. #fuses NOWRTD, NOEBTR, NOEBTRB, NOOSCSEN
  9.   
  10. #use delay(clock = 40M)   
  11.                                                                         
  12. #include "lcd.c"   
  13.                                           
  14. #define mode_button      input(pin_C0)   
  15.                                                
  16. #define C_cal_in_nF         100.0
  17. #define L_cal_in_uH         100.0              
  18. #define pi                            3.142                                                     
  19. #define cal_delay               1000   

  20. #define scaling_factor_c    ((10.0 / (4.0 * pi * pi * L_cal_in_uH)))   
  21. #define scaling_factor_l     ((10.0 / (4.0 * pi * pi * C_cal_in_nF)))         
  22.                                                                
  23. unsigned int32 overflow_count = 0;                                                      
  24. unsigned int32 pulse_ticks = 0;                                                   
  25. unsigned int16 start_time = 0;  
  26. unsigned int16 end_time = 0;                              
  27.                                                                                                
  28. void setup(void);                                                                             
  29.   
  30. #int_TIMER1                                                                                             
  31. void TMR_ISR(void)                 
  32. {                                                                                         
  33.     overflow_count++;      
  34. }              

  35. #int_CCP1                                                
  36.                                                   
  37. void CCP_ISR(void)
  38. {
  39.     end_time = CCP_1;                                                                                         
  40.     pulse_ticks = ((65536 * overflow_count) + end_time - start_time);
  41.     start_time = end_time;
  42.     overflow_count = 0;
  43. }
  44.   
  45. void main(void)  
  46. {
  47.      short calibration_done = 0;                                                                                          
  48.      unsigned char mode = 0;        
  49.      unsigned long t = 0;      
  50.      double ref = 0.0;
  51.      double value = 0.0;
  52.                  
  53.      setup();                                                                              
  54.      while(TRUE)                          
  55.      {                                                                     
  56.          t = (pulse_ticks);  
  57.          value = ((double)t * (double)t);
  58.          
  59.          if(mode_button == FALSE)
  60.          {
  61.             delay_ms(60);                                             
  62.             while(mode_button == FALSE);   
  63.             calibration_done = 0;
  64.             mode++;
  65.             
  66.             if(mode > 1)
  67.             {
  68.                 mode = 0;
  69.             }
  70.          }  
  71.                               
  72.          if(calibration_done == 0)
  73.          {
  74.              lcd_putc("\f");               
  75.              lcd_gotoxy(1, 1);
  76.              lcd_putc("Calibrating....");                                                               
  77.              lcd_gotoxy(1, 2);              
  78.              lcd_putc("Place no part.");                                                                 
  79.              delay_ms(cal_delay);        
  80.              lcd_putc("\f");   
  81.             
  82.              if(mode == 0)
  83.              {   
  84.                  ref = (value * scaling_factor_c);   
  85.                  lcd_gotoxy(1, 1);  
  86.                  lcd_putc("C.ref/nF:");         
  87.                  lcd_gotoxy(1, 2);
  88.                  printf(lcd_putc, "%3.1g   ", ref);   
  89.                   
  90.              }
  91.             
  92.              if(mode == 1)            
  93.              {                                             
  94.                  ref = (value * scaling_factor_l);
  95.                  lcd_gotoxy(1, 1);  
  96.                  lcd_putc("L.ref/uH:");        
  97.                  lcd_gotoxy(1, 2);
  98.                  printf(lcd_putc, "%3.1g   ", ref);   
  99.              }  
  100.             
  101.              delay_ms(cal_delay);        
  102.              lcd_putc("\f");
  103.                                                   
  104.              calibration_done = 1;
  105.          }
  106.          
  107.          else
  108.          {   
  109.              lcd_gotoxy(1, 1);  
  110.             
  111.              switch(mode)
  112.              {
  113.                  case 1:
  114.                  {
  115.                      value = (value * scaling_factor_c);  
  116.                      lcd_putc("Ind./uH:");      
  117.                                                 
  118.                      break;
  119.                  }   
  120.                                           
  121.                  default:
  122.                  {   
  123.                      value = (value * scaling_factor_l);   
  124.                      lcd_putc("Cap./nF:");        
  125.                               
  126.                      break;
  127.                  }
  128.              }
  129.             
  130.              value -= ref;
  131.                      
  132.              if((value < 0) || (value > 1000))            
  133.              {              
  134.                 value = 0;
  135.              }  
  136.                           
  137.              lcd_gotoxy(1, 2);                              
  138.              printf(lcd_putc, "%3.1g         ", value);   
  139.          }
  140.       
  141.          delay_ms(100);                  
  142.      };
  143. }
  144.   
  145. void setup(void)                                      
  146. {                        
  147.      setup_wdt(WDT_OFF);  
  148.      setup_adc(ADC_OFF);
  149.      setup_adc_ports(NO_ANALOGS);                                                                                    
  150.      setup_spi(SPI_DISABLED);   
  151.      setup_psp(PSP_DISABLED);                  
  152.      setup_ccp1(CCP_CAPTURE_RE);
  153.      setup_ccp2(CCP_OFF);
  154.      setup_low_volt_detect(LVD_43);                                                
  155.      setup_timer_0(T0_OFF | T0_8_BIT);
  156.      setup_timer_1(T1_INTERNAL);  
  157.      setup_timer_2(T2_DISABLED, T2_DIV_BY_1, 16);
  158.      setup_timer_3(T3_DISABLED);  
  159.      set_timer0(0);
  160.      set_timer1(0);  
  161.      set_timer2(0);                                            
  162.      set_timer3(0);
  163.      enable_interrupts(INT_CCP1);      
  164.      enable_interrupts(INT_TIMER1);
  165.      enable_interrupts(global);  
  166.      lcd_init();
  167.      lcd_putc("\f");                              
  168. }         
复制代码

代码说明

根据所讨论的理论知识,我们需要PIC18的高处理速度以及定时器和捕捉模块。我们还需要一个LCD来显示结果。下面显示的setup()函数显示了这些模块及其设置。

  1. void setup(void)                                             
  2. {                        

  3.      setup_ccp1(CCP_CAPTURE_RE);

  4.      setup_timer_1(T1_INTERNAL);  

  5.      set_timer1(0);  

  6.      enable_interrupts(INT_CCP1);      
  7.      enable_interrupts(INT_TIMER1);
  8.      enable_interrupts(global);  
  9.      lcd_init();
  10.      lcd_putc("\f");      
  11. }
复制代码

CCP1模块设置为上升沿捕捉。这意味着CCP1将在检测到上升沿时捕获定时器1的计数。PIC单片机中的CCP模块通常工作在定时器1模块中,因此它的计数被捕获。捕获两个连续的上升沿会导致输入波形的周期测量。这是我们最需要的。


为了进一步使事情明显以并发方式工作,使用了中断。 CCP1中断在出现上升沿捕获时触发,定时器1中断用于跟踪定时器溢出。在处理定时器1溢出时,会存储当前和先前的捕获计数。这些将用于确定时间段。定时器1很少会溢出,因为它只会在输入波形的频率非常低时才会溢出,而这实际上永远不会发生。

  1. #int_TIMER1                                                                                                                              
  2. void TMR_ISR(void)                 
  3. {         
  4.     overflow_count++;      
  5. }              
  6.                                                                                                          

  7. #int_CCP1                                                
  8.                                                   
  9. void CCP_ISR(void)
  10. {
  11.     end_time = CCP_1;                                                                                         
  12.     pulse_ticks = ((65536 * overflow_count) + end_time - start_time);
  13.     start_time = end_time;
  14.     overflow_count = 0;
  15. }
复制代码

PIC18的PLL用于将外部10MHz晶体振荡器时钟升频至40MHz。这反映在熔丝位和时钟设置中。

  1. #fuses H4 ….
  2.   
  3. #use delay(clock = 40M)   
复制代码

但是,PIC通常每条指令需要4个时钟周期,因此有效的系统时钟频率为10MHz。

image-10.png

因此,定时器1的一个滴答时间是:

image-11.png

因此,在50kHz (20 µs) 的基本频率下,定时器1将计数:

image-12.png

参考电感和电容值可以简单地知道以下等式:

image-13.png

这同样适用于电感测量,公式简化如下:

image-14.png

固定常量在代码顶部的定义中定义

  1. #define C_cal_in_nF         100.0
  2. #define L_cal_in_uH         100.0              
  3. #define pi                  3.142                                                                                                                                             
  4. #define cal_delay           1000   
  5.                                                                               
  6. #define scaling_factor_c    ((10.0 / (4.0 * pi * pi * L_cal_in_uH)))   
  7. #define scaling_factor_l    ((10.0 / (4.0 * pi * pi * C_cal_in_nF)))  
复制代码

现在假设我们要测量220nF。因此,对于这个电容量,振荡器频率将是:

image-15.png

定时器1将计数355个计数,同时从振荡器捕获此频率。


现在,如果我们使用前面显示的公式进行反算,则发现电容的值为:

image-16.png


是的,读数与实际值有点偏离,但与实际值足够接近。产生误差是因为计时器计数只能是整数。这个误差可以在代码中巧妙地补偿。


连接到引脚C0的按钮用于选择电感或电容测量模式。每次更改模式时,都需要进行校准。校准过程很简单。除了参考电容和电感外,我们只需要让我们的仪表不连接任何东西,如下面的电路图所示。这是Hartley振荡器,也是整个设备的核心部分。

image-17.png


在此期间,测量并保存参考分量值。 该值将在未知组件测量期间扣除。 在校准过程中,仪表的显示屏将显示不放置任何外部元件的说明。


校准完成后,可以对未知元件进行相应的放置和测量。这些工作在程序的主循环函数完成。


演示

以下是测量电容电感值的演示效果:

IMG_20220823_13005120-1024x576.jpg


本文提到的所有文件可以在以下链接获取:

https://libstock.mikroe.com/projects/view/5038/inductance-capacitance-measurement-using-pic18-microcontroller

跳转到指定楼层
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

主题 10 | 回复: 13



手机版|

GMT+8, 2024-4-25 14:51 , Processed in 0.068704 second(s), 8 queries , Gzip On, MemCache On. Powered by Discuz! X3.5

YiBoard一板网 © 2015-2022 地址:河北省石家庄市长安区高营大街 ( 冀ICP备18020117号 )

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