【电赛保姆级教程】别在比赛时从零写代码了!电赛“祖传代码库”搭建与OLED多级菜单硬核指南

发布时间:2026/5/30 20:49:29

【电赛保姆级教程】别在比赛时从零写代码了!电赛“祖传代码库”搭建与OLED多级菜单硬核指南 前言全国大学生电子设计竞赛虽然是“四天三夜”的极限挑战但它本质上是一场开卷考试。因为比赛允许你携带以前写好的所有代码和模块如果你在发题后还在慢吞吞地去网上找 OLED 驱动、还在写带 delay() 的按键防抖逻辑你的比赛已经输了一半。真正的高手在赛前就已经备好了一套**“祖传代码库”比赛时只需要像搭积木一样调用。本文将手把手教你如何打造一套包含无阻塞按键状态机、OLED 丝滑多级菜单、Flash 掉电保存**的终极人机交互框架TOC一、 为什么你需要一套“人机交互”框架不管你选什么题到了测评现场评委都会提出这些要求电源题“同学把输出电压从 5V 调到 12V 给我看看。”信号题“把正弦波频率切换到 100kHz步进 10Hz。”控制题“小车先跑基础题代码再跑发挥题代码。”如果你只能靠拔插杜邦线、或者重新烧录代码来改变状态评委直接扣掉操作分。你必须拥有一个**“屏幕显示 按键调参”**的 UI 系统。二、 告别 delay无阻塞按键状态机核心源码初学者的按键防抖都是 if(KEY0) { delay_ms(20); if(KEY0) { ... } }。在复杂的电赛系统中这 20ms 的死等可能会让你的无人机直接坠毁让你的 ADC 丢失几十个采样点 进阶方案基于时间片的按键状态机将按键检测放入每 10ms 执行一次的定时器中断或时间片中。通过记录按键按下的“持续时间”轻松实现单击、双击、长按功能且0阻塞CPU。核心逻辑直接抄作业codeC// 定义按键状态枚举 typedef enum { KEY_STATE_IDLE 0, // 空闲 KEY_STATE_PRESS, // 刚按下(防抖确认) KEY_STATE_HOLD, // 持续按下(长按判断) KEY_STATE_RELEASE // 松开 } KeyState_t; uint8_t Key_Scan_SM(void) { static KeyState_t state KEY_STATE_IDLE; static uint16_t hold_time 0; uint8_t key_event 0; // 0:无动作, 1:单击, 2:长按 uint8_t key_val HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0); // 读取物理按键(假设低电平按下) switch (state) { case KEY_STATE_IDLE: if (key_val 0) { state KEY_STATE_PRESS; // 发生跳变进入防抖 } break; case KEY_STATE_PRESS: if (key_val 0) { state KEY_STATE_HOLD; // 10ms后依然是低电平确认为有效按下 hold_time 0; } else { state KEY_STATE_IDLE; // 只是抖动 } break; case KEY_STATE_HOLD: if (key_val 0) { hold_time; // 计时 if (hold_time 100) { // 100 * 10ms 1秒 key_event 2; // 触发长按事件 } } else { if (hold_time 100) { key_event 1; // 未达到长按时间就松手触发单击事件 } state KEY_STATE_RELEASE; } break; case KEY_STATE_RELEASE: state KEY_STATE_IDLE; // 等待下一次按下 break; } return key_event; }用法把这个函数扔进 10ms 的定时器任务里。返回值是 1 就让菜单光标往下走返回值是 2 就进入子菜单丝滑无比。三、 C语言的艺术OLED 多级菜单架构如果要在 OLED 上写菜单很多人的代码是无数个 if...else 和 switch...case 嵌套最后连自己都不知道在哪一页了这叫“屎山代码”。真正优雅的做法是表驱动法Table-Driven 链表/结构体数组。1. 结构体定义菜单的“节点”我们把每一个菜单页面如“主菜单”、“PID设置”、“电压输出”看作一个节点节点里包含了当前页面的内容以及按下不同按键后应该跳转的下一个节点的索引。codeCtypedef struct { uint8_t current_index; // 当前页面索引 uint8_t next_up; // 按下上键跳转的索引 uint8_t next_down; // 按下下键跳转的索引 uint8_t next_enter; // 按下确认键跳转的索引 uint8_t next_back; // 按下返回键跳转的索引 void (*show_func)(void); // 刷新当前屏幕的函数指针重要 } Menu_Item_t;2. 菜单页面配置查表用一个静态数组把所有页面链接起来简直是艺术codeC// 页面索引宏定义 #define PAGE_MAIN 0 #define PAGE_SET_PID 1 #define PAGE_SET_VOLT 2 // 页面显示函数声明 void Show_Main_Page(void); void Show_PID_Page(void); void Show_Volt_Page(void); // 核心菜单映射表 const Menu_Item_t Menu_Table[] { // index, UP, DOWN, ENTER, BACK, show_func {PAGE_MAIN, PAGE_MAIN, PAGE_MAIN, PAGE_SET_PID, PAGE_MAIN, Show_Main_Page}, {PAGE_SET_PID, PAGE_SET_PID, PAGE_SET_PID, PAGE_SET_PID, PAGE_MAIN, Show_PID_Page}, {PAGE_SET_VOLT, PAGE_SET_VOLT, PAGE_SET_VOLT, PAGE_SET_VOLT, PAGE_MAIN, Show_Volt_Page}, };3. 主循环菜单调度器在你的主循环中只需要一个全局变量 current_page 记录当前处于哪一页然后根据按键查表跳转codeCuint8_t current_page PAGE_MAIN; void Menu_Task(void) { uint8_t key Get_Key_Value(); // 获取按键键值 // 状态转移逻辑 if (key KEY_UP) current_page Menu_Table[current_page].next_up; if (key KEY_DOWN) current_page Menu_Table[current_page].next_down; if (key KEY_ENTER) current_page Menu_Table[current_page].next_enter; if (key KEY_BACK) current_page Menu_Table[current_page].next_back; // 执行当前页面的显示函数 Menu_Table[current_page].show_func(); }总结有了这个框架比赛时如果要增加一个“视觉识别模式”的页面你只需要在表里加一行代码写一个对应的显示函数即可系统极度稳定一辈子都不会出现菜单卡死或死循环四、 救命神技掉电保存参数Flash / EEPROM想象一下你花了三个小时在赛场外面的走廊上把小车的 PID 调到了完美状态。然后你需要拔掉电池抱着小车走进测评室。一插电小车的参数全部归零了......每年都有这种惨案。比赛中所有重要的可调参数必须存入非易失性存储器STM32 内部 Flash 读写方案无需外挂芯片STM32 内部除了存代码还可以留出最后一两页Page作为数据存储区。封装一套简单的函数开机读取系统启动时首先从 Flash 指定地址如 0x0801FC00读取 PID 结构体。如果是 0xFFFFFFFF说明是第一次开机没存过就给一个默认值。菜单保存在你的 OLED 菜单里加一个选项叫“Save Parameters”。当你调好参数后点一下保存。保存逻辑先 HAL_FLASH_Unlock() 解锁再擦除对应的 Page最后用 HAL_FLASH_Program() 把当前的参数结构体写入 Flash上锁。注电赛期间不要在主循环里实时写入 FlashFlash 有擦写寿命限制且擦写过程耗时较长可能阻塞中断做成“手动触发保存”最稳妥。五、 赛前模块化大一统硬件接口标准化除了代码框架硬件的“祖传模块”也必须准备好。不要在比赛时东拼西凑杜邦线。IIC 大统一OLED 屏幕、MPU6050、EEPROM这些全是 IIC 接口。赛前自己画一块主板引出多个GND-VCC-SCL-SDA排母接口比赛时即插即用一条总线挂载所有设备。串口大统一预留至少 3 个标准 UART 接口VCC-GND-TX-RX。一个接蓝牙/透传模块调参用一个接 OpenMV/K210视觉用一个留作备用。万能测试夹准备几根一头是杜邦线、一头是“微型测试钩夹子”的线。测板子引脚信号时直接钩在芯片管脚上解放双手绝不会因为手抖造成短路。结语在电赛的考场上最可怕的不是你不会算某个复杂的算法而是你花了大量的时间在修补底层的 Bug按键不灵、屏幕花屏、数据丢失。磨刀不误砍柴工。距离比赛还有几个月趁现在去建立属于你们队伍的 Github/Gitee 仓库把这些造好的“轮子”封装成一个个 .c 和 .h 文件。当比赛发题的那一刻别的队伍还在新建工程写 HAL_Init你们的屏幕上已经亮起了丝滑的多级菜单这就是高手的降维打击。预祝大家按键零抖动菜单纵享丝滑参数永不丢失国一稳稳拿下觉得干货满满点赞 ⭐收藏赶快去你的工程里把这套框架搭起来你在写 OLED 菜单或者按键时踩过什么坑你有什么私藏的“造轮子”技巧欢迎在评论区分享交流

相关新闻