电赛H题队长生存指南:从ADC采样到FFT的完整软硬件打法
2026 电赛 H 题对很多队伍来说不是“选哪道题”的问题而是“选完之后怎么活着完赛”的问题。尤其是作为队长你会在比赛后半程发现一个扎心事实你既要做技术决策又要管进度还要协调队员情绪最后可能还得亲自去焊板子。标题里那句“干队长伤身体”我太理解了——这不是自嘲而是很多队伍在赛前没有把队长的职责拆清楚最后把压力全压到一个人身上的必然结果。这篇文章不谈具体题目答案而是给你一套从队长视角出发的完整打法H 题到底适不适合你的队伍、赛前几周该准备什么、四天三夜的时间怎么分配、哪些模块代码必须提前写好、遇到故障怎么排查。文中的代码以 STM32F407 配合 HAL 库为例覆盖 ADC 采集、FFT 频率计算、串口调试和 OLED 显示这也是 H 题里“测量检测类”方向最常见的软件底座。1. 为什么偏偏是 H 题以及队长为什么容易“伤身体”先说判断H 题在多数赛区的题目方向上属于典型的“仪器仪表题”。题干里经常出现“测量”“检测”“显示”“记录”这些关键词。它和小车、无人机、电源题有一个明显区别——对机械结构要求不高但对信号采集、处理精度和系统稳定性要求很高。这个特点会带来一个隐藏问题H 题的失败往往不是某一个模块彻底不工作而是模块之间互相干扰。比如 ADC 采样率不够导致波形失真前端信号调理电路存在直流偏置导致 FFT 结果有误差OLED 显示刷新占用太多 CPU 时间导致采样丢点。这种问题最折磨人因为从板子表面看不出任何异常但数据就是不对。所以“干队长伤身体”的第一个原因是 H 题的知识跨度太大。队长不仅要有写代码的能力还得看得懂运算放大器电路会在示波器上判断信号质量甚至还要学会快速焊接和飞线。很多队伍默认为“队长技术最强的人”结果所有难点都流向队长一个人从 Day1 开始就陷入连轴转。如果不改变这种角色认知队长再强也会被拖垮。正确的做法是队长不一定是代码写得最好的人但必须是最能判断“哪里会出问题、什么时候必须砍需求”的人。后面几个部分我会围绕这个定位展开。2. 备赛阶段把三个最小系统提前跑通很多人以为电赛是四天三夜的冲刺但真正决定完赛率的是赛前几周积累的“技术底座”。对于 H 题方向我建议备赛阶段至少跑通三个最小系统最小采集系统、最小处理系统、最小显示系统。这三个系统之间用清晰的接口连接到了赛场上只是换题目参数而不是重新发明轮子。2.1 队伍分工建议电赛三人队建议按“软、硬、测”来分工角色主要职责需要掌握的工具队长兼任软件接口方案决策、进度控制、接口定义、最终联调STM32CubeMX、Git、示波器硬件队员原理图、焊接、电源、信号调理电路Altium Designer / 立创EDA、万用表软件队员算法、显示、按键、状态逻辑Keil / STM32CubeIDE、串口助手这里不建议把“算法”和“显示”分给两个人做因为 H 题的显示和按键往往要跟着测试流程反复改接口很容易变。更合理的分工是一个人负责采集和信号处理算法一个人负责显示与交互逻辑队长负责把两者黏合起来同时盯测试指标。2.2 主控与器件选型H 题的测量检测方向主控首选带有 DSP 指令和 FPU 的 STM32F4 系列例如 STM32F407VET6。做 FFT 时FPU 和 DSP 库能明显减少计算时间。STM32F103 也不是不能用但频率和 ADC 等效位数都有限遇到需要同时测频率、幅值、相位差的情况会比较吃力。前端调理电路建议按信号发生器输出或传感器输出两种场景分别准备信号源直接输入用运放搭建电压跟随器或同相放大电路做好输入保护防止超压损坏 ADC。传感器小信号输入需要仪表放大器例如 AD620先把信号放大到 ADC 合适的量程范围。电源部分不要省。电赛现场供电环境不一定干净建议准备一路精度较高的 3.3V 稳压常用 AMS1117-3.3并加上 10uF 和 100nF 电容做滤波。如果用 DC-DC 模块要确认纹波不会影响 ADC 采样。2.3 三个最小系统的验收标准最小采集系统信号发生器输出 1kHz、2Vpp 正弦波ADC 通过 DMA 连续采样串口能打印出稳定的原始波形数据数值幅度和峰峰电压匹配。最小处理系统对采集到的正弦波做 FFT串口输出频率值误差在 1% 以内。最小显示系统OLED 或 TFT 能稳定刷新频率和幅值不出现闪烁、乱码。这三个系统中任何一个不能稳定运行都不要急着进入下一阶段。赛前多花一天调稳它们胜过赛场上通宵两天。3. 核心代码示例采集、处理、显示、调试下面给出四个核心模块的参考代码。代码以 STM32F407 HAL 库为背景使用 STM32CubeMX 生成基础工程后按文件添加逻辑。3.1 ADC DMA 连续采样H 题测量类题目里最忌讳在主循环里用阻塞方式读 ADC因为显示和按键会打断采样。推荐用 ADC DMA 循环模式让 ADC 持续把采样结果写入内存。// 文件adc_dma.c #include main.h #define ADC_SAMPLES 1024 static uint16_t adc_buf[ADC_SAMPLES]; void ADC_Init_With_DMA(void) { // 前提由STM32CubeMX生成ADC1、DMA、USART1配置 // ADC1_IN1 - PA1采样时间设置为最大DMA模式为Circular HAL_ADC_Start_DMA(hadc1, (uint32_t *)adc_buf, ADC_SAMPLES); } uint16_t Get_ADC_Value(uint16_t index) { if (index ADC_SAMPLES) { index ADC_SAMPLES - 1; } return adc_buf[index]; }这段代码的逻辑是DMA 不停地把 ADC 转换结果搬到内存数组里主循环随时可以读取最新数据。这样 FFT 或者其他算法拿到的数据是“最近一段时间”的连续波形而不是每次单独触发采样的离散点。真正容易踩坑的地方在 CubeMX 配置ADC 的连续转换模式必须打开DMA 模式必须选 Circular否则数组只会填充一次。3.2 FFT 频率计算测量类题目最核心的需求之一就是算频率。STM32 官方 DSP 库里提供了arm_cfft_f32函数可以直接对实数序列做 FFT。// 文件fft_process.c #include fft_process.h #include arm_math.h #include arm_const_structs.h #define FFT_SIZE 1024 #define SAMPLE_RATE 10000 // 采样率根据输入信号频率范围调整 static float32_t fft_input[FFT_SIZE * 2]; static float32_t fft_output[FFT_SIZE / 2]; float Estimate_Frequency(uint16_t *adc_buf, uint16_t *amp_out) { uint32_t i; float32_t max_val 0; float32_t freq 0; uint32_t max_index 0; // 去掉直流分量 for (i 0; i FFT_SIZE; i) { fft_input[2 * i] (float32_t)adc_buf[i] - 2048.0f; fft_input[2 * i 1] 0.0f; } // 1024点实数FFT arm_cfft_f32(arm_cfft_sR_f32_len1024, fft_input, 0, 1); arm_cmplx_mag_f32(fft_input, fft_output, FFT_SIZE / 2); // 跳过直流点找峰值位置 for (i 2; i FFT_SIZE / 2; i) { if (fft_output[i] max_val) { max_val fft_output[i]; max_index i; } } freq (float32_t)max_index * (float32_t)SAMPLE_RATE / FFT_SIZE; if (amp_out ! NULL) { *amp_out (uint16_t)(max_val * 2.0f / FFT_SIZE * 3300.0f / 4096.0f); } return freq; }这里有一个关键点FFT 的频率分辨率是采样率 / FFT点数。如果采样率是 10000HzFFT 点数 1024那么分辨率大约是 9.77Hz。这个精度对低频信号可能不够。遇到低频高精度题目时要么降低采样率要么增大 FFT 点数到 2048 或 4096要么改用过零检测先粗算频率再用 FFT 做精细校正。赛前最好把这两种方法都准备好。3.3 串口调试与 printf 重定向没有日志的电赛调试就像闭眼开车。在嵌入式里最方便的调试手段就是串口。Keil 和 STM32CubeIDE 下都习惯用 printf 输出只需要重定向fputc。// 文件uart_debug.c #include main.h #include stdio.h extern UART_HandleTypeDef huart1; int fputc(int ch, FILE *f) { HAL_UART_Transmit(huart1, (uint8_t *)ch, 1, 0xFFFF); return ch; } void Debug_Print_Task(void) { // 周期调用串口助手可看到频率和幅值 printf(freq %.2f Hz, amp %d mV\r\n, g_freq, g_amp); }用法很简单在 CubeMX 里把 USART1 配置成 115200-8-N-1在 Keil 的 Target 选项里勾选 Use MicroLIB就能直接使用 printf。比赛现场建议所有调试消息统一格式比如freqxxx ampxxx方便用串口助手的“字符串过滤”功能快速定位问题。3.4 OLED 显示与按键状态切换显示模块建议赛前选型后直接固定用同一个库。下面以 SSD1306 OLED 的单色屏为例展示如何显示结果。注意不同商家的 OLED 模块接线不一样使用前先确认 I2C 或 SPI 接口顺序。// 文件display_key.c #include ssd1306.h #include stdio.h void OLED_Show_Result(float freq, uint16_t amp) { char line[32]; sprintf(line, Freq:%.2fHz, freq); SSD1306_GotoXY(0, 0); SSD1306_Puts(line, Font_7x10, 1); sprintf(line, Amp:%dmV, amp); SSD1306_GotoXY(0, 20); SSD1306_Puts(line, Font_7x10, 1); SSD1306_UpdateScreen(); }按键扫描建议放在一个 1ms 到 5ms 的定时器中断里做去抖避免在主循环里用延时等待按键松开。去抖逻辑并不复杂连续读到同一电平持续 10ms 以上才认为按键状态有效。这样显示刷新和按键扫描不会互相阻塞。4. 硬件接线与测试验证代码写得再漂亮硬件接线错误一样白费。比赛现场建议提前打印一张接线表每个模块的信号线、电源线、地线都标清楚。4.1 典型接线方式这里给出一个常见的连接方案具体要以你手上的模块原理图为准模块引脚STM32F407 引脚信号输入经调理电路OUTPA1 (ADC1_IN1)OLED (SPI模式)SCKPB13OLEDMOSIPB15OLEDDCPB14OLEDCSPB12OLEDRSTPB10按键1OUTPE0按键2OUTPE1实际比赛时很多队伍会因为杜邦线接触不良而浪费几个小时。有条件的话信号链路尽量用焊接或者短粗的跳线电源线尽量用红黑两色区分地线要共地。ADC 输入端的信号地、电源地、单片机地一定要接到同一个参考点。4.2 验证结果是否正确在赛前验证阶段用信号发生器输出已知频率的正弦波例如 1kHz、2Vpp。然后看三处数据是否一致示波器观察 ADC 引脚的波形确认没有明显削顶和噪声。串口打印的原始 ADC 值统计最大值和最小值电压换算后应接近信号发生器设置的幅度。串口打印的 FFT 频率应落在 1kHz 附近。如果串口显示频率偏差超过 1%第一步检查采样率配置是否和代码里的SAMPLE_RATE一致。这是 H 题信号测量类错误里最常见的一种CubeMX 里定时器触发采样频率写的是 10000代码里预估的采样率却是 12000结果所有频率都按比例偏移。5. 四天三夜的推进节奏电赛的时间看起来有接近四天但真正高效的窗口只有前两天。如果前两天没把主流程跑通后面基本靠补丁过日子。5.1 赛前最后一天不要留到比赛当天早上才清点物料。工具、芯片、屏幕、传感器、下载器、备用杜邦线全部装进箱子。另外把常用驱动库、数据手册、参考代码传到 git 仓库并同步到每位队员电脑。现场网络不一定可靠不要依赖在线下载。5.2 Day1读题与方案收敛上午花两小时读题列出所有功能点和测试指标把题目要求拆成“必须满足”和“加分项”。中午之前必须确定整体方案队长拍板。H 题最容易犯的错误是方案内部分歧太多有人想用 FPGA有人想用 STM32到了晚上还在争论。下午把模块接口定下来比如 ADC 采样率、FFT 点数、显示刷新频率、按键功能定义。晚上结束前硬件队员至少完成电源和最小系统验证软件队员至少能在开发板上点亮屏幕。5.3 Day2软硬件并行第二天是效率最高的一天。硬件队员焊接前端调理电路并调试输出波形软件队员把采集、FFT、显示、按键四个模块单独调通。这里的诀窍是“先分后合”每一对接口都单独验证不要等所有模块都写完才联调。晚上收工时必须看到一块完整的链路数据从采集到屏幕的显示。如果还没有说明进度已经落后。5.4 Day3联调与优化第三天所有精力放在整机联调上。把题目里的每一条测试要求都跑一遍记录实际数据。不要只听队员说“软件看起来没问题”要用串口和示波器核对。这个时候发现的问题大概率是电源噪声、地线环路或者时序冲突导致的需要队长做出判断是花两个小时彻底解决还是先用一个妥协方案保证能交卷。5.5 Day4测试、文档、封箱最后一天上午不再加新功能。把能拿分的测试项反复跑三遍确认数据稳定。然后花一小时整理测试记录和演示视频把原理图转成 PDF把代码的关键注释补好。评测现场不需要你把代码写得像开源项目但关键接口要有注释评委问起来你能说清楚。6. 常见问题与排查思路比赛中最浪费时间的事情是反复试错而不是系统排查。下面这张表是 H 题信号测量方向最高频的几类问题建议打印出来贴在桌上。问题现象可能原因排查方式解决方案串口打印频率一直为 0FFT 输入数据没有更新检查 DMA 是否工作在 Circular 模式在 main 循环里打印 adc_buf[0] 确认数值在变化频率结果是理论值的两倍实信号 FFT 后正负频镜像确认只取 0 到 N/2 的索引不要拿整个 fft_output 数组找最大值输入 1kHz 信号显示 1.2kHz采样率配置与代码不一致用示波器对比触发频率统一 CubeMX 定时器配置和SAMPLE_RATE宏ADC 数据跳变很厉害电源纹波大或接线过长示波器观察 ADC 引脚波形添加 100nF 去耦电容缩短地线OLED 花屏或闪烁SPI 速率过高或供电不稳降低 SPI 分频系数调整 CubeMX 里 SPI BAUDDIV 至 4 或 8按键按下没反应没有做去抖或引脚上拉配置错误用万用表测按键引脚电平变化开启内部上拉添加 10ms 去抖程序下载失败SWD 引脚被占用或供电不足检查接线和 3.3V 电压复位状态下尝试下载必要时擦除 Flash这里每个问题都有对应的排查手顺。比赛现场不要一拍脑袋就改代码先确认信号链路的每一级数据是否正确。串口保存的原始值是最重要的诊断入口。7. 队长如何“少伤身体”避坑清单与协作原则队长不应该是那个最后把所有代码合在一起、然后通宵改 bug 的人。想让队伍高效必须建立几项最基本的协作约束。7.1 每天固定站会每天早晨和晚上各花 10 分钟每个人说三件事昨天完成什么、现在卡在什么、今晚打算做什么。这个动作不需要正式文档但能强迫队员自己盯进度。很多队伍输在信息不同步硬件队员以为软件已经支持某功能软件队员还根本不知道有这个需求。7.2 关键节点必须留备份比赛开始前每个人电脑上都应该有一份能编译通过的工程。比赛过程中每完成一个可运行版本就提交一次 git提交信息写清楚“ADC DMA 采集调通”“FFT 频率误差修正”。最后一天如果代码改崩了可以随时回退到上一个正常版本而不是所有人围着屏幕找 bug。7.3 学会砍需求电赛评审看的是完成度不是功能数量。如果某个加分功能到 Day3 傍晚还不稳定队长必须果断决定放弃把人力抽回来保住基础功能。这个决策很残酷但很现实。砍掉一个不稳定模块通常比继续投入时间更有利于总分。7.4 保证基本休息连续熬夜只会让判断力下降。最理想的节奏是每人每天至少有 4 到 6 小时睡眠采取“轮班互补”的方式硬件队员后半夜休息软件队员白天补觉。队长尤其不能全程死扛因为最后一天的测试和评审提问还需要你保持清醒。7.5 准备一个救急包多备一片同型号主控、一块 OLED、两根下载器、几片 AMS1117、一把杜邦线、一小卷焊锡丝。这些东西不占地方但关键时候能救全队。去年有支队伍就是因为现场烧了下载器又没人带备用硬生生浪费了两个小时。8. 现场心态与突发状况应对比赛现场一定会发生计划外的事。常见的包括队友因为压力吵架、模块突然烧掉、题目里有一个参数理解错、测试设备故障。作为队长你的情绪稳定程度直接决定队伍下限。读题阶段如果对参数有疑问第一反应是去查官方提供的数据手册或者问赛区志愿者不要在网上找版本不一的二手信息。硬件出现不可解释的问题时优先怀疑电源和接线其次怀疑程序逻辑最后才怀疑芯片坏了。千万不要在比赛现场临时换主控平台。从 STM32 换到 FPGA或者从 HAL 库换成寄存器写法都属于伤筋动骨的变化。如果发现现有方案性能不够优先优化算法和采样策略而不是更换技术路线。9. 完赛之后文档和复盘比成绩更重要交完作品之后队长最想做的事一定是睡觉。但睡醒之后我建议你花半天时间做三件事把最终代码完整备份并写明版本把整理好的原理图和接线图发给每位队员和指导老师再写一份简短复盘记录方案选型的原因、踩过的坑、以及如果再做一次会在哪里改进。这些东西看起来和成绩无关但对下一年参赛的队员来说是宝贵的资料。H 题的核心竞争点从来不在赛场上那四天而在赛前有没有把采集、处理、显示、调试这套底座彻底吃透。只要底座稳明年换什么题目你都有翻盘的底气。如果你决定带队冲 H 题从现在开始就把三个最小系统拿出来练。等你能在半小时内熟练配置 ADC DMA、跑通 FFT、点亮屏幕你就已经比大多数队伍领先一个晚上的睡眠了。
上一篇/下一篇内容由系统自动关联
返回资讯列表 →