赞
踩
目录
本项目为本人今年电赛校赛的训练题,也是本人备战今年市赛的第一个练习项目,主要内容为设计并制作一台简易元件测试仪,能够实现对一个二端元件参数的测量。使用单片机为stm32f411ceu6最小系统板。本项目已实现功能如下:
主要为时域方法进行测量。对于电阻和二极管,直接使用单片机ad测量其两端电压即可。电阻的阻值可以通过分压法计算得出。对于电容,对其充电后进行放电,通过测量其放电到一定电压所用时间或放电固定时长再次测得电容电压,通过电容放电公式即可求得电容容值。对于电感测量也是同样的原理。但是由于电感时间常数太小,放电太快,故最后没能实现电感的测量。
此方案外围电路设计比较简单,只需要外接几个电阻即可,故本人选择了此种测量方法。
元件特性测试仪上有一个插入被测元件的二端元件测试端子,端口标有1、2号。每个端口都连接到STM32芯片模块的几个引脚,引脚分别为直接连接(用于ADC测量或直接接入)或经电阻连接。可以通过设置引脚的状态(输出高电平、输出低电平、浮空输入、模拟)来判断元器件及对元器件参数的测量。
1 High 推挽输出高电平3.3v
2 Low 推挽输出低电平0v,电容电感放电时应该选用此模式最好
*推挽与开漏输出的区别:
推挽输出可以提供高电平和低电平的输出能力,适用于驱动各种负载。
开漏输出只能提供低电平的输出能力,适用于信号的共享和隔离。
3 Analog 模拟输入模式,用于读取外部模拟信号,并将其转换为数字值
4 Floating 浮空输入模式,此时该gpio口处于一种悬空的状态,用于屏蔽未使用到的管脚
以下为测试时常用的两种基本电路状态:
通过粗略判断端口处的通断情况(两处adc结果的差值)来确定元件类型。以下是判断流程:
此粗略判断方法容易误判大电容和大电阻,因此我的代码中加入了一段更换串联电阻以及充放电观察电压变化的判断。
- /**
- * 函数功能: 判断函数元件类型,并将判断结果打印在屏幕上
- * 输入参数: 无
- * 返 回 值: 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;
- }
-
- }
-
如下图所示,利用分压公式
即可求得被测电阻的阻值。对小电阻的测量用680Ω分压,对大电阻用470kΩ分压。
- /**
- * 函数功能: 电阻的计算与显示
- * 输入参数:
- * 返 回 值:
- * 说 明:计算电阻的值,并把结果打在屏幕上
- */
- 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两端并联了一个,会使得测量结果偏小,我们可以通过软件方法,调整代码中R的参数来减小误差。有关的大小可以见如下计算公式(下图中的):
同样,也可以用硬件方法消除adc内阻,在adc输出端加入一个电压跟随器使得输入阻抗无穷大,即可有效消除内阻。
首先对电容进行充电,测得电容电压(一般为3300mV),然后将电容通过680Ω电阻放电至固定电压值,再次测得电容电压。此时电路如下:
通过电容放电公式
为中间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");
-
- }
-
- }
这个比较简单,判断二极管导通方向后,置相应的高低电平,用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");
- }
利用spi点亮OLED屏,查找相关例程,移植到该板上,即可用OLED屏通过图形化的界面显示各种元器件的符号及测量得到的信息。值得一提的是,OLED可以充当一个很方便的调试助手,我们可以将想要看的变量直接打印到屏幕上来显示查看。
设置按键中断,在中断回调函数中执行判断和测量函数。
然而实际上难以测得跳变一瞬间的电压值,故无法得到较为精确的esr。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。