4. 进度规划的核心:关键路径法(CPM)与甘特图在嵌入式固件开发中的应用

进度规划,说白了就是回答三个问题:做什么、谁来做、做多久。但在嵌入式固件开发里,事情没那么简单。你想想看,一个固件项目里,驱动层没写完,应用层就没法联调;Bootloader 没搞定,固件更新功能就是空中楼阁。这些任务之间的依赖关系,才是进度管理的真正难点。

我个人习惯,拿到项目需求后,第一件事不是排时间,而是画任务依赖图。为什么?因为只有把依赖关系理清了,你才知道哪些任务可以并行,哪些必须串行,哪些一旦延期就会拖垮整个项目。

4.1 关键路径法(CPM):找到那条不能延期的链

关键路径法,英文叫 Critical Path Method,简称 CPM。它不是什么高深理论,就是帮你找出项目中最长的任务链。这条链上的任何一个任务延期,项目整体就延期。

我在项目中遇到过好几次这样的情况:团队觉得某个模块很简单,随手估了个时间,结果它偏偏就在关键路径上。一延期,整个项目跟着遭殃。所以,识别关键路径,是进度规划的第一步。

4.1.1 四个核心参数

要算关键路径,你得先搞清楚四个参数:

参数 含义 说明
ES (Earliest Start) 最早开始时间 前置任务全部完成后,本任务最早能开始的时间
EF (Earliest Finish) 最早完成时间 ES + 任务工期
LS (Latest Start) 最晚开始时间 不影响项目总工期的情况下,本任务最晚能开始的时间
LF (Latest Finish) 最晚完成时间 LS + 任务工期

关键路径上的任务,ES = LS,EF = LF。说白了,就是一点缓冲都没有。

4.1.2 计算步骤:前推法与后推法

计算过程分两步:

  1. 前推法:从项目开始往结束推,算 ES 和 EF。遇到分叉,取最大值。
  2. 后推法:从项目结束往开始推,算 LS 和 LF。遇到分叉,取最小值。

举个例子,一个简单的固件开发任务分解:

任务 工期(天) 前置任务
A. 需求分析 3 无
B. 架构设计 5 A
C. 驱动开发 10 B
D. 应用层开发 8 B
E. 联调测试 4 C, D

前推法算出来:A(0-3) → B(3-8) → C(8-18) → E(18-22),总工期 22 天。D 的 ES 是 8,EF 是 16,比 C 早结束,所以 D 不在关键路径上。

关键路径:A → B → C → E,总工期 22 天。

D 有 2 天的浮动时间(18 - 16 = 2 天),可以适当调整。

4.2 甘特图:把计划画出来

关键路径算出来了,下一步就是把它变成可视化的进度条。甘特图就是干这个的。

我习惯用甘特图来做三件事:

  • 展示任务时间线:每个任务的起止时间一目了然。
  • 标注依赖关系:用箭头把前置和后置任务连起来。
  • 跟踪实际进度:用不同颜色标记已完成、进行中和未开始的任务。

嗯,这里要注意:甘特图不是画完就完事了。你得每周更新一次,把实际进度和计划进度做对比。我曾经有个项目,甘特图画得漂漂亮亮,结果两个月没更新,最后发现进度已经偏离了 30%。那叫一个惨。

4.2.1 嵌入式固件开发的典型甘特图结构

下面是一个典型的嵌入式固件项目甘特图结构,我把它简化成表格形式:

阶段 任务 工期 依赖 资源
需求 需求评审 3天 无 PM, 架构师
设计 系统架构设计 5天 需求评审 架构师
设计 硬件接口定义 3天 系统架构设计 嵌入式工程师
开发 Bootloader 开发 7天 硬件接口定义 嵌入式工程师 A
开发 驱动层开发 10天 硬件接口定义 嵌入式工程师 B
开发 应用层开发 8天 驱动层开发 嵌入式工程师 C
测试 单元测试 5天 驱动层开发, 应用层开发 测试工程师
测试 集成测试 5天 单元测试 测试工程师

我的习惯:在甘特图上用红色标记关键路径上的任务,用绿色标记有浮动时间的任务。这样一眼就能看出哪些任务碰不得。

4.3 依赖关系的四种类型

嵌入式固件开发中,依赖关系不只是简单的「做完 A 才能做 B」。我总结了一下,常见的有四种:

类型 说明 嵌入式场景举例
完成-开始 (FS) 前置任务完成后,后续任务才能开始 驱动开发完成后,应用层开发才能开始
开始-开始 (SS) 前置任务开始后,后续任务就可以开始 硬件设计开始后,PCB 布局就可以开始(有重叠)
完成-完成 (FF) 前置任务完成后,后续任务才能完成 所有模块测试完成后,集成测试才能完成
开始-完成 (SF) 前置任务开始后,后续任务才能完成 比较少用,比如旧系统下线前,新系统必须上线

实际项目中,FS 类型占 80% 以上。但 SS 和 FF 类型用好了,能帮你压缩工期。比如驱动开发和应用层开发,如果接口定义清楚了,完全可以 SS 方式并行一部分。

避坑指南:我曾经在一个项目中,把两个任务设成了 SS 关系,结果前置任务改了接口,后置任务已经基于旧接口写了一半代码,返工了三天。所以,SS 关系一定要确保接口稳定,或者有变更通知机制。

4.4 关键路径与甘特图的联动:一个完整的嵌入式案例

我们来看一个真实的嵌入式固件项目案例。假设我们要开发一个智能传感器固件,功能包括数据采集、协议转换、OTA 升级。

任务分解如下:

  1. 需求确认(2天)
  2. 系统设计(3天,依赖 1)
  3. Bootloader 开发(5天,依赖 2)
  4. 传感器驱动开发(4天,依赖 2)
  5. 通信协议栈移植(6天,依赖 2)
  6. 数据采集逻辑开发(5天,依赖 4)
  7. OTA 功能开发(4天,依赖 3)
  8. 应用层联调(3天,依赖 5, 6, 7)
  9. 系统测试(4天,依赖 8)

通过 CPM 计算,关键路径是:1 → 2 → 5 → 8 → 9,总工期 2+3+6+3+4 = 18 天。

任务 3、4、6、7 都有浮动时间。比如任务 3(Bootloader)有 2 天浮动,任务 4(传感器驱动)有 3 天浮动。这意味着,如果关键路径上的任务延期了,你可以从这些有浮动的任务上临时调人支援。

下面是我为这个案例画的 CPM 网络图:

智能传感器固件 CPM 网络图 智能传感器固件 CPM 网络图 1. 需求确认 2天 2. 系统设计 3天 3. Bootloader 5天 4. 传感器驱动 4天 5. 协议栈移植 6天 6. 数据采集 5天 7. OTA开发 4天 8. 联调 3天 9. 系统测试 4天 图例说明 关键路径(红色):1→2→5→8→9,总工期 18 天 非关键路径(绿色/橙色):有浮动时间,可灵活调配资源 注意:任务 3(Bootloader)有 2 天浮动,任务 4(传感器驱动)有 3 天浮动

4.5 管理依赖关系的三个实战技巧

理论讲完了,说点实际的。我在多个嵌入式项目中总结出来的三个技巧:

4.5.1 技巧一:建立依赖清单

不要只靠脑子记。我每个项目都会建一个依赖清单,格式很简单:

依赖ID | 前置任务 | 后置任务 | 依赖类型 | 状态 | 风险等级
D001   | 驱动开发 | 应用开发 | FS       | 已确认 | 低
D002   | 硬件设计 | 驱动开发 | SS       | 待确认 | 高

每周例会过一遍这个清单,看看有没有新增的依赖,或者已有的依赖状态变了。

4.5.2 技巧二:给关键路径加缓冲

关键路径上的任务,我建议不要排得太满。比如估算出来是 10 天,我通常会加 10%-15% 的缓冲。为什么?因为嵌入式开发中,硬件问题、芯片缺货、调试环境出问题,这些都是常事。

我曾经有个项目,关键路径上的驱动开发估了 8 天,结果芯片勘误表里有个坑,多花了 3 天才绕过去。从那以后,我学乖了,关键路径上的任务,一定要留余量。

4.5.3 技巧三:用里程碑卡住关键节点

在甘特图上,我会在关键路径的每个阶段结束时设置一个里程碑。比如:

  • M1:需求确认完成
  • M2:系统设计评审通过
  • M3:协议栈移植完成
  • M4:联调通过
  • M5:系统测试通过

里程碑不占工期,但它是一个检查点。如果某个里程碑延期了,说明关键路径出问题了,需要立刻调整资源或计划。

核心总结:

  • CPM 帮你找到不能延期的任务链,甘特图帮你可视化整个计划。
  • 依赖关系不只是 FS,SS 和 FF 用好了能压缩工期,但风险也更高。
  • 关键路径上的任务,一定要加缓冲、设里程碑、每周跟踪。