可以看到这题网上没什么方案(

本文基于STM32F103C8T6主控来实现

上面有个AT24C02 EEPROM可以当作没看见

 

可以看到我们要测试的这个电路

等效电路板的实现

我们就先把对应的电路板搞出来先(((

根据题目可以指知道可以用跳线帽来控制器件的故障

于是电路如图:

对应的PCB如下:

PS:不要铺铜,铺铜你就废了(Doge)

测频率电路的实现

可以看到我们只有A+,A-和B+,B-这四个端口可以发挥

首先想到了往A+和B+注入高频正弦波测量 有效值

但是想到+多的正弦波用STM32F103C8T6ADC测多多少少有点不礼貌了

于是上网扒拉资源,发现可以用电路的谐振频率来判断故障

首先想到了电容三点式,但想想还是算了(只能电感)

基于LM311的电感电容表

Very Good,电容和电感都能测,输出的还是方波可以直接用STM32测量频率

频率的关系和课本上的一样

但是手头没有LM311,只有LM393但不都是电压比较器(Doge)

魔改一下得到如下电路

可以看到输出频率应该为

 搭出来试试水

可以看到基本没什么误差

接下来只需要把A-和B-接地C5的另一端接A+和B+分别测量数据?

显然是不行的,如果C5连接的端口输入端的电容C1或C4短路了频率不就没了

解决方法也很简单粗暴,串联一个电感

可以看到如果等效网络的L1和L2短路了频率应为

等效电感,也就是之前频率的

这里就不测了(绝对不是忘拍图片了)

 

切换电路的实现

 

接下来就是实现A+B+的功能测试切换了,为了避免到时候测二极管的时候引入干扰,需要控制TEST信号是否输出,也就是要用的两个HFD4/3信号继电器

测量二极管也很简单,把A-和B-的接地断开,这里又要一个HFD4/3信号继电器

 

在A-和B-上接两个IO

一个作输出模式,一个作输入模式,再颠倒测一次不就是测出来了,hhhh

可以看到GND和信号默认是接通的

然后再外挂一个OLED屏幕显示,这会有人不会吧(

 

程序的实现:

CubeMX配置如下

PA0接LM393的一脚,也就是方波输出

可以看到是TIM2_ETR也是外部时钟输入

无需进行预分频

 

计算出它的频率我们配合一个溢出时间为10ms的定时器TIM3的中断来实现

那实际频率是多少呢?

比如测试频率为,那1S内TIM2计数到1000

同理,10ms内就计数到10

也就是输入时钟频率为

然后记得把TIM2的计数清零,不然数据就都是错的了qwq

// main函数中的代码
HAL_TIM_Base_Start(&htim2);
HAL_TIM_Base_Start_IT(&htim3);
TIM2->CNT = 0;
// TIM3回调函数的代码
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) {
    if (htim->Instance == TIM3) {
        fre = TIM2->CNT * 100;
        TIM2->CNT = 0;
    }
}

然后计数二极管检测的实现

首先把B-和A-的接地断开以及测试信号端口

uint8_t status = 1;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);
HAL_Delay(1000);

接下来配置对应的速率和引脚,记得配置下拉(默认高电平怎么测都是高电平)

    GPIO_InitTypeDef PA4TypeDef, PA5TypeDef;
    PA4TypeDef.Pin = GPIO_PIN_4;
    PA5TypeDef.Pin = GPIO_PIN_5;
    PA4TypeDef.Speed = GPIO_SPEED_FREQ_LOW;
    PA5TypeDef.Speed = GPIO_SPEED_FREQ_LOW;
    PA4TypeDef.Pull = GPIO_PULLDOWN;
    PA5TypeDef.Pull = GPIO_PULLDOWN;

D1检测的实现

 // 检测D1 PA4→PA5
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
    PA4TypeDef.Mode = GPIO_MODE_OUTPUT_PP;
    PA5TypeDef.Mode = GPIO_MODE_INPUT;
    HAL_GPIO_Init(GPIOA, &PA4TypeDef);
    HAL_GPIO_Init(GPIOA, &PA5TypeDef);
    HAL_Delay(100);

    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5) == GPIO_PIN_RESET) {
        sprintf(dat, "D1 BR");
        status = 0;
    }

D2检测的实现

 // 检测D2 PA5→PA4
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
    PA4TypeDef.Mode = GPIO_MODE_INPUT;
    PA5TypeDef.Mode = GPIO_MODE_OUTPUT_PP;
    HAL_GPIO_Init(GPIOA, &PA4TypeDef);
    HAL_GPIO_Init(GPIOA, &PA5TypeDef);
    HAL_Delay(100);

    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4) == GPIO_PIN_RESET) {
        sprintf(dat, "D2 BR");
        status = 0;
    }

然后都恢复之前的输入模式

 

// 结束后全恢复为输入模式
    PA4TypeDef.Mode = GPIO_MODE_INPUT;
    PA4TypeDef.Mode = GPIO_MODE_INPUT;
    HAL_GPIO_Init(GPIOA, &PA4TypeDef);
    HAL_GPIO_Init(GPIOA, &PA5TypeDef);

 然后判断是否都正常,和恢复继电器状态

if (status)
        sprintf(dat, "Diode Pass Ok!");
 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);

 函数如下:


/**
 * @brief 检测对应的二极管是否断路
 * @param dat
 */
void DiodeMonitor(char *dat) {
    uint8_t status = 1;
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_SET);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);
    HAL_Delay(1000);

    GPIO_InitTypeDef PA4TypeDef, PA5TypeDef;
    PA4TypeDef.Pin = GPIO_PIN_4;
    PA5TypeDef.Pin = GPIO_PIN_5;
    PA4TypeDef.Speed = GPIO_SPEED_FREQ_LOW;
    PA5TypeDef.Speed = GPIO_SPEED_FREQ_LOW;
    PA4TypeDef.Pull = GPIO_PULLDOWN;
    PA5TypeDef.Pull = GPIO_PULLDOWN;

    // 检测D1 PA4→PA5
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET);
    PA4TypeDef.Mode = GPIO_MODE_OUTPUT_PP;
    PA5TypeDef.Mode = GPIO_MODE_INPUT;
    HAL_GPIO_Init(GPIOA, &PA4TypeDef);
    HAL_GPIO_Init(GPIOA, &PA5TypeDef);
    HAL_Delay(100);

    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_5) == GPIO_PIN_RESET) {
        sprintf(dat, "D1 BR");
        status = 0;
    }

    // 检测D2 PA5→PA4
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET);
    PA4TypeDef.Mode = GPIO_MODE_INPUT;
    PA5TypeDef.Mode = GPIO_MODE_OUTPUT_PP;
    HAL_GPIO_Init(GPIOA, &PA4TypeDef);
    HAL_GPIO_Init(GPIOA, &PA5TypeDef);
    HAL_Delay(100);

    if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_4) == GPIO_PIN_RESET) {
        sprintf(dat, "D2 BR");
        status = 0;
    }

    // 结束后全恢复为输入模式
    PA4TypeDef.Mode = GPIO_MODE_INPUT;
    PA4TypeDef.Mode = GPIO_MODE_INPUT;
    HAL_GPIO_Init(GPIOA, &PA4TypeDef);
    HAL_GPIO_Init(GPIOA, &PA5TypeDef);

    if (status)
        sprintf(dat, "Diode Pass Ok!");
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_RESET);
    HAL_GPIO_WritePin(GPIOA, GPIO_PIN_6, GPIO_PIN_RESET);
}

电路故障的检测:

我们只需要测量出对应的,然后判断的值

// 采集对应的频率
        fre_a = 0;
        fre_b = 0;
        for (i = 0; i < 2; i++) {
            fre_b += fre / 100;
            HAL_GPIO_WritePin(InputSel_GPIO_Port, InputSel_Pin, GPIO_PIN_SET);
            HAL_Delay(400);
            fre_a += fre / 100;
            HAL_GPIO_WritePin(InputSel_GPIO_Port, InputSel_Pin, GPIO_PIN_RESET);
            HAL_Delay(400);
        }
        fre_a /= 2;
        fre_b /= 2;

 然后记录对应状态的fre_a和fre_b ,这里就不演示了

定义一个error_proc来处理对应的情况(基于上面测量的fre_a和fre_b)

函数实现如下


void error_proc(uint16_t fre_a, uint16_t fre_b, char *dat) {
    if (fre_a >= 4500 && fre_a <= 4570 && fre_b >= 4500 && fre_b <= 4570)
        sprintf(dat, "M:PASS OK!");
    else if (fre_a >= 4520 && fre_a <= 4565 && fre_b >= 4540 && fre_b <= 4590)
        sprintf(dat, "M:C1 BR!!");
    else if (fre_a >= 4520 && fre_a <= 4580 && fre_b >= 4615 && fre_b <= 4660)
        sprintf(dat, "M:C2 BR!!");
    else if (fre_b >= 4520 && fre_b <= 4580 && fre_a >= 4615 && fre_a <= 4670)
        sprintf(dat, "M:C3 BR!!");
    else if (fre_b >= 4520 && fre_b <= 4565 && fre_a >= 4540 && fre_a <= 4590)
        sprintf(dat, "M:C4 BR!!");
    else if (fre_a >= 4560 && fre_a <= 4620 && fre_b >= 4738 && fre_b <= 4800)
        sprintf(dat, "M:C1 SC!!");
    else if (fre_a >= 4500 && fre_a <= 4580 && fre_b >= 4250 && fre_b <= 4310)
        sprintf(dat, "M:C2 SC!!"); // fre_a = 4536,fre_b = 4283
    else if (fre_b >= 4500 && fre_b <= 4580 && fre_a >= 4250 && fre_a <= 4310)
        sprintf(dat, "M:C3 SC!!"); // fre_a = 4254,fre_b = 4535
    else if (fre_b >= 4560 && fre_b <= 4620 && fre_a >= 4738 && fre_a <= 4800)
        sprintf(dat, "M:C4 SC!!");
    else if (((fre_a >= 4850 && fre_a <= 5080) || (fre_a > 1000 && fre_a < 3600)) && (fre_b >= 4470 && fre_b <= 4650))
        sprintf(dat, "M:L1 BR!!");
    else if (((fre_a >= 4610 && fre_a <= 4700)) && (fre_b >= 4610 && fre_b <= 4700))
        sprintf(dat, "M:L2 BR!!");
    else if (((fre_b >= 4850 && fre_b <= 5080) || (fre_b > 1000 && fre_b < 3600)) && (fre_a >= 4470 && fre_a <= 4650))
        sprintf(dat, "M:L3 BR!!");
    else if (fre_b >= 4530 && fre_b <= 4580 && fre_a >= 4590 && fre_a <= 4620)
        sprintf(dat, "M:L1 SC!!");
    else if (fre_a >= 4580 && fre_a <= 4650 && fre_b >= 4580 && fre_b <= 4650)
        sprintf(dat, "M:L2 SC!!");
    else if (fre_a >= 4530 && fre_a <= 4580 && fre_b >= 4590 && fre_b <= 4620)
        sprintf(dat, "M:L3 SC!!"); //fre_a = 4602,fre_b = 4554
    else
        sprintf(dat, "M:Please Wait...");
}

其中L1断路时fre_a有几率会出现奇怪的值

(fre_a > 1000 && fre_a < 3600)也就是为什么有这东西

其中L2断路时fre_b有几率会出现奇怪的值,同理

然后会得到对应的dat来显示

 

然后在main.c中的while(1)把上述代码缝合起来就行了

 OLED_clear();
        OLED_setTextSize(1);
        sprintf((char *) str, "f=%.2fkHz ", (float) fre / 1000);
        OLED_setCursor(0, 0);
        OLED_showString(str);
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_SET);
        // 采集对应的频率
        fre_a = 0;
        fre_b = 0;
        for (i = 0; i < 2; i++) {
            fre_b += fre / 100;
            HAL_GPIO_WritePin(InputSel_GPIO_Port, InputSel_Pin, GPIO_PIN_SET);
            HAL_Delay(400);
            fre_a += fre / 100;
            HAL_GPIO_WritePin(InputSel_GPIO_Port, InputSel_Pin, GPIO_PIN_RESET);
            HAL_Delay(400);
        }
        fre_a /= 2;
        fre_b /= 2;

        OLED_setTextSize(2);
//        sprintf((char *)str,"fre_a=%d",fre_a);
//        OLED_setCursor(0, 16);
//        OLED_showString(str);
//
//        sprintf((char *)str,"fre_b=%d",fre_b);
//
//        OLED_setCursor(0, 32);
//        OLED_showString(str);
        // 向串口发送对应的数据
        sprintf((char *) str, "fre_a = %d,fre_b = %d\n", fre_a, fre_b);
        HAL_UART_Transmit(&huart1, str, 30, 200);
        OLED_setTextSize(2);
        error_proc(fre_a, fre_b, (char *) str);
        OLED_setCursor(0, 16);
        OLED_showString(str);
        OLED_setTextSize(1);

        // 选择模式2后检测二极管,也就是对应发挥部分
        if (mode) {
            DiodeMonitor((char *) str);
            OLED_setCursor(0, 40);
            OLED_showString(str);
        }
        HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);
        /* 显示检测结果 */
        OLED_update();
        HAL_Delay(50);

PS:

由于题目有两个要求,一个不要判断二极管故障,一个要判断

于是咱在用按键来切换测量模式

所以再这个while之前还有一个while来切换功能

代码如下:

 while (1) {

        if (key1.click_flag) {
            key1.sate = 0;
            key1.click_flag = 0;
            mode = !mode;
        }
        OLED_setCursor(0, 0);
        OLED_showString((unsigned char *) "Wait For Start...");
        OLED_setCursor(0, 16);
        OLED_showString((unsigned char *) "Please press the key to select the mode!!!");
        OLED_setCursor(0, 32);
        sprintf((char *) str, "mode = %d ", mode);
        OLED_showString(str);
        OLED_setCursor(0, 48);
        sprintf((char *) str, "sys will begin after   %lu ms ", timeout - (HAL_GetTick() - last_time));
        OLED_showString(str);
        OLED_update();
        HAL_Delay(50);
        OLED_clear();
        if (timeout - (HAL_GetTick() - last_time) < 100)
            break;
    }
    /* USER CODE END 2 */

对应功能的测试: 

~~~完结撒花~~~

 

 

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐