资讯动态

嵌入式软件工程师如何快速熟悉陌生项目的代码

发布时间:2026/8/4 4:44:13 来源:尧图企业网站定制
到新公司接手智能猫砂盆项目代码千万别一上来就从main.c开始逐行看完整项目这样很容易迷路。正确方法是先跑起来 → 看业务流程 → 找入口 → 画模块关系 → 顺着一次完整动作追代码。一、第一目标先搞清楚“这个产品在干什么”智能猫砂盆本质上是一个嵌入式状态机产品不是单纯的驱动项目。你先把业务功能列出来功能模块说明滚筒电机控制清理、复位、抚平、倒砂、停止猫检测重量传感器、红外、雷达、霍尔等安全保护防夹、防堵转、防倾倒、超时保护按键控制手动清理、配网、模式切换WiFi/APP通信APP下发清理、模式、定时、参数状态灯/蜂鸣器显示工作状态、故障提示Flash参数保存模式、清理延时、校准数据OTA升级WiFi升级固件故障管理电机异常、传感器异常、桶未装好等先不要纠结代码细节先搞懂APP点“一键清理”后设备到底经历了哪些状态比如APP一键清理 ↓ 收到WiFi串口/网络指令 ↓ 解析成内部按键/命令事件 ↓ 进入清理业务状态机 ↓ 电机转到抚平位置 ↓ 电机转到复位位置 ↓ 电机转到清理位置 ↓ 停止3秒 ↓ 回到抚平/复位 ↓ 上报完成状态给APP你把这个流程追通项目就熟了一半。二、第一天先把项目跑起来刚到公司第一天优先做这些1. 编译通过先问清楚用什么IDEKeilIARVSCodeGCC 用哪个SDK 哪个分支是量产分支 哪个工程是当前产品 编译脚本怎么用 烧录工具是什么你要先拿到一个稳定结果代码能编译 固件能烧录 设备能启动 串口有日志 基本功能能跑不要一开始就改代码。2. 找到启动入口一般 MCU 项目入口是intmain(void){system_init();bsp_init();app_init();while(1){app_loop();}}或者 RTOS 项目是intmain(void){board_init();driver_init();app_task_create();vTaskStartScheduler();}你要重点找这些文件main.c app_main.c system_init.c board.c bsp.c task.c app.c mode.c motor.c uart.c wifi.c key.c然后画一个简单启动流程main() ├── 时钟初始化 ├── GPIO初始化 ├── UART初始化 ├── 电机驱动初始化 ├── 传感器初始化 ├── WiFi模块初始化 ├── 参数读取 └── 进入主循环/创建任务三、第二步不要看全部代码先看“主循环/任务”你之前给过类似这种代码voidact_routine(void){u32 key_valueKEY_NULL;physic_key_value_get(key_value);wifi_key_value_get(key_value);switch_read_key(mode.mode_runing,key_value);clear_all_keytype_flag();}这类函数就非常关键。因为它说明项目是这样设计的物理按键 ↓ WiFi按键/APP指令 ↓ 统一转换成 key_value ↓ 交给 switch_read_key() 处理 ↓ 进入不同模式/状态机也就是说APP指令和物理按键可能被抽象成了同一种“按键事件”。这是小家电/智能硬件里很常见的写法。你要优先找这些核心函数xxx_routine() xxx_task() xxx_loop() switch_read_key() mode_xxx() motor_xxx() uart_cmd_xxx() wifi_cmd_xxx()尤其注意名字里有这些单词的函数routine task loop proc process handler dispatch state mode run work这些一般都是业务调度入口。四、第三步顺着“一键清理”追代码智能猫砂盆最核心的功能一般是清理流程。你就拿它当切入点。1. 从 APP 指令开始追假设 APP 发了“一键清理”你先找clean clear cleaning wash roll motor wifi_cmd uart_cmd key_clean如果代码里是中文拼音也要搜qingli clean clear cln可能会看到类似#defineKEY_CLEAN0x01#defineCMD_CLEAN0x10#defineMODE_CLEAN1或者caseWIFI_CMD_CLEAN:wifi_uart_cmd_state[i].stateKEY_SHORT;wifi_uart_cmd_state[i].key_valKEY_CLEAN;break;这说明APP清理命令 → 转成内部 KEY_CLEAN2. 再追按键处理函数比如switch_read_key(mode.mode_runing,key_value);进去后可能是switch(mode){caseMODE_STANDBY:standby_key_process(key_value);break;caseMODE_AUTO:auto_key_process(key_value);break;caseMODE_CLEAN:clean_key_process(key_value);break;}继续追caseKEY_CLEAN:mode_set(MODE_CLEAN);break;这时候你就知道KEY_CLEAN 触发进入 MODE_CLEAN3. 再追清理状态机一般会有类似代码voidclean_mode_run(void){switch(clean_step){caseCLEAN_STEP_RESET:motor_run_to_reset();break;caseCLEAN_STEP_FLAT:motor_run_to_flat();break;caseCLEAN_STEP_CLEAN:motor_run_to_clean();break;caseCLEAN_STEP_WAIT:motor_stop();break;caseCLEAN_STEP_FINISH:mode_set(MODE_STANDBY);break;}}你要把它画成图CLEAN_IDLE ↓ RESET_POS ↓ FLAT_POS ↓ RESET_POS ↓ CLEAN_POS ↓ STOP_3S ↓ FLAT_POS ↓ FINISH这个图比你看 1000 行代码都有效。五、重点看这 6 类文件到新公司看项目代码建议按这个顺序看1. 配置文件先看宏定义和产品配置。常见文件config.h user_config.h product_config.h board_config.h app_config.h重点看#defineMOTOR_TYPE_DC#defineHAS_WIFI#defineHAS_WEIGHT_SENSOR#defineCLEAN_DELAY_TIME#defineAUTO_CLEAN_ENABLE#defineROLL_MOTOR_PWM_MAX这些决定了产品功能开关。2. 硬件板级文件常见文件board.c bsp_gpio.c bsp_uart.c bsp_pwm.c bsp_adc.c bsp_timer.c你要整理硬件MCU引脚用途滚筒电机PWMPAx控制电机速度电机方向PBx正转/反转霍尔/限位PCx检测位置重量ADCADCx猫进入检测WiFi UARTUSARTx和WiFi模块通信按键GPIO手动控制LEDGPIO/PWM状态显示这一步很重要因为你要知道代码里的 motor、sensor、wifi 到底对应板子上的哪个硬件。3. 驱动层文件例如motor_driver.c weight_sensor.c ir_sensor.c hall_sensor.c wifi_uart.c flash.c key.c led.c buzzer.c这一层主要关心怎么初始化 怎么读 怎么写 有没有中断 有没有DMA 有没有定时器比如电机驱动你要看motor_init();motor_forward();motor_reverse();motor_stop();motor_set_pwm();motor_get_position();motor_is_blocked();4. 服务层/中间层文件这一层最关键通常是把底层驱动封装成产品功能。例如motor_service.c clean_service.c cat_detect_service.c fault_service.c wifi_service.c param_service.c比如底层是motor_forward();motor_reverse();motor_stop();服务层可能封装成cat_litter_go_reset_pos();cat_litter_go_clean_pos();cat_litter_go_flat_pos();cat_litter_check_motor_timeout();这一层你要重点看因为它最接近业务。5. APP业务层文件例如app_clean.c app_auto.c app_mode.c app_key.c app_fault.c app_main.c这里决定什么时候清理 什么时候禁止清理 什么时候报警 什么时候上报APP 什么时候进入待机比如if(cat_leftauto_clean_enable){start_clean_after_delay(5*60);}这才是产品逻辑。6. 通信协议文件智能猫砂盆一般有 WiFi/蓝牙模块MCU 和通信模块之间可能走 UART。你重点看wifi_protocol.c uart_protocol.c cmd_parse.c app_cmd.c tuya.c aliyun.c mqtt.c重点搞清楚APP发来的命令格式是什么 MCU怎么解析 MCU怎么上报状态 有没有心跳包 有没有校验和 有没有命令应答例如APP命令一键清理 WiFi模块收到 UART发给MCU MCU解析 CMD_CLEAN 转换成 KEY_CLEAN 进入清理模式 清理完成后上报 CLEAN_DONE六、建议你做一张“项目总架构图”可以按你自己的分层思想画APP业务层 ├── 自动清理逻辑 ├── 手动清理逻辑 ├── 故障处理逻辑 ├── 模式管理逻辑 └── 状态上报逻辑 服务层 ├── 清理服务 clean_service ├── 电机动作服务 motor_action_service ├── 猫检测服务 cat_detect_service ├── 故障服务 fault_service ├── 参数服务 param_service └── 通信服务 wifi_service 设备驱动层 ├── 滚筒电机驱动 ├── 重量传感器驱动 ├── 霍尔/限位检测驱动 ├── LED驱动 ├── 蜂鸣器驱动 └── Flash驱动 外设驱动层 ├── UART ├── PWM ├── ADC ├── GPIO ├── TIMER └── FLASH HAL/芯片层 └── MCU厂家库你到公司后就按照这个图去归类代码。看到一个文件就判断它属于哪一层。七、快速熟悉代码的核心方法抓 5 条主线你不要平均用力看所有代码而是抓主线。主线 1启动主线main() → system_init() → driver_init() → app_init() → while/task搞清楚设备怎么启动。主线 2清理主线APP/按键触发清理 → key/cmd → mode → clean state machine → motor action → finish/report这是智能猫砂盆最核心业务。主线 3自动清理主线猫进入 → 重量/传感器检测 → 猫离开 → 延时5分钟 → 自动清理这条线涉及产品体验。主线 4安全保护主线电机运行 → 检测堵转/超时/限位/猫进入 → 立即停止 → 报警 → 上报APP这条线涉及安全必须重点看。主线 5通信主线APP命令 → WiFi模块 → UART协议 → MCU解析 → 执行动作 → 状态上报这条线决定 APP 和 MCU 如何协作。八、你可以直接用这个“看代码模板”每看一个模块就回答这几个问题1. 这个模块负责什么 2. 它对外提供哪些API 3. 它依赖哪些底层驱动 4. 它被哪些上层模块调用 5. 它有没有状态机 6. 它有没有定时器 7. 它有没有中断 8. 它有没有全局变量 9. 它有没有错误处理 10. 它和APP/WiFi有没有关系比如看motor.c1. 负责滚筒电机控制 2. 提供 motor_forward/motor_reverse/motor_stop 3. 依赖 PWM/GPIO/ADC/霍尔 4. 被 clean_service 调用 5. 有电机运行状态 6. 有超时检测 7. 可能有霍尔中断 8. 有 motor_state 全局变量 9. 有堵转/过流/超时保护 10. 清理完成后可能通知WiFi上报这样看代码才有结构。九、最重要一定要边看边做笔记建议你建一个自己的文档智能猫砂盆代码熟悉笔记.md里面记录1. 工程如何编译 2. 固件如何烧录 3. 串口波特率是多少 4. main函数启动流程 5. 任务/定时器列表 6. 核心模块说明 7. 清理流程状态机 8. 电机控制API 9. 传感器检测逻辑 10. APP通信协议 11. 常见故障码 12. 目前不理解的问题特别是状态机建议你画成这样待机 ↓ 收到清理命令 ↓ 检测是否允许清理 ↓ 电机运行到复位位置 ↓ 电机运行到清理位置 ↓ 停止等待 ↓ 回到抚平/复位位置 ↓ 结束十、到新公司可以这样问老员工不要直接问这个代码怎么看这样别人不好回答。你要问具体问题1. 当前量产分支是哪一个 2. 现在客户/测试主要反馈的问题是什么 3. 清理流程的核心状态机在哪个文件 4. APP命令是从哪个文件解析的 5. 电机位置是靠霍尔、编码器还是电流判断 6. 猫进入/离开是靠重量还是红外 7. 哪些模块最容易出问题 8. 哪些代码不要随便改 9. 当前产品有几种硬件版本 10. 有无协议文档、测试用例、故障码表这种问法显得你很专业也能快速获得关键信息。十一、你接手后最优先看这几个点智能猫砂盆项目我建议优先级是第一优先级清理流程状态机 第二优先级电机控制和位置检测 第三优先级安全保护逻辑 第四优先级APP/WiFi通信协议 第五优先级参数保存和模式管理 第六优先级LED/蜂鸣器提示 第七优先级OTA和生产测试因为清理流程、电机、安全保护是产品核心。LED、蜂鸣器、显示这些可以后面再看。十二、一个非常实用的技巧从日志反推代码如果项目有串口日志比如[clean] start [motor] go reset [motor] reach reset [motor] go clean [clean] finish你可以直接全局搜索clean start go reset reach reset clean finish这样能非常快定位到核心代码。如果日志太少你可以自己临时加日志printf([CLEAN] step %d\r\n,clean_step);printf([MOTOR] state %d, pwm %d\r\n,motor_state,pwm);printf([KEY] key_value 0x%08X\r\n,key_value);printf([WIFI] cmd 0x%02X\r\n,cmd);但是注意电机控制、定时器中断、通信中断里面不要乱加大量 printf容易影响时序。十三、总结一句话你到新公司熟悉智能猫砂盆代码不要从底层一点点硬啃而是按这个顺序先跑起来 再看启动流程 再看主循环/任务 再追一键清理流程 再追电机控制 再追传感器和安全保护 最后看通信协议和参数保存核心思路是用业务流程带着你看代码而不是被代码牵着走。对于智能猫砂盆最值得你第一个追通的流程就是APP/按键一键清理 → 命令解析 → 模式切换 → 清理状态机 → 电机动作 → 安全检测 → 完成上报把这条线搞明白你基本就能开始改 bug 和加功能了。这种情况很正常尤其是小公司/老项目/赶工产品代码常见现象就是全局变量很多 函数到处互相调用 状态机不清晰 驱动层和业务层混在一起 命名不统一 APP指令、按键、电机动作、传感器判断缠在一起你看不明白不一定是你水平不够很多时候是代码本身没有边界。核心策略是不要试图一次性看懂整个项目而是先把“数据怎么流动、状态怎么变化、谁在改全局变量”搞清楚。一、先别急着重构先做“代码侦察”新公司刚接手项目千万不要一上来就说这代码太烂了我要重构。这样风险很大。你第一阶段目标不是改好它而是能编译 能烧录 能复现功能 能知道某个功能从哪里进、从哪里出 能知道关键全局变量是谁改的也就是先做到看不懂全部代码但能追通一条业务链路。比如智能猫砂盆先追APP一键清理 / 按键清理 ↓ 命令解析 ↓ 模式切换 ↓ 清理状态机 ↓ 电机动作 ↓ 传感器/限位/堵转判断 ↓ 完成/故障上报只要这一条线能看懂项目就打开口子了。二、看不明白的地方先问自己 5 个问题遇到一个看不懂的函数不要一行一行死磕。先问1. 这个函数什么时候被调用 2. 谁调用它 3. 它修改了哪些全局变量 4. 它依赖哪些全局变量 5. 它最终影响了什么硬件动作比如看到voidclean_routine(void){if(clean_flag){motor_run();clean_step;}}不要只盯着clean_step看要查clean_flag 是谁置 1 的 clean_step 谁清零 motor_run() 里面控制哪个 IO/PWM clean_routine() 多久调用一次 clean_step 加到多少会结束你要追的是调用关系和变量变化不是单纯看语法。三、全局变量满天飞最重要是找“写入点”全局变量多不可怕最怕不知道谁在改。比如有个全局变量u8 clean_step;u8 motor_state;u8 mode_runing;u32 key_value;u8 fault_flag;你不要先管它定义在哪里第一步是全局搜索clean_step clean_step clean_step-- clean_step 也就是只找写入位置。因为读它的地方可能很多但真正改变系统状态的是写它的地方。对每个关键全局变量做一张表比如全局变量作用谁写它谁读它风险mode.mode_runing当前运行模式mode_set()、按键处理、故障处理主循环、状态机多处改模式容易乱跳clean_step清理流程步骤clean_mode_run()、异常处理电机控制、显示上报没有统一复位可能卡状态motor_state电机状态motor_start()、motor_stop()堵转检测、APP上报中断和主循环都可能改fault_flag故障标志传感器检测、电机保护模式控制、蜂鸣器、APP故障清除逻辑容易混乱这个表非常有用。你不用一下子做全项目先做核心变量表模式变量 电机状态变量 清理步骤变量 故障变量 按键/APP命令变量 传感器状态变量四、全局变量分析方法先分成 5 类全局变量多的时候你先把它们分类。1. 状态类全局变量比如u8 mode_runing;u8 clean_step;u8 motor_state;u8 wifi_state;这种最关键决定程序走向。重点看在哪里改变 改变后会进入哪个流程 有没有被异常处理强行修改2. 标志位类全局变量比如u8 clean_flag;u8 cat_in_flag;u8 fault_flag;u8 key_press_flag;这种通常是某处置 1 某处处理 某处清 0最容易出 bug 的地方是置 1 后没人清 还没处理就被清了 多个地方同时改 中断里改主循环里读3. 计时类全局变量比如u16 clean_delay_cnt;u16 motor_timeout_cnt;u16 key_long_press_cnt;重点看多久加一次 在哪里清零 单位是 ms、10ms、25ms 还是 1s 超时阈值是多少很多项目坑就在这里。比如代码里写if(motor_timeout_cnt200)但你不知道这个200是200ms 2s 5s这时候要看它在哪个周期函数里加。如果是在 25ms 调用一次的函数里200 * 25ms 5000ms 5秒4. 数据缓存类全局变量比如u8 uart_rx_buf[128];u8 wifi_cmd_buf[64];u16 adc_value[8];重点看谁写入 谁解析 有没有长度保护 有没有越界风险 是否中断/DMA里写5. 配置参数类全局变量比如u8 clean_delay_time;u8 auto_clean_enable;u8 child_lock_enable;u16 weight_threshold;重点看默认值在哪里 Flash读取在哪里 APP设置后是否保存 恢复出厂设置是否会清掉五、别直接改全局变量先“包一层”如果项目里到处都是mode.mode_runingMODE_CLEAN;mode.mode_runingMODE_IDLE;mode.mode_runingMODE_FAULT;这就很危险因为谁都能改模式。更好的做法是逐步改成voidapp_mode_set(u8 new_mode){mode.mode_runingnew_mode;}然后以后新代码不要直接写mode.mode_runingxxx;而是统一写app_mode_set(MODE_CLEAN);再进一步可以加日志voidapp_mode_set(u8 new_mode){printf([MODE] %d - %d\r\n,mode.mode_runing,new_mode);mode.mode_runingnew_mode;}这样你马上能看到模式什么时候跳了。这叫先封装入口不立刻大改结构。六、看不懂状态机就加日志画流程智能猫砂盆这类产品最核心就是状态机。比如清理流程可能是switch(clean_step){caseCLEAN_STEP_RESET:break;caseCLEAN_STEP_FLAT:break;caseCLEAN_STEP_CLEAN:break;caseCLEAN_STEP_WAIT:break;caseCLEAN_STEP_FINISH:break;}如果你看不懂它怎么跳就加日志staticu8 last_clean_step0xff;if(last_clean_step!clean_step){printf([CLEAN] step change: %d - %d\r\n,last_clean_step,clean_step);last_clean_stepclean_step;}这样设备跑一次清理你串口会看到[CLEAN] step change: 255 - 0 [CLEAN] step change: 0 - 1 [CLEAN] step change: 1 - 2 [CLEAN] step change: 2 - 3 [CLEAN] step change: 3 - 4然后你就能反推0 是复位 1 是抚平 2 是清理 3 是等待 4 是结束比你硬看代码快很多。七、调试全局变量用这几招1. 搜索写入点这是最基本的变量名 变量名 变量名-- memset(变量名2. 加变化日志比如voidmotor_state_set(u8 state){if(motor_state!state){printf([MOTOR] state: %d - %d\r\n,motor_state,state);motor_statestate;}}3. 用调试器 Watch如果有 J-Link / ST-Link可以直接 watchclean_step mode_runing motor_state fault_flag让程序跑起来看变量什么时候变。4. 用硬件断点/观察点比如怀疑clean_step被莫名其妙改了。你可以设置 watchpoint当 clean_step 被写入时暂停这样能直接抓到是哪行代码改的。这个对“全局变量被乱改”特别有效。八、不要从底层驱动开始看先从“功能入口”开始很多新人容易犯一个错先看 GPIO 再看 UART 再看 PWM 再看 ADC 最后看业务这样会很痛苦。智能猫砂盆项目应该倒过来先看业务入口 再看状态机 再看服务层 最后看底层驱动比如你要看“清理功能”顺序应该是APP命令 / 按键 ↓ clean_start() ↓ clean_step 状态机 ↓ motor_action_xxx() ↓ motor_forward/motor_reverse/stop ↓ PWM/GPIO你要看的是业务怎么调用驱动而不是一开始就研究 PWM 寄存器。九、遇到特别乱的代码采用“外围包围法”老代码很乱不能一下子推翻。你可以这样做旧代码保持不动 新需求写在新模块 旧代码只开放几个接口 慢慢把全局变量收口比如你可以新建app_clean_service.c app_motor_service.c app_fault_service.c app_param_service.c然后不要让新业务直接碰底层乱变量而是包一层voidlitter_clean_start(void){clean_flag1;clean_stepCLEAN_STEP_START;}voidlitter_clean_stop(void){clean_flag0;motor_stop();}u8litter_clean_is_busy(void){returnclean_flag;}虽然内部还是旧变量但外部调用变干净了。这叫先统一入口再慢慢治理内部。十、不要追求一次性看懂要做“局部可控”你可以把项目分成三类区域1. 已理解区域比如按键扫描 APP命令解析 清理状态机入口这些可以做笔记。2. 半理解区域比如电机到位判断 堵转检测 重量传感器滤波这些先标记不要马上改。3. 暂时黑盒区域比如WiFi模组底层协议 OTA升级 产测模式 历史兼容代码这些先当黑盒只知道输入输出。你刚接手项目不需要全部看懂。实际工作中很多老员工也不是全懂只是知道关键链路。十一、可以给自己建一个“项目地图”建议你自己建一个文档智能猫砂盆代码地图.md内容这样写1. 编译烧录方式 2. 串口日志波特率 3. main启动流程 4. 周期任务列表 5. 全局变量表 6. 模式状态机 7. 清理流程状态机 8. 电机控制接口 9. APP命令表 10. 故障码表 11. 当前不理解的问题尤其是这个表很重要函数名 作用 调用周期/调用者 act_routine 处理按键和APP命令 25ms clean_routine 清理流程状态机 25ms/100ms motor_routine 电机运行检测 10ms/25ms fault_routine 故障检测 100ms wifi_routine APP通信处理 主循环有了这个表混乱代码就开始变得有结构。十二、问老员工也要讲技巧不要问这代码怎么看别人很难回答。你要问具体问题clean_step 是清理流程的主状态吗 mode_runing 是不是全局模式 APP一键清理最后是不是转成 KEY_CLEAN 电机到位是靠霍尔还是电流判断 motor_state 是不是只能在 motor.c 里面改 fault_flag 哪些故障会置位这样别人一听就知道你真的在追代码也更愿意讲。十三、你可以按这个节奏熟悉项目第 1 阶段能跑编译 烧录 看日志 操作按键/APP 确认基本功能第 2 阶段追主流程一键清理 自动清理 停止/暂停 故障报警 APP上报第 3 阶段整理关键变量mode_runing clean_step motor_state fault_flag key_value cat_state第 4 阶段加日志验证状态变化日志 命令接收日志 电机动作日志 故障触发日志第 5 阶段小范围封装模式切换封装 电机状态设置封装 故障设置/清除封装 APP命令入口封装十四、最现实的建议面对这种乱项目你不要想着我要把整个架构搞优雅。而是先做到1. 不被全局变量绕晕 2. 能知道一个功能从哪里触发 3. 能知道关键状态在哪里改 4. 能定位 bug 是哪条业务链的问题 5. 新增功能时尽量不继续污染旧代码工作里真正有价值的是在混乱代码里建立秩序。你可以先从这几个核心变量开始整理mode_runing 当前模式 clean_step 清理步骤 motor_state 电机状态 fault_flag 故障标志 key_value 按键/APP命令值 cat_state 猫进入/离开状态把这几个变量的写入点、读取点、变化流程搞清楚智能猫砂盆项目你基本就能开始接活了。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价