在嵌入式開發領域,開發者常陷入一個陷阱:「軟體磨損(Software wears out)。」
因為程式碼與硬體綁定得太緊,導致硬體一換,程式碼就得重寫。
這樣的程式碼不叫軟體(Software),而叫韌體(Firmware)。
Uncle Bob 強調:「雖然軟體依存在韌體上,但韌體依存在硬體上,軟體本身不該成為韌體。」
一、軟體建置的三個活動#
引用 Kent Beck 的觀點,軟體建置應包含三階段,但大多數嵌入式工程師只停留在第一階段:
- 讓它工作 (Make it work): 這最難。確保程式碼能跑在目標硬體上。
如果只停在這,你得到的是一堆亂七八糟的程式碼。 - 把它做對 (Make it right): 重構程式碼,讓它結構良好、易於維護。這需要架構思維。
- 讓它變快 (Make it fast): 優化效能。
整潔的嵌入式架構,目標是讓我們能順利進行到第二階段,從「讓程式碼工作」轉向「建構長壽有用的程式碼」。
二、目標硬體瓶頸 (The Target-Hardware Bottleneck)#
嵌入式開發最大痛點是 「只能在目標硬體上測試」。
- 流程慢: 修改 ➡️ 編譯 ➡️ 燒錄 ➡️ 重啟 ➡️ 測試。這迴圈太長了
- 解法: 如果架構分層得當,大部分的業務邏輯應能在 主機(PC) 上測試,而不需要硬體參與
三、分層策略:隔離硬體與韌體#
為避免軟體被韌體汙染,我們必須明確界定三層結構:
- 軟體 (Software): 純粹的業務邏輯。完全不知硬體存在
- 韌體 (Firmware): 負責與硬體溝通的低層程式碼
- 硬體 (Hardware): 物理裝置

Figure 29.1: Three layers

Figure 29.2: Hardware must be separated

Figure 29.3: Software and firmware line
| 抽象層 | 全名 | 問題 | 解法 | 效益 |
|---|---|---|---|---|
| HAL | Hardware Abstraction Layer | 軟體直接控制 GPIO 或暫存器 | 建立 HAL;軟體呼叫 Led.TurnOn() | 硬體更換時,軟體層不用改 |
| PAL | Processor Abstraction Layer | 程式碼依賴 vendor_cpu.h | 將處理器特定功能隔離在 PAL 中 | 不被特定 CPU 綁架 |
| OSAL | Operating System Abstraction Layer | 直接使用 OS API(如 FreeRTOS) | 定義 OSAL 介面(如 OS_TaskCreate) | 可更換 OS,可離線測試 |

Figure 29.4: The hardware abstraction layer

Figure 29.5: Adding in an operating system

Figure 29.6: The operating system abstraction layer
硬體是細節,處理器是細節,作業系統也是細節。
一個整潔的嵌入式架構,能透過 HAL 和 OSAL 將這些細節隔離。
這不僅能讓程式碼在不同硬體間移植,更重要的是,
它讓你能脫離硬體進行離線測試(Off-target Testing),大幅提升開發速度與品質。