《ARM嵌入式系統(tǒng)原理及應(yīng)用開發(fā)》課件第4章0815_第1頁(yè)
《ARM嵌入式系統(tǒng)原理及應(yīng)用開發(fā)》課件第4章0815_第2頁(yè)
《ARM嵌入式系統(tǒng)原理及應(yīng)用開發(fā)》課件第4章0815_第3頁(yè)
《ARM嵌入式系統(tǒng)原理及應(yīng)用開發(fā)》課件第4章0815_第4頁(yè)
《ARM嵌入式系統(tǒng)原理及應(yīng)用開發(fā)》課件第4章0815_第5頁(yè)
已閱讀5頁(yè),還剩108頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

1第4章ARM嵌入式系統(tǒng)程序設(shè)計(jì)及調(diào)試基礎(chǔ)

4.1ARM嵌入式匯編語(yǔ)言程序設(shè)計(jì)基礎(chǔ)4.2ARM嵌入式C語(yǔ)言程序設(shè)計(jì)基礎(chǔ)4.3ARM匯編語(yǔ)言與C/C++的混合編程4.4ARMADS集成開發(fā)環(huán)境的使用4.5EmbestIDE集成開發(fā)環(huán)境的使用2

在ARM匯編語(yǔ)言程序里,有一些特殊指令助記符,這些助記符與指令系統(tǒng)的助記符不同,沒(méi)有相應(yīng)的操作碼,通常稱這些特殊指令助記符為偽指令,他們所完成的操作稱為偽操作。偽指令在源程序中的作用是為完成匯編語(yǔ)言程序作各種準(zhǔn)備工作的,這些偽指令僅在匯編過(guò)程起作用,一旦匯編結(jié)束,偽指令的使命就完成。在ARM得匯編程序中,有符號(hào)定義(SymbolDefintion)偽指令,數(shù)據(jù)定義(DataDefinition)偽指令,地址讀取偽指令,匯編控制(AssemblyControl)偽指令,宏指令以及其它偽指令。4.1ARM嵌入式匯編語(yǔ)言程序設(shè)計(jì)基礎(chǔ)4.1.1ARM匯編器支持的偽指令3

1.符號(hào)定義偽指令

1)GBLA、GBLL和GBLS

格式:GBLA(GBLL或GBLS)全局變量名用途:定義一個(gè)ARM程序中的全局變量,并將其初始化。其中GBLA偽指令用于定義一個(gè)全局的數(shù)字變量,并初始化為0;GBLL偽指令用于定義一個(gè)全局的邏輯變量,并初始化為F(假);GBLS偽指令用于定義一個(gè)全局的字符串變量,并初始化為空。由于以上3條偽指令用于定義全局變量,因此在整個(gè)程序范圍內(nèi)變量名必須唯一。例如:GBLATest1;定義一個(gè)全局的數(shù)字變量,變量名為Test1Test1SETA0xAA;將該變量賦值為0xAAGBLLTest2;定義一個(gè)全局的邏輯變量,變量名為Test2Test2SETL{TRUE};將該變量賦值為真GBLSTest3;定義一個(gè)全局的字符串變量,變量名為Test3Test3SETS“Testing”

;將該變量賦值為“Testing”4

2)LCLA、LCLL、LCLS

格式:LCLA(LCLL或LCLS)局部變量名用途:定義一個(gè)ARM程序中的局部變量,并將其初始化。其中LCLA偽指令用于定義一個(gè)局部的數(shù)字變量,并初始化為0;LCLL偽指令用于定義一個(gè)局部的邏輯變量,并初始化為F(假);LCLS偽指令用于一個(gè)局部的字符串變量,并初始化為空。由于以上3條偽指令用于聲明局部變量,因此在其作用范圍內(nèi)變量名必須唯一。例如:LCLATest4;聲明一個(gè)局部得數(shù)字變量,變量名為Test4Test4SETA0xAA;將該變量賦值為0xAALCLLTest5;聲明一個(gè)局部的邏輯變量,變量名為Test5Test5SETL{TURE};將該變量賦值為真LCLSTest6;定義一個(gè)局部的字符串變量,變量名為Test6Test6SETS“Testing”

;將該變量賦值為“Testing”53)SETA、SETL、SETS

格式:變量名SETA(SETL或SETS)表達(dá)式用途:給一個(gè)已經(jīng)定義的全局變量或局部變量賦值。其中變量名為已經(jīng)定義過(guò)的全局變量或局部變量,表達(dá)式為將要賦值給變量的值。SETA偽指令用于給一個(gè)數(shù)學(xué)變量賦值;SETL偽指令用于給一個(gè)邏輯變量賦值;SETS偽指令用于給一個(gè)字符串變量賦值。例如:LCLATest3;聲明一個(gè)局部的數(shù)字變量,變量名為Test3Test3SETA0xAA;將該變量賦值為0xAALCLLTest4;聲明一個(gè)局部的邏輯變量,變量名為Test5Test4SETL{TRUE};將該變量賦值為真64)RLIST

格式:名稱RLIST{寄存器列表}

用途:對(duì)一個(gè)通用寄存器列表定義名稱,使用該偽指令定義的名稱可在ARM指令LDM/STM中使用。在LDM/STM指令中,列表中的寄存器訪問(wèn)次序?yàn)楦鶕?jù)寄存器的標(biāo)號(hào)由低到高,而與列表中得寄存器排列次序無(wú)關(guān)。例如:

RegListRLIST{R0–R5,R8,R10};將寄存器列表名稱定義為RegList,可在ARM指令LDM/STM中通過(guò)該名稱訪問(wèn)寄存器列表。7

2.?dāng)?shù)據(jù)定義偽指令

1)DCB

格式:標(biāo)號(hào)DCB表達(dá)式用途:分配一片連續(xù)的字節(jié)存儲(chǔ)單元并用偽指令中的表達(dá)式初始化。其中,表達(dá)式可以為0~255的數(shù)字或字符串。DCB偽指令也可用“=”代替。例如:

StrDCB“Thisisatest!”

;分配一片連續(xù)的字節(jié)存儲(chǔ)單元并初始化

2)DCW(或DCWU)格式:標(biāo)號(hào)DCW(或DCWU)偽指令用途:分配一片連續(xù)的半字節(jié)存儲(chǔ)單元,并用偽指令中指定的表達(dá)式初始化。其中,表達(dá)式可以為程序標(biāo)號(hào)或數(shù)字表達(dá)式。DCW偽指令和DCWU偽指令的區(qū)別僅在于用DCW偽指令分配的字存儲(chǔ)單元是半字對(duì)齊,而用DCWU偽指令分配的字存儲(chǔ)單元并不嚴(yán)格半字對(duì)齊。例如:

DataTestDCW1,2,3;分配一片連續(xù)的半字存儲(chǔ)單元并初始化8

3)DCD(或DCDU)格式:標(biāo)號(hào)DCD(或DCDU)表達(dá)式用途:分配一片連續(xù)的字存儲(chǔ)單元并用偽指令指定的表達(dá)式初始化。其中,表達(dá)式可以為程序標(biāo)號(hào)或數(shù)字表達(dá)式。DCD偽指令也可用“&”代替。DCD偽指令和DCDU偽指令的區(qū)別僅在于用DCD偽指令分配的字存儲(chǔ)單元是字對(duì)齊的,而用DCDU偽指令分配的字存儲(chǔ)單元并不嚴(yán)格字對(duì)齊。例如:

FdataTestDCD4,5,6;分配一片連續(xù)的字存儲(chǔ)單元并初始化

4)DCFD(或DCFDU)格式:標(biāo)號(hào)DCFD(或DCFDU)表達(dá)式用途:為雙精度的浮點(diǎn)數(shù)分配一片連續(xù)的字存儲(chǔ)單元并用偽指令中指定得表達(dá)式初始化。每個(gè)雙精度的浮點(diǎn)數(shù)占據(jù)2個(gè)字單元。DCFD偽指令和DCFDU偽指令的區(qū)別僅在于用DCFD偽指令分配的字存儲(chǔ)單元是字對(duì)齊的,而用DCFDU偽指令分配的字存儲(chǔ)單元并不嚴(yán)格對(duì)齊。例如:

FdataTestDCFD2E115,-5E7;分配一片連續(xù)的字存儲(chǔ)單元并初始化為指定的雙精度數(shù)9

5)DCFS(或DCFSU)格式:標(biāo)號(hào)DCFS(或DCFDU)表達(dá)式用途:為單精度得浮點(diǎn)數(shù)分配一片連續(xù)的字存儲(chǔ)單元并用偽指令中指定的表達(dá)式初始化。每個(gè)單精度的浮點(diǎn)數(shù)占據(jù)1個(gè)字單元。DCFS偽指令和DCFSU偽指令的區(qū)別僅在于用DCFS偽指令分配的字存儲(chǔ)單元是字對(duì)齊的,而用DCFSU偽指令分配的字存儲(chǔ)單元并不嚴(yán)格字對(duì)齊。例如:

FDataTESTDCFS2E5,-5E-7;分配一片連續(xù)的字存儲(chǔ)單元并初始化為指定的單精度數(shù)

6)DCQ(或DCQU)格式:標(biāo)號(hào)DCQ(或DCQU)表達(dá)式用途:分配一片以8個(gè)字節(jié)為單位的連續(xù)存儲(chǔ)區(qū)域并用偽指令中指定的表達(dá)式初始化。DCQ偽指令和DCQU偽指令的區(qū)別僅在于用DCQ偽指令分配的存儲(chǔ)單元是字對(duì)齊的,而用DCQU偽指令分配的存儲(chǔ)單元并不嚴(yán)格字對(duì)齊。例如:

DataTestDCQ100;分配一片連續(xù)的字存儲(chǔ)單元并初始化為指定的值10

7)SPACE

格式:標(biāo)號(hào)SPACE表達(dá)式用途:SPACE偽指令用于分配1片連續(xù)的存儲(chǔ)區(qū)域并初始化為0。其中,表達(dá)式為要分配的字節(jié)數(shù)。SPACE也可用“%”代替。例如:DataSpaceSPACE100;分配連續(xù)100字節(jié)的存儲(chǔ)單元并初始化為08)MAP

格式:MAP表達(dá)式{,基址寄存器}

用途:定義結(jié)構(gòu)化的內(nèi)存表的首地址。MAP偽指令也可用“^”代替。表達(dá)式可以為程序中的標(biāo)號(hào)或數(shù)學(xué)表達(dá)式,基址寄存器為可選項(xiàng),當(dāng)基址寄存器選項(xiàng)不存在時(shí),表達(dá)式的值即是內(nèi)存表的首地址,當(dāng)該選項(xiàng)存在時(shí),內(nèi)存表的首地址為表達(dá)式的值與基址寄存器的和。

MAP偽指令僅用于定義數(shù)據(jù)結(jié)構(gòu),并不實(shí)際分配存儲(chǔ)單元,通常可與FIELD偽指令配合使用來(lái)定義結(jié)構(gòu)化的內(nèi)存表。例如:MAP0x100,R0;定義結(jié)構(gòu)化的內(nèi)存表的首地址的值位0x100+R011

9)FILED

格式:標(biāo)號(hào)FIELD表達(dá)式用途:定義一個(gè)結(jié)構(gòu)化內(nèi)存表中的數(shù)據(jù)域,其中,表達(dá)式的值為當(dāng)前數(shù)據(jù)域在內(nèi)存表中所占的字節(jié)數(shù)。FIELD偽指令也可用“#”代替。與MAP偽指令相同,F(xiàn)IELD偽指令僅用于定義數(shù)據(jù)結(jié)構(gòu),并不實(shí)際分配存儲(chǔ)單元。FIELD偽指令常與MAP偽指令配合使用來(lái)定義結(jié)構(gòu)化的內(nèi)存表。MAP偽指令定義內(nèi)存表的首地址,F(xiàn)IELD偽指令定義內(nèi)存表中的各個(gè)數(shù)據(jù)域,并可以為每個(gè)數(shù)據(jù)指定一個(gè)標(biāo)號(hào)供其他的指令引用。例如:

MAP0x100;定義結(jié)構(gòu)化內(nèi)存表首地址的值為0x100AFIELD16;定義A的長(zhǎng)度為16字節(jié),位置為0x100BFIELD32;定義B的長(zhǎng)度為32字節(jié),位置為0x110SFIELD256;定義S的長(zhǎng)度為256字節(jié),位置為0x130123.地址讀取偽指令13

1)ADR偽指令——小范圍的地址讀取在匯編編譯器編譯源程序時(shí),ADR偽指令被編譯器替換成一條合適的指令。通常,編譯器用一條ADD指令或SUB指令來(lái)實(shí)現(xiàn)ADR偽指令的功能,若不能用一條指令實(shí)現(xiàn),則產(chǎn)生錯(cuò)誤,編譯失敗。ADR偽指令中的地址是基于PC或寄存器的,當(dāng)ADR偽指令中的地址是基于PC時(shí),該地址與ADR偽指令必須在同一個(gè)代碼段中。地址表達(dá)式expression的取值范圍如下:當(dāng)?shù)刂分凳亲止?jié)對(duì)齊時(shí),其取值范圍為-255B~255B;當(dāng)?shù)刂分凳亲謱?duì)齊時(shí),其取值范圍為-1020B~1020B。例如:LOOPMOVR0,#10;LOOP為行標(biāo),指示某一行代碼ADRR4,LOOP;將LOOP地址放入r4(相對(duì)地址),因?yàn)镻C值為當(dāng)前指令地址值加8字節(jié),替換成ADR偽偽指令將被編譯器譯為;SUBR4,PC,0xC;NOP(MOVR0,R0)14

2)ADRL偽指令——中等范圍的地址讀取

ADRL比ADR偽指令可以讀取更大范圍的地址。在匯編編譯器編譯源程序時(shí),ADRL偽指令被編譯器替換成兩條合適的指令。若不能用兩條指令實(shí)現(xiàn),則產(chǎn)生錯(cuò)誤,編譯失敗。地址表達(dá)式expression的取值范圍如下:當(dāng)?shù)刂分凳亲止?jié)對(duì)齊時(shí),其取值范圍為-64KB~64KB;當(dāng)?shù)刂分凳亲謱?duì)齊時(shí),其取值范圍為-256KB~256KB。例如:LOOPMOVR0,#10;LOOP為行標(biāo),指示某一行代碼ADRLR4,LOOP;將LOOP地址放入R4(相對(duì)地址),因?yàn)镻C值為當(dāng)前指令地址值加8字節(jié),替換成本ADRL偽偽指令將被編譯器譯為;SUBR4,PC,#0xC;NOP(MOVR0,R0)15

3)LDR偽指令——大范圍的地址讀取在匯編編譯源程序時(shí),LDR偽指令被編譯器替換成一條合適的指令。若加載的常數(shù)未超出MOV或MVN的范圍,則使用MOV或MVN指令代替該LDR偽指令,否則匯編器將常量放入文字池,并使用一條程序相對(duì)偏移的LDR指令從文字池讀出常量。例如:

LDRR1,=0xFF;將0xFF讀取到R1中,編譯后得到

MOVR1,0xFF

例如:

LDRR1,=ADDR;將外部地址ADDR讀取到R1中,匯編后將得到:;LDRR1,[PC,OFFSET_TO_LPOOL]

;…

;LPOOLDCDADDR164.匯編控制偽指令匯編控制偽指令用于控制匯編程序的執(zhí)行流程。

1)IF、ELSE、ENDIF

格式:IF邏輯表達(dá)式指令序列1ELSE指令序列2ENDIFIF、ELSE、ENDIF偽指令能根據(jù)條件的成立與否決定是否執(zhí)行某個(gè)指令序列。當(dāng)IF后面的邏輯表達(dá)式為真,則執(zhí)行指令序列1,否則執(zhí)行指令序列2。其中,ELSE及指令序列2可以沒(méi)有,此時(shí),當(dāng)IF后面的邏輯表達(dá)式為真,則執(zhí)行指令序列1,否則繼續(xù)執(zhí)行后面的指令。IF、ELSE、ENDIF偽指令可以嵌套使用。例如:

GBLLTest;聲明一個(gè)全局的邏輯變量,變量名為Test

……IFTest=TRUE指令序列1ELSE指令序列2ENDIF17

2)WHILE、WEND

格式:WHILE邏輯表達(dá)式指令序列WENDWHILE、WEND偽指令能根據(jù)條件的成立與否決定是否循環(huán)執(zhí)行某個(gè)指令序列。當(dāng)WHILE后面的邏輯表達(dá)式為真,則執(zhí)行指令序列,該指令序列執(zhí)行完畢后,再判斷邏輯表達(dá)式的值,若為真則繼續(xù)執(zhí)行,一直到邏輯表達(dá)式的值為假。

WHILE、WEND偽指令可以嵌套使用。例如:GBLACounter;聲明一個(gè)全局的數(shù)學(xué)變量,變量名為CounterCouterSETA3;由變量Counter控制循環(huán)次數(shù)

……WHILECounter<10

指令序列

WEND185.宏指令

1)MACRO、MEND

格式:MACRO$標(biāo)號(hào)宏名$參數(shù)1,$參數(shù)2,……

指令序列

MENDMACRO、MEND偽指令可以將一段代碼定義為一個(gè)整體,稱為宏指令,然后就可以在程序中通過(guò)宏指令多次調(diào)用該段代碼。其中,$標(biāo)號(hào)在宏指令被展開時(shí),標(biāo)號(hào)會(huì)被替換為用戶定義的符號(hào),宏指令可以使用一個(gè)或多個(gè)參數(shù),當(dāng)宏指令被展開時(shí),這些參數(shù)被相應(yīng)的值替換。宏指令的使用方式和功能與子程序相似,子程序可以提供模塊化的程序設(shè)計(jì)、節(jié)省存儲(chǔ)空間并提高運(yùn)行速度。但在使用子程序結(jié)構(gòu)時(shí)需要保護(hù)現(xiàn)場(chǎng),從而增強(qiáng)了系統(tǒng)的開銷,因此,在代碼較短且需要傳遞的參數(shù)較多時(shí),可以使用宏指令代替子程序。

19

包含在MACRO和MEND之間的指令序列稱為宏定義體,在宏定義體的第一行應(yīng)聲明宏的原型(包含宏名、所需的參數(shù)),然后就可以在匯編程序中通過(guò)宏名來(lái)調(diào)用該指令序列。在源程序被編譯時(shí),匯編器將宏調(diào)用展開,用宏定義中的指令序列代替程序中的宏調(diào)用,并將實(shí)際參數(shù)的值傳剃給宏定義中的形式參數(shù)。

MACRO、MEND偽指令可以嵌套使用。

2)MEXIT

格式:MEXITMEXIT用于從宏定義中跳轉(zhuǎn)出去。206.其它常用的偽指令

1)AREA

格式:AREA段名屬性1,屬性2,……

用途:定義一個(gè)代碼段或數(shù)據(jù)段。屬性字段表示該代碼段(或數(shù)據(jù)段)的相關(guān)屬性,多個(gè)屬性用逗號(hào)分隔。常用的屬性如下。(1)屬性CODE用于定義代碼段,默認(rèn)為READONLY。(2)屬性DATA用于定義數(shù)據(jù)段,默認(rèn)為READWRITE。(3)屬性READONLY指定本段為只讀,代碼段默認(rèn)為READONLY。(4)屬性READWRITE指定本段為可讀可寫,數(shù)據(jù)段的默認(rèn)屬性為READWRITE。(5)屬性ALIGN表示使用方式為ALIGN表達(dá)式。在默認(rèn)時(shí),ELF(可執(zhí)行連接文件)的代碼段和數(shù)據(jù)段是按字對(duì)齊的,表達(dá)式的取值范圍為0~31,相應(yīng)的對(duì)齊方式為2表達(dá)式次方。(6)屬性COMMON定義一個(gè)通用的段,不包括任何的用戶代碼和數(shù)據(jù)。各源文件中同名的COMMON段共享同一段存儲(chǔ)單元。21

一個(gè)匯編語(yǔ)言程序至少要包含一個(gè)段,當(dāng)程序太長(zhǎng)時(shí),也可以將程序分為多個(gè)代碼段和數(shù)據(jù)段。例如:

AREAInit,CODE,READONLY

指令序列;該偽指令定義了一個(gè)代碼段,段名為Init,屬性為只讀

2)ALIGN

格式:ALIGN{表達(dá)式{,偏移量}}

用途:ALIGN偽指令可通過(guò)添加填充字節(jié)的方式,使當(dāng)前位置滿足一定的對(duì)齊方式。其中,表達(dá)式的值用于指定對(duì)齊方式,可能的取值為2的幕,如1、2、4、8、16等。若未指定表達(dá)式,則將當(dāng)前位置的對(duì)齊方式為:2的表達(dá)式次幕加偏移量。例如:

AREAInit,CODE,READONLY,ALIGN=3;指定后面的指令為8字節(jié)對(duì)齊指令序列

END22

3)CODE16(或CODE32)格式:CODE16(或CODE32)用途:CODE16偽指令通知編譯器,其后的指令序列為16位的Thumb指令;CODE32偽指令通知編譯器,其后的指令序列為32位的ARM指令。若在匯編源程序中同時(shí)包括ARM指令和Thumb指令時(shí),可用CODE16偽指令通知編譯器其后的指令序列為16位的Thumb指令,CODE32偽指令通知編譯器其后的指令序列為32位的ARM指令。因此,在使用ARM指令和Thumb指令混合編程的代碼里,可用這兩條偽指令進(jìn)行切換,但注意他們只通知編譯其后指令的類型,并不能處理器進(jìn)行狀態(tài)的切換。23例如:AREAInit,CODE,READONLY……CODE32;通知編譯器其后的指令為32位的ARM指令LDRR0,=NEXT+1;將跳轉(zhuǎn)地址放入寄存器R0BXR0;程序跳轉(zhuǎn)到新的位置執(zhí)行,并將處理器切換到Thumb工作狀態(tài)……CODE16;通知編譯器其后的指令為16位的Thumb工作狀態(tài)NEXTLDRR3,=0x3FF……END;程序結(jié)束24

4)ENTRY

格式:ENTRY

用途:指定匯編程序的入口點(diǎn)。在一個(gè)完整的匯編程序中至少要有一個(gè)ENTRY(也可以有多個(gè),當(dāng)有多個(gè)ENTRY時(shí),程序的真正入口點(diǎn)由鏈接器指定),例如:

AREAInit,CODE,READONLYENTRY;指定應(yīng)用程序的入口點(diǎn)

……5)END

格式:END

用途:用于通知編譯器已經(jīng)到了源程序的結(jié)尾。例如:

AREAInit,CODE,READONLY

……END;指定應(yīng)用程序的結(jié)尾25

4)ENTRY

格式:ENTRY

用途:指定匯編程序的入口點(diǎn)。在一個(gè)完整的匯編程序中至少要有一個(gè)ENTRY(也可以有多個(gè),當(dāng)有多個(gè)ENTRY時(shí),程序的真正入口點(diǎn)由鏈接器指定),例如:

AREAInit,CODE,READONLYENTRY;指定應(yīng)用程序的入口點(diǎn)

……5)END

格式:END

用途:用于通知編譯器已經(jīng)到了源程序的結(jié)尾。例如:

AREAInit,CODE,READONLY

……END;指定應(yīng)用程序的結(jié)尾

26

8)IMPORT

格式:IMPORT標(biāo)號(hào){[WEAK]}

用途:通知編譯器要使用的標(biāo)號(hào)在其它的源文件中定義,但要在當(dāng)前源文件引用,而且無(wú)論當(dāng)前源文件是否引用該標(biāo)號(hào),該標(biāo)號(hào)均會(huì)被加入到當(dāng)前源文件的符號(hào)表中。標(biāo)號(hào)在程序中區(qū)分大小寫,[WEAK]選項(xiàng)表示當(dāng)所有的源文件都沒(méi)有定義這樣一個(gè)標(biāo)號(hào)時(shí),編譯器也不給出錯(cuò)誤信息,在多數(shù)情況下將該標(biāo)號(hào)值為0,若該標(biāo)號(hào)為B或BL指令引用,則將B或BL指令值為NOP操作。例如:

AREAInit,CODE,READONLYIMPORTMain;通知編譯器當(dāng)前文件要引用標(biāo)號(hào)Main,但Main在其他源文件中定義

……END27

9)EXTERN

格式:EXTERN標(biāo)號(hào){[WEAK]}

用途:通知編譯器要使用的標(biāo)號(hào)在其它的源文件中定義,但要在當(dāng)前源文件引用,如果當(dāng)前源文件是否引用該標(biāo)號(hào),該標(biāo)號(hào)就不會(huì)被加入到當(dāng)前源文件的符號(hào)表中。標(biāo)號(hào)在程序中區(qū)分大小寫,[WEAK]選項(xiàng)表示當(dāng)所有的源文件都沒(méi)有定義這樣一個(gè)標(biāo)號(hào)時(shí),編譯器也不給出錯(cuò)誤信息,在多數(shù)情況下將該標(biāo)號(hào)值為0,若該標(biāo)號(hào)為B或BL指令引用,則將B或BL指令值為NOP操作。例如:

AREAInit,CODE,READONLYEXTERNMain;通知編譯器當(dāng)前文件要引用標(biāo)號(hào)Main,但Main在其他源文件中定義

……END2810)GET(或INCLUDE)格式:GET文件名用途:將一個(gè)源文件包含到當(dāng)前的源文件中,并將被包含的源文件在當(dāng)前位置進(jìn)行匯編處理??梢允褂肐NCLUDE代替GET。匯編程序中常用的方法是在某源文件中定義一些宏指令,用EQU定義常量的符號(hào)名稱,用MAP和FIELE定義結(jié)構(gòu)化的數(shù)據(jù)類型,然后用GET偽指令將這個(gè)源文件包含到其他的源文件中。使用方法與C語(yǔ)言中的“include”相似。

GET偽指令只能用于包含源文件,包含目標(biāo)文件使用INCBIN偽指令。例如:

AREAInit,CODE,READONLYGETa1,s;通知編譯器當(dāng)前源文件包含源文件a1.sGETC:\a2.s;通知編譯器當(dāng)前源文件包含源文件C:\a2.s

……END29

11)INCBIN

格式:INCBIN文件名用途:將一個(gè)目標(biāo)文件或數(shù)據(jù)文件包含到當(dāng)前的源文件中,被包含的文件不作任何變動(dòng)地存放在當(dāng)前文件中,編譯器從其后開始繼續(xù)處理。例如:

AREAInit,CODE,READONLYINCBINa1.dat;通知編譯器當(dāng)前源文件包含文件a1.datINCBINC:\a2.txt;通知編譯器當(dāng)前源文件包含文件C:\a2.txt

……END30

12)RN

格式:名稱RN表達(dá)式用途:給一個(gè)寄存器定義一個(gè)別名。采用這種方式可以方便程序員記憶該寄存器的功能。其中,名稱為給寄存器定義的別名,表達(dá)式為寄存器的編碼。例如:

TampRNR0;將R0定義一個(gè)別名Temp13)ROUT

格式:{名稱}ROUT

用途:給一個(gè)局部變量定義作用范圍。在程序中未使用該偽指令時(shí),局部變量的作用范圍為所在的AREA,而使用ROUT后,局部變量的作為范圍當(dāng)前ROUT和下一個(gè)ROUT之間。31

ARM(Thumb)匯編語(yǔ)言的語(yǔ)句格式為:

{標(biāo)號(hào)}{指令或偽指令}{;注釋}

在匯編語(yǔ)言程序設(shè)計(jì)中,每一條指令的助記符可以全部用大寫、或全部用小寫,但不允許在一條指令中大、小寫混用。如果一條語(yǔ)句太長(zhǎng),可將用該語(yǔ)句分為若干行來(lái)書寫,在行的末尾用“\”表示下一行與本行為同一條語(yǔ)句。

1.在匯編語(yǔ)言程序中常用的符號(hào)在匯編語(yǔ)言程序設(shè)計(jì)中,經(jīng)常使用各種符號(hào)代替地址、變量和常量等,以增加程序的可讀性。盡管符號(hào)的命名由編程者決定,但并不是任意的,必須遵守以下的約定:①符號(hào)區(qū)分大小寫,同名的大、小寫符號(hào)會(huì)被編譯器認(rèn)為是兩個(gè)不同的符號(hào);②符號(hào)在其作用范圍必須唯一;③自定義的符號(hào)名不能與系統(tǒng)的保留字相同;④符號(hào)名不應(yīng)與指令或偽指令同名。4.1.2ARM匯編語(yǔ)言的語(yǔ)句格式32

1)程序中的變量程序中的變量是指其值在程序的運(yùn)行過(guò)程中可以改變的量。ARM(或Thumb)匯編程序所支持的變量有數(shù)字變量、邏輯變量和字符串變量。其中數(shù)字變量用于在程序的運(yùn)行中保存數(shù)字值,但注意數(shù)字值的大小不應(yīng)超過(guò)數(shù)字變量所能表示的范圍;邏輯變量用于在程序的運(yùn)行中保存邏輯值,邏輯值只有真或假2種取值的情況;字符串變量用于在程序的運(yùn)行中保存一個(gè)字符串,但注意字符串的長(zhǎng)度不應(yīng)超過(guò)字符串變量所能表示的范圍。

2)程序中的常量程序中的常量是指其值在程序的運(yùn)行過(guò)程中不能被改變的量。ARM(Thumb)匯編程序所支持的常量有數(shù)字常量、邏輯常量和字符串常量。其中數(shù)字常量一般為32位的整數(shù),當(dāng)作為無(wú)符號(hào)數(shù)時(shí),其取值范圍為0~232–1;當(dāng)作為有符號(hào)數(shù)時(shí),其取值范圍為-232~232–1。邏輯常量只有真或假2種取值情況。字符串常量為一個(gè)固定的字符串,一般用于程序運(yùn)行時(shí)的信息提示。33

3)程序中的變量代換程序中的變量可通過(guò)代換操作取得一個(gè)常量。代換操作符為“$”。如果在數(shù)字變量前面有一個(gè)代換操作符“$”,編譯器會(huì)將該數(shù)字變量的值轉(zhuǎn)換為十六進(jìn)制的字符串,并將該十六進(jìn)制的字符串代換“$”后的數(shù)字變量;如果在邏輯變量前面有一個(gè)代換操作符“$”,編譯器會(huì)將該邏輯變量代換為它的取值(真或假);如果在字符串變量前面有一個(gè)代換操作符“$”,編譯器會(huì)將該字符串變量的值代換“$”后的字符串變量。例如:

LCLSS1;定義局部字符串變量S1和S2LCLSS2S1SETS“Test!“

S2SETS“Thisisa$S1”;字符串變量S2值為“ThisisaTest”342.匯編語(yǔ)言程序中的表達(dá)式和運(yùn)算符在匯編語(yǔ)言程序設(shè)計(jì)中,經(jīng)常使用各種表達(dá)式,表達(dá)式一般由變量、常量、運(yùn)算符和括號(hào)構(gòu)成,常用的表達(dá)式有數(shù)字表達(dá)式、邏輯表達(dá)式及字符串表達(dá)式3種,其運(yùn)算順序遵循如下優(yōu)先級(jí):①優(yōu)先級(jí)相同的雙目運(yùn)算符的運(yùn)算順序從左到右;②相鄰的單目運(yùn)算符的運(yùn)算順序?yàn)閺挠业阶螅覇文窟\(yùn)算符的優(yōu)先級(jí)高于其他運(yùn)算符;③括號(hào)運(yùn)算符的優(yōu)先級(jí)最高。35

1)數(shù)字表達(dá)式及運(yùn)算符數(shù)字表達(dá)式一般由數(shù)字常量、數(shù)值變量、數(shù)字運(yùn)算符和括號(hào)構(gòu)成。與數(shù)字表達(dá)式相關(guān)的運(yùn)算符有算術(shù)運(yùn)算符、移位運(yùn)算符及按位邏輯運(yùn)算符。(1)算術(shù)運(yùn)算符。數(shù)字表達(dá)式中的算術(shù)運(yùn)算符有“+”、“-”、“*”、“/”及“MOD”,分別代表加、減、乘、除及取余數(shù)運(yùn)算。以X和Y表示兩個(gè)數(shù)字表達(dá)式,這些算術(shù)運(yùn)算符代表的運(yùn)算如下:X+Y表示X與Y的和;X-Y表示X與Y的差;X*Y表示X與Y的乘積;X/Y表示X處以Y的余數(shù)。(2)移位運(yùn)算符。數(shù)字表達(dá)式中的移位運(yùn)算符有“ROL”、“ROR”、“SHL”及“SHR”,以X和Y表示兩個(gè)數(shù)字表達(dá)式,這些移位運(yùn)算符代表的運(yùn)算如下:X:ROL:Y表示將X循環(huán)左移Y位;X:ROR:Y表示X循環(huán)右移Y位;X:SHL:Y表示將X左移Y位;X:SHR:Y表示將X右移Y位。36

(3)按位邏輯運(yùn)算符。數(shù)字表達(dá)式中的按位邏輯運(yùn)算符有“AND”、“OR”、“NOT”及“EOR”,以X和Y表示兩個(gè)數(shù)字表達(dá)式,以上的按位邏輯運(yùn)算符代表的運(yùn)算如下:X:AND:Y表示將X和Y按位作邏輯與的操作;X:OR:Y表示將X和Y按位作邏輯或的操作;:NOT:Y表示將Y按位作邏輯非的操作;X:EOR:Y表示將X和Y按位作邏輯異或的操作。

2)邏輯表達(dá)式及運(yùn)算符邏輯表達(dá)式一般由邏輯量、邏輯運(yùn)算符和括號(hào)構(gòu)成,其表達(dá)式的運(yùn)算結(jié)果為真或假。與邏輯表達(dá)式相關(guān)的運(yùn)算符如下:(1)“=”、“>”、“<”、“>=”、“<=”、“/=”、“<>”運(yùn)算符。以X和Y表示兩個(gè)邏輯表達(dá)式,以上的運(yùn)算符代表的運(yùn)算如下:X=Y表示X等于Y;X>Y表示X大于Y;X<Y表示X小于Y;X>=Y表示X大于等于Y;X<=Y表示X小于等于Y;X/=Y表示X不等于Y;X<>Y表示X不等于Y。37

(2)“LAND”、“LOR“、“LNOT”及“LEOR”運(yùn)算符。以X和Y表示兩個(gè)邏輯表達(dá)式,以上的邏輯運(yùn)算符代表的運(yùn)算如下:X:LAND:Y表示將X和Y作邏輯與的操作;X:LOR:Y表示將X和Y作邏輯或的操作;:LNOT:Y表示將Y作邏輯非的操作;X:LEOR:Y表示將X和Y作邏輯異或的操作。

3)字符串表達(dá)式及運(yùn)算符字符串表達(dá)式一般由字符串常量、字符串變量、運(yùn)算符和括號(hào)組成。編譯器所支持的字符串的最大長(zhǎng)度為512字節(jié)。常用的與字符串表達(dá)式相關(guān)的運(yùn)算符如下。(1)LEN運(yùn)算符。LEN運(yùn)算符返回字符串的長(zhǎng)度(字符數(shù)),以X表示字符串表達(dá)式,其語(yǔ)法格式如下::LEN:X

(2)CHR運(yùn)算符。CHR運(yùn)算符將0~255之間的整數(shù)轉(zhuǎn)換為一個(gè)字符,以M表示某一個(gè)整數(shù),其語(yǔ)法格式如下::CHR:M38

(3)STR運(yùn)算符。STR運(yùn)算符將一個(gè)數(shù)字表達(dá)式或邏輯表達(dá)式轉(zhuǎn)換為一個(gè)字符串。對(duì)于數(shù)字表達(dá)式,STR運(yùn)算符將其轉(zhuǎn)換為一個(gè)以十六進(jìn)制組成的字符串;對(duì)于邏輯表達(dá)式,STR運(yùn)算符將其轉(zhuǎn)換為字符串T或F,其語(yǔ)法格式如下::STR:X其中X為一個(gè)數(shù)字表達(dá)式或邏輯表達(dá)式。(4)LEFT運(yùn)算符。LEFT運(yùn)算符返回某個(gè)字符串左端的一個(gè)字串,其語(yǔ)法格式如下:X:LEFT:Y其中X為源字符串,Y為一個(gè)整數(shù),表示要返回的字符個(gè)數(shù)。(5)RIGHT運(yùn)算符。與LEFT運(yùn)算符相對(duì)應(yīng),RIGHT運(yùn)算符返回某個(gè)字符串右端的一個(gè)字串,其語(yǔ)法格式如下:X:RIGHT:Y其中X為源字符串,Y為一個(gè)整數(shù),表示要返回的字符個(gè)數(shù)。39

(6)CC運(yùn)算。CC運(yùn)算符用于將兩個(gè)字符串連接成一個(gè)字符串,其語(yǔ)法格式如下:X:CC:Y其中X為源字符串1,Y為源字符串2,CC運(yùn)算符將Y連接到X后面。

4)與寄存器和程序計(jì)數(shù)器(PC)相關(guān)的表達(dá)式及運(yùn)算符常用的與寄存器和程序計(jì)數(shù)器相關(guān)的表達(dá)式及運(yùn)算符如下:(1)BASE運(yùn)算符。BASE運(yùn)算符返回基于寄存器的表達(dá)式中寄存器的編號(hào),其語(yǔ)法格式如下::BASE:X其中X為與寄存器相關(guān)的表達(dá)式(2)INDEX運(yùn)算符。INDEX運(yùn)算符返回基于寄存器的表達(dá)式中相對(duì)于其基址寄存器的偏移量,其語(yǔ)法格式如下::INDEX:X其中,X為與寄存器相關(guān)的表達(dá)式

5)其他常用運(yùn)算符(1)?運(yùn)算符。?運(yùn)算符返回某代碼行所生成的可執(zhí)行代碼的長(zhǎng)度,如“?X”表示返回定義符號(hào)X的代碼行所生成的可執(zhí)行代碼的字節(jié)數(shù)。(2)DEF運(yùn)算符。DEF運(yùn)算符判斷是否定義某個(gè)符號(hào),如:DEF:X:表示當(dāng)符號(hào)X已經(jīng)定義,結(jié)果為真;否則為假。40

1.匯編語(yǔ)言的程序結(jié)構(gòu)在ARM(Thumb)匯編語(yǔ)言程序中,以程序段位單位組織代碼。段是相對(duì)獨(dú)立的指令或數(shù)據(jù)序列,具有特定的名稱。段可以分為代碼段和數(shù)據(jù)段,代碼段的內(nèi)容為執(zhí)行代碼,數(shù)據(jù)段存放運(yùn)行時(shí)需要用到的數(shù)據(jù)。一個(gè)匯編程序至少要有一個(gè)代碼段,當(dāng)程序較長(zhǎng)時(shí),可以分割為多個(gè)代碼段和數(shù)據(jù)段,多個(gè)段在程序編譯鏈接時(shí)最終形成一個(gè)可執(zhí)行的映象文件??蓤?zhí)行映象文件通常由以下幾部分構(gòu)成。(1)一個(gè)或多個(gè)代碼段,代碼段的屬性為只讀。(2)零個(gè)或多個(gè)包含初始化數(shù)據(jù)的數(shù)據(jù)段,其屬性為可讀寫。(3)零個(gè)或多個(gè)不包含初始化數(shù)據(jù)的數(shù)據(jù)段,其屬性為可讀寫。鏈接器根據(jù)系統(tǒng)默認(rèn)或用戶設(shè)定的規(guī)則,將各個(gè)段安排在存儲(chǔ)器中的相應(yīng)位置。因此源程序中段之間的相對(duì)位置與可執(zhí)行的映象文件中段的相對(duì)位置一般不會(huì)相同。4.1.3ARM匯編語(yǔ)言的程序結(jié)構(gòu)41

以下是一個(gè)匯編語(yǔ)言的程序基本結(jié)構(gòu):

AREAInit,CODE,READONLYENTRYSTARTLDRR0,=0x3FF5000LDRR1,#0xFFSTRR1,[R0]LDRR0,=0x3FF5008LDRR1,0x01STRR1,[R0]

……

……END。在匯編語(yǔ)言程序中,用AREA偽指令定義一個(gè)段,并說(shuō)明所定義段的相關(guān)屬性,以上程序段中定義了一個(gè)名為Init的代碼段,屬性為只讀。ENTRY偽指令標(biāo)識(shí)程序的入口點(diǎn),接下來(lái)為指令序列,程序的末尾為END偽指令。422.匯編語(yǔ)言的子程序調(diào)用在ARM匯編語(yǔ)言程序中,子程序的調(diào)用一般是通過(guò)BL指令來(lái)實(shí)現(xiàn)的,其格式如下:

BL子程序名該指令在執(zhí)行時(shí)完成如下操作:將子程序的返回地址存放在連接寄存器(LR)中,同時(shí)將程序計(jì)數(shù)器(PC)指向子程序的入口點(diǎn),當(dāng)子程序執(zhí)行完畢需要返回調(diào)用處時(shí),只需要將存放在(LR)中的返回地址重新拷貝給PC即可。在調(diào)用子程序的同時(shí),也可以完成參數(shù)的傳遞和從子程序返回運(yùn)算的結(jié)果,通??梢允褂眉拇嫫鱎0至R3完成。43C語(yǔ)言是一種結(jié)構(gòu)化的程序設(shè)計(jì)語(yǔ)言,它的優(yōu)點(diǎn)是運(yùn)行速度快、編譯效率高、移植性好和可讀性強(qiáng)。C語(yǔ)言具有簡(jiǎn)單的語(yǔ)法結(jié)構(gòu)和強(qiáng)大的處理功能,并可方便的實(shí)現(xiàn)對(duì)硬件的直接操作。C語(yǔ)言支持模塊化程序設(shè)計(jì)結(jié)構(gòu),支持自頂向下的結(jié)構(gòu)化程序設(shè)計(jì)方法。因此C語(yǔ)言編寫的應(yīng)用軟件,可大大提高軟件的可讀性,縮短開發(fā)周期,便于系統(tǒng)的改進(jìn)和擴(kuò)充,這為開發(fā)大規(guī)模、高性能和高可靠性的應(yīng)用系統(tǒng)提供了基本保證。嵌入式C語(yǔ)言程序設(shè)計(jì)是利用基本的C語(yǔ)言知識(shí),面向嵌入式工程實(shí)際應(yīng)用進(jìn)行程序設(shè)計(jì)。嵌入式C語(yǔ)言程序設(shè)計(jì)首先是C語(yǔ)言程序設(shè)計(jì),必須符合C語(yǔ)言基本語(yǔ)法。嵌入式C語(yǔ)言程序設(shè)計(jì)又是面向嵌入式的應(yīng)用,因此就要利用C語(yǔ)言基本知識(shí)開發(fā)出面向嵌入式的應(yīng)用程序。如何能夠在嵌入式系統(tǒng)開發(fā)中熟練、正確的運(yùn)用C語(yǔ)言開發(fā)出高質(zhì)量的應(yīng)用程序,是學(xué)習(xí)嵌入式程序設(shè)計(jì)的基礎(chǔ)。4.2ARM嵌入式C語(yǔ)言程序設(shè)計(jì)基礎(chǔ)441.C語(yǔ)言的“預(yù)處理偽指令”在嵌入式程序設(shè)計(jì)中的應(yīng)用在C語(yǔ)言源程序中常常加入一些“預(yù)處理命令”,可以改進(jìn)程序設(shè)計(jì)環(huán)境,提高編程效率,它雖然寫在源程序中,但不產(chǎn)生程序代碼,因此稱為預(yù)處理偽指令。

C語(yǔ)言所有預(yù)處理偽指令都是以#號(hào)開頭,以區(qū)別于源文件中的語(yǔ)句行與說(shuō)明行。預(yù)處理偽指令有以下三種:文件包含、宏定義和條件編譯。預(yù)處理偽指令有以下特點(diǎn):把文件的正文替換進(jìn)來(lái),如標(biāo)準(zhǔn)頭文件和自定義頭文件;對(duì)宏定義進(jìn)行宏擴(kuò)展,減少了編程量,改進(jìn)源程序的可讀性;條件編譯改善了編程的靈活性,也改善了可移植性。4.2.1嵌入式C語(yǔ)言程序設(shè)計(jì)基礎(chǔ)45

1)文件包含偽指令文件包含偽指令可將頭文件包含到程序中,頭文件中定義的內(nèi)容包括符號(hào)常量、復(fù)合變量原型、用戶定義的變量類型原型和函數(shù)的原型說(shuō)明等。指令格式如下:

#include<頭文件名.h>;標(biāo)準(zhǔn)頭文件

#include“頭文件名.h”;用戶自定義頭文件

#include宏標(biāo)識(shí)符文件包含偽指令舉例如下:

#include<string.h>;標(biāo)準(zhǔn)頭文件

#include<stdio.h>;標(biāo)準(zhǔn)頭文件本例中string.h和stdio.h是標(biāo)準(zhǔn)頭文件,按環(huán)境變量include指定的目錄順序搜索string.h和stdio.h。462)宏定義偽指令(1)簡(jiǎn)單宏。定義格式為:#define宏標(biāo)識(shí)符宏體。在定義宏時(shí)應(yīng)盡量避免使用C語(yǔ)言的關(guān)鍵字和預(yù)處理器的預(yù)定義宏。(2)參數(shù)宏。定義格式為:#define宏標(biāo)識(shí)符(形式參數(shù)表)宏體。使用參數(shù)宏時(shí),形式參數(shù)表應(yīng)換為同樣個(gè)十的實(shí)參數(shù)表,這一點(diǎn)類似函數(shù)的調(diào)用。(3)條件宏定義。先測(cè)試是否定義過(guò)某個(gè)宏標(biāo)識(shí)符,然后決定如何處理。其定義格式如表4.2所示。(4)宏釋放。用于釋放原先定義的宏標(biāo)識(shí)符。經(jīng)釋放后的宏標(biāo)示符可再次用于定義其它宏體。其定義格式為:#undef宏標(biāo)識(shí)符。4748

3)條件編譯偽指令條件編譯偽指令是寫給編譯器的,指示編譯器在滿足某一條件時(shí)僅編譯源文件中與之相應(yīng)的比分。其格式如下:

#if(條件表達(dá)式1)...

#elif(條件表達(dá)式2)...

#elif(條件表達(dá)式n)...

#else

...

#endif49

2.嵌入式程序設(shè)計(jì)中的函數(shù)及函數(shù)庫(kù)

1)函數(shù)的定義格式

[存儲(chǔ)格式說(shuō)明符]類型說(shuō)明符[修飾符]標(biāo)識(shí)符(參數(shù)表){函數(shù)體}

其中:存儲(chǔ)格式說(shuō)明符有:static—靜態(tài)存儲(chǔ)類型,extern—外部存儲(chǔ)類型(全局)兩種。類型說(shuō)明符有:char,unsignedchar、int、unsigned、long、unsignedlong、float、double、longdouble、struct、union、void等幾種。若函數(shù)返回的是指針,在函數(shù)名前加“*”。標(biāo)識(shí)符有:函數(shù)名、*函數(shù)名—返回值是指針、(*函數(shù)名)—函數(shù)指針、*(*函數(shù)名))—標(biāo)識(shí)符是指針,返回值是指針等幾種。修飾符有:interrupt—為中斷函數(shù),其返回類型和參數(shù)均必須為void、near—近調(diào)用(16位段內(nèi)地址)、far—遠(yuǎn)調(diào)用(32位段間地址)、huge—規(guī)范化調(diào)用(32位段間規(guī)范地址)等幾種。504.處理器寄存器到協(xié)處理器寄存器的數(shù)據(jù)傳送指令格式:MCR{條件}協(xié)處理器編號(hào),操作碼1,源寄存器,目的寄存器1,目的寄存器2,操作碼2

用途:將ARM處理器寄存器中的數(shù)據(jù)傳送到協(xié)處理器寄存器中,若協(xié)處理器不能成功完成操作,則產(chǎn)生未定義指令異常。其中協(xié)處理器操作碼1和協(xié)處理器操作碼2為協(xié)處理器將要執(zhí)行的操作,源寄存器為ARM處理器的寄存器,目的寄存器1和目的寄存器2均為協(xié)處理器的寄存器。例如:MCRP3,3,R0,C4,C5,6;該指令將ARM處理器寄存器R0中的數(shù)據(jù)傳送到協(xié)處理器P3的寄存器C4和C5中。51

2)函數(shù)庫(kù)介紹以前面已提到的用戶自定義頭文件“44blib.h”為例進(jìn)行說(shuō)明。該頭文件對(duì)程序開發(fā)中所用到的函數(shù)進(jìn)行了聲明,這些函數(shù)構(gòu)成了一個(gè)基本函數(shù)庫(kù)44blib.C,用于用戶的程序開發(fā),它不屬于標(biāo)準(zhǔn)的C語(yǔ)言。圖4.1是44blib.c文件的代碼結(jié)構(gòu)圖。從該圖可以看出,用戶如何根據(jù)自己開發(fā)板的硬件及功能模塊來(lái)編寫自定義函數(shù)庫(kù)。52圖4.144blib.c文件的代碼結(jié)構(gòu)圖53

3.嵌入式程序設(shè)計(jì)中常用的C語(yǔ)言語(yǔ)句

1)if條件語(yǔ)句(1)兩重選擇

if(條件表達(dá)式)語(yǔ)句1;else語(yǔ)句2;(2)多重選擇

if(條件表達(dá)式1)語(yǔ)句1;

elseif(條件表達(dá)式2)語(yǔ)句2;

elseif(條件表達(dá)式3)語(yǔ)句3;...

elseif(條件表達(dá)式n)語(yǔ)句n;54

2)switch/case語(yǔ)句

switch(開關(guān)表達(dá)式){case常量表達(dá)式1:[語(yǔ)句1;]case常量表達(dá)式2:[語(yǔ)句2;]

......

case常量表達(dá)式n:[語(yǔ)句n;]default:[語(yǔ)句n+1;]

3)循環(huán)語(yǔ)句(1)for循環(huán)語(yǔ)句。

for(表達(dá)式1;表達(dá)式2;表達(dá)式3)語(yǔ)句;(2)while語(yǔ)句。

whlie(條件表達(dá)式)語(yǔ)句;(3)dowhile語(yǔ)句。

do語(yǔ)句;

whlie(條件表達(dá)式);55

4.嵌入式程序設(shè)計(jì)中C語(yǔ)言的變量、數(shù)組、結(jié)構(gòu)和聯(lián)合

1)變量定義格式為:[存儲(chǔ)類型]類型說(shuō)明符[修飾符]標(biāo)識(shí)符[=初值][,標(biāo)識(shí)符[=初值]]…;其中:類型說(shuō)明符:對(duì)于數(shù)字與字符,其類型共有9種:char,unsignedchar、int、unsigned、long、unsignedlong、float、double、longdouble。通過(guò)typedef來(lái)定義類型的別名。標(biāo)識(shí)符:變量,是不帶“*”的標(biāo)識(shí)符。指針,是帶有“*”的標(biāo)識(shí)符。存儲(chǔ)類型:auto---—自動(dòng)儲(chǔ)存的類型,是局部變量。register—寄存器儲(chǔ)存類型。extern—外部?jī)?chǔ)存類型。static—靜態(tài)儲(chǔ)存類型

56

賦初值部分:若初值缺省,則auto---儲(chǔ)存類型和register儲(chǔ)存類型的變量為隨機(jī)值;static儲(chǔ)存類型的變量被編譯器自動(dòng)清0;對(duì)于指針,無(wú)論什么存儲(chǔ)類型,一律為空指針(Null)修飾符:const—常量修飾符,指示被修飾的變量或變量指針是常量。volatile—易失性修飾符,說(shuō)明所定義的變量或指針,是可以被多種原因修改的。防止丟失任何一次這種修改,因此要把它修飾位易失性的變量。near、far—近、遠(yuǎn)修飾符,用于說(shuō)明訪問(wèn)內(nèi)存中變量在位置上的遠(yuǎn)近。

2)數(shù)組說(shuō)明

[存儲(chǔ)類類型]類型說(shuō)明符[修飾符]標(biāo)識(shí)符[=初始值][,標(biāo)識(shí)符[=初始值]]...;57

(1)一維數(shù)組。定義格式為:類型說(shuō)明符標(biāo)識(shí)符[常量表達(dá)式][={初值,初值,…}];char標(biāo)識(shí)符[]=“字符串”;(2)一維指針數(shù)組和一維數(shù)組指針。定義格式為:一維指針數(shù)組:類型說(shuō)明符*標(biāo)識(shí)符[常量表達(dá)式][={地址,地址…}];一維數(shù)組指針:類型說(shuō)明符(*標(biāo)識(shí)符)[][=數(shù)組標(biāo)識(shí)符];(3)二維數(shù)組。定義格式為:類型說(shuō)明符標(biāo)識(shí)符[m][n][={{初值表},{初值表}…}];(4)二維指針數(shù)組。定義格式為:類型說(shuō)明符*標(biāo)識(shí)符[m][n][={{地址表}},{地址表}}];

(5)二維數(shù)組指針。定義格式為:類型說(shuō)明符(*標(biāo)識(shí)符)[][n][=數(shù)組標(biāo)識(shí)符];(6)多重指針。定義格式為:類型標(biāo)識(shí)符**標(biāo)識(shí)符[=&指針];583)結(jié)構(gòu)說(shuō)明(1)原型法方法一:聲明結(jié)構(gòu)類型的同時(shí)定義變量名,其定義格式如下:

[存儲(chǔ)類說(shuō)明符]struct[結(jié)構(gòu)原型名]{類型說(shuō)明符[,標(biāo)識(shí)符…];類型說(shuō)明符[,標(biāo)識(shí)符…];

…}標(biāo)識(shí)符[={初值表}][,標(biāo)識(shí)符{={初值表}…}

方法二:先聲明結(jié)構(gòu)類型再定義變量名,其定義格式如下:

struct結(jié)構(gòu)原型名

{類型說(shuō)明標(biāo)識(shí)符[,標(biāo)識(shí)符…];

…}[存儲(chǔ)類說(shuō)明符]結(jié)構(gòu)原型名標(biāo)識(shí)符[={初值表}[,標(biāo)識(shí)符{={初值表}…};59

(2)類型別名法。先為結(jié)構(gòu)原型名起別名,再用別名做定義說(shuō)明,其格式如下:

typedefstruct[結(jié)構(gòu)原型名]{類型說(shuō)明符標(biāo)識(shí)符[,標(biāo)識(shí)符…];類型說(shuō)明符標(biāo)識(shí)符[,標(biāo)識(shí)符…];

…}結(jié)構(gòu)別名

[存儲(chǔ)類說(shuō)明符]結(jié)構(gòu)別名標(biāo)識(shí)符[={初值表}[,標(biāo)識(shí)符{={初值表}…};604)聯(lián)合說(shuō)明聯(lián)合是在內(nèi)村中定義的一段多種類型數(shù)據(jù)所共享的空間,空間的大小以最長(zhǎng)的類型為準(zhǔn)。(1)聲明聯(lián)合類型的同時(shí)定義變量名,其定義格式如下:

[存儲(chǔ)類說(shuō)明符]union[聯(lián)合原型名]{類型說(shuō)明符標(biāo)識(shí)符[,標(biāo)識(shí)符…];類型說(shuō)明符標(biāo)識(shí)符[,標(biāo)識(shí)符…];

…}標(biāo)識(shí)符={初值表}[,標(biāo)識(shí)符[={初值表}]…]

(2)先聲明聯(lián)合類型再定義變量名,其定義格式如下:

union結(jié)構(gòu)原型名

{類型說(shuō)明標(biāo)識(shí)符[,標(biāo)識(shí)符…];

…}[存儲(chǔ)類說(shuō)明符]union結(jié)構(gòu)原型名標(biāo)識(shí)符[={初值表}[,標(biāo)識(shí)符{={初值表}…};61

下面以S3VCE40開發(fā)板各功能模塊的整個(gè)測(cè)試程序?yàn)槔?,介紹基于ARM的嵌入式C語(yǔ)言程序設(shè)計(jì)結(jié)構(gòu)。圖4.2是S3VCE40開發(fā)板各功能模塊的測(cè)試主程序組成結(jié)構(gòu)圖。從圖4.3可以看出:一個(gè)完整的成功的主文件包括以下一個(gè)組成部分:①包含頭文件:用#include指令將本文件所用到的頭文件包含到該程序中;②函數(shù)聲明:將本文件中定義的函數(shù)進(jìn)行函數(shù)聲明;③各種類型的變量、數(shù)組定義:定義本文件中用到的各種類型的外部變量及數(shù)組;④本文件中各個(gè)函數(shù)代碼的定義,其中必須包括一個(gè)主函數(shù)main()。4.2.2嵌入式C語(yǔ)言程序設(shè)計(jì)結(jié)構(gòu)62圖4.2S3VCE40開發(fā)板各功能模塊的測(cè)試主程序組成結(jié)構(gòu)圖631.變量定義在變量聲明時(shí),最好把所有相同類型的變量放在一塊定義,這樣可以優(yōu)化存儲(chǔ)器布局。變量定義中,為了精簡(jiǎn)程序,程序員總是竭力避免使用冗余變量。

2.參數(shù)傳遞為了使單獨(dú)編譯的C語(yǔ)言程序和匯編程序能夠相互調(diào)用,定義了統(tǒng)一的函數(shù)過(guò)程調(diào)用標(biāo)準(zhǔn)ATPCS。ATPCS定義了寄存器組中的{R0~R3}作為參數(shù)傳遞和結(jié)果返回寄存器。如果參數(shù)數(shù)目超過(guò)4個(gè),則使用堆棧進(jìn)行傳遞。由于內(nèi)部寄存器的訪問(wèn)速度遠(yuǎn)遠(yuǎn)大于存儲(chǔ)器,所以要盡量使參數(shù)傳遞在寄存器里面進(jìn)行。

3.循環(huán)條件在C語(yǔ)言中,常用下面累加計(jì)數(shù)的循環(huán)形式:for(loop=1;loop<=limit;loop++),而下面這種遞減計(jì)數(shù)的方法很少使用:for(loop=limit;loop!=0;loop--),但在ARM的體系結(jié)構(gòu)下編程,建議采用遞減至0的方法來(lái)設(shè)置循環(huán)條件。4.2.3嵌入式C語(yǔ)言程序設(shè)計(jì)技巧64ATPCS即ARM-ThumbProcedureCallStandard。ATPCS規(guī)定了一些子程序之間調(diào)用的基本原則,這些基本規(guī)則包括子程序調(diào)用過(guò)程中寄存器的使用規(guī)則,數(shù)據(jù)棧的使用規(guī)則,參數(shù)的傳遞規(guī)則。幾種特定的子程序調(diào)用規(guī)則:支持?jǐn)?shù)據(jù)棧限制檢查的ATPCS,支持只讀段位置無(wú)關(guān)的ATPCS,支持可讀寫段位置無(wú)關(guān)的ATPCS,支持ARM程序Thumb程序混合使用的ATPCS,處理浮點(diǎn)運(yùn)算的ATPCS。有調(diào)用關(guān)系的所有子程序必須遵守同一種ATPCS。編譯器或者匯編器在ELF格式的目標(biāo)文件中設(shè)置相應(yīng)的屬性,標(biāo)識(shí)用戶選定的ATPCS類型。對(duì)應(yīng)不同類型的ATPCS規(guī)則,有相應(yīng)的C語(yǔ)言庫(kù),連接器根據(jù)用戶指定的ATPCS類型鏈接相應(yīng)的C語(yǔ)言庫(kù)。4.3ARM匯編語(yǔ)言與C/C++的混合編程4.3.1ATPCS過(guò)程調(diào)用規(guī)范概述65

使用ADS的C語(yǔ)言編譯器編譯的C語(yǔ)言子程序滿足用戶指定的ATPCS類型。而對(duì)于匯編語(yǔ)言程序來(lái)說(shuō),完全要依賴用戶來(lái)保證各子程序滿足選定的ATPCS類型。具體來(lái)說(shuō),匯編語(yǔ)言子程序必須滿足下面3個(gè)條件:在子程序編寫時(shí)必須遵守相應(yīng)的ATPCS規(guī)則;數(shù)據(jù)棧的使用要遵守ATPCS規(guī)則;在匯編編譯器中使用-apcs選項(xiàng)。

1.基本ATPCS

基本ATPCS規(guī)定了在子程序調(diào)用時(shí)的一些基本規(guī)則,包括以下三個(gè)方面的內(nèi)容:各寄存器的使用規(guī)則及其相應(yīng)的名字,數(shù)據(jù)棧的使用規(guī)則,參數(shù)傳遞的規(guī)則。相對(duì)于其它類型的ATPCS,滿足基本ATPCS的程序的執(zhí)行速度更快,所占用的內(nèi)存更少。但是它不能提供以下的支持:ARM程序和Thumb程序的相互調(diào)用,數(shù)據(jù)以及代碼的位置無(wú)關(guān)的支持,子程序的可重入性,數(shù)據(jù)棧檢查的支持。而派生的其它幾種特定的ATPCS就是在基本ATPCS的基礎(chǔ)上再添加其它的規(guī)則而形成的,其目的就是提供上述的功能。662)數(shù)據(jù)棧的使用規(guī)則棧指針通常可以指向不同的位置。當(dāng)棧指針指向棧頂元素時(shí),稱為FULL棧。當(dāng)棧指針指向與棧頂元素相鄰的一個(gè)元素時(shí),成為Empty棧。數(shù)據(jù)棧的增長(zhǎng)方向也可以不同,當(dāng)數(shù)據(jù)棧向內(nèi)存減小的地址方向增長(zhǎng)時(shí),稱為Descending棧;當(dāng)數(shù)據(jù)棧向著內(nèi)存地址增加的方向增長(zhǎng)是,成為Ascending棧。綜合這兩種特點(diǎn)可以有以下4種數(shù)據(jù)棧,即FD、ED、FA、EA。ATPCS規(guī)定數(shù)據(jù)棧為FD類型,并對(duì)數(shù)據(jù)棧的操作是8字節(jié)對(duì)齊的。1)寄存器的使用規(guī)則673)參數(shù)的傳遞規(guī)則根據(jù)參數(shù)個(gè)數(shù)是否固定,可以將子程序分為參數(shù)個(gè)數(shù)固定的子程序和參數(shù)個(gè)數(shù)可變的子程序。這兩種子程序的參數(shù)傳遞規(guī)則是不同的。(1)參數(shù)個(gè)數(shù)可變的子程序參數(shù)傳遞規(guī)則。對(duì)于參數(shù)個(gè)數(shù)可變的子程序,當(dāng)參數(shù)不超過(guò)4個(gè)時(shí),可以使用寄存器R0~R3來(lái)進(jìn)行參數(shù)傳遞;當(dāng)參數(shù)超過(guò)4個(gè)時(shí),還可以使用數(shù)據(jù)棧來(lái)傳遞參數(shù)。在參數(shù)傳遞時(shí),將所有參數(shù)看做是存放在連續(xù)的內(nèi)存單元中的字?jǐn)?shù)據(jù)。然后,依次將各字?jǐn)?shù)據(jù)傳送到寄存器R0,R1,R2,R3;如果參數(shù)多于4個(gè),將剩余的字?jǐn)?shù)據(jù)傳送到數(shù)據(jù)棧中,入棧的順序與參數(shù)順序相反,即最后的一個(gè)字?jǐn)?shù)據(jù)先入棧。按照上面的規(guī)則,一個(gè)浮點(diǎn)型參數(shù)可以通過(guò)寄存器傳遞,也可以通過(guò)數(shù)據(jù)棧傳遞,也可以一半通過(guò)寄存器傳遞,另一半通過(guò)數(shù)據(jù)棧傳遞。68

(2)參數(shù)個(gè)數(shù)固定的子程序參數(shù)傳遞規(guī)則。對(duì)于參數(shù)個(gè)數(shù)固定的子程序,參數(shù)傳遞與參數(shù)個(gè)數(shù)可變的子程序參數(shù)傳遞規(guī)則不同,如果系統(tǒng)包含浮點(diǎn)運(yùn)算的硬件部件,浮點(diǎn)參數(shù)將按照下面的規(guī)則傳遞:各個(gè)浮點(diǎn)參數(shù)按順序處理;為每個(gè)浮點(diǎn)參數(shù)分配FP寄存器;分配的方法是,滿足該浮點(diǎn)參數(shù)需要的且編號(hào)最小的一組連續(xù)的FP寄存器。第1個(gè)整數(shù)參數(shù)通過(guò)寄存器R0~R3來(lái)傳遞,其它參數(shù)通過(guò)數(shù)據(jù)棧傳遞。(3)子程序結(jié)果返回規(guī)則當(dāng)結(jié)果為一個(gè)32位的整數(shù)時(shí),可以通過(guò)寄存器R0返回。當(dāng)結(jié)果為一個(gè)64位的整數(shù)時(shí),可以通過(guò)R0~R1返回,以此類推。當(dāng)結(jié)果為一個(gè)浮點(diǎn)數(shù)時(shí),可以通過(guò)浮點(diǎn)運(yùn)算部件的寄存器F0、D0或者S0來(lái)返回。當(dāng)結(jié)果為一個(gè)復(fù)合的浮點(diǎn)數(shù)時(shí),可以通過(guò)寄存器F0~Fn或者D0~Dn來(lái)返回。對(duì)于位數(shù)更多的結(jié)果,需要通過(guò)調(diào)用內(nèi)存來(lái)處傳遞。692.支持ARM程序和Thumb程序混合使用的ATPCS

在編譯或匯編時(shí),使用/intework告訴編譯器或匯編器生成的目標(biāo)代碼遵守支持ARM程序和Thumb程序混合使用的ATPCS,它用在以下場(chǎng)合:程序中存在ARM程序調(diào)用Thumb程序的情況;程序中存在Thumb程序調(diào)用ARM程序的情況;需要鏈接器來(lái)進(jìn)行ARM狀態(tài)和Thumb狀態(tài)切換的情況;在下述情況下使用選項(xiàng)nointerwork:程序中不包含Thumb程序;用戶自己進(jìn)行ARM程序和Thumb程序切換。需要注意的是:在同一個(gè)C/C++程序中不能同時(shí)有ARM指令和Thumb指令。70

在應(yīng)用系統(tǒng)的程序設(shè)計(jì)中,若所有的編程任務(wù)都用匯編語(yǔ)言來(lái)完成,其工作量是可想而知的,同時(shí),不利于系統(tǒng)升級(jí)或應(yīng)用軟件移植,事實(shí)上,ARM體系結(jié)構(gòu)支持C/C+與匯編語(yǔ)言的混合編程,在一個(gè)完整的程序設(shè)計(jì)當(dāng)中,除了初始化部分用ARM匯編語(yǔ)言完成以外,其主要的編程任務(wù)一般都用C/C++完成。

ARM匯編語(yǔ)言與C/C++的混合編程通常用以下幾種方式:(1)在C/C++代碼中嵌入?yún)R編指令。(2)在匯編程序和C/C++的程序之間進(jìn)行變量的互訪。(3)匯編程序、C/C++程序間的相互調(diào)用。在實(shí)際的編程設(shè)計(jì)中,使用較多的方式是:程序的初始化部分用匯編語(yǔ)言完成,然后用C/C++完成主要的編程任務(wù),程序在執(zhí)行時(shí)首先完成初始化過(guò)程,然后跳轉(zhuǎn)到C/C++程序代碼中,匯編程序和C/C++程序之間一般沒(méi)有參數(shù)的傳遞,也沒(méi)有頻繁的相互調(diào)用,因此,整個(gè)程序的結(jié)構(gòu)顯得相對(duì)簡(jiǎn)單,容易理解。4.3.2匯編語(yǔ)言與C/C++的混合編程711.從匯編程序訪問(wèn)C全局變量在使用嵌入式匯編時(shí),有可能涉及匯編程序和C/C++的程序之間的數(shù)據(jù)傳遞問(wèn)題,怎樣從嵌入式匯編程序中獲取訪問(wèn)C/C++程序中的全局變量?在通常情況下,可以訪問(wèn)全局變量的地址單元。要訪問(wèn)一個(gè)全局變量,應(yīng)該先使用IMPORT偽指令引入這個(gè)全局變量,并利用LDR和STR指令根據(jù)全局變量的地址訪問(wèn)它們。對(duì)于不同類型的變量,需要采用不同選項(xiàng)的LDR和STR指令。下面例子是一個(gè)匯編代碼的函數(shù),它讀取全局變量globval,將其加1后寫回。AREAglobals,CODE,READONLY;聲明代碼段globals,只讀屬性EXPORTasmsubroutine;可以被外部引用IMPORTglobval;聲明引用外部變量globvalasmsubroutineLDRR1,=globval;加載變量地址LDRR0,[R1];讀出數(shù)據(jù)ADDR0,R0,#1;加1操作STRR0,[R1];保存變量MOVPC,LR;返回調(diào)用處END722.匯編程序調(diào)用C程序匯編程序的設(shè)計(jì)要遵守基本的ATPCS規(guī)則,一邊正確使用數(shù)據(jù)棧和預(yù)定義的寄存器。在匯編語(yǔ)言程序中應(yīng)該使用IMPORT偽操作來(lái)聲明要引用的C語(yǔ)言程序,并通過(guò)BL指令來(lái)調(diào)用子程序。下面是匯編程序調(diào)用C程序的例子。以下是匯編語(yǔ)言程序調(diào)用C程序的示例,匯編語(yǔ)言調(diào)用C語(yǔ)言程序所寫的函數(shù)g,以求出5個(gè)特定整數(shù)的和。//在C語(yǔ)言程序中,g()返回5個(gè)整數(shù)a,b,c,d,e的和intg(inta,intb,intc,intd,inte){returna+b+c+d+e;}73在下面的匯編語(yǔ)言程序中,調(diào)用C程序計(jì)算5個(gè)整數(shù)R0,2R0,3R0,4R0,5R0的和EXPORTf;聲明f可以被外部引用AREAf,CODE,READONLY;聲明代碼段f,只讀屬性IMPORTg;聲明引用函數(shù)g()STRLR,[SP,#-4]!;保存返回地址ADDR1,R0,R0;R1=2R0ADDR2,R1,R0;R2=3R0ADDR3,R1,R2;R3=5R0STRR3,[SP,#-4]!;把R3=5R0存儲(chǔ)在數(shù)據(jù)棧中ADDR3,R1,R1;R3=4R0BLg

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

評(píng)論

0/150

提交評(píng)論