arm原理與c程序設(shè)計(jì) 第六章_第1頁
arm原理與c程序設(shè)計(jì) 第六章_第2頁
arm原理與c程序設(shè)計(jì) 第六章_第3頁
arm原理與c程序設(shè)計(jì) 第六章_第4頁
arm原理與c程序設(shè)計(jì) 第六章_第5頁
已閱讀5頁,還剩207頁未讀 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

1、第六章C 語言程序設(shè)計(jì)6.1 C程序框架實(shí)例 6.2 SDRAM重定位技術(shù) 6.3 C語言語法 6.4 混合語言程序設(shè)計(jì) 6.5 中斷效勞程序設(shè)計(jì) 本章小結(jié) 6.1 C程序框架實(shí)例6.1.1 跑馬燈工程設(shè)計(jì) 進(jìn)入RealView MDK集成開發(fā)環(huán)境,通過點(diǎn)擊菜單“Project | New uVision Project,創(chuàng)立新工程ex6_1,保存目錄為E:ARM9BOOKex6_1,添加啟動代碼文件到工程ex6_1中。編寫C程序,并添加到工程ex6_1中。此時(shí),工程ex6_1的主界面如圖6-1所示。圖6-1 工程ex6_1的主界面工程ex6_1中的文件代碼羅列于小節(jié)中。翻開工程選項(xiàng),設(shè)置其“

2、Target頁簽如圖6-2所示。圖6-2 目標(biāo)選項(xiàng)卡設(shè)置圖6-2說明,NAND FLASH只使用了低32MB,SDRAM使用了高32MB。然后,設(shè)置“Output、“Debug和“Utilities頁簽如第四章圖4-28、圖4-9、圖4-10以及圖4-16圖4-19所示。設(shè)置“Linker頁簽如圖6-3所示。圖6-3 連接選項(xiàng)卡設(shè)置此時(shí),先不要編譯工程ex6_1,需要按圖6-4至圖6-10配置啟動代碼文件。圖6-4 堆、棧、中斷向量表和看門狗配置 圖6-5 時(shí)鐘管理器配置一 圖6-6 時(shí)鐘管理器配置二 圖6-7 存儲器配置一 圖6-8 存儲器配置二 圖6-9 存儲器配置三和I/O口配置一 圖6

3、-10 I/O口配置二圖6-7至圖6-9中,Bank2Bank5的配置與Bank1的相同,Bank7的配置與Bank6的相同。最后,修改文件的第09781043行,即從“IF PIO_SETUP0開始的行,修改為如下所示代碼:IF PIO_SETUP 0 LDR R14, =PIO_BASEIF PIOA_SETUP 0 ADR R0, PIOA_CFGLDR R2, R0 ; Added by ZY STR R2, R14, #PCONA_OFS ; Changed by ZY ENDIF IF PIOB_SETUP 0 ADR R0, PIOB_CFGLDR R2, R0 ; Added

4、by ZY LDR R1, R0,#4 STR R2, R14, #PCONB_OFS ; Changed by ZY STR R1, R14, #PUPB_OFS ENDIF IF PIOC_SETUP 0 ADR R0, PIOC_CFGLDR R2, R0; Added by ZY LDR R1, R0,#4 STR R2, R14, #PCONC_OFS ; Changed by ZY STR R1, R14, #PUPC_OFS ENDIF IF PIOD_SETUP 0 ADR R0, PIOD_CFGLDR R2, R0; Added by ZY LDR R1, R0,#4 ST

5、R R2, R14, #PCOND_OFS; Changed by ZY STR R1, R14, #PUPD_OFS ENDIF IF PIOE_SETUP 0 ADR R0, PIOE_CFGLDR R2, R0 ; Added by ZY LDR R1, R0,#4 STR R2, R14, #PCONE_OFS; Changed by ZY STR R1, R14, #PUPE_OFS ENDIF IF PIOF_SETUP 0 ADR R0, PIOF_CFG LDR R2, R0 ; Added by ZY LDR R1, R0,#4 STR R2, R14, #PCONF_OFS

6、; Changed by ZY STR R1, R14, #PUPF_OFS ENDIF IF PIOG_SETUP 0 ADR R0, PIOG_CFG LDR R2, R0 ; Added by ZY LDR R1, R0,#4 STR R2, R14, #PCONG_OFS; Changed by ZY STR R1, R14, #PUPG_OFS ENDIF IF PIOH_SETUP 0 ADR R0, PIOH_CFG LDR R2, R0 ; Added by ZY LDR R1, R0,#4 STR R2, R14, #PCONH_OFS; Changed by ZY STR

7、R1, R14, #PUPH_OFS ENDIF ENDIF現(xiàn)在,編譯連接并下載工程ex6_1,可以看到UP-NETARM2410實(shí)驗(yàn)箱上的LED13循環(huán)依次閃爍,實(shí)現(xiàn)了跑馬燈的功能。工程ex6_1只有兩個(gè)文件,即和,其中,文件在前幾章已經(jīng)講述了,這里把該文件的完整代碼附于附錄四,供讀者對照參考;文件將在下一小節(jié)中介紹。6.1.2 跑馬燈程序解釋 C語言文件的代碼如下:1 #define GPCDAT_ADDR (*(volatile unsigned int *)0 x56000024)2 #define LED1_MASK 0 x20 3 #define LED2_MASK 0 x404

8、#define LED3_MASK 0 x805 6 void Delay(int n)7 8 int i,j;9 for(i=0;in;i+)10 11 for(j=0;jn;j+)12 13 14 15 16 17 int main()18 19 int nLED;20 nLED = 0;21 while(1)22 23 nLED = 0;24 nLED =(LED2_MASK | LED3_MASK);/ LED1 light25 GPCDAT_ADDR = nLED;26 Delay(0 x300);27 28 nLED = 0;29 nLED =(LED1_MASK | LED3_M

9、ASK); / LED2 light30 GPCDAT_ADDR = nLED;31 Delay(0 x300);32 33 nLED = 0;34 nLED =(LED1_MASK | LED2_MASK);/ LED3 light35 GPCDAT_ADDR = nLED;36 Delay(0 x300);37 38 39 40 上述程序代碼按行解釋如下:第1行:定義C口的數(shù)據(jù)存放器地址,該地址固定為0 x56000004。第24行:定義LED13燈的屏蔽位,對應(yīng)于第57位,為1時(shí)滅,為0時(shí)亮。第615行:延時(shí)子程序。第17行:主函數(shù),格式應(yīng)該為int main()的形式,MDK要求函數(shù)返

10、回值為int,但是,不要求函數(shù)有return語句(返回值)。函數(shù)名為main,是由于中的跳轉(zhuǎn)至C語言程序時(shí)使用了標(biāo)號_main。ARM的C語言程序設(shè)計(jì)中沒有主函數(shù)的概念,如果中跳轉(zhuǎn)標(biāo)號為_C_Entry,那么函數(shù)名應(yīng)為C_Entry。 第1920行:定義整型量nLED,并賦為0。第21行:死循環(huán)。第2326行:只有LED1亮,并延時(shí)一段時(shí)間。第2831行:只有LED2亮,并延時(shí)一段時(shí)間。第3336行:只有LED3亮,并延時(shí)一段時(shí)間。6.1.3 C程序框架 基于RealView MDK設(shè)計(jì)ARM芯片級的C程序,需要考慮系統(tǒng)初始化、接口初始化、控制算法和數(shù)字信號處理算法等,一般地,系統(tǒng)初始化代碼由

11、匯編語言編寫,至少異常向量表由匯編語言編寫,其他局部均可由C語言實(shí)現(xiàn)。從程序與硬件的聯(lián)系方面考慮,ARM程序可以分為兩局部:其一為與硬件密切相關(guān)的系統(tǒng)初始化和接口設(shè)計(jì);其二為與硬件無關(guān)的控制信號和數(shù)字信號處理算法。 C程序框架是指實(shí)現(xiàn)了前一局部功能的程序工程,且該工程盡可能地用C語言編寫,能實(shí)現(xiàn)系統(tǒng)初始化和幾乎所有硬件接口的抽象,以變量的形式向算法提供接口。在C程序框架的根底上,只需要添加C語言控制算法或數(shù)字信號處理算法即可以實(shí)現(xiàn)相應(yīng)的功能。新建工程ex6_2(與工程ex6_1相同),在中添加數(shù)組賦值語句,并添加一個(gè)頭文件。工程ex6_2如圖6-11所示。圖6-11 工程ex6_2的工作界面工

12、程ex6_2中頭文件的代碼如下:1 / filename: 2 float mysin(float v)3 4 float res;5 res=vv*v*v/6+v*v*v*v*v/120v*v*v*v*v*v*v/(7*6*120);6 return res;7 主程序文件代碼如下:1 #include 2 3 #define GPCDAT_ADDR (*(volatile unsigned int *)0 x56000024)4 #define LED1_MASK 0 x20 5 #define LED2_MASK 0 x406 #define LED3_MASK 0 x807 8 int

13、 arr10=1,2,3,4,5,6,7,8,9,10;9 10 void Delay(int n)11 12 int i,j;13 for(i=0;in;i+)14 15 for(j=0;jn;j+)16 17 18 19 20 21 int main()22 23 int nLED;24 int i;25 26 float val = mysin(1.57f);27 28 for(i=0;i10;i+)29 arri=arri*arri;30 31 32 nLED = 0;33 while(1)34 35 /Rand3();36 nLED = 0;37 nLED =(LED2_MASK |

14、 LED3_MASK); / LED1 light38 GPCDAT_ADDR = nLED;39 Delay(0 x300);40 41 nLED = 0;42 nLED =(LED1_MASK | LED3_MASK); / LED2 light43 GPCDAT_ADDR = nLED;44 Delay(0 x300);45 46 nLED = 0;47 nLED =(LED1_MASK | LED2_MASK);/ LED3 light48 GPCDAT_ADDR = nLED;49 Delay(0 x300);50 51 52 53 工程ex6_2展示頭文件及函數(shù)調(diào)用方法,在此根底上

15、,再添加各種中斷響應(yīng)效勞程序,即可構(gòu)成一個(gè)典型的C程序框架工程。中斷效勞程序設(shè)計(jì)將在第節(jié)中介紹,絕大局部控制功能和數(shù)據(jù)處理算法應(yīng)放在中斷效勞程序中完成。 6.2 SDRAM重定位技術(shù) UP-NETARM2410實(shí)驗(yàn)箱支持從NAND型FLASH啟動,前面所有的工程均是將執(zhí)行代碼下載到NAND型FLASH芯片K9F1208中,并在FLASH中運(yùn)行的。SDRAM重定位技術(shù)是指上電復(fù)位后,F(xiàn)LASH映射到地址0 x00000000開始的區(qū)段,代碼從FLASH開始執(zhí)行,代碼初始化系統(tǒng)完畢后,將FLASH代碼搬移到SDRAM中,并把SDRAM映射到地址0 x00000000開始的區(qū)段,程序代碼從SDRAM

16、運(yùn)行。由于SDRAM訪問速度快,所以,實(shí)際的工程文件均需要進(jìn)行SDRAM重定位。新建工程ex6_3,其中包括的文件與工程ex6_2完全相同。修改ex6_3工程目標(biāo)選項(xiàng)卡,如圖6-12所示,即ROM1映射到0 x00 x1000000,RAM1映射到0 x10000000 x2000000。圖6-12 工程ex6_3目標(biāo)選項(xiàng)卡修改啟動代碼文件的配置向?qū)鐖D6-13所示,即中斷向量表的地址修改為0 x010FFF20處。圖6-13 啟動代碼設(shè)置向?qū)г趩哟a文件的代碼中添加代碼段,如圖6-14所示。圖6-14 橫線中間的代碼為添加的代碼段圖6-14中第10441055行的代碼表示將FLASH中從0

17、 x00 x1000的代碼拷貝到SDRAM的0 x300000000 x30001000處。如果想把圖6-12中設(shè)置的ROM空間內(nèi)容全部拷貝到SDRAM中,只需要將第1048行的0 x1000修改為0 x01000000即可。這里,由于工程ex6_3的代碼長度缺乏0 x1000,故只需拷貝FLASH的0 x00 x1000存儲區(qū)。第10561060行的代碼為設(shè)置協(xié)處理器p15的存放器13,使SDRAM的0 x300000000 x32000000映射到0 x00 x2000000處。這樣,SDRAM被重定位到地址0 x0處,使得代碼在SDRAM中執(zhí)行。這樣,在SDRAM重定位后,圖6-12中的

18、配置表示SDRAM的低16MB用于存放只讀的可執(zhí)行代碼,而高16MB用于存儲可讀寫的數(shù)據(jù)。這樣配置的工程,SDRAM中有32MB沒有使用。如果想使得SDRAM的低16MB存放代碼,而高48MB存放數(shù)據(jù),可采用如圖6-15所示配置。無論采用圖6-12還是圖6-15所示配置,64MB的FLASH存放程序代碼(代碼長度可從HEX文件中查到)后,還有大量充裕的空間,這些空間在SDRAM重定位后,均可用作永久性存儲空間使用,在編程這些空間時(shí),切記不可編程已寫入代碼的區(qū)塊。在第節(jié)將介紹K9F1208的編程方法。圖6-15 工程目標(biāo)選項(xiàng)卡 6.3 C語言語法6.3.1 數(shù)據(jù)類型在ARM的C語言程序設(shè)計(jì)中,具

19、有char、short、int、long、float、long long以及double等根本數(shù)據(jù)類型,分別表示8位、16位、32位、32位、32位、64位以及64位的數(shù)據(jù),每種數(shù)據(jù)可以加上unsigned表示無符號型。同時(shí),ARM的C語言支持結(jié)構(gòu)體以及基于根本數(shù)據(jù)類型的自定義數(shù)據(jù)類型,自定義數(shù)據(jù)類型使用typedef關(guān)鍵字,例如:typedef int INT32;需要注意的是,在通用C編程時(shí),針對浮點(diǎn)數(shù),人們更偏愛double;而在ARM的C程序設(shè)計(jì)中,由于float占32位,double占64位,ARM為32位機(jī),故人們更傾向于使用float。例如,定義一個(gè)單精度浮點(diǎn)數(shù)變量,并初始化為,

20、其語句如下:float PI = 3.14159f;眾所周知,上述語句為定義一個(gè)常數(shù),這里一般定義它為常量,即const float PI = 3.14159f;在ARM的C程序中,最常用的數(shù)制為32位的十六進(jìn)制數(shù),以0 x開頭,例如:0 x30000000、0 x10、0 x800等。常量也稱為常數(shù),對應(yīng)的地址空間的內(nèi)容保持不變;而變量是指ARM內(nèi)存中可變內(nèi)容的地址,定義例如如下:char ch_1;short sh_2;long lg_3;float fl_4;unsigned int * p1;變量名和常量名必須為字符或以下劃線開頭。工程ex6_3中的中出現(xiàn)過以下語句:#define G

21、PCDAT_ADDR (*(volatile unsigned int *)0 x56000024)表示地址0 x56000024的值,而(*(volatile unsigned int *)0 x56000024) = 0 x0;表示地址0 x56000024的值賦為0 x0,這里volatile表示該地址標(biāo)號固定不變,不會被編譯器優(yōu)化掉,用于外設(shè)存放器地址等固定地址訪問時(shí)使用,一般的內(nèi)存地址,可以直接使用unsigned int *。數(shù)據(jù)類型中最常用的是指針,此外,數(shù)組和結(jié)構(gòu)體用得也比較多。工程ex6_3的中定義了一個(gè)整型數(shù)組,并初始化如下:int arr10=1,2,3,4,5,6,7,

22、8,9,10;在主函數(shù)中用for循環(huán)對該數(shù)組進(jìn)行了賦值,即for(i=0;ish_fra1 = 0 x1234;枚舉和聯(lián)合體類型與通用C語言的語法相同。例如,定義一個(gè)枚舉型變量:enum TrueOrFalse false, true;enum TrueOrFalse en_trueorfalse;枚舉型變量從0開始算起,即false代表0,而true代表1。賦值方法如下:en_trueorfalse = false;聯(lián)合體用得較少,不再舉例。特別需要注意的是,在MDK中單精度浮點(diǎn)數(shù)需要在數(shù)值后添加“f!6.3.2 常用運(yùn)算符C語言由函數(shù)組成,函數(shù)由語句組成,語句是指以分號結(jié)尾的表達(dá)式,表達(dá)式

23、是指由常量或變量經(jīng)過運(yùn)算符連接起來的式子。常用的運(yùn)算符包括賦值運(yùn)算符、數(shù)學(xué)運(yùn)算符、關(guān)系運(yùn)算符、邏輯運(yùn)算符、位運(yùn)算符、sizeof運(yùn)算符、逗號運(yùn)算符、三元運(yùn)算符、數(shù)組下標(biāo)運(yùn)算符、結(jié)構(gòu)/聯(lián)合成員運(yùn)算符、結(jié)構(gòu)/聯(lián)合成員指針運(yùn)算符、地址運(yùn)算符、強(qiáng)制類型轉(zhuǎn)換運(yùn)算符等。1賦值運(yùn)算符賦值運(yùn)算符只有一個(gè),即“=。例如:int x1;x1 = 5;此外,賦值運(yùn)算符可以和數(shù)學(xué)運(yùn)算符結(jié)合,構(gòu)成復(fù)合賦值運(yùn)算符,例如:x1 = 0;x1+= 1;相當(dāng)于 x1 = x1 + 1;復(fù)合賦值運(yùn)算符主要有+=、=、*=、/=和%=等。2數(shù)學(xué)運(yùn)算符 數(shù)學(xué)運(yùn)算符包括+(加)、 (減)、*(乘)、/(除)、%(取余)、+(加加)和

24、(減減)等。 假定變量a1為10,a2為3,那么依次執(zhí)行以下語句:b1 = a1 + a2;b2 = a1 a2; b3 = a1 * a2; b4 = a1 % a2;b5 = a1 +;b6 = a1 ;b7 = + a1;b8 = a1; 上述運(yùn)算結(jié)果為:b1=13,b2=7,b3=30,b4=1,b5=10,b6=11,b7=11,b8=10,全部執(zhí)行完后,a1的值為10,a2的值為3。3關(guān)系運(yùn)算符關(guān)系運(yùn)算符可用于比較兩個(gè)數(shù)值,關(guān)系表達(dá)式返回0表示假,返回1表示真,如表6-1所示。運(yùn)算符含 義示 例值=等于0 x08=0 x0A0!=不等于0 x08!=0 x0A1大于0 x0A0 x

25、081=大于等于0 x0A=0 x081小于0 x0A0 x080=小于等于0 x08=0 x081表6-1 關(guān)系運(yùn)算符 關(guān)系表達(dá)式常出現(xiàn)在if語句中,表示條件的成立與否。4邏輯運(yùn)算符 邏輯運(yùn)算符只有三個(gè),即&(邏輯與)、|(邏輯或)、!(邏輯非),用以進(jìn)行關(guān)系表達(dá)式運(yùn)算結(jié)果之間的邏輯運(yùn)算,如表6-2所示。注:假定x=0 x05,y=0 x06。本小節(jié)前面所介紹的所有運(yùn)算符的優(yōu)先級自高至低排序?yàn)椋哼壿嫹?!),數(shù)學(xué)運(yùn)算符,關(guān)系運(yùn)算符,邏輯運(yùn)算符&和|,賦值運(yùn)算符。表6-2 邏輯運(yùn)算符運(yùn)算符含 義示 例值&邏輯與(x = 0 x05) & (y = 0 x06)1|邏輯或(x = 0 x05)

26、| (y != 0 x06)1!邏輯非!(y = 0 x06)05位運(yùn)算符位運(yùn)算符是C語言的優(yōu)勢(而著名的MATLAB在2021版本前仍不支持位運(yùn)算),同時(shí),也是C語言可以作為ARM或DSP硬件編程語言的一個(gè)重要因素(另一個(gè)重要因素在于,借助C語言指針可實(shí)現(xiàn)地址操作)。C語言具有以下位運(yùn)算符:&(按位與)、|(按位或)、(按位異或)、(按位取反)、(右移)位運(yùn)算符主要用于整型數(shù)據(jù)。6sizeof運(yùn)算符 sizeof運(yùn)算符返回一個(gè)變量或類型占有存儲空間的字節(jié)數(shù),例如:struct numStruct int i1; float f1; double d1;struct numStruct num

27、1;struct numStruct *num2;int iS1=sizeof(num1);int iS2=sizeof(num2);int iS3=sizeof(float);上述語句執(zhí)行完后,iS1 = 16,iS2 = 4,iS3 = 4。因?yàn)?,整型?個(gè)字節(jié),單精度浮點(diǎn)型占4個(gè)字節(jié),雙精度浮點(diǎn)型占8個(gè)字節(jié),指針類型占4個(gè)字節(jié)。7逗號運(yùn)算符 使用逗號“,連接起來的表達(dá)式,按從左向右的次序依次計(jì)算各個(gè)表達(dá)式的值,整個(gè)逗號表達(dá)式的值為最后一個(gè)表達(dá)式的值,例如: i=(num1.i1=5),sizeof(short);執(zhí)行完后,num1結(jié)構(gòu)體的成員i1為5,但i的值為2。8三元運(yùn)算符C語言中僅

28、有一個(gè)三元運(yùn)算符,或稱三目運(yùn)算符 ,即“? :,它有三個(gè)參加運(yùn)算的元素,而且有返回值,調(diào)用格式為:(表達(dá)式)?(值1):(值2)其功能是先判斷“表達(dá)式的真假,為真時(shí)返回“值1,為假時(shí)返回“值2。例如,求兩個(gè)整數(shù)a和b的最大值:int a,b,c;a = 0 x56;b = 0 x78;c = (ab)?a:b;其運(yùn)算結(jié)果為c = 0 x78,即為b的值。9數(shù)組下標(biāo)運(yùn)算符數(shù)組下標(biāo)運(yùn)算符用“ 表示,通過這個(gè)運(yùn)算符可以訪問數(shù)組中任意位置的元素,例如如下:short sh_a10;sh_a8 = 0 x1234;數(shù)組下標(biāo)從0開始算起,上述數(shù)組sh_a的第一個(gè)元素為sh_a0,最后一個(gè)元素為sh_a9。

29、10結(jié)構(gòu)/聯(lián)合成員運(yùn)算符結(jié)構(gòu)體或聯(lián)合體成員運(yùn)算符為“.,該運(yùn)算符也用于C+的對象成員訪問中,例如如下:struct st_table short sh_ord; float fl_val;struct st_table st_table_list; = 0 x01; = 0.7329; / 賦值11結(jié)構(gòu)/聯(lián)合成員指針運(yùn)算符 結(jié)構(gòu)體或聯(lián)合體指針運(yùn)算符為“-,例如如下:struct st_table short sh_ord; float fl_val;struct st_table *st_table_list2; st_table_list2-fl_val = 0.7329; / 賦值12地址

30、運(yùn)算符 地址運(yùn)算符“&用于取得一個(gè)變量的地址,而指針運(yùn)算符“*是指一個(gè)地址內(nèi)的變量的值,正好與地址運(yùn)算符的作用相逆,例如如下:short sh_org;short *sh_addr;short sh_val;sh_org = 0 x08;sh_addr = &sh_org;sh_val = *(&sh_org);sh_org = sh_val + (*sh_addr);上述語句執(zhí)行后,sh_org = 0 x10。13強(qiáng)制類型轉(zhuǎn)換運(yùn)算符不同類型之間可以相互賦值,例如,short型和int型之間可以相互賦值。在C程序中,不同類型的變量間賦值時(shí)不可能產(chǎn)生溢出的情況下賦值是允許的,例如,short型

31、變量賦給int型變量。相反情況下賦值,例如,int型變量賦給short型變量那么可能出現(xiàn)截?cái)喱F(xiàn)象,此時(shí)編譯器會給出警告信息,這種情況下,必須采用顯式的強(qiáng)制類型轉(zhuǎn)換方法,即在變量前添加變量類型,如下:short sh_val1, sh_val2;int int_val = 0 x1234;float fl_val = 78.8; sh_val1 = (short)int_val;sh_val 2= (short)fl_val;執(zhí)行完上述語句后,sh_val1 = 0 x1234,sh_val2 = 78 6.3.3 程序控制語句 函數(shù)是C程序的組成單元,語句又是函數(shù)的根本單元。C程序的語句組有三

32、種執(zhí)行方式,即順序、分支和循環(huán)。無論功能如何強(qiáng)大的C程序,在程序流程上只有這三種方式。1順序結(jié)構(gòu) 順序執(zhí)行是最根本的程序執(zhí)行方式,容易被接受和理解。順序結(jié)構(gòu)形式的語句組中,語句是依次被執(zhí)行的,即前一條語句執(zhí)行完后,再去執(zhí)行下一條語句。2分支結(jié)構(gòu) 分支結(jié)構(gòu)形式的語句組中,通過判斷關(guān)系式或邏輯表達(dá)式的值,決定哪些語句將被執(zhí)行,哪些語句不會被執(zhí)行。有兩種實(shí)現(xiàn)形式,即if結(jié)構(gòu)和switch結(jié)構(gòu)。if結(jié)構(gòu)的根本形式為:if(表達(dá)式) 語句組1else 語句組2當(dāng)語句組1或語句組2中只有一個(gè)語句時(shí),上述花括號“可以去掉。當(dāng)表達(dá)式的值為真時(shí),執(zhí)行語句組1;否那么,執(zhí)行語句組2。當(dāng)判斷條件表達(dá)式較多時(shí),可以用

33、以下形式,如圖6-16所示:圖6-16 分支結(jié)構(gòu)if(表達(dá)式1) 語句組1else if(表達(dá)式2) 語句組2else if(表達(dá)式n) 語句組nelse 語句組n+1 if語句支持嵌套,二級if嵌套的典型形式如下:if(表達(dá)式1) if(表達(dá)式11) 語句組11else 語句組12else if(表達(dá)式2) if(表達(dá)式21) 語句組21 else 語句組22 else if(表達(dá)式3)if(表達(dá)式31) 語句組31 else 語句組32 else 語句組4if語句亦支持多級嵌套。if語句可以沒有else局部。switch語句的語法如下:switch(表達(dá)式) case 常量表達(dá)式1: 語句

34、組1; break; case 常量表達(dá)式2: 語句組2; break; case 常量表達(dá)式3: 語句組3; break; case 常量表達(dá)式n: 語句組n; break; default: 語句組n+1;圖6-16 分支結(jié)構(gòu)當(dāng)switch關(guān)鍵字后的表達(dá)式值為某一常量表達(dá)式的值時(shí),程序會跳轉(zhuǎn)到相應(yīng)的語句組去,執(zhí)行完該語句組后,將通過執(zhí)行“break;語句跳出switch語句。如果有多種情況對應(yīng)于同一組操作時(shí),可以使用如下形式:case 常量表達(dá)式2: case 常量表達(dá)式21:case 常量表達(dá)式22:語句組2;break;上述語句中,表達(dá)式的值為常量表達(dá)式2、21或22中的某一個(gè)時(shí),都將

35、執(zhí)行語句組2。當(dāng)switch語句中的表達(dá)式的值不等于case中任一值時(shí),那么執(zhí)行default后的語句,并且,default語句可以省略。3循環(huán)結(jié)構(gòu)C語言語句循環(huán)模式有三種,即當(dāng)型循環(huán)、直到型循環(huán)和指定次數(shù)或條件的循環(huán),均可以用來實(shí)現(xiàn)死循環(huán),而且,循環(huán)可以多級嵌套。循環(huán)結(jié)構(gòu)如圖6-17所示。圖6-17 三種循環(huán)模式(a) 當(dāng)型循環(huán); (b) 直到型循環(huán); (c) 指定次數(shù)或條件的循環(huán)實(shí)現(xiàn)循環(huán)的C語句如下:1) goto語句goto語句實(shí)現(xiàn)循環(huán)的一般格式為:g_Label: / 指定一個(gè)標(biāo)號 語句組; goto g_Label;跳出循環(huán)的方法為:g_L1: 語句組1; if(條件表達(dá)式) bre

36、ak; 語句組2;goto g_L1;關(guān)鍵字break可用于跳出循環(huán),即結(jié)束循環(huán);另一個(gè)關(guān)鍵字continue用于跳出本次循環(huán),而從循環(huán)頭再繼續(xù)下一次循環(huán)。在結(jié)構(gòu)化語言程序設(shè)計(jì)中,goto語句普遍不受歡送,但是,在一些多級循環(huán)嵌套中,使用goto跳出循環(huán)體是有效的方法。在ARM的C程序中,goto語句可以使用。2) while語句while語句實(shí)現(xiàn)的循環(huán)體有兩種,即while(條件表達(dá)式1) 語句組1; / 當(dāng)條件表達(dá)式1為真時(shí)循環(huán)執(zhí)行語句組1,為假時(shí)跳出循環(huán)或do 語句組2;while(條件表達(dá)式2) / 當(dāng)條件表達(dá)式2為真時(shí)循環(huán)執(zhí)行語句組2,為假時(shí)跳出循環(huán) 上述循環(huán)體的不同之外在于“do

37、while();該結(jié)構(gòu)中語句組2至少可以執(zhí)行一次,而“while()結(jié)構(gòu)中,當(dāng)表達(dá)式1為假時(shí),語句組1得不到執(zhí)行。常用如下形式實(shí)現(xiàn)死循環(huán),即 while(1) 語句組;3) for語句for語句實(shí)現(xiàn)的循環(huán)體如下:for(表達(dá)式1 ; 循環(huán)條件 ; 表達(dá)式2) 語句組;表達(dá)式1在開始for循環(huán)時(shí)計(jì)算,表達(dá)式2從第二次循環(huán)起每次循環(huán)時(shí)都計(jì)算,循環(huán)條件在每次循環(huán)時(shí)都判斷。當(dāng)循環(huán)條件為假時(shí),跳出循環(huán),因此,語句組有可能一次也得不到執(zhí)行??梢栽谡Z句組中添加break關(guān)鍵字,跳出循環(huán)體,該關(guān)鍵字只能跳出一級循環(huán)體;可以添加continue語句跳出本次循環(huán)?!氨磉_(dá)式1、“循環(huán)條件以及“表達(dá)式2均可省略,但是

38、“;號不能省略。例如,下面的形式可構(gòu)成死循環(huán):for(;) 語句組;6.3.4 C語言函數(shù)C語言函數(shù)由函數(shù)頭部和函數(shù)體組成,函數(shù)頭部常被復(fù)制到主函數(shù)前作為函數(shù)的聲明,即函數(shù)原型,告訴編譯器該函數(shù)的主體在主函數(shù)后面定義了。語法形式如下:返回類型 函數(shù)名(形式參數(shù)列表) 函數(shù)體; 返回類型可以為根本數(shù)據(jù)類型,也可以為擴(kuò)展的數(shù)據(jù)類型或空類型。當(dāng)函數(shù)有返回值時(shí),使用return語句。形式參數(shù)列表可以為空,也可以有多個(gè),用來向函數(shù)體內(nèi)部傳遞數(shù)據(jù)或地址。形式參數(shù)和函數(shù)體內(nèi)部定義的變量均為局部變量,它們的作用域僅限于函數(shù)體內(nèi)部,而定義于主函數(shù)的變量或主函數(shù)體外的變量(又稱全局變量),其作用域?yàn)閺亩x開始到主

39、函數(shù)結(jié)束或主程序結(jié)束。調(diào)用函數(shù)時(shí),必須用實(shí)際的數(shù)據(jù)變量代替形式參數(shù)(形參),這些實(shí)際的變量稱為實(shí)參。實(shí)參對形參的傳遞方式有兩種:其一為傳值方式;其二為傳址方式。 在傳值方式中,實(shí)參的值傳給形參,形參在函數(shù)體內(nèi)參與運(yùn)算受到改變時(shí),不會影響到實(shí)參的值,這時(shí),實(shí)參和形參占用完全不同的地址空間;在傳址方式中,實(shí)參的地址傳給了形參,實(shí)參和形參存儲在同一個(gè)地址空間,對形參的修改就是對實(shí)參的修改。當(dāng)函數(shù)需要有多個(gè)返回值時(shí),往往需要采取傳址的函數(shù)工作方式,主要針對指針和引用類型參數(shù)。C語言支持遞歸調(diào)用,即函數(shù)可以調(diào)用其本身。一個(gè)著名的例子如下:int iFib(int iNum)if(iNum 0.75)14

40、 led3=led3+1;15 else 16 led2=led2+1;17 end18 x0=y0;19 end20 disp( led1= );disp(led1);21 disp(led2= );disp(led2);22 disp(led3=);disp(led3);根據(jù)上述程序設(shè)定了左右閾值為和。在RealView MDK中新建工程ex6_4(與工程ex6_3相同),修改文件,該文件源碼如下:1 #define GPCDAT_ADDR (*(volatile unsigned int *)0 x56000024)2 #define LED1_MASK 0 x20 3 #define

41、LED2_MASK 0 x404 #define LED3_MASK 0 x805 6 float logistic4(float); / function protype 7 void Delay(int n) / Delay function8 9 int i,j;10 for(i=0;in;i+)11 12 for(j=0;jn;j+)13 14 15 16 17 float x0;18 float y0;19 20 int main()21 22 int nLED;23 x0 = 0.22f;24 25 while(1)26 27 28 y0=logistic4(x0);29 30 n

42、LED = 0;31 32 if(y00.75f)37 38 nLED =(LED1_MASK | LED2_MASK);/ LED3 light39 40 else41 42 nLED =(LED1_MASK | LED3_MASK); / LED2 light43 44 45 GPCDAT_ADDR = nLED;46 Delay(0 x500);47 x0 = y0;48 49 50 51 52 float logistic4(float x0)53 54 float y0;55 y0=4.0f*x0*(1.0f - x0);56 57 return y0;58 此時(shí),工程ex6_4的工

43、作窗口如圖6-18所示。圖6-18 工程ex6_4的工作界面6.3.6 演示實(shí)例二 新建工程ex6_5(與工程ex6_4完全相同),修改文件,使用代碼如下所示:1 #include “2 3 #define GPCDAT_ADDR (*(volatile unsigned int *)0 x56000024)4 #define LED1_MASK 0 x20 5 #define LED2_MASK 0 x406 #define LED3_MASK 0 x807 8 float logistic4(float);/ Function protype9 10 void Delay(int); /

44、Delay function11 12 float x0;13 float y0;14 15 double valx1;16 int main()17 18 int nLED;19 20 x0 = mysin(0.57f); /0.22f;21 22 23 while(1)24 25 26 y0=logistic4(x0);27 28 nLED = 0;29 30 if(y00.75f)35 36 nLED =(LED1_MASK | LED2_MASK);/ LED3 light37 38else39 40 nLED =(LED1_MASK | LED3_MASK); / LED2 ligh

45、t41 42 43 GPCDAT_ADDR = nLED;44 Delay(0 x500);45 x0 = y0;46 47 48 49 50 51 float logistic4(float x0)52 53 float y0;54 y0=4.0f*x0*(1.0f - x0);55 56 return y0;57 58 59 60 void Delay(int n) / Delay function61 62 int i,j;63 for(i=0;in;i+)64 65 for(j=0;jn;j+)66 67 68 69 編寫頭文件,在文件的右鍵彈出菜單中選中Include Depende

46、ncies,那么頭文件在編譯時(shí)自動添加到工程中。代碼如下:/ filename: float mysin(float v) float res;res=vv*v*v*v*v*v*v/(7.0f*6.0f*120.0f);return res;隨著程序代碼的增長,編譯連接后的可執(zhí)行文件越來越大,因此,需要修改圖6-19中的R3。這里設(shè)置R3為0 x100000,即假定可執(zhí)行代碼不會越過1MB;按圖6-15的配置,最大可以設(shè)為16MB。R3的值越大,啟動時(shí)間越長,因此,R3的最正確值為程序可執(zhí)行代碼的長度。圖6-19 FLASH到SDRAM的代碼復(fù)制此時(shí)的工程ex6_5如圖6-20所示。 圖6-2

47、0 工程ex6_5的工作界面配置工程選項(xiàng)卡如圖6-21至圖6-23所示,沒有改動的地方與工程ex6_4選項(xiàng)卡相同。這些配置的作用在于編譯連接后的可執(zhí)行代碼全部為ARM指令,而不再是ARM與Thumb指令交叉的代碼。在圖6-22中,優(yōu)化方法使用“或“l(fā)evel 3(-O3)?,F(xiàn)在,可以編譯連接并下載工程ex6_5到UP-NETARM2410實(shí)驗(yàn)箱的FLASH中,可以看到三個(gè)LED燈隨機(jī)閃爍。圖6-21 “目標(biāo)選項(xiàng)卡圖6-22 “C/C+選項(xiàng)卡圖6-23 “Asm選項(xiàng)卡6.4 混合語言程序設(shè)計(jì) 從第節(jié)例子中可知,在ARM工程文件中,C語言程序和匯編語言程序可以并存,啟動代碼文件使用匯編語言編寫,可

48、以通過“BX R0地址跳轉(zhuǎn)指令跳到C語言函數(shù)地址處執(zhí)行C語言的程序。這說明第節(jié)的例子也屬于混合語言程序設(shè)計(jì)。事實(shí)上,通過地址和參數(shù)傳遞,可以實(shí)現(xiàn)匯編語言跳轉(zhuǎn)到C函數(shù)、匯編語言調(diào)用C函數(shù)、C函數(shù)中嵌套匯編語句、C函數(shù)調(diào)用匯編子程序等操作。相關(guān)的資料有“ARM Developer Suite Developer Guide等。本節(jié)重點(diǎn)介紹C函數(shù)嵌套匯編語句和C函數(shù)調(diào)用匯編子程序形式的混合語言程序設(shè)計(jì)方法。6.4.1 C函數(shù)嵌套匯編語句 C函數(shù)中嵌套匯編語句,使用關(guān)鍵字“_asm,匯編語言中不能使用R0等操作符,只能使用C語言中定義的變量作為操作符,可能是.c文件在編譯時(shí)沒有定義R0等標(biāo)識符,因此,

49、C語言的文件中無法使用R0等操作符?!癬asm括號內(nèi)的局部為匯編指令,其中,使用“;分隔語句,因此,不能在其中添加匯編語言中的分號開頭的注釋,但可以使用C語言的“/進(jìn)行匯編語句的注釋。新建工程ex6_6(與工程ex6_5完全相同),修改文件,添加一個(gè)求-3的絕對值的函數(shù),源碼如下:1 #define GPCDAT_ADDR (*(volatile unsigned int *)0 x56000024)2 #define LED1_MASK 0 x20 3 #define LED2_MASK 0 x404 #define LED3_MASK 0 x805 6 float logistic4(fl

50、oat);/ Function protype7 8 void Delay(int); / Delay function9 10 float x0;11 float y0;12 int x=-3;13 int y; 14 double valx1;15 int main()16 17 int nLED;18 19 20 _asm21 22 MVN y, #0 / y = 0 xFFFF FFFF23 CMP x,#024 BGE posnum25 EOR x, x, y26 ADD x, x, #1/ x= 0 x0000 000327 posnum:28 NOP29 30 31 x0 = 0

51、.22f;32 while(1)33 34 35 y0=logistic4(x0);36 37 nLED = 0;38 39 if(y00.75f)44 45 nLED =(LED1_MASK | LED2_MASK);/ LED3 light46 47 else48 49 nLED =(LED1_MASK | LED3_MASK); / LED2 light50 51 52 GPCDAT_ADDR = nLED;53 Delay(0 x500);54 x0 = y0;55 56 57 58 59 60 float logistic4(float x0)61 62 float y0;63 y0

52、=4.0f*x0*(1.0f - x0);64 65 return y0;66 67 68 69 void Delay(int n) / Delay function70 71 int i,j;72 for(i=0;in;i+)73 74 for(j=0;jn;j+)75 76 77 78 注意上述代碼的第2029行。此時(shí)工程ex6_6如圖6-24所示。圖6-24 工程ex6_6的工作界面6.4.2 C函數(shù)調(diào)用匯編子程序 C函數(shù)調(diào)用匯編子程序,也可以稱為用匯編語言編寫C函數(shù),需要考慮C函數(shù)的輸入?yún)?shù)和返回值的匯編語言表示方法,這種表示方法必須符合ATPCS調(diào)用標(biāo)準(zhǔn)。本小節(jié)的局部程序代碼參考自資

53、料“ARM Developer Suite v1.2 - Developer Guide和“S3C2410A Users Manual。1ATPCS調(diào)用標(biāo)準(zhǔn)ATPCS標(biāo)準(zhǔn)規(guī)定了ARM代碼、Thumb代碼、C代碼和C+代碼之間的調(diào)用標(biāo)準(zhǔn),這里僅討論C代碼調(diào)用ARM代碼時(shí)的相關(guān)規(guī)定。C函數(shù)調(diào)用匯編子程序,需要使用extern關(guān)鍵字將匯編子程序(以.s為擴(kuò)展名)在C程序內(nèi)(以.c為擴(kuò)展名)聲明為C函數(shù)的形式,其中的參數(shù)傳遞有以下三種情況:情況一:參數(shù)為指針,那么參數(shù)從左向右依次傳遞給R0、R1、R2、R3,當(dāng)參數(shù)多于4個(gè)時(shí),多余的參數(shù)使用數(shù)據(jù)堆棧(必須按FD方式訪問,8字節(jié)首地址對齊),按從右向左的

54、順序入棧,即最后的參數(shù)先入棧。實(shí)例參考本小節(jié)的2.中的內(nèi)容。 情況二:參數(shù)為整型,與情況一根本上相同,實(shí)例參考本小節(jié)3. 中的內(nèi)容。情況三:參數(shù)為浮點(diǎn)數(shù),當(dāng)ARM微處理器有浮點(diǎn)協(xié)處理器時(shí),將浮點(diǎn)數(shù)參數(shù)傳遞給浮點(diǎn)協(xié)處理器存放器。如果沒有浮點(diǎn)協(xié)處理器,那么按情況一方式傳遞,實(shí)例參考本小節(jié)4.中的內(nèi)容。 當(dāng)匯編子程序?qū)崿F(xiàn)的C函數(shù)有返回值時(shí),一般通過R0返回。在匯編子程序中,R4至R11用于保存局部變量。 ATPCS對存放器的功能限定如表6-3所示。表6-3 ATPCS標(biāo)準(zhǔn)下存放器的功能寄存器助記符功 能R0a1a1a4用于存儲參數(shù)或結(jié)果,可視為全局變量R1a2R2a3R3a4R4v1v1v4用作局部

55、變量R5v2R6v3R7v4R8v5在ARM工作狀態(tài)時(shí),用作局部變量。在某些情況下,v6和v7還可用作變量基址和棧指針R9v6(sb)R10v7(sl)R11v8R12ip內(nèi)部程序間調(diào)用的暫存器R13sp棧指針R14lr連接寄存器R15pc程序計(jì)數(shù)器指針2程序?qū)嵗唬褐羔槄?shù)傳遞在工程ex6_6的根底上,修改文件,并添加文件,得到工程ex6_7。其中,的代碼如下:1 ; 2 AREA STRCOPY, CODE, READONLY3 EXPORT strcopy4 strcopy ; r0 points to destination string5 ; r1 points to source

56、string6 LDRB a3, a2, #1 ; R2, R1, #17 STRB a3, a1, #1 ; R2, R0, #18 CMP a3, #0 ; R2, #09 BNE strcopy10 MOV PC, LR ; return11 END上述代碼中,a1a3可以寫為R0R2(還可以借助RN偽指令,形如“R0_User RN R0,在指令中使用自定義的助記符R0_User),a2指向源字符串地址,a1指向目的字符串地址,通過循環(huán),借助于a3,將a2指向的字符串復(fù)制到a1指向的地址空間。該段匯編語言子程序在C語言程序中聲明為如下形式:extern void strcopy(cha

57、r *d, const char *s);即d傳給了a1(R0),s傳給了a2(R1)。文件的代碼如下:1 #include “2 3 #define GPCDAT_ADDR (*(volatile unsigned int *)0 x56000024)4 #define LED1_MASK 0 x20 5 #define LED2_MASK 0 x406 #define LED3_MASK 0 x807 8 extern void strcopy(char *d, const char *s);9 10 float logistic4(float);/ Function protype11

58、12 void Delay(int); / Delay function13 14 float x0;15 float y0;16 17 double valx1;18 int main()19 20 int nLED;21 / String copy22 const char *strS=“Source String: Copy me!;23 char strD50=“;24 25 strcopy(strD, strS);26 27 x0 = mysin(0.57f); /0.22f;28 29 while(1)30 31 32 y0=logistic4(x0); 33 34 nLED =

59、0;35 36 if(y00.75f)41 42 nLED =(LED1_MASK | LED2_MASK);/ LED3 light43 44 else45 46 nLED =(LED1_MASK | LED3_MASK); / LED2 light47 48 49 GPCDAT_ADDR = nLED;50 Delay(0 x500);51 x0 = y0;52 53 54 55 56 57 float logistic4(float x0)58 59 float y0;60 y0=4.0f*x0*(1.0f - x0);61 62 return y0;63 6465 66 void De

60、lay(int n) / Delay function67 68 int i,j;69 for(i=0;in;i+)70 71 for(j=0;jn;j+)72 73 74 75 上述代碼在執(zhí)行LED燈隨機(jī)閃爍(while)前,調(diào)用匯編語言程序的函數(shù)“strcopy(strD, strS);將strS字符串復(fù)制到strD中。工程ex6_7的工作窗口和調(diào)試結(jié)果如圖6-25和圖6-26所示。 圖6-26中可以看到strD的地址為0 x01000428,從“Memory窗口中的地址0 x01000428處可以看到復(fù)制后的結(jié)果。圖6-25 工程ex6_7的工作界面圖6-26 工程ex6_7的調(diào)試界面3

溫馨提示

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

評論

0/150

提交評論