基於 ATmega2560 開發多外設系統,期望像 APM 飛控、Android HAL 一樣,通過硬件抽象層實現代碼跨平台復用。
「C++ 不能直接訪問硬件」
**錯誤**。C/C++ 通過 內存映射 I/O 直接操作硬件寄存器:
// 將寄存器地址映射為 volatile 指針
#define REG_PORTB (*(volatile uint8_t*)0x25) // ATmega2560 PORTB 地址
REG_PORTB |= (1 << 5); // 設置 PB5 輸出高電平
編譯器不會優化 volatile 讀寫,確保指令真正發送到總線。
+------------------------+
| Application Layer | 業務邏輯:飛控算法、任務調度
+------------------------+
| Hardware Abstraction | 統一接口:IGpio, IUart, ISpi, ITimer...
+------------------------+
| Driver Implementations| 具體芯片驅動:ATmega2560_Gpio, STM32_Gpio...
+------------------------+
| Register Definitions | 廠商提供:iomxx.h, CMSIS core_cm4.h...
+------------------------+
| Silicon (MCU) |
+------------------------+
// 統一接口
class IGpio {
public:
virtual void SetMode(Pin pin, Mode mode) = 0;
virtual void Write(Pin pin, bool level) = 0;
virtual bool Read(Pin pin) = 0;
virtual ~IGpio() {}
};
// 具體實現
class AvrGpio : public IGpio {
void SetMode(Pin pin, Mode mode) override {
// 操作 DDRx, PORTx 寄存器
}
// ...
};
// 工廠創建
IGpio* CreateGpio() {
#ifdef MCU_AVR
return new AvrGpio();
#elif defined(MCU_STM32)
return new Stm32Gpio();
#endif
}
template
class GpioBase {
public:
void SetMode(Pin pin, Mode mode) { Impl::SetMode(pin, mode); }
void Write(Pin pin, bool level) { Impl::Write(pin, level); }
};
struct AvrGpioImpl {
static void SetMode(Pin pin, Mode mode) { /* 寄存器操作 */ }
static void Write(Pin pin, bool level) { /* 寄存器操作 */ }
};
using AvrGpio = GpioBase; // 零開銷抽象
struct PinMap { uint8_t port; uint8_t pin; };
constexpr PinMap s_ledPins[] = {
{ 'B', 5 }, { 'B', 6 }, { 'B', 7 } // PB5, PB6, PB7
};
// 驅動內部遍歷表格,無需硬編碼
void AvrGpio::Write(Pin pin, bool level) {
auto pm = s_ledPins[pin];
volatile uint8_t* portReg = GetPortRegister(pm.port);
if (level) *portReg |= (1 << pm.pin);
else *portReg &= ~(1 << pm.pin);
}
project/
├── hal/ # 純虛接口 (IGpio, IUart...)
├── drivers/
│ ├── avr/ # ATmega2560 實現
│ └── stm32/ # STM32 實現
├── config/
│ ├── board_avr.h # 針腳映射、外設啟用宏
│ └── board_stm32.h
├── app/ # 業務代碼,僅依賴 hal/
└── build/ # CMake 腳本,根據 BOARD 選擇驅動
AP_HAL 目錄,典型 C++ HAL 設計,支持 AVR, STM32, Linux 等。#ifdef 或 CMake 切換實現。ucOS-II 或 FreeRTOS 移植層,理解 OS 抽象與硬件抽制的邊界。