基于stm32的简易元件测试仪

目录

前言简介

一、项目方案

1.测量原理

其他备选方案

2.电路图

二、具体代码实现

       1.元件的识别:

       2.电阻的测量:

       3.电容的测量:

       4.二极管导通压降的测量:

       5.OLED屏幕显示:

       6.按键启动测量:

三、功能效果

四、项目总结

本方案测量的局限之处(未实现的功能):

 相关知识积累:

源工程文件见:


前言简介

        本项目为本人今年电赛校赛的训练题,也是本人备战今年市赛的第一个练习项目,主要内容为设计并制作一台简易元件测试仪,能够实现对一个二端元件参数的测量。使用单片机为stm32f411ceu6最小系统板。本项目已实现功能如下:

  • 可测量元器件及参数:
    • 电阻:量程1Ω~1MΩ
    • 电容:量程100pF~100μF(针对较小电容测量误差较大)
    • 二极管:判断二极管的引脚并测量正向导通压降
    • 能够自动识别元器件类型(电阻/电容/二极管/空)
  • 通过单击作品上的实体“启动按键”来启动一次测量,在OLED屏幕上通过图形化的界面显示各种元器件的符号及测量得到的信息。

一、项目方案

1.测量原理

        主要为时域方法进行测量。对于电阻和二极管,直接使用单片机ad测量其两端电压即可。电阻的阻值可以通过分压法计算得出。对于电容,对其充电后进行放电,通过测量其放电到一定电压所用时间或放电固定时长再次测得电容电压,通过电容放电公式即可求得电容容值。对于电感测量也是同样的原理。但是由于电感时间常数太小,放电太快,故最后没能实现电感的测量。

        此方案外围电路设计比较简单,只需要外接几个电阻即可,故本人选择了此种测量方法。

其他备选方案

2.电路图

83af59b6c1394d24b040dbebcd2bf165.png

二、具体代码实现

        元件特性测试仪上有一个插入被测元件的二端元件测试端子,端口标有1、2号。每个端口都连接到STM32芯片模块的几个引脚,引脚分别为直接连接(用于ADC测量或直接接入)或经电阻连接。可以通过设置引脚的状态(输出高电平、输出低电平、浮空输入、模拟)来判断元器件及对元器件参数的测量。

  •   *这里解释一下四种模式对应的gpio八种工作模式中的哪四种:

    1 High 推挽输出高电平3.3v
    2 Low 推挽输出低电平0v,电容电感放电时应该选用此模式最好
    *推挽与开漏输出的区别:
    推挽输出可以提供高电平和低电平的输出能力,适用于驱动各种负载。
    开漏输出只能提供低电平的输出能力,适用于信号的共享和隔离。
    
    3 Analog 模拟输入模式,用于读取外部模拟信号,并将其转换为数字值
    4 Floating 浮空输入模式,此时该gpio口处于一种悬空的状态,用于屏蔽未使用到的管脚

        以下为测试时常用的两种基本电路状态:

  • 1高2低

4699cce1c9bb4389a919021c77a33649.png

  • 2高1低

9d8435dbe341432099ec706ce26b61b2.png

       1.元件的识别:

       通过粗略判断端口处的通断情况(两处adc结果的差值)来确定元件类型。以下是判断流程:

2ca56a40cd944990961259eda28c9e73.jpeg

        此粗略判断方法容易误判大电容和大电阻,因此我的代码中加入了一段更换串联电阻以及充放电观察电压变化的判断。

/**
  * 函数功能: 判断函数元件类型,并将判断结果打印在屏幕上
  * 输入参数: 无
  * 返 回 值: 1-3的整数
  * 说    明:1电阻2电容3电感4二极管1-2 5二极管2-1
  */

int Element_Type()
{
	uint32_t adcget1,adcget2,adc_values[2];
	Measure_F1T2_470k();
	HAL_Delay(300);
	GetVol(adc_values);
	if(adc_values[1]>=3250 && adc_values[0]<=70)
	{
		Measure_F2T1_680();
	    HAL_Delay(300);
	    GetVol(adc_values);
		if(adc_values[0]>=3250 && adc_values[1]<=50) return 2;
		else return 5;
			
	}
	else{
	  Measure_F1T2_680();
	  HAL_Delay(500);
	  GetVol(adc_values);
		if(adc_values[1]>=3250 && adc_values[0]<=50) 
		{
			Measure_680_discharge();
			HAL_Delay(300);
			Measure_F2T1_680();
			HAL_Delay(100);
			GPIO_SwitchMode(GPIOB,GPIO_PIN_5,Low);
			adcget1=GetVol2(1);
			HAL_Delay(1);
			adcget2=GetVol2(1);
			if(adcget1-adcget2 >=10 && adcget2-adcget1>=10) return 2;
			else return 1;
		}
		Measure_F2T1_680();
	    HAL_Delay(300);
	    GetVol(adc_values);
		if(adc_values[0]>=3250 && adc_values[1]<=50) return 4;
		else return 1;
	}

}

       2.电阻的测量:

       如下图所示,利用分压公式   

 eq?R_x%20%3D%20%5Cleft%28%5Cfrac%7B%5Ctext%7BADC2%7D%20-%20%5Ctext%7BADC1%7D%7D%7B%5Ctext%7BADC1%7D%7D%5Cright%29%20%5Ctimes%20R

即可求得被测电阻的阻值。对小电阻的测量用680Ω分压,对大电阻用470kΩ分压。

       cce25d20656544c6803e36c6b8579c4a.png

       

/**
  * 函数功能: 电阻的计算与显示
  * 输入参数: 
  * 返 回 值: 
  * 说    明:计算电阻的值,并把结果打在屏幕上
  */
void Resistance_Check()
{
	float Res_1;
	uint32_t Res_2;
	uint32_t adc_values[2];
	Measure_F1T2_680();
	HAL_Delay(5);
	GetVol(adc_values);
	Res_1 = ( ( (float)adc_values[1] ) / ( (float)adc_values[0] )-1.0)*680;
	Measure_F1T2_470k();
	HAL_Delay(5);
	GetVol(adc_values);
	Res_2 = (int)(( ( (float)adc_values[1] ) / ( (float)adc_values[0] )-1.0)*470000);
	
	OLED_DrawBMP(32,2,80,4,BMP1);//画电阻
	if(Res_1 <= 15000) OLED_Showdecimal(0,4,Res_1,7,1,16);   
	else OLED_ShowNum(0,4,Res_2,7,16);
	OLED_ShowCHinese(80,4,7);				
}

       非常值得注意的是,由于单片机的ADC存在内阻,这就相当于在R两端并联了一个eq?R_%7BADC%7D,会使得测量结果偏小,我们可以通过软件方法,调整代码中R的参数来减小误差。有关eq?R_%7BADC%7D的大小可以见如下计算公式(下图中的eq?R_%7BAIN%7D):

64826cf2f7d449198d15f9a4a369b968.png

        同样,也可以用硬件方法消除adc内阻,在adc输出端加入一个电压跟随器使得输入阻抗无穷大,即可有效消除内阻。

       3.电容的测量:

       首先对电容进行充电,测得电容电压(一般为3300mV),然后将电容通过680Ω电阻放电至固定电压值,再次测得电容电压。此时电路如下:

c728d0151c054a0bbe3dcada9035a8af.png

通过电容放电公式

eq?C%3D%5Cfrac%7Bt_2-t_1%7D%7BR%20ln%7B%5Cfrac%7Bv_%7Bt_1%7D%7D%7Bv_%7Bt_2%7D%7D%7D%7D

eq?v为中间adc1在不同时刻测得的电压值。即可求得电容容值。

       为追求测量精度,又添加了如下操作:

       (1)若测得电容电压过小,则说明电容较小,放电过快,应再完成充电操作并改为通过470kΩ放电。

       (2)若测得电容电压依然过小,再完成充电操作并改为通过1MΩ放电。若仍然检测到放电过快,则取一个一定的adc阈值,低于该电压则说明是空端口,未检测到元件。

       (3)类似对电阻的测量,可以通过调整代码中R的参数来减小误差使得测量结果更为精确。

/**
  * 函数功能: 电容的计算与显示
  * 输入参数: 
  * 返 回 值: 
  * 说    明:计算电容的值,并把结果打在屏幕上
  */
void Capacitance_Check()
{
	uint16_t adcget1, adcget2;
	float Res;
  uint32_t time1, time2;
  uint16_t i = 0;
	
	Measure_F2T1_680();
	HAL_Delay(100);
	GPIO_SwitchMode(GPIOB,GPIO_PIN_5,Low);
	adcget1 = GetVol2(1);
	time1 = GetTime();
	
	 while (i < 0xffff) {
       adcget2 = GetVol2(1);
       i++;
       if (adcget2 < ADCZERO) {
           break;
      }
  }
	time2 = GetTime();
	
	Res = (time2 - time1) / (680 * log(adcget1 / (float) adcget2)) * 1000;

		
		if(Res >= 1000) {
			OLED_DrawBMP(32,2,80,4,BMP2);//画电容
		OLED_Showdecimal(0,4,Res/1000,4,2,16);
		OLED_ShowString(80,4,"uF");	
			return;
	}
		
	
		Measure_F2T1_470k();
		HAL_Delay(100);
	  GPIO_SwitchMode(GPIOB,GPIO_PIN_4,Low);
		adcget1 = GetVol2(1);
	  time1 =GetTime();
	
	  while (i < 0xffff) {
       adcget2 = GetVol2(1);
       i++;
       if (adcget2 < ADCZERO) {
           break;
      }
  }
	time2 = GetTime();
	
	Res = (time2 - time1) / (470000 * log(adcget1 / (float) adcget2)) * 1000;
	if(Res >= 10){
		OLED_DrawBMP(32,2,80,4,BMP2);//画电容
	    OLED_Showdecimal(0,4,Res,4,2,16);
		  OLED_ShowString(80,4,"nF");	
			return;
	}
	
	else {
		Measure_F2T1_1M();
		HAL_Delay(100);
	  GPIO_SwitchMode(GPIOB,GPIO_PIN_9,Low);
		adcget1 = GetVol2(1);
	  time1 =GetTime();
	
	  while (i < 0xffff) {
       adcget2 = GetVol2(1);
       i++;
       if (adcget2 < ADCZERO) {
           break;
      }
  }
	time2 = GetTime();
	
		  if(adcget1<=550) {
		OLED_ShowCHinese(0,2,8); OLED_ShowCHinese(16,2,9); OLED_ShowCHinese(32,2,10);
	    OLED_ShowCHinese(48,2,11); OLED_ShowCHinese(64,2,12); 
        OLED_ShowCHinese(80,2,13);return;//显示“未检测到元件”
		}
	
	Res = (time2 - time1) / (1.0 * log(adcget1 / (float) adcget2));
	OLED_DrawBMP(32,2,80,4,BMP2);//画电容
	OLED_Showdecimal(0,4,Res,4,2,16);
	OLED_ShowString(80,4,"pF");

	}

}

       4.二极管导通压降的测量:

       这个比较简单,判断二极管导通方向后,置相应的高低电平,用ADC测得二极管两端电压相减即可得到导通压降。

/**
  * 函数功能: 二极管压降的计算与显示
  * 输入参数: 
  * 返 回 值: 
  * 说    明:计算压降的值,并把结果打在屏幕上
  */
void Diode_Check_1()//返回4时使用
{
	  uint32_t adcget,adc_values[2];
	  Measure_F1T2_680();
      GetVol(adc_values);	  
	  HAL_Delay(100);
	  adcget = adc_values[1] - adc_values[0];
	  OLED_ShowNum(16,2,1,1,16);
	  OLED_DrawBMP(32,2,80,4,BMP4);//画二极管
	  OLED_ShowNum(80,2,2,1,16);
	  OLED_ShowString(0,4,"Vd=");	
	  OLED_Showdecimal(32,4,adcget/1000.0,1,2,16);
	  OLED_ShowString(64,4,"V");	
}

void Diode_Check_2()//返回5时使用
{
	  float adcget;
	  Measure_F2T1_680();
	  HAL_Delay(100);
	  adcget = GetVol1(1) / 1000.0;
	  OLED_ShowNum(16,2,2,1,16);
	  OLED_DrawBMP(32,2,80,4,BMP4);//画二极管
	  OLED_ShowNum(80,2,1,1,16);
	  OLED_ShowString(0,4,"Vd=");	
	  OLED_Showdecimal(32,4,adcget,1,2,16);
	  OLED_ShowString(64,4,"V");	
}

       5.OLED屏幕显示:

       利用spi点亮OLED屏,查找相关例程,移植到该板上,即可用OLED屏通过图形化的界面显示各种元器件的符号及测量得到的信息。值得一提的是,OLED可以充当一个很方便的调试助手,我们可以将想要看的变量直接打印到屏幕上来显示查看。

       6.按键启动测量:

        设置按键中断,在中断回调函数中执行判断和测量函数。

三、功能效果

71aa547b877a4b25ac6d0d6eba568e60.heic

3571c835233d4e5789c33203ead39931.heic

6f6d2bfc906849d59cb087f37e576321.heic

19b3e34684e9405c81ef84485f09e532.heic

db7cb70e4af94cef8fc08628fbc4d927.heic

363b2dd88a4b4f43b5e8f597e718fa04.heic

c6008138a0de441b92c2240264991d50.heic

3f8ccc4df73946db8cdd78332b02e470.heic

四、项目总结

本方案测量的局限之处(未实现的功能):

  • 理论上,可以通过与测量电容相似的方法来测量电感大小。然而实际上由于电感时间常数太小,跳变瞬间电压变化过快,单片机ad采样是需要一定的转换时间的,故造成采样值不精确。
  • 测量电容esr同理,理论上可以通过如下推导计算得出:7b5b468b1f1842e9abc9fe863979b4cc.png

 然而实际上难以测得跳变一瞬间的电压值,故无法得到较为精确的esr。

  • 对于小电容放电过快,误差较大,大于20%。

 相关知识积累:

  1. 单片机io口相关知识:当单片机输出电流过大时,输出电压会急剧下降,因此在选择串联的电阻时不宜使用过小的;同时io口本身的内阻也会对测量造成一定的误差影响。具体可以见文章:STM32 IO端口对应的内阻icon-default.png?t=N7T8https://blog.csdn.net/zhuoqingjoking97298/article/details/135946519?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522171833314216800213091342%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=171833314216800213091342&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-1-135946519-null-null.142%5Ev100%5Epc_search_result_base6&utm_term=stm32io%E5%8F%A3%E5%AF%B9%E5%BA%94%E7%9A%84%E7%94%B5%E9%98%BB&spm=1018.2226.3001.4187
  2. 单片机ad采样内阻:这个问题在电阻测量时已经提到,在测量其他元件时也会造成一定的影响,因此可以在外部再外接一个电路,具体思路可以见下文:STM32 ADC电路输入阻抗问题icon-default.png?t=N7T8https://blog.csdn.net/shawn_shao/article/details/108508131?ops_request_misc=&request_id=&biz_id=102&utm_term=STM32%20ADC%E7%94%B5%E8%B7%AF%E8%BE%93%E5%85%A5%E9%98%BB%E6%8A%97%E9%97%AE%E9%A2%98&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-1-108508131.142%5Ev100%5Epc_search_result_base6

源工程文件见:

https://github.com/uppermomo/stm32-component-tester

  • 35
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值