2023年电赛J题实现
基于STM32F103C8T6+LM393测频的2023电赛J题实现~~~
可以看到这题网上没什么方案(
本文基于STM32F103C8T6主控来实现


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

可以看到我们要测试的这个电路
等效电路板的实现
我们就先把对应的电路板搞出来先(((
根据题目可以指知道可以用跳线帽来控制器件的故障
于是电路如图:

对应的PCB如下:

PS:不要铺铜,铺铜你就废了(Doge)
测频率电路的实现

可以看到我们只有A+,A-和B+,B-这四个端口可以发挥
首先想到了往A+和B+注入高频正弦波测量 有效值
但是想到+多的正弦波用STM32F103C8T6ADC测多多少少有点不礼貌了
于是上网扒拉资源,发现可以用电路的谐振频率来判断故障
首先想到了电容三点式,但想想还是算了(只能电感)
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 */
对应功能的测试:


~~~完结撒花~~~
更多推荐



所有评论(0)