ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

2026电赛H题全复盘:信号链调测与队长生存指南

2026电赛H题全复盘:信号链调测与队长生存指南 电赛结束后的第一个晚上我把清单最后一栏“提交物”打上勾盯着桌面上那堆焊锡丝、杜邦线和示波器探头忽然意识到整个四天三夜里最累的不是哪一个模块而是“队长”这个角色。2026电赛H题完赛技术上的成就感确实很足但“干队长伤身体”这句话也是真话。这一篇文章不打算写成“模板题解”或者“获奖感言”。我想从带队完赛的角度把 H 题从备赛、方案设计、代码实现、调测排错到最后封箱的全过程拆开重点说清楚三件事H 题到底在考什么哪几个环节最容易让队伍翻车以及怎么把任务拆到队员手上既把题做完又能让队长少受点罪。如果你正在备赛或者刚打完一场硬仗准备复盘这篇文章可以直接收藏。1. H题在比什么把“信号链”三个字先刻进脑子里H 题在电赛里通常定位为系统类题目常见组合是信号测量、信号发生、数据采集与显示控制。这类题和纯硬件题、纯软件题都不一样它的核心特征是“软硬耦合”模拟前端出问题数字端看到的数据全是错的数字端时序出了问题模拟前端做得再干净也白搭。很多队伍第一天信心满满第二天开始怀疑人生原因就在这。从架构上看H 题绕不开下面这条链路输入信号调理 → ADC / 比较器 → 主控MCU/DSP → 计算处理 → 输出显示 / 控制信号。这条链路上的每一个环节都有自己的指标。信号调理决定输入端能不能把真实信号“翻译”成数字逻辑可识别的范围ADC 决定采样精度和速度主控决定算法能不能跑得过来显示和控制决定最终的人机体验。难点在于这些环节不是孤立的。我见过不少队伍把大量时间花在算法仿真上结果上电后一测发现 ADC 采集到的波形有台阶、有过冲、有直流偏置算法再漂亮也救不回来。反过来也有的队伍硬件调得很扎实但代码没有做临界条件保护数据一跳变就死机。所以 H 题真正的胜负手不是某一门科目学得有多深而是哪支队伍能在四天三夜里“少犯错”。哪支队伍能保证每个模块单独可测、每个接口都有明确约定、每个指标都有验证方法哪支队伍就能稳定完赛。2. 从题目到方案先把模块拆开再想集成拿到题目后的前两个小时是最影响后续节奏的。很多队伍上来就开焊、开写代码这是一个非常常见的误区。更稳妥的顺序是先做需求拆解再确定整体方案。2.1 把指标转换成可验证的模块需求不管当年的 H 题具体是什么你都可以从题目描述中提取出这几类信息输入信号的类型、频率范围、幅度范围需要实现的功能指标例如测量精度、分辨率、响应时间显示、交互、数据记录等附加要求供电方式和场地限制。把这些信息写在一张共享表格里然后给每个模块定义“输入是什么、输出是什么、可测指标是什么”。比如信号调理模块的输入是毫伏级正弦波输出是 0~3.3V 的摆幅那验收方式就是用信号发生器灌入固定幅值再用示波器测量输出是否在预期范围内。2.2 主控选型用熟不用新主控是整个系统的核心。STM32F103 和 STM32F407 是电赛里用得最多的选择资源资料多、库函数成熟、团队里一般也有人用过。如果手头的题目需要更多浮点运算或 FFTF407 或 H7 会更从容。这里有一条很实用的建议比赛期间不要轻易换主控平台。就算换的芯片性能更好重新迁移外设驱动、调试启动配置也要消耗大半天时间这笔账不划算。2.3 信号发生与测量方案先保证“能测准”再追求“能测快”测量类 H 题的常见难点是频率测量、幅值测量、波形识别。频率测量既可以用定时器输入捕获也可以用外部中断计数幅值测量既可以通过 ADC 采样计算也可以通过峰值检波电路配合 ADC 读取。比较推荐的方案是“模拟前端 主控内置 ADC 定时器捕获”的组合先用运放把信号调理到合适范围再用定时器捕获频率用 ADC 采集幅值。这套方案物料成本低、实现周期短、排查起来也直观。如果题目涉及信号发生比如需要输出正弦波或任意波形常见实现有 DDS 芯片如 AD9833或者 MCU DAC 查表输出。DDS 芯片的优点是频率稳定、相位连续缺点是初始化和配置要多写一点代码MCU DAC 的方案更灵活但输出频率上限受 DAC 速度和查询表大小限制。建议比赛前把两种方案的驱动都写好并验证过现场再根据题目选择。3. 环境准备工具、物料、开发环境一次配齐电赛最怕的不是题目难而是赛前工具没配齐比赛时花几个小时找一根杜邦线。这里列一份比较实用的清单可以照着检查。3.1 软件工具链STM32CubeMX用于生成初始化代码减少低级寄存器配置错误。Keil MDK 或 IAR主流的嵌入式编译环境。Keil 的工程配置相对简单IAR 的代码优化效果好一些选一个团队最熟的即可。串口调试助手或 Vofa、SerialPlot用于观察输出数据和波形。立创EDA 或嘉立创专业版如果赛前需要画 PCB这是最常用的工具。Git强烈建议搭建一个本地 Git 仓库不需要远程服务器本地分支就够用至少能避免“改坏代码没法回退”的悲剧。3.2 硬件工具与耗材万用表、示波器、函数信号发生器、直流稳压电源、逻辑分析仪这五样是电赛调试的必备设备。示波器要注意带宽至少要能覆盖题目信号频率的 5 倍以上。元器件方面常用的运放有 OPA2277、LMV358、TL072 等ADC 如果主控内置不够用可以考虑外部 ADC如 ADS1256 或 AD7606DDS 芯片准备 AD9833 即可显示部分可以用 OLED 或串口屏OLED 占用引脚少串口屏交互方便。所有主控板建议准备两块一块用来调代码一块备用防止现场烧坏。3.3 提前写好三份“保底驱动”赛前最重要的一件事是把三份基础驱动提前写好并验证过分别是ADC 多通道采集驱动、定时器输入捕获驱动、UART 打印驱动。这三份驱动是几乎所有 H 题都会用到的底层模块。提前写好意味着比赛开始后的前半天不用从零开始而是可以直接进入应用逻辑开发。4. 软件架构与关键代码实现嵌入式软件最大的坑是代码写到后期堆成一团调一个问题带动三个问题。为了避免这种情况建议从一开始就按照“底层驱动—模块接口—应用逻辑”三层来组织。4.1 文件结构与模块划分一个稳妥的工程目录结构大概是这样的Project ├─ Core │ ├─ Inc │ └─ Src ├─ Drivers │ ├─ CMSIS │ └─ STM32F4xx_HAL_Driver ├─ App │ ├─ app_main.c // 应用主循环 │ ├─ app_main.h │ ├─ adc_task.c // ADC 采集任务 │ ├─ freq_task.c // 频率测量任务 │ └─ display_task.c // 显示刷新任务 └─ Bsp ├─ uart_debug.c └─ led_indicator.cBSP 层放板级外设驱动App 层放每个功能模块Core 是 STM32 的标准库文件。这样划分的好处是每一个人负责的代码文件相互独立合在一起不至于冲突。4.2 ADC 采集模块用 DMA别用轮询如果使用 STM32 HAL 库ADC 采样建议优先采用 DMA 方式。DMA 可以自动把 ADC 转换结果搬到内存里主控不用在等待转换上浪费时间。下面是一个基于 STM32F407 的单通道 ADC DMA 采集示例可以直接作为工程模板。// 文件路径Bsp/adc_task.c #include adc_task.h #include main.h static ADC_HandleTypeDef hadc1; static DMA_HandleTypeDef hdma_adc1; static volatile uint32_t adc_value 0; void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc) { GPIO_InitTypeDef GPIO_InitStruct {0}; __HAL_RCC_ADC1_CLK_ENABLE(); __HAL_RCC_GPIOA_CLK_ENABLE(); __HAL_RCC_DMA2_CLK_ENABLE(); GPIO_InitStruct.Pin GPIO_PIN_1; GPIO_InitStruct.Mode GPIO_MODE_ANALOG; HAL_GPIO_Init(GPIOA, GPIO_InitStruct); hdma_adc1.Instance DMA2_Stream0; hdma_adc1.Init.Channel DMA_CHANNEL_0; hdma_adc1.Init.Direction DMA_PERIPH_TO_MEMORY; hdma_adc1.Init.PeriphInc DMA_PINC_DISABLE; hdma_adc1.Init.MemInc DMA_MINC_DISABLE; hdma_adc1.Init.PeriphDataAlignment DMA_PDATAALIGN_WORD; hdma_adc1.Init.MemDataAlignment DMA_MDATAALIGN_WORD; hdma_adc1.Init.Mode DMA_CIRCULAR; HAL_DMA_Init(hdma_adc1); __HAL_LINKDMA(hadc, DMA_Handle, hdma_adc1); } void Adc_Init(void) { hadc1.Instance ADC1; hadc1.Init.ClockPrescaler ADC_CLOCK_SYNC_PCLK_DIV4; hadc1.Init.Resolution ADC_RESOLUTION_12B; hadc1.Init.ScanConvMode DISABLE; hadc1.Init.ContinuousConvMode ENABLE; hadc1.Init.DiscontinuousConvMode DISABLE; hadc1.Init.ExternalTrigConv ADC_SOFTWARE_START; hadc1.Init.DataAlign ADC_DATAALIGN_RIGHT; hadc1.Init.NbrOfConversion 1; HAL_ADC_Init(hadc1); ADC_ChannelConfTypeDef sConfig {0}; sConfig.Channel ADC_CHANNEL_1; sConfig.Rank 1; sConfig.SamplingTime ADC_SAMPLETIME_84CYCLES; HAL_ADC_ConfigChannel(hadc1, sConfig); HAL_ADC_Start_DMA(hadc1, (uint32_t *)adc_value, 1); } uint16_t Adc_Get_Value(void) { return (uint16_t)(adc_value 0xFFFF); }这段代码的关键逻辑是初始化 ADC1配置 PA1 为模拟输入然后通过 DMA2 的 Stream0 循环搬运转换结果。由于 DMA 采用的是 circular 模式ADC 会不停采样无需 CPU 介入。上层逻辑只需要调用Adc_Get_Value()读取最新的值。注意如果你的芯片是 STM32F103 或其它系列DMA 通道和 ADC 通道映射可能不一样需要查阅对应数据手册。最稳妥的方式是先用 CubeMX 生成一个 DMA ADC 工程再把上面的逻辑对照着移植过去。4.3 频率测量模块用定时器输入捕获频率测量的思路很多门槛最低、稳定性最好的是定时器输入捕获。以 STM32F407 为例TIM2 的 CH1 可以配置为上升沿捕获每次捕获到一个上升沿就记录当前计数器的值。两次捕获的差值就是信号的周期周期取倒数就得到频率。// 文件路径Bsp/freq_task.c #include freq_task.h #include main.h static TIM_HandleTypeDef htim2; static volatile uint32_t last_capture 0; static volatile uint32_t period_ticks 0; void Freq_Timer_Init(void) { __HAL_RCC_TIM2_CLK_ENABLE(); htim2.Instance TIM2; htim2.Init.Prescaler 84 - 1; // 84MHz / 84 1MHz即 1us 计数一次 htim2.Init.CounterMode TIM_COUNTERMODE_UP; htim2.Init.Period 0xFFFFFFFF; htim2.Init.ClockDivision TIM_CLOCKDIVISION_DIV1; HAL_TIM_Base_Init(htim2); TIM_IC_InitTypeDef sConfigIC {0}; sConfigIC.Channel TIM_CHANNEL_1; sConfigIC.ICPolarity TIM_INPUTCHANNELPOLARITY_RISING; sConfigIC.ICSelection TIM_ICSELECTION_DIRECTTI; sConfigIC.ICPrescaler TIM_ICPSC_DIV1; sConfigIC.ICFilter 0x0F; HAL_TIM_IC_ConfigChannel(htim2, sConfigIC); HAL_TIM_IC_Start_IT(htim2, TIM_CHANNEL_1); } void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim) { if (htim-Instance TIM2) { uint32_t now HAL_TIM_ReadCapturedValue(htim2, TIM_CHANNEL_1); period_ticks now - last_capture; last_capture now; } } float Freq_Get_Hz(void) { if (period_ticks 0) { return 0.0f; } return 1000000.0f / (float)period_ticks; }关于这段代码有几个细节需要强调。Prescaler的值决定了计数器的分辨率84MHz 的系统时钟经过 84 分频后计数器每 1 微秒加一次。这样测量 1kHz 信号时周期大约是 1000 个 tick精度足够。另一个容易被忽略的是输入捕获的滤波配置如果信号有明显抖动在ICFilter里设置一个较大的值可以滤掉毛刺但要权衡延时频率很高时需要适当调低。4.4 调度器与显示刷新别在主循环里死等编写应用代码时最忌讳的是在一个 while 循环里用HAL_Delay()做同步等待。比如读取一次 ADC 等 10ms刷一次屏又等 100ms一旦某个环节耗时过长整个系统就会卡住。推荐用“非阻塞任务调度”的思路把周期性的任务拆开。// 文件路径App/app_main.c #include app_main.h #define TASK_ADC_PERIOD_MS 5 #define TASK_FREQ_PERIOD_MS 100 #define TASK_DISPLAY_PERIOD_MS 200 void App_Main_Loop(void) { uint32_t last_adc_time 0; uint32_t last_freq_time 0; uint32_t last_display_time 0; while (1) { uint32_t now HAL_GetTick(); if (now - last_adc_time TASK_ADC_PERIOD_MS) { last_adc_time now; uint16_t adc_val Adc_Get_Value(); Process_Adc_Data(adc_val); } if (now - last_freq_time TASK_FREQ_PERIOD_MS) { last_freq_time now; float freq Freq_Get_Hz(); Process_Freq_Data(freq); } if (now - last_display_time TASK_DISPLAY_PERIOD_MS) { last_display_time now; Display_Refresh(); } // 让出 CPU降低功耗 __WFI(); } }这是典型的“时间片轮询”思路。三个任务各自的周期不同互不阻塞。HAL_GetTick()返回系统启动以来的毫秒数只要注意溢出问题即可。实际上 32 位可以扛 49 天对一场比赛来说完全够用。5. 完整示例让一条信号测量链路跑起来有了前面几个模块我们就可以把它们串成一条完整链路。以一个典型的 H 题测量场景为例系统要做的事情是检测输入正弦波的频率和幅值并把结果显示在 OLED 或串口屏上。主循环的逻辑可以分为三步周期读取 ADC 值计算幅值读取定时器捕获结果计算频率把所有数据格式化后送到屏幕。为了方便调试建议先做一步串口打印而不是直接驱动显示。串口打印可以看到完整数据流定位问题的速度比看屏幕快得多。把 printf 重定向到 UART是嵌入式调试里最实用的操作。// 文件路径Bsp/uart_debug.c #include uart_debug.h #include stdio.h #include main.h extern UART_HandleTypeDef huart1; int fputc(int ch, FILE *f) { HAL_UART_Transmit(huart1, (uint8_t *)ch, 1, 50); return ch; } void Debug_Print_Measure(float freq, float volt) { printf(freq%.2fHz, vpp%.3fV\r\n, freq, volt); }打印出来的数据既可以看到频率是否稳定也可以看到幅值是否已经处理成有效值。建议在主控和显示模块联调之前先在串口里看到正确的数据。这一步能省下大量排查显示驱动的时间。当你把这些模块都运行起来后验证成功的标准很简单用函数信号发生器输入一个已知的信号比如 1kHz、1Vpp 的正弦波串口打印出来的频率误差在 1% 以内幅值误差在允许范围内就说明整条链路是通的。接下来再优化精度比一开始直接追求高精度要容易得多。6. 调测顺序与效果判断先电源再时钟最后才是算法比赛期间很多队伍在“调测”这个环节浪费了大量时间。一上来就测算法结果算法每次输出都不对绕了一圈才发现是某个模块的供电有问题。这里推荐一个固定调测顺序每一步都有明确的退出标准。6.1 第一步电源与硬件静态检查上电前先测电源轨确认电压没有明显跌落、电流没有异常偏大。用手摸一下主控、运放是否异常发烫。很多莫名其妙的问题最后都出在电源纹波大或地线接触不良上。6.2 第二步时钟与基本外设先用示波器确认主控晶振起振然后看 GPIO 是否能正常翻转。如果这一步不通过后面所有测试都没有意义。6.3 第三步模拟前端静态值给一级运放输入一个固定直流电压用示波器量运放输出是否符合预期。如果直流偏置都不对交流信号进来之后只会更乱。6.4 第四步数字端数据链路用信号发生器输出一个稳定的方波或正弦波然后用串口打印 ADC 数据或频率值确认主控读到的数据跟示波器观察到的波形一致。这一步是“软硬验证”的关键节点。6.5 第五步算法与显示前四步都通过后再进入算法调优和显示联调。此时你已经有把握数据从输入到 MCU 是正确的剩下的问题只会在算法逻辑或显示驱动里排查范围一下子缩小了很多。调测阶段的另一个建议是每调通一个模块就在共享表格里打一个勾。人的记忆在高压状态下不可靠表格比脑子靠谱。7. 常见问题与排查思路四天三夜不可能不遇到问题真正拉开差距的是遇到问题后的排查速度。下面这张表格总结了 H 题调试中最常见的几类问题和处理思路。问题现象可能原因排查方式解决方案串口打印乱码晶振频率与代码配置不一致查看系统时钟配置和串口波特率用 CubeMX 重新配置系统时钟和 UARTADC 读数始终偏高或偏低参考电压不稳或前端偏置错误用万用表量参考电压对照原理图检查 REF 引脚增加退耦电容频率测量抖动大输入信号边沿抖动或滤波配置不当示波器观察波形毛刺调整输入捕获的 ICFilter增加施密特整形上电后程序不运行启动文件缺失或 BOOT 引脚错误检查下载器连接和 BOOT 状态重新配置启动文件检查 BOOT0 电平OLED 显示花屏I2C/SPI 时序不正确或电平不匹配用逻辑分析仪抓取通信波形降低通信速率检查上拉电阻部分数据偶尔丢失中断优先级冲突检查中断优先级分组为关键外设设置更高优先级一插信号线就死机输入过压或静电损坏 IO测量输入端电压增加钳位二极管和限流电阻这里最想强调的一行是“参考电压”。ADC 测量的精度很大程度上取决于参考电压是否稳定。如果主控的 VREF 直接接到了电源而电源本身纹波很大那么 ADC 读数跳变几乎是必然的。解决方法是加一个高质量的参考电压源芯片或者在 VREF 引脚附近并联一个低 ESR 的陶瓷电容。很多“明明硬件没问题代码也没问题但就是测不准”的情况最后都栽在参考电压上。8. 干队长伤身体任务拆解、节奏管理与防翻车原则说了这么多技术内容终于要回到标题那句话干队长伤身体。这句话并不是玩笑。队长在比赛里承担的角色往往是一个“人形集成调试器”队员遇到问题找他硬件和软件对接找他文档封箱还是找他所有的信息都汇到一个人身上。如果这个状态持续四天身体不出问题才怪。但我观察到一个规律优秀队长和普通队长之间的差别并不在于谁更能熬夜而在于谁更能把任务拆出去。8.1 把“队长”拆成三个角色硬件负责人负责模拟前端、电源、传感器接口以及所有硬件指标的验证。软件负责人负责主控驱动、信号处理算法、显示和通信。文档与测试负责人负责写测试记录、保存每一次实验数据、整理封箱材料。队长可以兼任其中一个角色但绝不应该三头都管。核心原则是每个队员手里都必须有一个“可以独立验证”的子任务。有了子任务队员就有了明确的目标和成就感队长就不需要处理所有细节。8.2 用“里程碑”代替“全程盯守”不要把比赛当成连续 96 小时的无差别冲刺。更合理的时间安排是第一天中午前完成需求拆解和整体方案第一天晚上每个模块都开始有可以跑通的最小代码第二天晚上完成信号链路打通即“输入信号 → 串口打印”已经正确第三天晚上完成算法优化、显示和交互最后一天上午只做测试、记录、整理文档不新增功能。如果第四天还在改核心算法说明前三天某个环节出了问题。这时候队长的第一反应不是继续加班而是立即叫停新增需求保住已经实现的成果。比赛比的是“完赛”不是“炫技”在最后半天改一个没有充分验证的代码翻车概率远大于拿分概率。8.3 给队长的四条“保命”建议第一每四小时强制休息十五分钟别以为连续熬夜能换来更多产出连续工作到三十小时之后人的有效思考能力会明显下降。第二每一次修改代码前先备份不管是 Git 还是复制一份文件都行。第三遇到连续半小时解决不了的问题立即换一个思路比如把队员叫过来一起看很多时候三个人盯着屏幕比一个人死磕有用。第四睡前把明天要做的三件事写下来哪怕只写一句话都行第二天醒来就不会因为“不知道从哪开始”而焦虑。9. 最后一夜该做什么文档、封箱与现场应变最后一天的状态往往决定你能拿什么奖。很多队伍在最后一天还在焊板子、改代码最后交上去的文档却只写了半页这是非常可惜的事情。电赛的评审不仅看功能还看文档和现场演示。功能一样的队伍文档更完整、演示更流畅的那一支分数往往会更高。封箱前建议制作一个“自查清单”至少包含以下几项系统电源是否正常多次重启后是否能复现同样的功能所有关键测试数据是否已经截图保存代码是否已经烧录到板载 Flash且断电重启后可以直接运行文档中是否描述了系统架构、模块划分、测试方法和测试结果备用板和工具是否已经分类装好方便现场快速取用。现场演示环节最容易翻车的不是功能实现而是“演示的时候没反应”。原因多半是接线松动、电源没插紧或者程序还停留在调试模式。建议在正式封箱之前完整走一遍“断电 → 重新上电 → 自动运行 → 展示结果”的全流程。如果断电重启后系统能直接工作现场基本就稳了。10. 总结与后续学习方向打完 2026 电赛 H 题最值得记住的经验其实不是某个具体电路而是一套“如何完成复杂系统”的方法先拆需求再定方案然后让每个模块单独可测最后按固定顺序完成系统集成。这个流程不只适用于电赛以后做毕业设计、实习项目、甚至工作里的硬件开发都是同一个套路。如果还想继续深入建议重点关注三个方向。第一嵌入式实时系统的设计和调试方法尤其是中断管理、DMA 和任务调度第二信号处理基础包括有限冲激响应滤波、快速傅里叶变换以及如何用 DSP 库完成运算第三模拟前端的设计能力因为很多系统级问题最终都出在信号调理和抗干扰上。下次比赛如果还要当队长记得备好眼药水、耳塞和一个“强制休息提醒”的定时器。干队长确实伤身体但把方法理顺了至少能把伤害控制在一个可持续的范围内。
返回列表