
这次我们来看一个针对2026年电子设计竞赛电赛的实战技术专栏聚焦于吉林省赛区发挥部分的第一问。对于电赛选手而言发挥部分往往是拉开差距的关键它不仅考验对基础知识的掌握更挑战系统设计、算法实现和工程调试的综合能力。本文将直接切入核心围绕STM32和FPGA这两个在电赛中应用最广泛的平台为你拆解一个典型发挥部分题目的解题思路、硬件选型、软件框架与调试技巧。无论你是初次参赛的新手还是希望优化方案的老手这篇文章都将提供一套从分析到验证的完整流程。我们会重点关注方案的可实现性、代码的模块化设计以及常见坑点的规避。你将看到如何将抽象的题目要求转化为具体的电路连接、驱动代码和算法逻辑并最终通过实测数据验证方案的可行性。1. 核心能力速览在深入细节之前我们先通过下表快速了解应对此类电赛发挥部分题目所需的核心技术栈与资源准备。这能帮助你快速判断自己是否具备相应的基础以及需要提前准备哪些内容。能力项说明与要求核心控制器STM32系列单片机(如F103、F407、H743等) 或FPGA(如Xilinx Artix-7, Intel Cyclone IV)。STM32适合复杂逻辑与控制FPGA擅长高速并行处理。开发环境STM32: Keil MDK-ARM / STM32CubeIDE / VSCode PlatformIO。 FPGA: Xilinx Vivado / Intel Quartus Prime。关键外设掌握必会: GPIO、定时器(TIM)、ADC/DAC、USART/UART。提高: SPI/I2C通信、DMA、高级定时器、中断嵌套。典型题目方向信号发生器(DDS)、数据采集、电机控制、通信协议、算法实现(如滤波、编码)、人机交互。硬件门槛一套基础的STM32或FPGA开发板、示波器、信号源、万用表是调试必备。根据题目可能还需传感器、电机、屏幕等模块。代码管理强烈推荐使用模块化、分层设计(如HAL/LL库驱动层、业务逻辑层)便于调试与复用。调试能力熟练使用串口调试、逻辑分析仪、仿真器(ST-Link/J-Link)进行在线调试与问题定位。2. 适用场景与使用边界本专栏讨论的方案主要适用于全国大学生电子设计竞赛及其各省赛区的“发挥部分”题目。这类题目通常具有以下特点适合谁正在备赛的电赛学生团队、希望深入学习STM32/FPGA系统设计的嵌入式爱好者、需要解决特定测量或控制问题的工程师。能解决什么问题将题目需求技术化把“测量某参数”、“生成某波形”、“实现某通信”等要求分解为具体的传感器选型、电路设计、外设驱动和算法。提供可复用的框架建立清晰的软件架构如状态机、任务调度使代码易于维护和扩展。规避常见陷阱分享在ADC采样精度、定时器同步、中断冲突、通信稳定性等方面的实战经验。不适合什么场景对嵌入式开发毫无基础需要从点亮LED学起的纯新手建议先完成基础教程。追求单一固定答案的题目。发挥部分通常没有标准答案本文提供的是方法论和典型实现路径。完全脱离STM32/FPGA平台的其他技术栈题目。安全与合规边界硬件安全注意开发板的供电电压和IO口电平避免短路或过压烧毁芯片。代码原创在理解的基础上借鉴和重构避免直接抄袭注重培养独立解决问题的能力。仪器使用规范使用示波器、电源等仪器遵守实验室安全规定。3. 环境准备与前置条件在开始具体设计前请确保你的软硬件环境已就绪。一个稳定的环境是高效调试的基础。3.1 硬件准备清单主控板根据题目复杂度和性能要求选择。STM32F103C8T6最小系统板适合逻辑控制、简单通信。STM32F407ZGT6资源丰富带FPU适合需要浮点运算或复杂算法的场景。FPGA开发板如Basys3、DE10-Lite适合需要高速、并行或定制硬件逻辑的场景。调试工具ST-Link V2 或 J-Link 仿真器用于STM32程序下载与调试。USB-TTL 串口模块用于打印调试信息。逻辑分析仪可选但分析数字信号时序非常有用。测试仪器数字示波器必备观察波形、测量频率幅值。函数信号发生器用于产生测试信号。直流稳压电源为系统提供稳定供电。其他模块根据往届题目推测可能需要准备OLED/LCD屏幕、按键/编码器、各类传感器温湿度、光敏、超声波等、电机驱动模块等。3.2 软件开发环境STM32开发IDE选择Keil MDK-ARM经典需安装芯片包、STM32CubeIDE免费集成CubeMX推荐、VSCode PlatformIO轻量可定制性强。关键软件STM32CubeMX图形化配置工具生成初始化代码。驱动安装确保ST-Link/USB-TTL的驱动已正确安装。FPGA开发IDE选择Xilinx Vivado用于Xilinx芯片、Intel Quartus Prime用于Intel/Altera芯片。注意版本与开发板芯片型号的兼容性。学习基础需要掌握Verilog或VHDL硬件描述语言。3.3 知识储备C语言基础指针、结构体、位操作必须熟练。单片机/FPGA核心概念时钟树、中断、定时器、通信协议UART, SPI, I2C。基本电路知识能看懂原理图理解上拉/下拉电阻、滤波电容的作用。4. 解题思路分析与框架设计面对一个发挥部分的题目切忌直接动手写代码。合理的分析设计能事半功倍。我们以一个假设的题目为例“设计一个正弦波信号发生器要求频率可调范围为1Hz-10kHz步进1Hz幅度可调范围为0.1Vpp-3.3Vpp可通过键盘设置参数并在LCD上显示。”4.1 需求分解与技术选型波形生成核心是DDS直接数字频率合成技术。既可以用STM32的DAC配合定时器DMA实现也可以用FPGA实现以获得更高的频率精度和速度。这里假设选用STM32F407带DAC和高级定时器。频率/幅度控制需要精确的时钟控制和幅度缩放算法。人机交互矩阵键盘或独立按键输入OLED/LCD显示。系统调度需要处理按键扫描、显示刷新、波形计算输出等多个任务考虑使用状态机或简单的RTOS如FreeRTOS。4.2 系统框架设计采用分层设计的思想硬件驱动层利用HAL库或LL库完成DAC、TIM、GPIO按键、LCD、SPI/I2C用于屏幕的初始化。算法服务层实现DDS查表算法、频率/幅度换算函数。业务逻辑层实现主状态机处理按键事件更新显示内容设置DDS参数。应用层main函数中的主循环调度各层任务。5. 关键模块实现与代码解析接下来我们针对核心的DDS波形生成模块给出具体的实现步骤和代码片段。5.1 DDS原理与查表法DDS的核心是一个相位累加器。我们采用查表法提前计算好一个正弦周期波形的数字量并存入数组正弦表。通过改变相位累加器的步进值频率控制字来改变输出频率。// dds_generator.h #ifndef __DDS_GENERATOR_H #define __DDS_GENERATOR_H #include stm32f4xx_hal.h #define SINE_TABLE_SIZE 1024 // 正弦表长度影响频率分辨率 #define REF_CLOCK_FREQ 84000000 // 假设定时器时钟为84MHz #define DAC_MAX_VALUE 4095 // 12位DAC最大值 typedef struct { uint32_t phase_accumulator; // 相位累加器 uint32_t tuning_word; // 频率控制字决定步进 uint16_t amplitude; // 幅度系数 (0 ~ DAC_MAX_VALUE) uint16_t *sine_table; // 正弦表指针 DAC_HandleTypeDef *hdac; // DAC句柄 TIM_HandleTypeDef *htim; // 触发DAC转换的定时器句柄 } DDS_HandleTypeDef; void DDS_Init(DDS_HandleTypeDef *hdds, DAC_HandleTypeDef *hdac, TIM_HandleTypeDef *htim); void DDS_SetFrequency(DDS_HandleTypeDef *hdds, float freq); void DDS_SetAmplitude(DDS_HandleTypeDef *hdds, float amplitude_volt); void DDS_Update(DDS_HandleTypeDef *hdds); // 在定时器中断中调用更新DAC值 #endif// dds_generator.c #include dds_generator.h #include math.h static uint16_t sine_table[SINE_TABLE_SIZE]; // 初始化生成正弦表 void DDS_Init(DDS_HandleTypeDef *hdds, DAC_HandleTypeDef *hdac, TIM_HandleTypeDef *htim) { hdds-hdac hdac; hdds-htim htim; hdds-phase_accumulator 0; hdds-tuning_word 0; hdds-amplitude DAC_MAX_VALUE; hdds-sine_table sine_table; // 生成正弦表值范围 0 ~ DAC_MAX_VALUE for (int i 0; i SINE_TABLE_SIZE; i) { // 正弦值范围[-1, 1]映射到[0, DAC_MAX_VALUE] float sine_value sin(2 * M_PI * i / SINE_TABLE_SIZE); sine_table[i] (uint16_t)((sine_value 1.0) / 2.0 * DAC_MAX_VALUE); } // 启动DAC和定时器 HAL_DAC_Start(hdds-hdac, DAC_CHANNEL_1); HAL_TIM_Base_Start_IT(hdds-htim); // 使用定时器中断触发更新 } // 设置输出频率 (Hz) void DDS_SetFrequency(DDS_HandleTypeDef *hdds, float freq) { // 计算频率控制字: Tuning_Word (freq * TABLE_SIZE) / F_timer // F_timer 是定时器更新频率由定时器分频和重载值决定 uint32_t timer_freq REF_CLOCK_FREQ / (hdds-htim-Instance-PSC 1) / (hdds-htim-Instance-ARR 1); hdds-tuning_word (uint32_t)((freq * SINE_TABLE_SIZE) / timer_freq); } // 设置输出幅度 (Vpp, 需根据硬件放大电路调整换算关系) void DDS_SetAmplitude(DDS_HandleTypeDef *hdds, float amplitude_volt) { // 假设 3.3V 对应 DAC_MAX_VALUE // 此处为简化模型实际需考虑后端运放增益 float ratio amplitude_volt / 3.3; if (ratio 1.0) ratio 1.0; if (ratio 0.0) ratio 0.0; hdds-amplitude (uint16_t)(ratio * DAC_MAX_VALUE); } // 在定时器中断服务函数中调用此函数 void DDS_Update(DDS_HandleTypeDef *hdds) { hdds-phase_accumulator hdds-tuning_word; uint32_t index (hdds-phase_accumulator 22) (SINE_TABLE_SIZE - 1); // 取高10位作为索引假设SINE_TABLE_SIZE1024 uint16_t dac_value (hdds-sine_table[index] * hdds-amplitude) / DAC_MAX_VALUE; HAL_DAC_SetValue(hdds-hdac, DAC_CHANNEL_1, DAC_ALIGN_12B_R, dac_value); }5.2 定时器与DMA配置为了高效、不间断地输出波形我们使用一个定时器如TIM6产生固定频率的中断并在中断中调用DDS_Update。更高效的方式是使用定时器触发DMA将正弦表数据自动搬运到DAC数据寄存器。// 使用STM32CubeMX配置或代码初始化 // TIM6 配置为更新频率 100kHz (ARR839, PSC0, 时钟84MHz) // 开启TIM6更新中断 // DAC 配置为定时器触发转换 // 在 stm32f4xx_it.c 的中断服务函数中 void TIM6_DAC_IRQHandler(void) { if (__HAL_TIM_GET_FLAG(htim6, TIM_FLAG_UPDATE) ! RESET) { __HAL_TIM_CLEAR_FLAG(htim6, TIM_FLAG_UPDATE); DDS_Update(hdds); // 更新DAC输出值 } }5.3 人机交互实现按键扫描和显示刷新不宜在中断中长时间执行建议在主循环中处理。// main.c 主循环示例 int main(void) { // HAL初始化、外设初始化、DDS初始化... System_Init(); DDS_Init(hdds, hdac1, htim6); LCD_Init(); Key_Init(); // 设置初始频率和幅度 DDS_SetFrequency(hdds, 1000.0); // 1kHz DDS_SetAmplitude(hdds, 1.65); // 1.65Vpp float current_freq 1000.0; float current_amp 1.65; while (1) { // 1. 扫描按键 Key_Scan(); if (Key_GetPress(KEY_UP)) { current_freq 1.0; // 步进1Hz DDS_SetFrequency(hdds, current_freq); } else if (Key_GetPress(KEY_DOWN)) { current_freq - 1.0; DDS_SetFrequency(hdds, current_freq); } // ... 其他按键处理 // 2. 更新显示 (避免过于频繁) static uint32_t display_tick 0; if (HAL_GetTick() - display_tick 200) { // 每200ms更新一次显示 display_tick HAL_GetTick(); char buf[32]; sprintf(buf, Freq:%5.1fHz, current_freq); LCD_DisplayString(0, 0, buf); sprintf(buf, Amp:%4.2fV, current_amp); LCD_DisplayString(1, 0, buf); } // 3. 其他任务... HAL_Delay(10); // 主循环延时 } }6. 系统调试与效果验证代码编写完成后必须通过系统化的调试来验证功能是否达标。6.1 调试步骤单元测试先不接DDS测试按键和LCD显示是否正常。确保参数设置和显示逻辑正确。使用printf通过串口打印当前的频率控制字、幅度值等关键变量。信号观测将STM32的DAC输出引脚连接到示波器。上电观察是否有波形输出。如果没有检查定时器是否成功启动并进入中断。DAC是否使能并配置为定时器触发模式。在DDS_Update函数中设置断点查看相位累加器和查表索引是否正常变化。参数验证频率精度通过按键将频率设置为1Hz, 100Hz, 1kHz, 5kHz, 10kHz。用示波器的频率测量功能对比实际测量值与设定值。计算误差。幅度精度设置幅度为0.5Vpp, 1.0Vpp, 2.0Vpp, 3.0Vpp。用示波器测量峰峰值电压对比设定值。注意DAC输出范围是0-3.3V后端可能需要运放进行衰减或放大来匹配题目要求。波形失真度观察正弦波是否光滑有无明显的台阶查表分辨率不足或毛刺干扰。边界与稳定性测试测试频率调到下限1Hz和上限10kHz时波形是否稳定。快速连续按按键改变参数观察系统响应是否及时显示是否卡顿。长时间运行如10分钟观察波形是否有漂移或异常。6.2 性能优化方向提高频率分辨率增大正弦表长度(SINE_TABLE_SIZE)或提高定时器触发频率。降低CPU占用使用DMA自动传输代替定时器中断解放CPU。改善波形质量如果波形有台阶感可考虑使用插值算法如果高频时波形失真需检查定时器频率和代码执行效率是否够快。增加功能扩展为多波形方波、三角波发生器或加入频率扫描、幅度调制等功能。7. 常见问题与排查方法在电赛调试中90%的时间都在解决问题。下表汇总了本方案可能遇到的典型问题及解决思路。问题现象可能原因排查方式解决方案无波形输出1. DAC或定时器未正确初始化。2. 定时器中断未开启或未进入。3. 输出引脚配置错误。1. 检查CubeMX配置或初始化代码。2. 在定时器中断函数内设置断点或翻转一个测试引脚。3. 用万用表测量DAC输出引脚电压是否有变化。1. 核对参考手册确保外设时钟使能配置参数正确。2. 检查中断优先级和使能位。3. 确认GPIO模式配置为模拟模式DAC或复用推挽输出。波形频率不准1. 定时器时钟源或分频计算错误。2. 频率控制字计算有误。3. 系统主频未正确配置。1. 用示波器测量定时器更新中断的实际频率。2. 打印出计算的tuning_word值与理论值对比。3. 检查SystemClock_Config函数。1. 重新计算定时器ARR和PSC值。2. 核对DDS_SetFrequency函数中的计算公式注意数据类型和浮点运算。3. 使用STM32CubeMX重新生成时钟树配置。波形幅度不对1. DAC参考电压不是预期的3.3V。2. 幅度换算公式错误。3. 后端运放电路增益计算错误。1. 测量开发板上的VREF电压。2. 设置固定幅度值如DAC_MAX_VALUE/2看输出是否为1.65V左右。3. 单独测试运放电路。1. 确保供电稳定。有些板子VREF需单独连接。2. 修正DDS_SetAmplitude中的换算系数。3. 根据运放电路重新计算软件中的幅度映射关系。按键或显示不响应1. 按键去抖处理不当。2. 显示驱动时序错误。3. 主循环被阻塞。1. 用逻辑分析仪抓取按键波形。2. 检查LCD初始化序列和发送的数据。3. 在按键扫描和显示函数中插入调试灯或串口打印。1. 增加软件去抖或硬件电容滤波。2. 对照LCD数据手册严格遵循时序要求。3. 避免在主循环中使用长延时HAL_Delay改用状态机或定时器管理任务。高频时波形失真1. 定时器更新频率跟不上。2. 查表法输出速率达到极限。3. 代码执行时间过长。1. 提高定时器时钟或减小ARR值以提高中断频率。2. 考虑使用DMA或FPGA方案。3. 优化DDS_Update函数使用查表代替实时计算。1. 评估系统性能瓶颈必要时更换更高主频的MCU或使用FPGA。2. 使用DMA从内存向DAC自动传输数据不占用CPU。系统运行一段时间后死机1. 中断嵌套或优先级冲突导致死锁。2. 堆栈溢出。3. 看门狗未处理。1. 检查所有中断的优先级配置。2. 增大启动文件中的堆栈大小。3. 检查是否开启了看门狗但未及时喂狗。1. 合理规划中断优先级避免在中断中调用可能阻塞的函数。2. 优化局部变量减少递归调用。3. 若未使用看门狗则禁用它。8. 最佳实践与备赛建议基于以上分析和实现为电赛发挥部分准备提出以下建议模块化代码仓库提前构建自己的代码库将常用的驱动OLED、按键、ADC、DAC、PWM、编码器封装成独立的、接口清晰的模块。比赛时可以直接移植节省大量时间。掌握核心算法熟练掌握DDS、PID控制、数字滤波如均值、中值、卡尔曼、FFT等常用算法。理解其原理并能用C语言实现。善用调试工具串口调试是最重要的信息输出渠道用于打印变量、程序状态。逻辑分析仪分析SPI、I2C、UART等数字通信时序是否准确排查通信故障的神器。示波器观察模拟信号、测量频率、幅值、观察噪声。重视硬件可靠性电源为数字部分和模拟部分分别供电或做好隔离使用滤波电容。信号调理ADC前端加运放跟随、滤波电路DAC后端加运放驱动。布线竞赛中虽不要求PCB但杜邦线连接应整齐、牢固避免虚焊和短路。时间管理四天三夜的比赛合理规划时间。第一天确定方案、绘制框图、分配任务第二、三天实现主要功能并调试最后一天完善、优化、撰写报告。报告撰写报告是评分的重要依据。图文并茂框图、流程图、电路图、程序流程图、测试数据图表一个都不能少。突出方案创新点、理论计算和实测数据的对比。9. 总结与下一步应对电赛发挥部分核心在于系统性的分析和快速实现的能力。本文以“可调信号发生器”为例详细展示了从题目分析、技术选型、模块编码到系统调试的全过程。最关键的不是记住这段代码而是掌握这种“分解-实现-集成-验证”的方法论。对于下一步建议你动手复现找一块STM32开发板尝试将本文的DDS代码跑起来用示波器观察波形。尝试变种将正弦波改为方波或三角波尝试用PWM滤波电路实现DAC功能尝试用FPGA实现更高性能的DDS。拓展功能加入频率测量功能使用输入捕获做成一个简单的示波器或频谱分析仪。学习RTOS当系统任务复杂时引入FreeRTOS等实时操作系统来管理任务会让程序结构更清晰。电赛的魅力在于将理论知识转化为实实在在的、能工作的系统。希望这篇长文能为你提供一条清晰的路径助你在2026年电赛乃至未来的工程实践中更加从容地应对挑战。建议收藏本文在备赛过程中随时参考。