第三章 軟件設計
關於程序,單片機首先運行的就是啓動文件。本節重點介紹 .s文件中彙編的基本用法,其實所有單片機的啓動文件很類似,基本上用法一樣。
;/************************************************************************/
;/* Startup for ARM */
;/* Version V1.02 */
;/* Date 2011-01-12 */
;/* Target-mcu MB9B5xx */
;/* 說明:本啓動文件分析適合大多數單片機的啓動文件,大致相同,僅供參考*/
;/************************************************************************/
;說明 一
;僞指令:EQU
;語法格式:名稱 EQU 表達式{,類型}
;EQU僞指令用於爲程序中的常量、標號等定義一個等效的字符名稱,類似於 C 語言的#define。
;其中 EQU可以用“*”代替。
;名稱爲 EQU 僞指令定義的字符名稱,當表達式爲 32 位的常量時,可以指定表達式的數據
;類型,可以有一下三種類型:
;CODE16、CODE32 和 DATA
;僞指令:AREA
;語法格式:AREA 段名{,屬性 1}{,屬性 2}……
;AREA命令指示彙編程序彙編一個新的代碼段或數據段。段是獨立的、指定的、不可見的代
;碼或數據塊,它們由鏈接程序處理。
;段名:可以爲段選擇任何段名。但是,以一個數字開始的名稱必須包含在豎槓號內,否則會
;產生一個缺失段名錯誤。例如,|1_DataArea|。
;有些名稱是習慣性的名稱。例如:|.text|用於表示由 C 編譯程序產生的代碼段,或用於以某
;種方式與 C 庫關聯的代碼段。
;屬性字段表示該代碼段(或數據段)的相關屬性,多個屬性用逗號分隔。常用的屬性如下:
;——CODE屬性:用於定義代碼段,默認爲 READONLY。
;——D AT A屬性:用於定義數據段,默認爲 READWRITE。
;——READONLY屬性:指定本段爲只讀,代碼段默認爲 READONLY。
;——READWRITE屬性:指定本段爲可讀可寫,數據段的默認屬性爲 READWRITE。
;——ALIGN 屬性:使用方式爲 ALIGN 表達式。在默認時,ELF(可執行連接文件)的代碼
;段和數據段是按字對齊的,表達式的取值範圍爲 0~31,相應的對齊方式爲2 表達式次方。
;——NOINIT 屬性:表示數據段是未初始化的或初始化爲零。其只包含零初始化的空間保留
;命令 SPACE或 DCB、DCD、DCDU、DCQ、DCQU、DCW 或 DCWU。可以決定在鏈接時
;AREA是未初始化的還是零初始化的。
;一個彙編語言程序至少要包含一個段,當程序太長時,也可以將程序分爲多個代碼段和數據段。
; Stack Configuration
; Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; 定義棧段 不初始化
;棧名:STACK
;大小:Stack_Size
;只分配空間不做初始化,或者初始化爲0: NOINIT
;可讀可寫:READWRITE
;按8字節對齊:ALIGN=3
;棧頂地址:__initial_sp
;
Stack_Size EQU 0x00000200 ;定義棧空間大小爲0x00000200個字節。此語行亦等價於:#define Stack_Size 0x00000200
AREA STACK, NOINIT, READWRITE, ALIGN=3 ;僞指令AREA
Stack_Mem SPACE Stack_Size
__initial_sp
; Heap Configuration
; Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; 定義堆段 不初始化
;堆名:HEAP
;大小:Heap_Size
;只分配空間不做初始化,或者初始化爲0: NOINIT
;可讀可寫:READWRITE
;按8字節對齊:ALIGN=3
;堆起始地址:__heap_base
;堆終止地址:__heap_limit
;
Heap_Size EQU 0x00000000
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
PRESERVE8 ;指示編譯器8字節對齊(keil編譯器時需加上)
THUMB ;指示編譯器爲THUMB指令集
;說明:二
; 僞指令:EXPORT
; 語法格式:EXPORT 標號{[WEAK]}
; EXPORT 僞指令用於在程序中聲明一個全局的標號,該標號可在其他的文件中引用。
; EXPORT 可用 GLOBAL 代替。標號在程序中區分大小寫,[WEAK]選項聲明其他的同名標
; 號優先於該標號被引用。
; 僞指令:DCD
; 語法格式:DCD(或 DCDU) 表達式
; DCD(或 DCDU)僞指令用於分配一片連續的字存儲單元並用僞指令中指定的表達式初始
; 化。其中,表達式可以爲程序標號或數字表達式。DCD 也可用“&”代替。
; 用 DCD 分配的字存儲單元是字對齊的,而用 DCDU分配的字存儲單元並不嚴格字對齊
; Vector Table Mapped to Address 0 at Reset
; 定義復位段 (中斷向量表),並初始化
;段名:RESET
;大小:__Vectors_Size
;數據段:DATA
;只讀:READONLY
;按字節對齊:默認ALIGN
;向量表起始地址:__Vectors
;向量表終止地址:__Vectors_End
AREA RESET, DATA, READONLY
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
DCD NMI_Handler ; NMI Handler
DCD HardFault_Handler ; Hard Fault Handler
DCD MemManage_Handler ; MPU Fault Handler
DCD BusFault_Handler ; Bus Fault Handler
DCD UsageFault_Handler ; Usage Fault Handler
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD 0 ; Reserved
DCD SVC_Handler ; SVCall Handler
DCD DebugMon_Handler ; Debug Monitor Handler
DCD 0 ; Reserved
DCD PendSV_Handler ; PendSV Handler
DCD SysTick_Handler ; SysTick Handler
DCD CSV_Handler ; 0: Clock Super Visor
DCD SWDT_Handler ; 1: Software Watchdog Timer
DCD LVD_Handler ; 2: Low Voltage Detector
DCD MFT_WG_IRQHandler ; 3: Wave Form Generator / DTIF
DCD INT0_7_Handler ; 4: External Interrupt Request ch.0 to ch.7
DCD INT8_15_Handler ; 5: External Interrupt Request ch.8 to ch.15
DCD DT_Handler ; 6: Dual Timer / Quad Decoder
DCD MFS0RX_IRQHandler ; 7: MultiFunction Serial ch.0
DCD MFS0TX_IRQHandler ; 8: MultiFunction Serial ch.0
DCD MFS1RX_IRQHandler ; 9: MultiFunction Serial ch.1
DCD MFS1TX_IRQHandler ; 10: MultiFunction Serial ch.1
DCD MFS2RX_IRQHandler ; 11: MultiFunction Serial ch.2
DCD MFS2TX_IRQHandler ; 12: MultiFunction Serial ch.2
DCD MFS3RX_IRQHandler ; 13: MultiFunction Serial ch.3
DCD MFS3TX_IRQHandler ; 14: MultiFunction Serial ch.3
DCD MFS4RX_IRQHandler ; 15: MultiFunction Serial ch.4
DCD MFS4TX_IRQHandler ; 16: MultiFunction Serial ch.4
DCD MFS5RX_IRQHandler ; 17: MultiFunction Serial ch.5
DCD MFS5TX_IRQHandler ; 18: MultiFunction Serial ch.5
DCD MFS6RX_IRQHandler ; 19: MultiFunction Serial ch.6
DCD MFS6TX_IRQHandler ; 20: MultiFunction Serial ch.6
DCD MFS7RX_IRQHandler ; 21: MultiFunction Serial ch.7
DCD MFS7TX_IRQHandler ; 22: MultiFunction Serial ch.7
DCD PPG_Handler ; 23: PPG
DCD TIM_IRQHandler ; 24: OSC / PLL / Watch Counter
DCD ADC0_IRQHandler ; 25: ADC0
DCD ADC1_IRQHandler ; 26: ADC1
DCD ADC2_IRQHandler ; 27: ADC2
DCD MFT_FRT_IRQHandler ; 28: Free-run Timer
DCD MFT_IPC_IRQHandler ; 29: Input Capture
DCD MFT_OPC_IRQHandler ; 30: Output Compare
DCD BT_IRQHandler ; 31: Base Timer ch.0 to ch.7
DCD CAN0_IRQHandler ; 32: CAN ch.0
DCD CAN1_IRQHandler ; 33: CAN ch.1
DCD USBF_Handler ; 34: USB Function
DCD USB_Handler ; 35: USB Function / USB HOST
DCD DummyHandler ; 36: Reserved
DCD DummyHandler ; 37: Reserved
DCD DMAC0_Handler ; 38: DMAC ch.0
DCD DMAC1_Handler ; 39: DMAC ch.1
DCD DMAC2_Handler ; 40: DMAC ch.2
DCD DMAC3_Handler ; 41: DMAC ch.3
DCD DMAC4_Handler ; 42: DMAC ch.4
DCD DMAC5_Handler ; 43: DMAC ch.5
DCD DMAC6_Handler ; 44: DMAC ch.6
DCD DMAC7_Handler ; 45: DMAC ch.7
DCD DummyHandler ; 46: Reserved
DCD DummyHandler ; 47: Reserved
__Vectors_End
__Vectors_Size EQU __Vectors_End - __Vectors
;說明 三
;過程定義僞指令:PROC、ENDP
;語法格式:<過程名> PROC [類型]
; ……
; RET
; <過程名> ENDP
;過程就是子程序。一個過程可以被其它程序所調用(用 CALL指令),過程的最後一條指令一般是返回指令(RET)。
;僞指令:IMPORT
;語法格式:IMPORT 標號 {[WEAK]}
;IMPORT 僞指令用於通知編譯器要使用的標號在其他源文件中定義,但是在當前源文件中引
;用,而且無論當前源文件是否引用該標號,該標號均會被加入到當前源文件的標號表中。
;標號在程序中區分大小寫,[WEAK]選項表示當所有的源文件都沒有定義這樣的一個標號時,
;編譯器也不給出錯誤信息,在多數情況下將該標號置爲 0,若該標號爲 B 或 BL 指令引用,
;則將 B或 BL指令置爲 NOP 操作。
;僞指令:LDR
;語法格式:LDR{執行條件,如 EQ、NE等} register,=expr/label_expr
;大範圍的地址讀取僞指令 LDR 用於加載 32 位的立即數或一個地址值到指定寄存器,在彙編
;編譯源程序時,LDR 僞指令被編譯器替換成一條合適的指令。若加載的常數未超出 MOV
;或MVN的範圍,則使用MOV或MVN指令代替 LDR僞指令,否則彙編器將常量放入字池,
;並使用一條程序相對偏移的 LDR 指令從文字池讀出常量。
;Thumb跳轉指令:B、BL、BX
;語法格式: B{執行條件,如 EQ、NE等} labe l
;帶鏈接 BL{執行條件,如 EQ、NE等} labe l
;帶狀態切換 BX{執行條件,如 EQ、NE等} labe l
; 定義代碼段(異常處理函數) ,並初始化
;段名:.text
;代碼段:CODE
;只讀:READONLY
;按字節對齊:默認 ALIGN
;代碼段起始地址:Reset_Handler
AREA |.text|, CODE, READONLY
; Reset Handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT SystemInit
IMPORT __main
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
;說明 四
;內置變量: {PC} 或“.” 當前指令地址
;彙編語句格式規範:
;ARM 彙編中,所有標號必須在一行的頂格書寫,其後面不要添加“:”,而所有指令均不能頂格書寫。
;ARM 彙編器對標識符大小寫敏感,書寫標號及指令時字母大小寫要一致,在 ARM 彙編程
;序中,一個 ARM 指令、僞指令、寄存器名可以全部爲大寫字母,也可以全部爲小寫字母,但不要大小寫混合使用。
;註釋使用“;”,註釋內容由“;”開始到此行結束,註釋可以在一行的頂格書寫。
;源程序中允許有空行,適當地插入空行可以提高源程序代碼的可讀性。如果單行太長,可以使用字符“\”將其分行,“\”後不能有任何字符,包括空格和製表符等。
;對於變量的設置,常量的定義,其標識符必須在一行的頂格書寫。
; Dummy Exception Handlers (infinite loops which can be modified)
;異常處理函數
NMI_Handler PROC
EXPORT NMI_Handler [WEAK]
B .
ENDP
HardFault_Handler\
PROC
EXPORT HardFault_Handler [WEAK]
B .
ENDP
MemManage_Handler\
PROC
EXPORT MemManage_Handler [WEAK]
B .
ENDP
BusFault_Handler\
PROC
EXPORT BusFault_Handler [WEAK]
B .
ENDP
UsageFault_Handler\
PROC
EXPORT UsageFault_Handler [WEAK]
B .
ENDP
SVC_Handler PROC
EXPORT SVC_Handler [WEAK]
B .
ENDP
DebugMon_Handler\
PROC
EXPORT DebugMon_Handler [WEAK]
B .
ENDP
PendSV_Handler PROC
EXPORT PendSV_Handler [WEAK]
B .
ENDP
SysTick_Handler PROC
EXPORT SysTick_Handler [WEAK]
B .
ENDP
;這個默認的異常處理函數處理所有外部中斷
Default_Handler PROC
EXPORT CSV_Handler [WEAK]
EXPORT SWDT_Handler [WEAK]
EXPORT LVD_Handler [WEAK]
EXPORT MFT_WG_IRQHandler [WEAK]
EXPORT INT0_7_Handler [WEAK]
EXPORT INT8_15_Handler [WEAK]
EXPORT DT_Handler [WEAK]
EXPORT MFS0RX_IRQHandler [WEAK]
EXPORT MFS0TX_IRQHandler [WEAK]
EXPORT MFS1RX_IRQHandler [WEAK]
EXPORT MFS1TX_IRQHandler [WEAK]
EXPORT MFS2RX_IRQHandler [WEAK]
EXPORT MFS2TX_IRQHandler [WEAK]
EXPORT MFS3RX_IRQHandler [WEAK]
EXPORT MFS3TX_IRQHandler [WEAK]
EXPORT MFS4RX_IRQHandler [WEAK]
EXPORT MFS4TX_IRQHandler [WEAK]
EXPORT MFS5RX_IRQHandler [WEAK]
EXPORT MFS5TX_IRQHandler [WEAK]
EXPORT MFS6RX_IRQHandler [WEAK]
EXPORT MFS6TX_IRQHandler [WEAK]
EXPORT MFS7RX_IRQHandler [WEAK]
EXPORT MFS7TX_IRQHandler [WEAK]
EXPORT PPG_Handler [WEAK]
EXPORT TIM_IRQHandler [WEAK]
EXPORT ADC0_IRQHandler [WEAK]
EXPORT ADC1_IRQHandler [WEAK]
EXPORT ADC2_IRQHandler [WEAK]
EXPORT MFT_FRT_IRQHandler [WEAK]
EXPORT MFT_IPC_IRQHandler [WEAK]
EXPORT MFT_OPC_IRQHandler [WEAK]
EXPORT BT_IRQHandler [WEAK]
EXPORT CAN0_IRQHandler [WEAK]
EXPORT CAN1_IRQHandler [WEAK]
EXPORT USBF_Handler [WEAK]
EXPORT USB_Handler [WEAK]
EXPORT DMAC0_Handler [WEAK]
EXPORT DMAC1_Handler [WEAK]
EXPORT DMAC2_Handler [WEAK]
EXPORT DMAC3_Handler [WEAK]
EXPORT DMAC4_Handler [WEAK]
EXPORT DMAC5_Handler [WEAK]
EXPORT DMAC6_Handler [WEAK]
EXPORT DMAC7_Handler [WEAK]
EXPORT DummyHandler [WEAK]
;下面的全部異常處理函數標號都對應同一個地址,這個地址也是 Default_Handler 的地址
CSV_Handler
SWDT_Handler
LVD_Handler
MFT_WG_IRQHandler
INT0_7_Handler
INT8_15_Handler
DT_Handler
MFS0RX_IRQHandler
MFS0TX_IRQHandler
MFS1RX_IRQHandler
MFS1TX_IRQHandler
MFS2RX_IRQHandler
MFS2TX_IRQHandler
MFS3RX_IRQHandler
MFS3TX_IRQHandler
MFS4RX_IRQHandler
MFS4TX_IRQHandler
MFS5RX_IRQHandler
MFS5TX_IRQHandler
MFS6RX_IRQHandler
MFS6TX_IRQHandler
MFS7RX_IRQHandler
MFS7TX_IRQHandler
PPG_Handler
TIM_IRQHandler
ADC0_IRQHandler
ADC1_IRQHandler
ADC2_IRQHandler
MFT_FRT_IRQHandler
MFT_IPC_IRQHandler
MFT_OPC_IRQHandler
BT_IRQHandler
CAN0_IRQHandler
CAN1_IRQHandler
USBF_Handler
USB_Handler
DMAC0_Handler
DMAC1_Handler
DMAC2_Handler
DMAC3_Handler
DMAC4_Handler
DMAC5_Handler
DMAC6_Handler
DMAC7_Handler
DummyHandler
B .
ENDP
;由於前面只是定義了堆棧段並沒有初始化,這裏對堆棧段進行初始化。就像定義了:int a; 初始化 a = 1;也可以像代碼段一樣定義的同時就初始化:int b = 2;
;下面代碼中有個__MICROLIB,對應後面 MDK 截圖的 Use MicroLIB,如果選了勾選了 Use MicroLIB,IF 就爲真,否則爲假。
ALIGN
; User Initial Stack & Heap
IF :DEF:__MICROLIB
EXPORT __initial_sp
EXPORT __heap_base
EXPORT __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
ALIGN
ENDIF
END