尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

电赛G题代码方案:从拆题到联调的完整工程实践

电赛G题代码方案:从拆题到联调的完整工程实践 简介面向2025全国大学生电子设计竞赛信号类赛题这份代码包为G题《电路模型探究装置》提供了从基础到发挥部分的完整实现思路。方案覆盖传递函数计算、RMS有效值检测、VGA增益控制并给出基于LMS算法学习未知电路传递函数、结合FIR数字滤波与查表法判断滤波器类型及信号重建的进阶做法。包体规模小巧共3个文件包含HTML说明页、inscode代码文件及.gitignore配置压缩后仅13KB便于下载后直接查看核心程序和电路设计要点。已有327人学习/浏览适合正在备赛信号类题目的学生参考。资源价值在于既包含基础题目的软硬件协同调试细节也提供了拓展部分的算法创新路径同时附录了实战评审中突发问题的处理经验可帮助读者快速理解赛题难点和备赛重点。 每年电赛结束后技术社区里都会冒出一批复盘帖其中最常见的一句话是硬件调通了算法也推出来了代码却拖到最后一天才磕磕绊绊跑通。我自己带队和参赛的经历里见过太多队伍倒在软件这一关真不是代码有多难而是没有一套从拆题阶段就开始推进的组织方法。2025年G题的方向不管怎么变测控类题目的共性都在那里——采集、控制、显示、交互。代码方案怎么组织直接决定四天三夜里你的睡觉时间和最终成绩。这篇不押具体考题赛题每年都会换而是把一套能在G题里直接落地的代码方案完整讲一遍从拿到题目怎么拆模块到工程怎么搭、驱动怎么写、算法怎么落再到联调排错有哪些规律可循。准备参赛的队伍可以直接照这套思路搭自己的代码框架做嵌入式项目或者课程设计的同学也能从中找到一套通用的工程组织方法。1. 拿到G题别急着敲键盘花半天时间把题目拆成代码任务1.1 赛题拆解先画数据流再定代码边界G题这类测控题本质上就是一条数据链路传感器把物理量变成电信号单片机把电信号变成数字量做处理然后输出到执行器同时把状态甩到屏幕上。拿到题的第一天上午别碰键盘先拿张纸把这条链路画出来。我们队当时的做法是拆成“输入—处理—输出”三层输入层列出所有传感器和按键处理层写出需要解算的状态量输出层列出屏幕显示内容和执行器动作。画完这张图代码要做的事就有了一大半。这种拆法最大的好处是让硬件和软件在第一时间对齐接口。比如输入层有一个模拟量传感器硬件决定用运放放大后接ADC那代码里就要有对应的ADC采集任务如果硬件说这个信号在电路上已经做了比较器输出高低电平那它就根本不需要ADC驱动只要读一个GPIO。很多队后期反复改代码就是因为刚开始没做这层拆解软件一直在跟着硬件改动打补丁。1.2 指标到代码的映射表每一条题目要求都要有人负责拆完链路后要把题目里的硬指标翻译成代码参数。比如“温度控制误差不超过±1℃显示刷新率不低于5Hz”翻译过来就是ADC采样的有效位数够不够、滤波时间常数会不会拖慢响应、控制周期该取多少毫秒、屏幕刷新用全屏还是局部刷新。我们队常用一张表把指标对应到代码模块题目里每个指标都至少有一个模块在负责题目指标负责模块关键参数采样精度±0.5℃adc.c filter.c12位ADC 16次均值滤波控制响应时间2scontroller.c控制周期100ms屏幕刷新率≥5Hzui/screen_home.c局部刷新避免全屏重绘按键不误触发driver/key.c状态机消抖窗口20ms这张表里最有价值的是“关键参数”这一列它逼着你在写代码之前就想好具体数值而不是到时候凑合。我们有一项指标是刷新率一开始没定参数后来全屏重绘一次界面卡了快400ms刷新率连2Hz都不到改成局部刷新才救回来。1.3 软硬分工的边界能把代码解决的尽量往软件搬拆解时还要判断一件事哪些任务是硬件兜底哪些必须靠软件补。比如电源纹波大导致ADC值抖动硬件加电容能改善软件加数字滤波也能压下去按键按下瞬间的抖动硬件RC能消软件状态机也能消。这个分工要提前和硬件队友定死否则就会出现两边都在做、两边都没做透的情况。我个人的建议是凡是能用代码低成本做到的事尽量往软件搬。因为比赛现场硬件改版代价高代码改起来相对便宜。但反过来如果硬件能用一个运放解决信号调理问题也别指望代码里写一堆复杂算法去代偿嵌入式芯片的算力有限把简单问题复杂化只会增加调试负担。拆题阶段多花半天后面三天少熬一个通宵绝对值。2. 代码架构怎么搭三人同时开发不乱套的工程布局2.1 裸机状态机构架别一上来就上RTOS很多队伍一看“控制系统”就想着上RTOS我见过不少队伍在比赛第三天还困在任务优先级和信号量的问题上。G题的工作量其实用裸机主循环加状态机完全能扛住。状态机的思路是把系统运行过程拆成几个稳定状态每个状态下只做固定的事状态切换由事件触发。一个典型的控制系统可以分成“初始化、待机、运行、报警”四个状态主循环只负责查事件、切状态、执行当前状态的任务。裸机状态机的最大优势是可控性强出现bug时顺着状态转移和事件表就能查不会遇到“线程卡死”这类玄学问题。当然裸机也有代价主循环不能被某个耗时操作堵住否则按键响应和显示刷新都会卡。解决思路在后文驱动部分会细说所有耗时的操作尽量用“分片执行”或“非阻塞”的方式去写。2.2 目录和接口先定好代码才是可并行的三个人同时写几千行代码最大的噩梦就是“你改你的我改我的合到一起崩了”。要避免这个问题工程的目录结构和模块接口必须在动手前固定下来。这是我们当时用的布局Project/ ├── main.c ├── sys/ │ ├── clock.c │ ├── clock.h │ └── uart_debug.c ├── driver/ │ ├── key.c │ ├── lcd.c │ ├── adc.c │ └── pwm.c ├── algorithm/ │ ├── filter.c │ ├── controller.c │ └── calibration.c └── ui/ ├── screen_home.c ├── screen_setting.c └── screen_home.h每个目录对应一个队员负责.h文件就是队员之间的契约。比如负责UI的人只需要知道adc.h里有一个uint16_t adc_read_mv(void)函数至于它是怎么采样、怎么滤波的完全不用关心。负责算法的人只要从driver层拿到原始数据处理完通过结构体丢给UI层就行。各层之间数据流向从main.c一眼就能看懂不怕被某个队友随手改乱。2.3 数据流接口单位不统一联调必翻车模块接口里最容易出问题的不是函数名而是数据类型和单位。就拿温度来举例有人用原始ADC码值传递有人用标定后的浮点温度传递还有人用温度乘以10的整数传递。三种格式混在一个工程里联调的时候一定出问题。我们队当时约定所有跨模块的物理量一律用整数温度用“摄氏度乘以100”表示电压用mV表示任何模块需要浮点运算就自己内部转换。这个约定看起来小效果却立竿见影。ADC的原始码值只允许出现在driver层一旦经过algorithm层的标定后面所有模块用的都是统一单位。关键的全局结构体也要提前写好比如typedef struct { int32_t temperature_x100; uint16_t adc_raw; uint8_t key_event; } MeasureData;每个成员都按同一个结构体取数据就再也不用反复问“你那个变量是啥单位”了。所有跨模块传递的物理量必须统一单位和数值格式。这个约定越早定越好。3. 驱动层代码逐个击破从按键防抖到TFT圆弧的完整链路3.1 按键防抖状态机消抖比延时消抖靠谱得多按键是G题里最常见的输入方式也是容易被忽略的代码坑。很多新手喜欢按下检测到低电平后delay20ms再判断一次这在主循环里是非常糟糕的写法——CPU被卡住20ms显示刷新和ADC采样都会被拖慢。正确姿势是状态机消抖不阻塞CPU按键只在状态翻转后返回一次有效事件uint8_t key_scan(void) { static uint8_t state 0; static uint16_t cnt 0; uint8_t level HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin); uint8_t event KEY_NONE; switch (state) { case 0: /* 等待按下 */ if (level 0) { state 1; cnt 0; } break; case 1: /* 连续读到低电平才生效 */ if (level 0) { if (cnt 10) { state 2; event KEY_PRESS; } } else { state 0; } break; case 2: /* 等待释放 */ if (level 1) { state 0; } break; default: state 0; break; } return event; }这个函数在主循环里每次被调用只跑几个if几乎不耗时。10次连续采样大概对应10到20ms的消抖窗口实测下来误触发和漏触发都很少。还有一点容易被忽略按键事件处理完后要及时清掉否则主循环里同一个事件会被执行多次。3.2 TFT显示先封装底层绘图再谈界面TFT屏幕在G题里也是常客。新手拿到屏幕驱动第一反应就是复制整屏图片或者调用现成GUI库实际上裸机环境下自己封装几个底层函数就够了画点、画线、画矩形、显示字符串。所有界面都是这四个函数的组合。那类“TFT屏幕绘制圆弧”的需求本质上也只是画点函数的循环调用。比如要画一个圆环仪表盘上的圆弧可以按角度步进采样坐标点把落点画出来void draw_arc(uint16_t cx, uint16_t cy, uint16_t r, int16_t start_deg, int16_t end_deg, uint16_t color) { for (int16_t d start_deg; d end_deg; d 2) { float rad d * 3.14159f / 180.0f; int16_t x cx (int16_t)(r * cosf(rad)); int16_t y cy (int16_t)(r * sinf(rad)); draw_pixel(x, y, color); } }角度步进取2度对320x240的屏幕已经足够平滑绘制100度左右的圆弧耗时也就十几毫秒。如果界面里有仪表盘、曲线、数字框就把它们拆成不同的刷新函数每个函数只重绘自己负责的区域屏幕刷新率自然就上去了。3.3 ADC采样与滤波均值滤波是最稳的起手式ADC采样是测控题的命根子。代码上最容易犯的错是“测一次就用一次”导致显示数值跳来跳去本文还有配套的精品资源点击获取
返回列表