0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

基于STM32的元器件特性測試儀過程

電子森林 ? 來源:電子森林 ? 作者:葉開 ? 2021-04-09 11:42 ? 次閱讀

元器件特性測試儀任務(wù)要求

通過編程完成對(duì)5種以上元器件特性的測量

能夠自動(dòng)識(shí)別元器件

OLED屏幕上通過圖形化的界面顯示各種元器件的符號(hào)及測量得到的信息

實(shí)驗(yàn)環(huán)境

硬件STM32G031G8U6核心板、硬禾學(xué)堂制作的底板

軟件:STM32CubeMX、CLion、STM32CubeProgrammer

實(shí)現(xiàn)思路

首先進(jìn)行一個(gè)大致的元器件類型的判斷,再精確地測量元器件的各項(xiàng)屬性,最后顯示在OLED屏幕上

各部分的介紹元器件類型的判斷

思路:首先給元器件放電,再輪番給這3pin中的每2pin進(jìn)行正反地通電,會(huì)得到六次結(jié)果。將每2pin的結(jié)果存儲(chǔ)下來,進(jìn)行排序后根據(jù)元器件特性進(jìn)行判斷元器件的類型,初步判斷后存下引腳信息并進(jìn)行參數(shù)的測量和屏幕顯示,具體參考如圖:

49bb3588-9876-11eb-8b86-12bb97331649.png

代碼如下

void QuickCheck() {

QUICKJUDGE result = {0}; //before compare, the result.sat should be sorted

uint8_t BJTFEA[4] = “011”; //BJT

uint8_t DioFea[4] = “001”; //diode/E-MOS

uint8_t ResFea[4] = “002”; //resistance/inductance/charged capacitance

uint8_t CapFea[4] = “000”; //capacitance/no element

uint8_t temp; //交換時(shí)用于緩存變量

discharge();

if (QuickTestBetween2Pin(MiddlePort, HighPort, LowPort))

result.Bmh = 1;

/* 共六組測量,代碼省略 */

discharge();

if (QuickTestBetween2Pin(LowPort, HighPort, MiddlePort))

result.Blh = 1;

result.Sta[0] = result.Bmh + result.Bhm + ‘0’;

result.Sta[1] = result.Bml + result.Blm + ‘0’;

result.Sta[2] = result.Bhl + result.Blh + ‘0’;

/// Sort the result.sta from little to big

if (result.Sta[0] 》 result.Sta[1])

temp = result.Sta[0], result.Sta[0] = result.Sta[1], result.Sta[1] = temp;

if (result.Sta[1] 》 result.Sta[2])

temp = result.Sta[1], result.Sta[1] = result.Sta[2], result.Sta[2] = temp;

if (result.Sta[0] 》 result.Sta[2])

temp = result.Sta[0], result.Sta[0] = result.Sta[2], result.Sta[2] = temp;

result.Sta[3] = ‘’;

/// 以下是逐個(gè)判斷元器件特征是否和已知特征符合

if (strcmp(result.Sta, CapFea) == 0) {

if (IsCap_Check()) {

ComponentFound = COMPONENT_CAPACITANCE;

Capacitance_Check(*ComponentParam.CAPPARAM.front, *ComponentParam.CAPPARAM.rear);

Capacitance_Display(ComponentParam);

} else {

Error_Report();

}

} else if (strcmp(result.Sta, DioFea) == 0) {

//TODO:Add emos and diode check

//TODO:Sometimes the caps may be metered as a diode

ComponentFound = COMPONENT_DIODE;

if (result.Bml + result.Blm) {

ComponentParam.DiodeParam.front = &MiddlePort;

ComponentParam.DiodeParam.rear = &LowPort;

} else if (result.Bhm + result.Bmh) {

ComponentParam.DiodeParam.front = &MiddlePort;

ComponentParam.DiodeParam.rear = &HighPort;

} else if (result.Blh + result.Bhl) {

ComponentParam.DiodeParam.front = &LowPort;

ComponentParam.DiodeParam.rear = &HighPort;

}

Diode_Check(*ComponentParam.DiodeParam.front, *ComponentParam.DiodeParam.rear);

Diode_Display(ComponentParam);

} else if (strcmp(result.Sta, ResFea) == 0) {

uint8_t ret = 0;

if (result.Bml + result.Blm) {

ret = IsIndOrRes_Check_Between2Pin(MiddlePort, LowPort, HighPort);

ComponentParam.RESPARAM.front = &MiddlePort;

ComponentParam.RESPARAM.rear = &LowPort;

ComponentParam.INDPARAM.front = &MiddlePort;

ComponentParam.INDPARAM.rear = &LowPort;

} else if (result.Bhm + result.Bmh) {

ret = IsIndOrRes_Check_Between2Pin(HighPort, MiddlePort, LowPort);

ComponentParam.RESPARAM.front = &MiddlePort;

ComponentParam.RESPARAM.rear = &HighPort;

ComponentParam.INDPARAM.front = &MiddlePort;

ComponentParam.INDPARAM.rear = &HighPort;

} else if (result.Blh + result.Bhl) {

ret = IsIndOrRes_Check_Between2Pin(LowPort, HighPort, MiddlePort);

ComponentParam.RESPARAM.front = &LowPort;

ComponentParam.RESPARAM.rear = &HighPort;

ComponentParam.INDPARAM.front = &LowPort;

ComponentParam.INDPARAM.rear = &HighPort;

}

if (ret == 1) {

Inductance_Check(*ComponentParam.INDPARAM.front, *ComponentParam.INDPARAM.rear);

Inductance_Display(ComponentParam);

} else if (ret == 2) {

Resistance_Check(*ComponentParam.RESPARAM.front, *ComponentParam.RESPARAM.rear);

Resistance_Display(ComponentParam);

} else {

Error_Report();

}

} else if (strcmp(result.Sta, BJTFEA) == 0) {

ComponentFound = COMPONENT_BJT;

if (result.Bhm + result.Bmh) {

ComponentParam.BJTPARAM.b = &LowPort;

ComponentParam.BJTPARAM.Channel = result.Blm;

} else if (result.Blm + result.Bml) {

ComponentParam.BJTPARAM.b = &HighPort;

ComponentParam.BJTPARAM.Channel = result.Bhl;

} else {

ComponentParam.BJTPARAM.b = &MiddlePort;

ComponentParam.BJTPARAM.Channel = result.Bmh;

}

BJT_Check();

BJT_Display(ComponentParam);

} else {

Error_Report();

}

discharge();

}

區(qū)分電阻和電感

可以給元器件充電后斷電,如果檢測到下端不為低電平,那就是電感。具體代碼如下

/**

* @brief check the element is a inductance or a resistance

* @note firstly,set the fromPin to High and set the toPin to low

* the current direction will like that and the ADC will set here:

* fromPin---element---680r---toPin

* VCC ADC1 GND

* secondly,set the fromPin to Low and set a 470k to protect the io

* the current direction will like that and the ADC will set here:

* fromPin---470k---element---680r---toPin

* GND ADC2 GND

* if it is a inductance the ADC1 and the ADC2 will get a voltage

* while if it is a resistance the ADC1 will get a voltage and the ADC2 will be GND

* @param fromPort

* @param toPort

* @param unusedPort

* @return return 0 if it is no element ,

* return 1 if it is a inductance and

* return 2 if it is a resistance

*/

uint8_t IsIndOrRes_Check_Between2Pin(MEASUREPORT fromPort, MEASUREPORT toPort, MEASUREPORT unusedPort) {

uint16_t adcVol1, adcVol2;

MeasurePort_Init(fromPort, PORT_WITH_NONE, GPIO_PIN_SET);

MeasurePort_Init(toPort, PORT_WITH_680, GPIO_PIN_RESET);

MeasurePort_Init(unusedPort, PORT_FLOATING, GPIO_PIN_RESET);

HAL_GPIO_ReInit(toPort.PIN_WITH_NONE.GPIOx, toPort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

adcVol1 = GetVol(toPort);

MeasurePort_Init(fromPort, PORT_WITH_470K, GPIO_PIN_RESET);

adcVol2 = GetVol(toPort);

if ((adcVol1 《 ADCZERO) && (adcVol2 《 ADCZERO)) {

return 0;

} else if (adcVol2 《 ADCZERO) {

ComponentParam.INDPARAM.front = &fromPort;

ComponentParam.INDPARAM.rear = &toPort;

return 2;

} else {

ComponentParam.RESPARAM.front = &fromPort;

ComponentParam.RESPARAM.rear = &toPort;

return 1;

}

}

電阻的測量

電阻的參數(shù)主要有電阻值,可通過分壓法測量。

首先使用680r電阻,電阻接在上端和下端各測試一次,并計(jì)算電阻值。如果電阻阻值過大,可以換用470k電阻。代碼如下

/**

* @brief measure the value of resistance

* @note first measure will set as follows:

* FrontPort---resistance---680r---RearPort

* GND ADC VCC

* second measure will set as follows:

* FrontPort---680r---resistance---RearPormt

* GND ADC VCC

* third and forth measure will use the 470k resistance

* to instead the 680r to have a more accurate value

* when the resistance is big.

* @param FrontPort

* @param RearPort

*/

//TODO:the resistance of the ADC may cause some deviations when use the 470k resistance

void Resistance_Check(MEASUREPORT FrontPort, MEASUREPORT RearPort) {

uint16_t adcget[4];

float res[4];

MEASUREPORT unusedPort = GetUnusedPort(&FrontPort, &RearPort);

/// MeasurePort_Init函數(shù)用于重新初始化一個(gè)pin上的3個(gè)引腳至指定電阻和電平。

/// 如使用680r電阻,重新初始化其他兩個(gè)引腳為浮空高阻,將連接著680r電阻的引腳設(shè)為指定電平

MeasurePort_Init(FrontPort, PORT_WITH_NONE, GPIO_PIN_RESET);

MeasurePort_Init(RearPort, PORT_WITH_680, GPIO_PIN_SET);

MeasurePort_Init(unusedPort, PORT_FLOATING, GPIO_PIN_RESET);

/// 重新初始化ADC引腳。ADC引腳一般為提供電阻的那組引腳中未接電阻的引腳

HAL_GPIO_ReInit(RearPort.PIN_WITH_NONE.GPIOx, RearPort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

/// GetVol函數(shù)用于測量指定引腳組中未接電阻那個(gè)引腳的電壓

adcget[0] = GetVol(RearPort);

res[0] = 680 / (3300.0 / adcget[0] - 1);

MeasurePort_Init(FrontPort, PORT_WITH_680, GPIO_PIN_RESET);

MeasurePort_Init(RearPort, PORT_WITH_NONE, GPIO_PIN_SET);

MeasurePort_Init(unusedPort, PORT_FLOATING, GPIO_PIN_RESET);

HAL_GPIO_ReInit(FrontPort.PIN_WITH_NONE.GPIOx, FrontPort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

adcget[1] = GetVol(FrontPort);

res[1] = 680 / (adcget[1] / 3300.0) - 680;

if ((res[0] + res[1]) 》 1000) {

/* 與上面的代碼類似,僅將680R改為470K電阻,省略 */

}

if ((res[0] + res[1]) 《= 10000) {

ComponentParam.RESPARAM.ResVal = (uint32_t) (res[0] + res[1]) / 2;

} else if ((res[0] + res[1]) 《= 1000000) {

qsort(res, 4, sizeof(float), cmpfunc);

ComponentParam.RESPARAM.ResVal = (uint32_t) (res[1] + res[2]) / 2;

} else {

ComponentParam.RESPARAM.ResVal = (uint32_t) (res[2] + res[3]) / 2;

}

}

電感的測量

電感的測量可以通過充電后測量放電時(shí)間來大致計(jì)算出電感值

/**

* @brief charge the inductance and discharge it

* @note get the discharge time and then calculate the value of the inductance

* the current direction will like that and the ADC will set here:

* FrontPort---680r---inductance---RearPort

* VCC ADC GND

* after charge, set the FrontPort to low

* the current direction will like that and the ADC will set here:

* FrontPort---680r---inductance---RearPort

* GND ADC GND

* if the discharge speed is too fast, use the 470k to instead and test again.

* @note calculating the value of the inductance is not verified

* @param FrontPort

* @param RearPort

*/

void Inductance_Check(MEASUREPORT FrontPort, MEASUREPORT RearPort) {

uint16_t adcget1, adcget2;

uint16_t time1, time2;

uint16_t i = 0;

MEASUREPORT unusedPort = GetUnusedPort(&FrontPort, &RearPort);

MeasurePort_Init(FrontPort, PORT_WITH_680, GPIO_PIN_SET);

MeasurePort_Init(RearPort, PORT_WITH_NONE, GPIO_PIN_RESET);

MeasurePort_Init(unusedPort, PORT_FLOATING, GPIO_PIN_RESET);

HAL_GPIO_ReInit(FrontPort.PIN_WITH_NONE.GPIOx, FrontPort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

HAL_Delay(100);

adcget1 = GetVol(FrontPort);

MeasurePort_Init(FrontPort, PORT_WITH_680, GPIO_PIN_RESET);

HAL_GPIO_ReInit(FrontPort.PIN_WITH_NONE.GPIOx, FrontPort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

time1 = HAL_GetTick();

while (i 《 0xffff) {

adcget2 = GetVol(FrontPort);

i++;

if (adcget2 《 ADCZERO) {

break;

}

}

time2 = HAL_GetTick();

if (i 《 100) {

MeasurePort_Init(FrontPort, PORT_WITH_680, GPIO_PIN_SET);

MeasurePort_Init(RearPort, PORT_WITH_NONE, GPIO_PIN_RESET);

MeasurePort_Init(unusedPort, PORT_FLOATING, GPIO_PIN_RESET);

HAL_GPIO_ReInit(FrontPort.PIN_WITH_NONE.GPIOx, FrontPort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

HAL_Delay(100);

adcget1 = GetVol(FrontPort);

MeasurePort_Init(FrontPort, PORT_WITH_470K, GPIO_PIN_RESET);

HAL_GPIO_ReInit(FrontPort.PIN_WITH_NONE.GPIOx, FrontPort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

time1 = HAL_GetTick();

while (i 《 0xffff) {

adcget2 = GetVol(FrontPort);

i++;

if (adcget2 《 ADCZERO) {

break;

}

}

time2 = HAL_GetTick();

ComponentParam.INDPARAM.IndVal = (time2 - time1) / (470000 * log(adcget1 / (float) adcget2)) / 1000;

} else {

ComponentParam.INDPARAM.IndVal = (time2 - time1) / (680 * log(adcget1 / (float) adcget2)) / 1000;

}

}

電容的測量

和電感類似,充電后放電,計(jì)算放電的時(shí)間。

需要注意的是這邊似乎可能會(huì)對(duì)有極性的電容進(jìn)行了反向充電,或者對(duì)低耐壓的電容充過壓,暫時(shí)沒想到好的解決方法。

/**

* @brief get the value of the capacitance

* @note charge the cap and use a 680r res to discharge the cap

* calculate the value of the cap by the discharge time

* if the discharge speed is too fast, use 470k to instead the 680r

* @warning when checking the electrolytic and tantalum capacitance

* it is important to avoid reverse connection

* @param FrontPort

* @param RearPort

*/

//TODO:the value may not accurate, may caused by HAL_GetTick.

//TODO:Using a timer to caculate the discharge time may better.

void Capacitance_Check(MEASUREPORT FrontPort, MEASUREPORT RearPort) {

uint16_t adcget1, adcget2;

uint16_t time1, time2;

uint16_t i = 0;

MEASUREPORT unusedPort = GetUnusedPort(&FrontPort, &RearPort);

MeasurePort_Init(FrontPort, PORT_WITH_680, GPIO_PIN_SET);

MeasurePort_Init(RearPort, PORT_WITH_NONE, GPIO_PIN_RESET);

MeasurePort_Init(unusedPort, PORT_FLOATING, GPIO_PIN_RESET);

HAL_Delay(100);

adcget1 = GetVol(FrontPort);

MeasurePort_Init(FrontPort, PORT_WITH_680, GPIO_PIN_SET);

HAL_GPIO_ReInit(FrontPort.PIN_WITH_NONE.GPIOx, FrontPort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

time1 = HAL_GetTick();

while (i 《 0xffff) {

adcget2 = GetVol(FrontPort);

i++;

if (adcget2 《 ADCZERO) {

time2 = HAL_GetTick();

break;

}

}

if (i 《 100) {

MeasurePort_Init(FrontPort, PORT_WITH_680, GPIO_PIN_SET);

HAL_Delay(100);

adcget1 = GetVol(FrontPort);

MeasurePort_Init(FrontPort, PORT_WITH_470K, GPIO_PIN_SET);

HAL_GPIO_ReInit(FrontPort.PIN_WITH_NONE.GPIOx, FrontPort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

time1 = HAL_GetTick();

while (i 《 0xffff) {

adcget2 = GetVol(FrontPort);

i++;

if (adcget2 《 ADCZERO) {

time2 = HAL_GetTick();

break;

}

}

ComponentParam.CAPPARAM.CapVal = (time2 - time1) / (470000 * log(adcget1 / (float) adcget2)) / 1000;

} else {

ComponentParam.CAPPARAM.CapVal = (time2 - time1) / (680 * log(adcget1 / (float) adcget2)) / 1000;

}

}

二極管的測量

二極管的測量最為簡單,直接測正反壓降取小的即可

/**

* @brief get the voltage drop of the diode

* @note the current direction will like that and the ADC will set here:

* frontPort---680r---diode---680---rearPort

* VCC ADC1 ADC2 GND

* if the voltage of the diode is close to 3.3V

* exchange the VCC and GND and test it again

* @param FrontPort

* @param RearPort

*/

void Diode_Check(MEASUREPORT FrontPort, MEASUREPORT RearPort) {

uint16_t adcget1, adcget2;

uint16_t dropVol;

MEASUREPORT unusedPort = GetUnusedPort(&FrontPort, &RearPort);

MeasurePort_Init(FrontPort, PORT_WITH_680, GPIO_PIN_SET);

MeasurePort_Init(RearPort, PORT_WITH_680, GPIO_PIN_RESET);

MeasurePort_Init(unusedPort, PORT_FLOATING, GPIO_PIN_RESET);

HAL_GPIO_ReInit(FrontPort.PIN_WITH_NONE.GPIOx, FrontPort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

HAL_GPIO_ReInit(RearPort.PIN_WITH_NONE.GPIOx, RearPort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

adcget1 = GetVol(FrontPort);

adcget2 = GetVol(RearPort);

dropVol = abs(adcget1 - adcget2);

if (dropVol 》 3000) {

MeasurePort_Init(FrontPort, PORT_WITH_680, GPIO_PIN_RESET);

MeasurePort_Init(RearPort, PORT_WITH_680, GPIO_PIN_SET);

MeasurePort_Init(unusedPort, PORT_FLOATING, GPIO_PIN_RESET);

HAL_GPIO_ReInit(FrontPort.PIN_WITH_NONE.GPIOx, FrontPort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

HAL_GPIO_ReInit(RearPort.PIN_WITH_NONE.GPIOx, RearPort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

adcget1 = GetVol(FrontPort);

adcget2 = GetVol(RearPort);

dropVol = abs(adcget1 - adcget2);

MEASUREPORT *temp = ComponentParam.DiodeParam.rear;

ComponentParam.DiodeParam.rear = ComponentParam.DiodeParam.front;

ComponentParam.DiodeParam.front = temp;

}

ComponentParam.DiodeParam.Uon = dropVol;

}

三極管的測量

可以知道得到0次導(dǎo)通的那兩個(gè)腳為集電極和發(fā)射極,因?yàn)榛鶚O與其他兩個(gè)集都能導(dǎo)通一次。再檢查基極向集電極或者發(fā)射集是否導(dǎo)通,導(dǎo)通即為NPN,不導(dǎo)通即為PNP。分出三極管類型后測量放大和倒置狀態(tài)下的hFE,也就是beta,大者即為放大狀態(tài)和正確的放大倍數(shù)。

三極管測量hFE的方法:以NPN為例,給基極和集電極通過一個(gè)680R電阻接高電平,測量基極和集電極電壓。如果基極電壓不為接近0,表明三極管處于放大狀態(tài),基極電流為(3300mv-adcget1)/680r,集電極電流為(3300mv-adcget2)/680r,hFE即為(3300 - adcget2) / (3300 - adcget1)。如果基極電壓接近0,表明三極管基極電流過大,處于飽和狀態(tài)。增大基極電阻再試一次。

/* 晶體管極性 */

#define P_CHANNEL 1 //NPN

#define N_CHANNEL 0 //PNP

/**

* @brief check the bjt

* @note copy from the program of the CH579

* @attention haven‘t tested yet

*/

void BJT_Check() {

uint16_t adcget1, adcget2, adcget3, adcget4;

uint16_t hfe1, hfe2;

if (ComponentParam.BJTPARAM.Channel == P_CHANNEL) {

if (ComponentParam.BJTPARAM.b == &LowPort) {

discharge();

hfe1 = BJT_Check_NPN(LowPort, MiddlePort, HighPort);

discharge();

hfe2 = BJT_Check_NPN(LowPort, HighPort, MiddlePort);

if (hfe1 》 hfe2) {

ComponentParam.BJTPARAM.c = &MiddlePort;

ComponentParam.BJTPARAM.e = &HighPort;

ComponentParam.BJTPARAM.hFE = hfe1;

} else {

ComponentParam.BJTPARAM.c = &HighPort;

ComponentParam.BJTPARAM.e = &MiddlePort;

ComponentParam.BJTPARAM.hFE = hfe2;

}

} else if (ComponentParam.BJTPARAM.b == &HighPort) {

discharge();

hfe1 = BJT_Check_NPN(HighPort, LowPort, MiddlePort);

discharge();

hfe2 = BJT_Check_NPN(HighPort, MiddlePort, LowPort);

if (hfe1 》 hfe2) {

ComponentParam.BJTPARAM.c = &LowPort;

ComponentParam.BJTPARAM.e = &MiddlePort;

ComponentParam.BJTPARAM.hFE = hfe1;

} else {

ComponentParam.BJTPARAM.c = &MiddlePort;

ComponentParam.BJTPARAM.e = &LowPort;

ComponentParam.BJTPARAM.hFE = hfe2;

}

} else {

discharge();

hfe1 = BJT_Check_NPN(MiddlePort, HighPort, LowPort);

discharge();

hfe2 = BJT_Check_NPN(MiddlePort, LowPort, HighPort);

if (hfe1 》 hfe2) {

ComponentParam.BJTPARAM.c = &HighPort;

ComponentParam.BJTPARAM.e = &LowPort;

ComponentParam.BJTPARAM.hFE = hfe1;

} else {

ComponentParam.BJTPARAM.c = &LowPort;

ComponentParam.BJTPARAM.e = &HighPort;

ComponentParam.BJTPARAM.hFE = hfe2;

}

}

} else {

if (ComponentParam.BJTPARAM.b == &LowPort) {

discharge();

hfe1 = BJT_Check_PNP(LowPort, MiddlePort, HighPort);

discharge();

hfe2 = BJT_Check_PNP(LowPort, HighPort, MiddlePort);

if (hfe1 》 hfe2) {

ComponentParam.BJTPARAM.c = &MiddlePort;

ComponentParam.BJTPARAM.e = &HighPort;

ComponentParam.BJTPARAM.hFE = hfe1;

} else {

ComponentParam.BJTPARAM.c = &HighPort;

ComponentParam.BJTPARAM.e = &MiddlePort;

ComponentParam.BJTPARAM.hFE = hfe2;

}

} else if (ComponentParam.BJTPARAM.b == &HighPort) {

discharge();

hfe1 = BJT_Check_PNP(HighPort, LowPort, MiddlePort);

discharge();

hfe2 = BJT_Check_PNP(HighPort, MiddlePort, LowPort);

if (hfe1 》 hfe2) {

ComponentParam.BJTPARAM.c = &LowPort;

ComponentParam.BJTPARAM.e = &MiddlePort;

ComponentParam.BJTPARAM.hFE = hfe1;

} else {

ComponentParam.BJTPARAM.c = &MiddlePort;

ComponentParam.BJTPARAM.e = &LowPort;

ComponentParam.BJTPARAM.hFE = hfe2;

}

} else {

discharge();

hfe1 = BJT_Check_PNP(MiddlePort, HighPort, LowPort);

discharge();

hfe2 = BJT_Check_PNP(MiddlePort, LowPort, HighPort);

if (hfe1 》 hfe2) {

ComponentParam.BJTPARAM.c = &HighPort;

ComponentParam.BJTPARAM.e = &LowPort;

ComponentParam.BJTPARAM.hFE = hfe1;

} else {

ComponentParam.BJTPARAM.c = &LowPort;

ComponentParam.BJTPARAM.e = &HighPort;

ComponentParam.BJTPARAM.hFE = hfe2;

}

}

}

}

/**

* @brief test the hfe with the imaginary collector and emitter

* @param bPort the base port

* @param cPort the imaginary collector

* @param ePort the imaginary emitter

* @return hfe

*/

uint16_t BJT_Check_PNP(MEASUREPORT bPort, MEASUREPORT cPort, MEASUREPORT ePort) {

uint16_t adcget1, adcget2;

uint16_t hfe;

MeasurePort_Init(ePort, PORT_WITH_680, GPIO_PIN_SET);

MeasurePort_Init(bPort, PORT_WITH_680, GPIO_PIN_RESET);

MeasurePort_Init(cPort, PORT_WITH_NONE, GPIO_PIN_RESET);

HAL_GPIO_ReInit(bPort.PIN_WITH_NONE.GPIOx, bPort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

adcget1 = GetVol(bPort);

if (adcget1 》 ADCZERO) {

HAL_GPIO_ReInit(ePort.PIN_WITH_NONE.GPIOx, ePort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

adcget2 = GetVol(ePort);

hfe = (3300 - adcget2) / adcget1;

} else {

MeasurePort_Init(bPort, PORT_WITH_470K, GPIO_PIN_RESET);

HAL_GPIO_ReInit(bPort.PIN_WITH_NONE.GPIOx, bPort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

adcget1 = GetVol(bPort);

HAL_GPIO_ReInit(ePort.PIN_WITH_NONE.GPIOx, ePort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

adcget2 = GetVol(ePort);

hfe = (470000 * (3300 - adcget2) / 1000) / (680 * adcget1 / 1000) - 1;

}

return hfe;

}

/**

* @brief test the hfe with the imaginary collector and emitter

* @param bPort the base port

* @param cPort the imaginary collector

* @param ePort the imaginary emitter

* @return hfe

*/

uint16_t BJT_Check_NPN(MEASUREPORT bPort, MEASUREPORT cPort, MEASUREPORT ePort) {

uint16_t adcget1, adcget2;

uint16_t hfe;

MeasurePort_Init(ePort, PORT_WITH_NONE, GPIO_PIN_RESET);

MeasurePort_Init(cPort, PORT_WITH_680, GPIO_PIN_SET);

MeasurePort_Init(bPort, PORT_WITH_680, GPIO_PIN_SET);

HAL_GPIO_ReInit(bPort.PIN_WITH_NONE.GPIOx, bPort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

adcget1 = GetVol(bPort);

if (adcget1 》 ADCZERO) {

HAL_GPIO_ReInit(cPort.PIN_WITH_NONE.GPIOx, cPort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

adcget2 = GetVol(cPort);

hfe = (3300 - adcget2) / (3300 - adcget1);

} else {

MeasurePort_Init(bPort, PORT_WITH_470K, GPIO_PIN_RESET);

HAL_GPIO_ReInit(bPort.PIN_WITH_NONE.GPIOx, bPort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

adcget1 = GetVol(bPort);

HAL_GPIO_ReInit(cPort.PIN_WITH_NONE.GPIOx, cPort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

adcget2 = GetVol(cPort);

hfe = (470000 * (3300 - adcget2) / 1000) / (680 * (3300 - adcget1) / 1000);

}

return hfe;

}

OLED的顯示

元器件的各種信息通過一個(gè)全局共用體傳遞。OLED使用軟件I2C進(jìn)行驅(qū)動(dòng),具體的庫和實(shí)現(xiàn)省略,我直播時(shí)也有講過,可以參考我整理的一些驅(qū)動(dòng)。

由于macOS上缺少一些取模軟件,這里我暫時(shí)使用字符象形一下元件,比如電阻:

void Resistance_Display(COMPONENTPARAMETER ComParam) {

char ch[70];

sprintf(ch, “Res %d-[]-%dR=%d Ohm”,

ConvPinToNum(ComParam.RESPARAM.front-》PIN_WITH_NONE.GPIO_Pin),

ConvPinToNum(ComParam.RESPARAM.rear-》PIN_WITH_NONE.GPIO_Pin),

ComParam.RESPARAM.ResVal);

OLED_Clear();

OLED_ShowString(0, 0, (uint8_t *) ch, 12);

}

一些中間層的函數(shù)

QuickTestBetween2Pin

測試兩腳之間有沒有元件

/**

* @brief test if it is a element between 2 pins

* @note the current direction will like that and the ADC will set here:

* fromPort---element---680r---toPort

* VCC ADC GND

* the toPort will have a 680r resistance to serial connect into the current direction

* and have a no-resistance Pin which will be used as a ADC to

* get the voltage and calculate the equivalent resistance of the element

* @param fromPort the current from, will be set high

* @param toPort the current to, will be set low and use a 680r resistance

* @retval if it is a element between fromPort and toPort

*/

uint8_t QuickTestBetween2Pin(MEASUREPORT fromPort, MEASUREPORT toPort, MEASUREPORT unusedPort) {

MeasurePort_Init(fromPort, PORT_WITH_NONE, GPIO_PIN_SET);

MeasurePort_Init(toPort, PORT_WITH_680, GPIO_PIN_RESET);

MeasurePort_Init(unusedPort, PORT_FLOATING, GPIO_PIN_SET);

HAL_GPIO_ReInit(toPort.PIN_WITH_NONE.GPIOx, toPort.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_ANALOG);

HAL_Delay(50);

uint16_t ADCVol = GetVol(toPort);

return ADCVol 》 ADCZERO;

}

GetVol

測量指定腳位電壓

/**

* @brief get the voltage of the no-resistance pin in the

* selected pin group.

* @param PinGroup

* @return the average voltage in 5 times test (mv)

*/

uint16_t GetVol(MEASUREPORT PinGroup) {

/**

* arrget[0]-》PA5

* arrget[1]-》PA6

* arrget[2]-》PA7

* arrget[3]-》V_ref

*/

uint16_t arrget[4] = {0};

uint16_t vol = 0, vdda = 0;

uint16_t vref = *(__IO uint16_t *) 0x1FFF75AA;

for (uint8_t i = 0; i 《 5; i++) {

for (uint8_t j = 0; j 《 4; j++) {

arrget[j] += HAL_ADC_Read(&hadc1);

}

}

arrget[3] /= 5;

HAL_ADC_Stop(&hadc1);

vdda = (uint16_t) (vref * 3000.0 / arrget[3]);

switch (PinGroup.PIN_WITH_NONE.GPIO_Pin) {

case GPIO_PIN_5:

vol = arrget[0] * 3300 / 4096.0 / 5;

break;

case GPIO_PIN_6:

vol = arrget[1] * 3300 / 4096.0 / 5;

break;

case GPIO_PIN_7:

vol = arrget[2] * 3300 / 4096.0 / 5;

break;

default:

break;

}

return vol;

}

discharge

給元器件放電

/**

* @brief discharge the element

* @param None

* @retval None

*/

void discharge() {

MeasurePort_Init(HighPort, PORT_WITH_NONE, GPIO_PIN_RESET);

MeasurePort_Init(MiddlePort, PORT_WITH_NONE, GPIO_PIN_RESET);

MeasurePort_Init(LowPort, PORT_WITH_NONE, GPIO_PIN_RESET);

HAL_Delay(50);

}

MeasurePort_Init

重新初始化一個(gè)pin上的3個(gè)引腳至指定電阻和電平

/**

* @brief Init the selected test group

* @param port the selected test group

* @param mode select the resistance and its pin

* @param PinState test pin power state select

* @retval None

*/

void MeasurePort_Init(MEASUREPORT port, PORTMODE mode, GPIO_PinState PinState) {

switch (mode) {

case PORT_WITH_NONE:

HAL_GPIO_ReInit(port.PIN_WITH_NONE.GPIOx, port.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_OUTPUT_PP);

HAL_GPIO_ReInit(port.PIN_WITH_680.GPIOx, port.PIN_WITH_680.GPIO_Pin, GPIO_MODE_INPUT);

HAL_GPIO_ReInit(port.PIN_WITH_470K.GPIOx, port.PIN_WITH_470K.GPIO_Pin, GPIO_MODE_INPUT);

HAL_GPIO_WritePin(port.PIN_WITH_NONE.GPIOx, port.PIN_WITH_NONE.GPIO_Pin, PinState);

break;

case PORT_WITH_680:

HAL_GPIO_ReInit(port.PIN_WITH_NONE.GPIOx, port.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_INPUT);

HAL_GPIO_ReInit(port.PIN_WITH_680.GPIOx, port.PIN_WITH_680.GPIO_Pin, GPIO_MODE_OUTPUT_PP);

HAL_GPIO_ReInit(port.PIN_WITH_470K.GPIOx, port.PIN_WITH_470K.GPIO_Pin, GPIO_MODE_INPUT);

HAL_GPIO_WritePin(port.PIN_WITH_680.GPIOx, port.PIN_WITH_680.GPIO_Pin, PinState);

break;

case PORT_WITH_470K:

HAL_GPIO_ReInit(port.PIN_WITH_NONE.GPIOx, port.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_INPUT);

HAL_GPIO_ReInit(port.PIN_WITH_680.GPIOx, port.PIN_WITH_680.GPIO_Pin, GPIO_MODE_INPUT);

HAL_GPIO_ReInit(port.PIN_WITH_470K.GPIOx, port.PIN_WITH_470K.GPIO_Pin, GPIO_MODE_OUTPUT_PP);

HAL_GPIO_WritePin(port.PIN_WITH_470K.GPIOx, port.PIN_WITH_470K.GPIO_Pin, PinState);

break;

case PORT_FLOATING:

HAL_GPIO_ReInit(port.PIN_WITH_NONE.GPIOx, port.PIN_WITH_NONE.GPIO_Pin, GPIO_MODE_INPUT);

HAL_GPIO_ReInit(port.PIN_WITH_680.GPIOx, port.PIN_WITH_680.GPIO_Pin, GPIO_MODE_INPUT);

HAL_GPIO_ReInit(port.PIN_WITH_470K.GPIOx, port.PIN_WITH_470K.GPIO_Pin, GPIO_MODE_INPUT);

default:

break;

}

HAL_ADC_Read

進(jìn)行一次ADC的測量

uint16_t HAL_ADC_Read() {

HAL_ADC_Start(&hadc1);

HAL_ADC_PollForConversion(&hadc1,0xff);

return HAL_ADC_GetValue(&hadc1);

}

HAL_GPIO_ReInit

重新初始化GPIO

void HAL_GPIO_ReInit(GPIO_TypeDef *GPIOx, uint16_t GPIO_Pin, uint32_t Mode){

HAL_GPIO_DeInit(GPIOx,GPIO_Pin);

GPIO_InitTypeDef GPIO_InitStruct = {0};

GPIO_InitStruct.Pin = GPIO_Pin;

GPIO_InitStruct.Mode = Mode;

GPIO_InitStruct.Pull = GPIO_NOPULL;

HAL_GPIO_Init(GPIOx, &GPIO_InitStruct);

}

ConvPinToNum

將GPIO_PIN_X轉(zhuǎn)換成引腳1/2/3

uint16_t ConvPinToNum(uint16_t GPIO_Pin) {

if (GPIO_Pin == GPIO_PIN_5) {

return 1;

} else if (GPIO_Pin == GPIO_PIN_6) {

return 2;

} else if (GPIO_Pin == GPIO_PIN_7) {

return 3;

}

return 0;

}

遇到的問題

STM32的ADC采得電壓不是很準(zhǔn)確,使用校準(zhǔn)后漂移更為離譜

電阻測量時(shí)使用470k電阻時(shí)測得電阻偏差較大,猜測可能為ADC內(nèi)阻導(dǎo)致

電容的測量暫未想到較好的方案

FLASH占用較高(約90%),以后可以使用LL庫代替HAL庫來節(jié)省FLASH開支

由于忙于第四期FPGA活動(dòng)等事,僅針對(duì)部分元件為了直播從沁恒于浩然老師的代碼中移植整理了部分代碼,同時(shí)電感的代碼僅移植也未經(jīng)測試

原文標(biāo)題:基于STM32的元器件特性測試

文章出處:【微信公眾號(hào):FPGA入門到精通】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

責(zé)任編輯:haq

聲明:本文內(nèi)容及配圖由入駐作者撰寫或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • 電子元器件
    +關(guān)注

    關(guān)注

    133

    文章

    3230

    瀏覽量

    104228
  • STM32
    +關(guān)注

    關(guān)注

    2257

    文章

    10828

    瀏覽量

    352446

原文標(biāo)題:基于STM32的元器件特性測試

文章出處:【微信號(hào):xiaojiaoyafpga,微信公眾號(hào):電子森林】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。

收藏 人收藏

    評(píng)論

    相關(guān)推薦

    內(nèi)阻測試儀原理是電橋原理嗎

    的核心原理是歐姆定律,即電流等于電壓除以電阻。在測量過程中,內(nèi)阻測試儀會(huì)通過對(duì)電源輸出電壓和電流的測量,然后經(jīng)過精密計(jì)算得到電池或電源內(nèi)部的電阻值。這種方法主要用于評(píng)估電源的性能和健康狀況,通過測試電池的內(nèi)部電
    的頭像 發(fā)表于 09-18 18:02 ?115次閱讀

    磁芯特性測試儀中的f3什么意思

    在磁芯特性測試儀中,關(guān)于“F3”的具體含義,可能因不同的測試儀型號(hào)、品牌或界面設(shè)計(jì)而有所差異。然而,在沒有具體測試儀型號(hào)或操作手冊(cè)的詳細(xì)指導(dǎo)下,我們可以根據(jù)一般性的理解和常見的操作習(xí)慣
    的頭像 發(fā)表于 09-18 11:32 ?93次閱讀

    磁芯特性測試儀使用方法

    磁芯特性測試儀是一種專門用于測量和分析磁性材料特性的儀器,廣泛應(yīng)用于電子、電力、通信、汽車等行業(yè)。這種測試儀可以幫助工程師評(píng)估磁芯材料的性能,包括磁導(dǎo)率、損耗、飽和磁通密度等關(guān)鍵參數(shù)。
    的頭像 發(fā)表于 09-18 11:30 ?90次閱讀

    山東防水測試儀的標(biāo)準(zhǔn)設(shè)置

    作為檢測產(chǎn)品防水性能的重要設(shè)備,防水測試儀的標(biāo)準(zhǔn)設(shè)置對(duì)于保證測試結(jié)果的準(zhǔn)確性和可靠性非常重要。本文將簡要介紹防水測試儀的標(biāo)準(zhǔn)設(shè)置過程及其關(guān)鍵參數(shù)。防水
    的頭像 發(fā)表于 08-21 11:46 ?130次閱讀
    山東防水<b class='flag-5'>測試儀</b>的標(biāo)準(zhǔn)設(shè)置

    LCR測試儀怎么測試電感?

    LCR測試儀是一種電子測試儀器,用于測量電感(L)、電容(C)和電阻(R)的值。它通過向被測元件施加交流信號(hào),并測量其響應(yīng)來確定元件的電氣特性。
    的頭像 發(fā)表于 05-31 15:17 ?1403次閱讀

    頻率特性測試儀的詳細(xì)解析

    在現(xiàn)代電子工程、通信和測試領(lǐng)域中,頻率特性測試儀(也稱為掃頻)是一種不可或缺的測量工具。它主要用于測量和分析電子系統(tǒng)或網(wǎng)絡(luò)在不同頻率下的響應(yīng)特性
    的頭像 發(fā)表于 05-21 17:59 ?894次閱讀

    半導(dǎo)體分立器件測試儀

    HUSTEC-DC-2010分立器件測試儀,是我司團(tuán)隊(duì)結(jié)合多年半導(dǎo)體器件測試經(jīng)驗(yàn)而研發(fā)的,可以應(yīng)用于多種場景,如: ? 測試分析(功率
    的頭像 發(fā)表于 05-20 16:50 ?333次閱讀
    半導(dǎo)體分立<b class='flag-5'>器件</b><b class='flag-5'>測試儀</b>

    LCR測試儀是測啥的?與電感測試儀有啥區(qū)別?

    LCR測試儀是一種用于測量電子元件的電阻、電容和電感特性的電子測試儀器。
    的頭像 發(fā)表于 05-14 17:19 ?1175次閱讀

    靜電電壓測試儀跟靜電測試儀有什么區(qū)別?

    靜電電壓測試儀和靜電測試儀是兩種用于測量靜電特性的儀器,它們?cè)诠δ芎蛻?yīng)用方面存在一些差異。
    的頭像 發(fā)表于 05-14 16:22 ?724次閱讀

    如何選擇合適的LCR測試儀

    隨著電子行業(yè)的快速發(fā)展,LCR測試儀在電子元器件和電路性能測試中發(fā)揮著越來越重要的作用。然而,市場上的LCR測試儀種類繁多,功能各異,如何選擇合適的LCR
    的頭像 發(fā)表于 05-11 16:49 ?464次閱讀

    鋰電池短路測試儀是什么?

    鋰電池短路測試儀的主要功能是通過模擬鋰電池在短路情況下的反應(yīng),來檢測電池的放電特性、溫度變化和可能的安全隱患。這種測試儀通常具備高精度的電流和電壓測量功能,能夠?qū)崟r(shí)監(jiān)控鋰電池在短路測試過程
    的頭像 發(fā)表于 04-23 10:35 ?597次閱讀
    鋰電池短路<b class='flag-5'>測試儀</b>是什么?

    HDJB六相微機(jī)繼電保護(hù)測試儀時(shí)間特性試驗(yàn)方法

    時(shí)間特性時(shí)間特性試驗(yàn)單元主要用于反時(shí)限繼電器的動(dòng)作時(shí)間特性測試,包括i-t特性、v-t特性、f-
    的頭像 發(fā)表于 04-08 13:48 ?317次閱讀
    HDJB六相微機(jī)繼電保護(hù)<b class='flag-5'>測試儀</b>時(shí)間<b class='flag-5'>特性</b>試驗(yàn)方法

    接地電阻測試儀使用方法 接地電阻測試儀與絕緣電阻測試儀的區(qū)別

    接地電阻測試儀使用方法 接地電阻測試儀是一種用于測量接地體電阻的儀器,廣泛應(yīng)用于建筑、電力、通信、化工等領(lǐng)域。以下是接地電阻測試儀的使用方法: 首先,將接地電阻測試儀的紅色
    的頭像 發(fā)表于 02-18 16:11 ?1133次閱讀

    光功率測試儀怎么使用?

    光功率測試儀怎么使用? 光功率測試儀是一種用于測量光纖連接的光功率的儀器。它是光通信設(shè)備測試和維護(hù)的重要工具。下面將詳細(xì)說明光功率測試儀的使用方法。 一、準(zhǔn)備工作 首先,確保光功率
    的頭像 發(fā)表于 01-05 14:31 ?1235次閱讀

    LCR測試儀有什么用?LCR測試儀使用說明

    和技術(shù)人員提供了一種快速、準(zhǔn)確、可靠地測試和分析電學(xué)元件特性的方法。 一、LCR測試儀的功能 1.測試電感:LCR測試儀可以準(zhǔn)確地測量電感的
    的頭像 發(fā)表于 12-21 16:01 ?1765次閱讀