許多嵌入式開發者習慣直接在 main() 開始編寫代碼,卻忽略了 MCU 上電後如何找到並執行 main()。事實上,編譯器分配的 main 入口地址並非固定絕對地址,微控制器無法直接從硬體定位。啟動文件(Startup Code)正是填補這一鴻溝的關鍵:它完成從「復位」到「開始執行 main()」之間的所有必要初始化配置,功能類比 Linux 的 Bootloader。
MDK 建立專案時預設提供 STM32F10x.s,但這並非通用於所有 STM32 型號。該文件僅定義了 3 個 UART、4 個 Timer 的中斷向量,若使用 STM32F103ZET6(5 UART、8 Timer)卻沿用此文件,UART4/5 及 Timer5-8 的中斷將找不到入口,導致程序跑飛。正確做法是根據 Flash 容量選擇 ST 官方提供的三款啟動文件:
startup_stm32f10x_ld.s — 小容量(Flash ≤ 32KB)startup_stm32f10x_md.s — 中容量(64KB ≤ Flash ≤ 128KB)startup_stm32f10x_hd.s — 大容量(Flash ≥ 256KB)stm32f10x_vector.s 為例)Stack_Size EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp ; 堆疊頂地址標號
Heap_Size EQU 0x00000400
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base ; 堆起始地址
Heap_Mem SPACE Heap_Size
__heap_limit ; 堆結束地址
AREA 偽指令定義段屬性:NOINIT(不初始化,內存歸零)、READWRITE(可讀寫,放入 SRAM)、ALIGN=3(8 字節對齊)。AREA RESET, DATA, READONLY
EXPORT __Vectors
__Vectors
DCD __initial_sp ; 0x00: 堆疊頂指針
DCD Reset_Handler ; 0x04: 復位中斷入口
DCD NMIException
DCD HardFaultException
... ; 後續各中斷向量
__initial_sp,0x08000004 存 Reset_Handler。DCD 分配 32 位字空間,相當於 C 的函數指針數組。Reset_HandlerReset_Handler PROC
EXPORT Reset_Handler
... ; 可選:外部 SRAM 初始化(DATA_IN_ExtSRAM=1 時)
IMPORT __main
LDR R0, =__main
BX R0 ; 跳轉至 C 庫初始化入口
ENDP
關鍵點:__main 並非用戶 main(),而是 C/C++ 標準庫的初始化例程,負責初始化堆疊、靜態數據段、全局構造函數,最後調用用戶 main()。
__user_initial_stackheap)IF :DEF:__MICROLIB
EXPORT __initial_sp, __heap_base, __heap_limit
ELSE
IMPORT __use_two_region_memory
EXPORT __user_initial_stackheap
__user_initial_stackheap
LDR R0, =Heap_Mem
LDR R1, =Stack_Mem + Stack_Size
LDR R2, =Heap_Mem + Heap_Size
LDR R3, =Stack_Mem
BX LR
ENDIF
__user_initial_stackheap 將堆疊/堆邊界傳遞給 C 庫(R0-R3 對應 heap_base, stack_top, heap_limit, stack_base)。| 特性 | ARM7/9 | Cortex-M3 |
|---|---|---|
| 復位後 PC | 固定 0x00000000 | 由 BOOT 引腳決定(0x20000000/0x08000000/內部 Bootloader) |
| 中斷向量表位置 | 可配置(VTOR) | 固定在啟動地址開頭 |
| 首要動作 | 取指 0x00000000 執行復位 ISR | 自動讀取 [SP] 和 [SP+4] 跳轉復位處理程序 |
Reset_Handler 地址並跳轉執行。Reset_Handler 執行必要外設初始化(如外部 SRAM)→ 跳轉 __main。__main 初始化 C 運行環境(堆疊、.data/.bss 段、全局構造函數)→ 調用用戶 main()。stm32f10x_it.c 定義的處理函數名稱是否與向量表一致。Stack_Size 或檢查遞歸/大數組局部變量使用情況。.s 文件,圖標上無紅點者不參與編譯。Linux 裝置驅動第三版範例程式編譯實戰:從 Makefile 到核心模組測試
CentOS 核心服務管理速查:Apache、VNC、MySQL、Nginx 啟動/重啟/停止指令大全
elementary OS 體驗評測:最像 Mac 的 Linux 發行版值得遷移嗎?
Ubuntu Linux NVIDIA 顯卡驅動安裝與解析度問題徹底解決:nvidia-settings 與 xorg.conf 手動修正
Sarg (Squid Analysis Report Generator) 完整部署與自動化報表指南