目录
一、2020 电赛 E 题初印象
全国大学生电子设计竞赛,作为电子信息领域极具影响力的学科竞赛 ,一直是高校学子展现专业技能与创新能力的大舞台。每一届的电赛题目都紧密结合行业前沿与实际应用,旨在激发学生的创新思维,锻炼他们解决实际问题的能力。2020 年的电子设计大赛也不例外,众多赛题中,E 题以其独特的挑战性和趣味性,吸引了众多参赛队伍的目光。
2020 年电赛 E 题聚焦于 [具体方向],要求参赛团队设计并实现一个 [系统或装置简述]。这道题不仅涉及模拟电路、数字电路、信号处理等电子专业的核心知识,还对学生的编程能力、工程实践能力以及团队协作能力提出了全面考验。从硬件电路的搭建,到软件代码的编写与优化,再到系统的联调与测试,每一个环节都充满了挑战,同时也蕴含着创新的机遇。
二、E 题深度剖析
2.1 赛题要求拆解
2020 年电子设计大赛 E 题要求设计并制作一个放大器非线性失真研究装置 。具体来说,参赛者需要利用晶体管、阻容元件、模拟开关等元器件搭建一个受控晶体管放大器。该放大器有特定的输入要求,当外接信号源输出频率为 1kHz、峰峰值为 20mV 的正弦波作为输入电压时,放大器要输出无明显失真及四种失真波形,分别是顶部失真、底部失真、双向失真和交越失真,并且输出波形的峰峰值不能低于 2V 。
在完成波形输出的基础上,还需要对这五种输出电压的 “总谐波失真” 近似值进行测量并显示。总谐波失真(THD)是衡量线性放大器非线性失真程度的重要指标,在测量 THD 时,全程不能有任何人工干预,这对系统的自动化和智能化提出了较高要求。 整个设计过程不仅要实现硬件电路的搭建,还要撰写设计报告,在报告中详细阐述方案论证、理论分析、电路设计以及失真原因分析等内容。
2.2 方案对比与抉择
面对这样复杂的赛题要求,参赛团队在设计之初就需要思考多种实现方案,并进行深入的对比分析。在众多可能的方案中,有两种方案较为典型,各有利弊。
方案一是采用五个晶体管放大电路分别产生不同的波形,即一个放大电路对应一种波形,如一个电路专门产生无明显失真的正弦波,另外四个分别产生顶部失真、底部失真、双向失真和交越失真波形。这种方案的好处显而易见,每个电路功能单一,调试起来相对容易。当其中一个元器件出现故障时,只会影响对应的那个波形的输出,不会导致其他波形也无法产生结果,系统的稳定性和可靠性较高。然而,它的缺点也很突出,由于需要搭建五个独立的放大电路,元器件数量多,焊接和调试的工作量巨大,这不仅增加了硬件成本,也会耗费大量的时间和精力在电路搭建和调试上,对于比赛这种时间紧张的场景来说,可能会面临时间不够用的风险。
方案二则是只用一路放大电路,通过改变阻值来产生不同的波形。比如通过模拟开关切换不同阻值的电阻,从而改变放大电路的静态工作点,进而产生不同类型的失真波形以及无失真的正弦波。这种方案最大的优势在于焊接电路的工作量大大减少,硬件成本也相对较低,而且由于电路结构相对简单,在理论上可能更容易进行整体的优化和调整。但是,它也存在明显的劣势,由于所有波形都依赖于这一路放大电路,一旦这部分电路出现问题,比如某个电阻焊接错误、模拟开关故障等,就可能导致所有波形都无法正常显示,调试难度较大,排查故障需要花费更多的时间和精力,对团队成员的技术水平和经验要求更高。
综合考虑两种方案的优缺点,在实际比赛中,如果团队成员对电路调试的经验相对较少,且时间有限,为了求稳,方案一可能是更好的选择,虽然工作量大,但胜在稳定可靠,能保证在规定时间内实现基本功能。而如果团队成员技术实力较强,对电路调试有足够的信心,且追求更高的效率和更简洁的电路结构,方案二或许能展现出更大的优势,在完成功能的同时,还可能在创新性和简洁性方面获得额外的加分。
三、硬件电路搭建攻略
3.1 放大电路设计与实践
在硬件电路搭建中,放大电路是核心部分。以常用的共射极放大电路为例,它利用三极管的电流放大作用,将输入信号进行放大 。在设计时,需要仔细计算和选择各个电阻、电容的参数,以确保放大电路能够正常工作,并满足赛题对输出波形的要求。例如,基极偏置电阻的选择要保证三极管处于合适的静态工作点,避免出现截止失真或饱和失真 。
在实际调试放大电路的过程中,可能会遇到各种问题。比如,在某次调试中,按照仿真结果搭建电路后,测量某个节点的电压,发现与预期值相差甚远。经过仔细检查焊接情况,排除了虚焊、短路等问题后,怀疑是三极管性能异常。更换三极管后,电压仍然没有恢复正常。最后,通过重新计算并调整相关电阻的阻值,才使电路达到了预期的工作状态 。还有一次,在电路调试过程中,原本正常工作的放大电路突然出现输出异常,经过排查,发现是由于长时间工作导致某个电容发热,参数发生变化,更换电容后电路恢复正常 。
3.2 信号调理电路要点
信号调理电路的作用是将放大电路输出的信号进行处理,使其符合 STM32 ADC(模数转换器)的输入要求 。STM32 ADC 通常只能接收 0 - 3.3V 的正电压信号,而放大电路输出的信号可能包含负半周,且幅值也不一定在 ADC 的输入范围内 。因此,需要通过信号调理电路对信号进行抬升和幅值调整。
一种常见的信号调理方法是使用加法器电路,将一个直流偏置电压(如 1.65V)与放大后的交流信号相加,使信号整体抬高到正电压范围 。同时,还需要根据信号的幅值大小,通过电阻分压或放大器进一步调整信号的幅值,确保其在 0 - 3.3V 之间 。此外,为了防止高频噪声对 ADC 采样的影响,还需要在信号输入 ADC 之前,加入低通滤波器,滤除高频干扰信号 。
四、软件代码实现之路
4.1 开发环境与工具准备
在软件代码实现环节,我们选用了开发芯片 STM32F103ZET6 ,它是一款基于 ARM Cortex - M3 内核的 32 位微控制器,拥有丰富的资源和强大的处理能力,非常适合本次电赛 E 题的开发需求 。与之配套的开发工具是 Keil MDK(Microcontroller Development Kit),这是一款专业的嵌入式软件开发工具,提供了丰富的库函数和强大的调试功能,能够大大提高开发效率 。在 Keil MDK 中,我们还需要安装对应 STM32F103ZET6 的器件支持包,以便能够正确识别和使用芯片的各种外设 。此外,为了方便进行代码版本管理,我们使用了 Git 工具,它可以帮助团队成员更好地协同开发,追踪代码的修改历史,避免代码冲突等问题 。
4.2 核心代码逻辑解读
在软件代码实现过程中,核心代码逻辑主要围绕测量功能、波形显示以及 THD 计算等功能展开,我们通过不同版本的代码迭代来逐步优化和完善这些功能。
4.2.1 定时器版本代码
定时器版本代码主要利用定时器定时实现测量功能 。在这个版本中,我们设置定时器的定时周期,当定时器定时时间到,触发中断 。在中断服务函数中,进行 AD 采样,获取电压数据 。例如,假设我们设置定时器每 1ms 触发一次中断,每次中断时启动 AD 采样,将采样得到的数据存储到数组中 。
// 定时器中断服务函数
void TIM3_IRQHandler(void)
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) // 判断是否是更新中断
{
// 启动AD采样
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
// 等待AD转换完成
while (!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC));
// 获取AD转换结果
uint16_t adc_value = ADC_GetConversionValue(ADC1);
// 将数据存储到数组中
static uint8_t index = 0;
adc_data[index++] = adc_value;
if (index >= ADC_DATA_LEN)
{
index = 0;
}
TIM_ClearITPendingBit(TIM3, TIM_IT_Update); // 清除中断标志位
}
}
在显示波形方面,我们根据采集到的电压数据,通过液晶屏驱动函数将波形绘制在液晶屏上 。对于 THD 的计算,我们采用快速傅里叶变换(FFT)算法 。先对采集到的电压数据进行 FFT 变换,将时域信号转换为频域信号,然后根据频域信号计算出各次谐波的幅值,进而计算出 THD 。
// 计算THD
float calculateTHD(uint16_t *data, uint16_t len)
{
// 进行FFT变换
fft(data, len);
// 计算基波幅值
float fundamental_amplitude = calculateFundamentalAmplitude(data, len);
// 计算各次谐波幅值平方和
float harmonic_power_sum = 0;
for (uint16_t i = 2; i < len / 2; i++)
{
float harmonic_amplitude = calculateHarmonicAmplitude(data, i);
harmonic_power_sum += harmonic_amplitude * harmonic_amplitude;
}
// 计算THD
float thd = sqrt(harmonic_power_sum) / fundamental_amplitude;
return thd;
}
4.2.2 DMA 版本代码
DMA 版本代码相较于定时器版本,在数据传输和处理方式上有了较大改进 。在这个版本中,采用 DMA 传输数据,实现了数据的快速传输,减少了 CPU 的干预,提高了系统的效率 。同时,利用定时器产生 PWM 模拟输出采样时钟,保证了采样的准确性和稳定性 。
在配置 DMA 时,我们需要设置 DMA 的源地址(即 ADC 数据寄存器的地址)、目的地址(存储数据的数组地址)、传输数据量等参数 。例如:
// 配置DMA
void DMA_Config(void)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); // 使能DMA1时钟
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = (u32)&(ADC1->DR); // 源地址:ADC1数据寄存器
DMA_InitStructure.DMA_MemoryBaseAddr = (u32)adc_data; // 目的地址:存储数据的数组
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; // 数据传输方向:外设到内存
DMA_InitStructure.DMA_BufferSize = ADC_DATA_LEN; // 传输数据量
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; // 外设地址不自增
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; // 内存地址自增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; // 外设数据宽度:半字(16位)
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; // 内存数据宽度:半字(16位)
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; // 循环模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High; // 优先级:高
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; // 禁止内存到内存传输
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel1, ENABLE); // 使能DMA通道1
}
定时器产生 PWM 模拟输出采样时钟的配置如下,通过设置定时器的预分频系数和自动重载值,来控制 PWM 的频率和占空比 :
// 配置定时器产生PWM
void TIM_PWM_Config(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 使能TIM3时钟
// 定时器基本配置
TIM_TimeBaseStructure.TIM_Period = 999; // 自动重载值,决定PWM周期
TIM_TimeBaseStructure.TIM_Prescaler = 71; // 预分频系数,72MHz时钟分频后为1MHz
TIM_TimeBaseStructure.TIM_ClockDivision = 0;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
// PWM模式配置
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 499; // 占空比50%
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
TIM_OC1Init(TIM3, &TIM_OCInitStructure);
TIM_Cmd(TIM3, ENABLE); // 使能TIM3
}
这样,通过 DMA 快速传输数据和定时器精准控制采样时钟,系统在性能上得到了显著提升,为后续的数据处理和分析提供了更可靠的基础 。
4.2.3 最终版本代码亮点
最终版本代码在前面版本的基础上,进一步优化了精度和数据处理能力 。在精度方面,通过多次测量取平均值的方式,减少了测量误差 。例如,在测量 THD 时,进行 5 次测量,然后计算平均值作为最终结果 :
// 多次测量求平均THD
float averageTHD(void)
{
float thd_sum = 0;
for (int i = 0; i < 5; i++)
{
// 进行一次测量并计算THD
float thd = calculateTHD(adc_data, ADC_DATA_LEN);
thd_sum += thd;
}
return thd_sum / 5;
}
在数据拟合方面,针对硬件板子可能存在的问题,对采集到的电压数据进行了拟合处理 。通过拟合算法,使测量结果更加准确和稳定 。同时,在代码结构上,对各个功能模块进行了更合理的封装和优化,提高了代码的可读性和可维护性 。例如,将波形显示、THD 计算等功能封装成独立的函数,每个函数只负责单一的功能,这样在后续的调试和升级过程中,能够更方便地进行修改和扩展 。
最终版本代码实现了系统的高效、稳定运行,满足了赛题对放大器非线性失真研究装置的各项要求,为整个项目的成功完成奠定了坚实的基础 。
五、常见问题与解决锦囊
在 E 题的实现过程中,无论是硬件还是软件,都可能遇到各种各样的问题 。下面我们来总结一些常见问题,并给出相应的解决方法 。
在硬件方面,焊接问题是最容易出现的。虚焊、短路等问题会导致电路无法正常工作 。比如,某个焊点虚焊,可能会造成信号传输不稳定,时而正常,时而异常 。对于这类问题,我们可以使用万用表进行测量,检查焊点的电阻值是否正常 。如果电阻值过大,可能是虚焊;如果电阻值为零,可能是短路 。一旦发现问题,重新焊接即可解决 。
元器件故障也是常见问题之一 。例如,三极管性能不良,可能导致放大电路无法正常放大信号 。在遇到这种情况时,可以使用替换法,将可疑的元器件替换掉,看电路是否恢复正常 。如果替换后电路正常工作,说明原来的元器件确实有问题 。
在软件方面,代码逻辑错误是比较常见的 。比如,在计算 THD 时,如果公式写错,或者数据处理逻辑有误,就会导致计算结果错误 。为了避免这类问题,在编写代码时,要仔细检查逻辑,多进行注释,提高代码的可读性 。同时,可以使用调试工具,逐步跟踪代码的执行过程,查看变量的值是否正确,从而找出错误所在 。
此外,还可能会遇到硬件与软件不兼容的问题 。例如,硬件的采样频率与软件设置的采样频率不一致,导致数据采集错误 。在这种情况下,需要仔细检查硬件和软件的配置,确保两者的参数一致 。
六、经验与技巧大放送
回顾整个参与 2020 电赛 E 题的过程,从最初对题目的迷茫,到逐步理清思路,再到克服重重困难实现最终的系统,每一步都充满了挑战与收获,也积累了不少宝贵的经验和实用技巧 。
从团队协作的角度来看,明确分工至关重要 。在团队中,每个成员都有自己的优势和特长,比如有的成员擅长硬件电路设计,有的对软件编程更在行,还有的在理论分析和报告撰写方面表现出色 。根据成员的特长进行合理分工,能够充分发挥每个人的优势,提高工作效率 。比如,在硬件电路搭建阶段,让硬件能力强的成员负责电路设计和焊接,软件成员可以同步进行前期的代码框架搭建和功能规划,这样可以并行推进项目,避免因为某个环节的拖延而影响整个进度 。同时,团队成员之间要保持密切的沟通,每天定时进行进度汇报和问题讨论,及时解决遇到的问题,确保项目方向的一致性 。
在硬件设计和制作过程中,前期的准备工作不容忽视 。在拿到题目后,不要急于动手焊接,而是要先进行充分的方案论证和电路设计 。可以多参考一些相关的资料和以往的比赛经验,拓宽思路 。在选择元器件时,要综合考虑性能、价格和易购性等因素 。比如,在本次 E 题中,对于三极管的选择,要根据放大倍数、频率特性等参数进行筛选,同时要确保能够在当地的电子市场或者网上商城容易买到 。在焊接电路时,要注意焊接质量,使用合适的焊接工具和焊接材料,避免出现虚焊、短路等问题 。焊接完成后,要进行全面的检查,使用万用表等工具对电路的各个节点进行测试,确保电路连接正确 。
软件编程方面,良好的代码规范和模块化设计是关键 。从一开始就要制定统一的代码风格和注释规范,这样可以提高代码的可读性和可维护性 。将不同的功能模块封装成独立的函数或类,比如将 AD 采样、波形显示、THD 计算等功能分别封装,每个模块只负责单一的功能,这样在后续的调试和升级过程中,能够更方便地进行修改和扩展 。同时,要注重代码的优化,合理使用定时器、中断、DMA 等资源,提高系统的运行效率 。例如,在进行大量数据传输时,使用 DMA 可以大大减轻 CPU 的负担,提高数据传输的速度 。
在比赛过程中,时间管理也非常重要 。要制定详细的时间计划,将整个比赛过程划分为不同的阶段,每个阶段设定明确的目标和时间节点 。比如,在第一天要完成方案设计和硬件电路的初步搭建,第二天进行软件编程和硬件调试的初步结合,第三天进行系统的优化和完善,最后一天进行测试和报告撰写 。按照时间计划严格执行,避免出现前松后紧的情况 。同时,要预留一定的时间来应对突发情况,比如硬件故障、软件调试困难等 。
对于后续参赛或学习的同学来说,平时的知识积累和实践经验也很重要 。电子设计竞赛考察的是多方面的知识和技能,要注重平时对模拟电路、数字电路、信号处理、编程等基础知识的学习和掌握 。多参加一些实践项目,提高自己的动手能力和解决实际问题的能力 。可以利用学校的实验室资源,自己动手搭建一些电路,编写一些程序,积累实践经验 。此外,还可以参加一些电子设计相关的社团或竞赛培训,与其他同学交流学习,拓宽视野 。
参与 2020 电赛 E 题的经历不仅让我们在专业知识和技能上得到了提升,也在团队协作、问题解决和时间管理等方面积累了宝贵的经验 。希望这些经验和技巧能够对后续参赛或学习的同学有所帮助,在电子设计的道路上取得更好的成绩 。