文章目錄
- 一、匯編語言簡介
- 二、在Keil下完成一個匯編程式的撰寫
- 三、 用匯編程式完成每間隔1秒鐘閃爍一次LED的程式,
- 四、參考資料
一、匯編語言簡介
匯編語言, 即第二代計算機語言,用一些容易理解和記憶的字母,單詞來代替一個特定的指令,比如:用“ADD”代表數字邏輯上的加減,“MOV”代表資料傳遞等等,通過這種方法,人們很容易去閱讀已經完成的程式或者理解程式正在執行的功能,對現有程式的bug修復以及運營維護都變得更加簡單方便,但計算機的硬體不認識字母符號,這時候就需要一個專門的程式把這些字符變成計算機能夠識別的二進制數,因為匯編語言只是將機器語言做了簡單編譯,所以并沒有根本上解決機器語言的特定性,所以匯編語言和機器自身的編程環境息息相關,推廣和移植很難,但是還是保持了機器語言優秀的執行效率,因為他的可閱讀性和簡便性,匯編語言到現在依然是常用的編程語言之一, 匯編語言不像其他大多數的程式設計語言一樣被廣泛用于程式設計,在今天的實際應用中,它通常被應用在底層,硬體操作和高要求的程式優化的場合,驅動程式、嵌入式作業系統和實時運行程式都需要匯編語言,
二、在Keil下完成一個匯編程式的撰寫
- 1、新建工程,點擊上方的的Project->New μVision Project… 選擇工程存放位置及工程名,
- 選擇芯片

-
添加啟動檔案

-
在左側Source Group 1檔案上右鍵,選擇Add new item…,選擇Asm File,然后點擊Add

-
添加代碼
AREA MYDATA, DATA
AREA MYCODE, CODE
ENTRY
EXPORT __main
__main
MOV R0, #10
MOV R1, #11
MOV R2, #12
MOV R3, #13
;LDR R0, =func01
BL func01
;LDR R1, =func02
BL func02
BL func03
LDR LR, =func01
LDR PC, =func03
B .
func01
MOV R5, #05
BX LR
func02
MOV R6, #06
BX LR
func03
MOV R7, #07
MOV R8, #08
BX LR
END
- 為了能在MDK中進行仿真,需要進行一些設定,點擊魔法棒,選擇Debug,Use Simulator,將下方的Dialog.DLL修改成DARMSTM.DLL,Parameter修改成-pSTM32F103C8(根據你選的芯片來寫),如果這里不進行修改,仿真除錯的時候就會一直回圈在

這是由于我們進行的仿真,沒有外部晶振進行起振,

- 開始仿真,點擊上方的Start/Stop Debug(或者直接ctrl+F5),然后點擊②處的RUN,再點擊Stop

- 運行結果

- 最終生成 hex檔案的各段的大小

Code:指程式中代碼的位元組數
RO-data:指程式中定義的常量位元組數
RW-data :程式中已初始化的變數位元組數
ZI-Data:程式中未初始化的變數位元組數
可計算出flash和RAM的占用情況:
flash = Code + RO-data + RW-data
ram = RW-data + ZI-dat
- 打開hex檔案

如圖,其中第一行020000040800F2中,可以看做是0x02 0x00 0x00 0x04 0x08 0x00 0xf2,其前四個位元組和最后一個位元組有特殊含義,中間為資料
第一個0×02表示該行資料中有兩個資料
第二個,第三個0x00 0x00表示本行資料的起始地址位
第四個位元組有0x00 0x01 0x02 0x03 0x04 0x05,分別有以下含義
'00’Data Rrecord:用來記錄資料,HEX檔案的大部分記錄都是資料記錄
'01’檔案結束記錄:用來標識檔案結束,放在檔案的最后,標識HEX檔案的結尾**
'02’擴展段地址記錄:用來標識擴展段地址的記錄
'03’開始段地址記錄:開始段地址記錄
'04’擴展線性地址記錄:用來標識擴展線性地址的記錄
'05’開始線性地址記錄:開始線性地址記錄
最后一個位元組0xf2為校驗和,
校驗和的演算法為:
計算0xf2前所有16進制碼的累加和(不計進位),檢驗和 = 0x100 - 累加和
三、 用匯編程式完成每間隔1秒鐘閃爍一次LED的程式,
- 按上面的步驟再建立一個新工程,不用加啟動檔案,加啟動檔案的步驟可省略,
- 主要代碼
LED0 EQU 0x422201b4
RCC_APB2ENR EQU 0x40021018
GPIOC_CRH EQU 0x40011004 ;預定義
Stack_Size EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
AREA RESET, DATA, READONLY
__Vectors DCD __initial_sp ; Top of Stack
DCD Reset_Handler ; Reset Handler
AREA |.text|, CODE, READONLY ;開始代碼段
;支持THUMB指令,代碼段按8位元組對齊
THUMB
REQUIRE8
PRESERVE8
ENTRY ;宣告整個程式的入口
Reset_Handler
BL LED_Init
MainLoop BL LED_ON
BL Delay
BL LED_OFF
BL Delay
B MainLoop
LED_Init
PUSH {R0,R1, LR} ;將R0,R1,LR入堆疊
LDR R0,=RCC_APB2ENR
ORR R0,R0,#0x04
LDR R1,=RCC_APB2ENR
STR R0,[R1]
LDR R0,=GPIOC_CRH
BIC R0,R0,#0XFF0FFFFF ;配置為模擬輸入模式
LDR R1,=GPIOC_CRH
STR R0,[R1]
LDR R0,=GPIOC_CRH
ORR R0,R0,#0X00300000 ;配置為通用推挽輸出模式,最大速度為50MHz
LDR R1,=GPIOC_CRH
STR R0,[R1]
MOV R0,#1 ;將立即數1送入R0.
LDR R1,=LED0 ;將PC13 bit-bond的地址送入R1.
STR R0,[R1] ;將R0的值,也就是1,送給R1中的值所指向的地址中
POP {R0,R1,PC} ;將R0,R1,PC出堆疊
LED_ON
PUSH {R0,R1, LR}
MOV R0,#0
LDR R1,=LED0
STR R0,[R1]
POP {R0,R1,PC}
LED_OFF
PUSH {R0,R1, LR}
MOV R0,#1
LDR R1,=LED0
STR R0,[R1]
POP {R0,R1,PC}
Delay
PUSH {R0,R1, LR}
MOVS R0,#0
MOVS R1,#0
MOVS R2,#0
DelayLoop0
ADDS R0,R0,#1 ;加法,R0=R0+1
CMP R0,#330 ;計算R0-330的值,R0<330,則C=0;否則C=1,
BCC DelayLoop0 ;若是C=0,則跳到DelayLoop0,若是c=1,則不跳轉
MOVS R0,#0
ADDS R1,R1,#1
CMP R1,#330
BCC DelayLoop0
MOVS R0,#0
MOVS R1,#0
ADDS R2,R2,#1
CMP R2,#15
BCC DelayLoop0
POP {R0,R1,PC}
NOP
END
- 代碼決議
1、預定義
LED0 EQU 0x422201b4 //PC13的Bit-Bond地址
RCC_APB2ENR EQU 0x40021018 //時鐘總線APB2地址
GPIOC_CRH EQU 0x40011004 //GPIO埠C高位暫存器CRH起始地址
為方便操作,給每個需要用到的暫存器地址定義一個名字,博主的stm32F103核心板的燈在PC13,計算公式:
((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
經過查詢stm32中文手冊可知,埠C地址為0x4001100C,bitnum=D(16進制),計算程序:

最終算出PC13埠地址為0x422201b4,后兩個地址是固定的,查詢stm32手冊即可,
2,分配堆疊空間
Stack_Size EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
這一段摘自啟動檔案,
AREA命令: AREA 命令指示匯編器匯編一個新的代碼段或資料段,段是獨立的、指定的、不可見的代碼或資料塊,它們由聯結器處理,
格式如下:
AREA 段名,段屬性1,段屬性2,段屬性3,,,
SPACE命令: SPACE 命令保留一個用零填充的存盤器塊,
所以整段的意思為:分配一個STACK段,該段不初始化,可讀寫,按8位元組對齊,分配一個大小為Stack_Size的存盤空間,并使堆疊頂的地址為__initial_sp,
3,其他命令
ENTRY命令: 宣告整個程式的入口點,入口點有且僅有一個,
LDR和STR: 暫存器的裝載和存盤指令,
LDR是把地址裝載到暫存器中(比如R0),
STR是把值存盤到暫存器所指的地址中,
ORR和BIC:
ORR 按位或操作,ORR R0,R0,#0x04意思即將R0中的數或上0x04,再將結果送往R0中,實際意思就是將R0的第二位置1,其他位不變,
BIC 先把立即數取反,再按位與,
CMP和BCC:
CMP是比較兩個數,相等或大于則將標志位C置位,否則將C清零,BCC是個組合指令,實際為B+CC,意思是如果C=0則跳轉,
CMP R2,#15; 計算R2-15的值,若是R2<15,則C=0;若是R2>=15,則C=1,
BCC DelayLoop0;若是C=0,則跳到DelayLoop0,若是c=1,則不跳轉,
4、PC13埠
LDR R0,=GPIOC_CRH
BIC R0,R0,#0XFF0FFFFF ;配置為模擬輸入模式
LDR R1,=GPIOC_CRH
STR R0,[R1]
LDR R0,=GPIOC_CRH
ORR R0,R0,#0X00300000 ;配置為通用推挽輸出模式,最大速率為50MHz

- 將代碼下載到核心板上,效果展示:

四、參考資料
1、HEX檔案格式詳解:https://blog.csdn.net/weixin_43836778/article/details/108598294
2、簡單的STM32 匯編程式—閃爍LED:https://www.cnblogs.com/WeyneChen/p/4860764.html
3、ARM匯編基礎之基于MDK創建純匯編語言的STM32工程:https://blog.csdn.net/u010632165/article/details/106481146
4、STM32中文參考手冊_V10
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/241416.html
標籤:其他
上一篇:樹莓派4B 暫存器基地址查詢
