嵌入式系統(tǒng)的C語(yǔ)言.doc_第1頁(yè)
嵌入式系統(tǒng)的C語(yǔ)言.doc_第2頁(yè)
嵌入式系統(tǒng)的C語(yǔ)言.doc_第3頁(yè)
嵌入式系統(tǒng)的C語(yǔ)言.doc_第4頁(yè)
嵌入式系統(tǒng)的C語(yǔ)言.doc_第5頁(yè)
已閱讀5頁(yè),還剩56頁(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)介

嵌入式系統(tǒng)的C語(yǔ)言譯自C for Embedded Systems講稿劉永重 譯一、C語(yǔ)言基礎(chǔ)1、什么是C?C程序語(yǔ)言最初是由Dennis Ritchie在1971年為UNIX系統(tǒng)開(kāi)發(fā)并實(shí)現(xiàn)的。C的一個(gè)最大優(yōu)點(diǎn)是與任何特定的硬件或系統(tǒng)無(wú)關(guān)。這使得一個(gè)用戶寫(xiě)的程序不作任何修改就能運(yùn)行在幾乎所有的機(jī)器上。C通常被稱為中級(jí)計(jì)算機(jī)語(yǔ)言,因?yàn)樗鼘⒏呒?jí)語(yǔ)言的要素與匯編語(yǔ)言的功能結(jié)合了在一起。2、為什么用C?C非常靈活,而且可隨心所欲。這種自由賦予C非常強(qiáng)大的功能,有經(jīng)驗(yàn)的用戶可以掌握;C是一個(gè)相對(duì)小的語(yǔ)言,但是它經(jīng)久耐用;C有時(shí)被認(rèn)為是“高級(jí)匯編語(yǔ)言”;低級(jí)(位操作)編程也容易實(shí)現(xiàn);松類型(不象其它高級(jí)語(yǔ)言);C是結(jié)構(gòu)化編程語(yǔ)言;C允許你創(chuàng)建你腦海中已有的任何任務(wù)。C保留了程序員知道正在做的事情的基本體系;它只需要他們明白地表達(dá)其意圖。3、為什么不用C?文化的問(wèn)題當(dāng)考慮轉(zhuǎn)到C語(yǔ)言時(shí),我們會(huì)遇到一些共同的問(wèn)題:產(chǎn)生大而低效的代碼;標(biāo)準(zhǔn)IO程序的雍余代碼(printf,scanf,strcpy等);存貯器定位的使用:malloc(),alloc();堆棧的使用,在C中不很直接;在RAM和ROM中數(shù)據(jù)的聲明;難于寫(xiě)中斷服務(wù)程序。4、8位微控制器的ANSI C對(duì)于嵌入式系統(tǒng),純粹的ANSI C并不方便,因?yàn)椋呵度胧较到y(tǒng)與硬件打交道。ANSI C 提供的在固定存貯空間用寄存器尋址的工具非常拙劣;幾乎所有的嵌入式系統(tǒng)使用中斷;ANSI C有各種類型的促進(jìn)規(guī)則,對(duì)8位機(jī)來(lái)說(shuō)絕對(duì)是性能殺手;一些微控制器結(jié)構(gòu)沒(méi)有硬件支持C堆棧;很多微控制器有多個(gè)存貯空間。5、打破一些C范例當(dāng)在低端的8位微控制器上用C語(yǔ)言,應(yīng)想法使代碼變小。這意味著打破一些編程規(guī)則:開(kāi)/關(guān)全局中斷;使用GOTO語(yǔ)句;全局標(biāo)號(hào);全局寄存器段;指針支持。6、嵌入式與桌面編程嵌入式編程環(huán)境的主要特點(diǎn):有限的RAM;有限的ROM;有限的棧空間;面向硬件編程;嚴(yán)格的定時(shí)(ISR,任務(wù),);很多不同種類的指針(far/near/rom/uni/paged/);特殊關(guān)鍵字/標(biāo)識(shí)符(,interrupt,tiny,)。7、匯編與C編譯器只是一個(gè)能干的優(yōu)秀匯編程序員。寫(xiě)能夠轉(zhuǎn)換為高效率匯編代碼的好的C代碼,比手工寫(xiě)高效率的匯編代碼容易得多。C是終極解決辦法,但其本身并未終結(jié)。8、為什么改用C?有很多原因用C語(yǔ)言而不用匯編:C使我們提高效益;用C寫(xiě)的代碼更可靠;C代碼更容易升級(jí)和擴(kuò)展;不同平臺(tái)之間更容易遷移;代碼容易維護(hù);文檔、書(shū)籍、第三方庫(kù)和程序都可得到。9、C代碼結(jié)構(gòu)如下圖所示,一個(gè)C程序基本由以下部分組成:預(yù)處理命令、類型定義、函數(shù)原型(聲明傳給函數(shù)的函數(shù)類型和變量)、變量和函數(shù)。一個(gè)程序必須有一個(gè)main()函數(shù),每個(gè)命令行必須用分號(hào)(;)結(jié)束。10、C函數(shù)一個(gè)函數(shù)的結(jié)構(gòu)如下:類型 函數(shù)名(參數(shù))本地變量C語(yǔ)句11、C關(guān)鍵字1)數(shù)據(jù)類型char short signed unsigned int float long double2) 修飾符const static volatile restrict3)標(biāo)識(shí)符struct union void enum4) 選擇體if else switch case default5) 存貯指定register typedef auto extern6)循環(huán)體do while for7)跳轉(zhuǎn)goto continue break return8)功能指定inline9) 預(yù)處理指示#include #define #undef #line #error #pragma 10)條件編譯# if # ifdef # ifndef # elif # else # endif12、C操作符1)基本表達(dá)式和后綴操作符( ) 子表達(dá)式和函數(shù)調(diào)用 數(shù)組下標(biāo) - 結(jié)構(gòu)指針 結(jié)構(gòu)成員+ 增加(后綴) - 減少(后綴)2) 一元操作符! 邏輯非 取補(bǔ) + 增加(前綴) - 減少(后綴) - 一元減 + 一元加(類型) 類型強(qiáng)制 * 間接指針 & 取地址 sizeof 大小3) 賦值符= 相等賦值 += 加等于 -= 減等于 *= 乘等于 /= 除等于 %= 求余等于=右移位等于 &=按位與等于 = 按位異或等于|= 按位或等于4) 位操作& 位與 位異或 | 位或 位右移5)數(shù)學(xué)運(yùn)算* 乘 / 除 %求余 + 加 - 減6) 關(guān)系運(yùn)算 小于 大于 =大于或等于 =相等測(cè)試 !=不等測(cè)試7) 邏輯運(yùn)算& 邏輯與 | 邏輯或 8) 條件運(yùn)算?: 條件測(cè)試9) 序列, 逗號(hào)二、嵌入式編程1、變量變量的類型決定其可帶值的類型。也就是說(shuō),為變量選擇一個(gè)類型與我們使用這個(gè)變量的方法直接相關(guān)。我們將學(xué)習(xí)C的基本類型、怎樣寫(xiě)常量和聲明這些變量。11 選擇一個(gè)類型“值集合”是有限的。C的整數(shù)類型不能代表所有整數(shù);它的浮點(diǎn)類型也不能代表所有浮點(diǎn)數(shù)。當(dāng)聲明一個(gè)變量并為它選擇一個(gè)類型,你應(yīng)緊記你需要的值和操作。12 C的基本數(shù)據(jù)類型ANSI標(biāo)準(zhǔn)并沒(méi)為本地類型規(guī)定尺寸大小,但CodeWarrior規(guī)定了。C只有一些基本數(shù)據(jù)類型:所有數(shù)量類型(除了char)缺省都是有符號(hào)的,例如:int = signed int。注意:INT型的大小依賴于不同的機(jī)器。13 CodeWarrior數(shù)據(jù)類型例如,按ALT+F7打開(kāi)工程的通用設(shè)置,選擇“Compiler for HC08”面板并點(diǎn)擊類型尺寸。這個(gè)窗口向你顯示CodeWarrior 編譯器使用的標(biāo)準(zhǔn)類型設(shè)置。所有基本類型可以改變,盡管這可能不是個(gè)好主意。14 數(shù)據(jù)類型的事實(shí)代碼大小和執(zhí)行時(shí)間的最大節(jié)約可通過(guò)為變量選擇最合適的數(shù)據(jù)類型得到。8位微控制器內(nèi)部的數(shù)據(jù)的長(zhǎng)度是8位(一字節(jié)),然而C首選的數(shù)據(jù)類型是int。8位機(jī)處理8位數(shù)據(jù)類型比16位類型效率更高?!癷nt“和大數(shù)據(jù)類型只有當(dāng)所描述的數(shù)據(jù)的大小需要時(shí)才使用。當(dāng)效率非常重要時(shí),雙精度和浮點(diǎn)操作效率低,應(yīng)當(dāng)避免。15 選擇數(shù)據(jù)類型8位微控制器選擇數(shù)據(jù)類型有3個(gè)規(guī)則:1)用最可能小的類型來(lái)完成工作,大小越小占用存貯空間越少;2)若可能,用無(wú)符號(hào)類型;3)在表達(dá)式內(nèi)聲明以將數(shù)據(jù)類型減到最少需要。使用類型定義得到固定大?。?)根據(jù)編譯器和系統(tǒng)而改變;2)移植到不同的機(jī)器代碼不變;3)當(dāng)值需要固定位時(shí)使用。打開(kāi)文件:Lab1-Variables.mcp定義了一個(gè)數(shù)據(jù)類型的完整集合Main函數(shù)內(nèi)定義了三種不同類型的變量變量在堆棧中有一個(gè)地址。每個(gè)變量剩余位用:clr ,x清除。只寫(xiě)了意義最少的位;寄存器用于此目的。主函數(shù)外定義了三個(gè)不同類型的變量。主函數(shù)外定義了三個(gè)不同類型的變量。編譯器為作用的變量保留了內(nèi)存。本例中VarA是唯一使用的變量。所有聲明的全局變量均被使用。在這種情況下,編譯器為所有變量保留了內(nèi)存。變量聲明的內(nèi)存區(qū),每個(gè)變量有不同的大?。?、2和4字節(jié))根據(jù)變量大小的不同,每個(gè)加操作用不同的方法完成。2、存貯類修飾符以下關(guān)鍵字用于聲明變量,以指定特定需要或內(nèi)存中變量存貯的相關(guān)條件。static volatile const這三個(gè)關(guān)鍵字,一起讓我們不僅可寫(xiě)出好的代碼,而且可寫(xiě)出緊湊的代碼。21 靜態(tài)變量使用靜態(tài)有二個(gè)主要功能:第一個(gè)最常用的用法是定義一個(gè)變量,在函數(shù)連續(xù)調(diào)用期間,變量不會(huì)消失。第二個(gè)使用靜態(tài)的用法是限制變量的范圍。在模塊級(jí)定義時(shí),能被整個(gè)模塊中所有函數(shù)訪問(wèn),不能被其它函數(shù)訪問(wèn)。這非常重要,因?yàn)楫?dāng)嚴(yán)格限制全局變量眾所周知的問(wèn)題時(shí),它讓我們獲得所有全局變量執(zhí)行性能的好處。因此,如果我們有必須被一些函數(shù)頻繁訪問(wèn)的數(shù)據(jù)結(jié)構(gòu),就應(yīng)當(dāng)將函數(shù)放入同一模塊中,并將結(jié)構(gòu)聲明為靜態(tài)。這樣所有函數(shù)能夠訪問(wèn)而不必通過(guò)一個(gè)訪問(wèn)函數(shù)的上層,同時(shí)與數(shù)據(jù)結(jié)構(gòu)無(wú)關(guān)的代碼禁止訪問(wèn)它。這一技術(shù)是一種變通方法,立即可訪問(wèn)變量在小的機(jī)器上實(shí)質(zhì)上取得了足夠的性能。聲明模塊級(jí)靜態(tài)變量(與將其設(shè)為全局相反)能取得一些其他潛在的益處。靜態(tài)變量由于定義,只能被一組特定的函數(shù)訪問(wèn)。因此,編譯器和連接器能夠明智地選擇變量在存貯空間的放置。例如,對(duì)于靜態(tài)變量,編譯器/連接器也許選擇將一個(gè)模塊中所有靜態(tài)變量放在連續(xù)的區(qū)域,這樣增加了各種優(yōu)化機(jī)會(huì),例如用簡(jiǎn)單的增加或減少代替重載。相反,全局變量在存貯空間的位置通常計(jì)劃于優(yōu)化編譯器的哈稀算法,這排除了可能的優(yōu)化。須著重指出, 這些變量不會(huì)存貯在堆棧中,因?yàn)樗鼈儽仨毐4嫫渲?。下面給出一個(gè)靜態(tài)變量怎樣工作的例子:FILE1.c#include /包含文件FILE2.c/中的函數(shù)void main (void)/第一次進(jìn)入MyFunction之前,myVar=0。MyFunction(); /在FILE2.c中/第二次進(jìn)入MyFunction之前,myVar=1。MyFunction(); /在FILE2.c中FILE2.cvoid MyFunction (void) /FILE2.C中定義/MyFunction函數(shù)static char myVar = 0; /本地變量/聲明為staticmyVar = myVar + 1; /盡管myVar是本地變量,但它保持了自己的值。22 靜態(tài)函數(shù)一個(gè)靜態(tài)函數(shù)只能被其所在模塊中的其它函數(shù)調(diào)用。使用靜態(tài)函數(shù)是結(jié)構(gòu)化編程的好習(xí)慣。你也許驚訝地知道靜態(tài)函數(shù)能產(chǎn)生小/快的代碼。這是可能的,因?yàn)榫幾g器在編譯時(shí)確切地知道什么函數(shù)能調(diào)用一個(gè)給定的靜態(tài)函數(shù)。因此,函數(shù)的相關(guān)內(nèi)存區(qū)域能被調(diào)整,以致使用調(diào)用的一個(gè)短版本或跳轉(zhuǎn)指令。潛在的改進(jìn)甚至更好,編譯器足夠聰明地用跳轉(zhuǎn)代替調(diào)用。23 關(guān)鍵字“static”的使用在函數(shù)體聲明靜態(tài)的變量,在函數(shù)調(diào)用期間保持其質(zhì);在模塊內(nèi)聲明靜態(tài)的變量,(但在函數(shù)體之外)能被模塊內(nèi)所有函數(shù)訪問(wèn);在模塊內(nèi)聲明靜態(tài)的函數(shù),只能被模塊內(nèi)其它函數(shù)調(diào)用。對(duì)于嵌入式系統(tǒng):封裝持續(xù)生存的數(shù)據(jù)(包裝);模塊化編碼(數(shù)據(jù)隱藏);在每個(gè)模塊中隱藏內(nèi)部處理。24 可變(volatile)變量可變變量是其值在正常程序流程以外可能改變的變量。在嵌入式系統(tǒng)中,這種情況通過(guò)兩種主要途徑發(fā)生:通過(guò)一個(gè)中斷服務(wù)程序,或作為硬件動(dòng)作的結(jié)果。例如,通過(guò)一個(gè)串口接收到一個(gè)字符,結(jié)果串口狀態(tài)寄存器更新,這完全在程序流程之外發(fā)生。很多程序員知道編譯器不會(huì)試圖優(yōu)化一個(gè)volatile寄存器,而寧可每次重載它。在嵌入式設(shè)備中,將所有外設(shè)寄存器聲明為volatile是一個(gè)好習(xí)慣。許多編譯器供應(yīng)商經(jīng)常炫耀他們的代碼優(yōu)化,它們通常非常好,它們有些根本不明顯,但能極大地減少周期和內(nèi)存。但有時(shí)我們不想編譯器聰明和優(yōu)化一個(gè)部份,因?yàn)槲覀兇_實(shí)需要代碼那樣作。我們?cè)鯓硬拍苓_(dá)到呢?那么,訪問(wèn)定義為volatile的變量從不會(huì)被編譯器優(yōu)化。讓我們分析一個(gè)例子,看看編譯器是怎樣處理一個(gè)volatile和一個(gè)非volatile變量volatile unsigned char PORTA 0x00;volatile unsigned char SCS1 0x16;unsigned char value;void main(void)PORTA = 0x05;/* PORTA = 00000101 */PORTA = 0x05;/* PORTA = 00000101 */SCS1;value = 10; 未使用Volatile關(guān)鍵字,編譯器將其編譯為:MOV #5,PORTALDA #10STA value使用Volatile關(guān)鍵字后,編譯器將其編譯為:MOV #5,PORTAMOV #5,PORTALDA SCS1LDX #10STX value這段代碼實(shí)際上不做任何事,但它很好地表達(dá)了優(yōu)化怎樣強(qiáng)烈地影響程序的結(jié)果。在main()中連續(xù)兩次使用語(yǔ)句:PORTA=5,這沒(méi)有意義,但讓我們假設(shè)這是正確開(kāi)發(fā)程序所必須的在這兩個(gè)語(yǔ)句之后,明顯地有一條無(wú)意義語(yǔ)句“SCS1;”。讓我們看當(dāng)不使用volatile變量會(huì)發(fā)生什么我們得到了優(yōu)化過(guò)的匯編代碼。重復(fù)的語(yǔ)句Port A = 5消失了只剩下一句“move #5 to Port A”。語(yǔ)句“SCS1;”似乎什么都不做,因此聰明的編譯器將它消去了。最后,將10加載到累加器并作為值存貯。使用volatile關(guān)鍵字聲明PORTA 和SCS1,得到的匯編代碼沒(méi)有優(yōu)化,連續(xù)兩次在Port A寫(xiě)入數(shù)值5,然后將SCS1加載到累加器。最后由于累加器被使用,于是用X寄存器存貯數(shù)值10。好了,連續(xù)兩次用數(shù)值5寫(xiě)PortA,假設(shè)這是需要這樣做,但是加載SCS1到累加器有一個(gè)很有意義的值。這是串行通信接口SCI需要的,讀SCS1寄存器目的是清除任何未決的標(biāo)志。無(wú)意義的語(yǔ)句“SCS1;”被翻譯為讀寄存器的的匯編語(yǔ)句,這將清除SCI中未決的標(biāo)志。前面說(shuō)過(guò),在嵌入式設(shè)備中將所有外設(shè)寄存器聲明為volatile是一個(gè)好習(xí)慣。在分開(kāi)的頭文件中定義所有外設(shè)的名字,能使所寫(xiě)代碼更友好并使遷移簡(jiǎn)化。下面這個(gè)例子用volatile變量聲明所有寄存器,這樣做較妥當(dāng),因?yàn)槿魏芜@些寄存器能在任何時(shí)候在程序流程之外被修改。/* MC68HC908GP20/32 Official Peripheral Register Names */volatile unsigned char PORTA 0x0000; /* Ports and data direction */volatile unsigned char PORTB 0x0001;volatile unsigned char PORTC 0x0002;volatile unsigned char PORTD 0x0003;volatile unsigned char PORTE 0x0008;volatile unsigned char DDRA 0x0004; /* Data Direction Registers */volatile unsigned char DDRB 0x0005;volatile unsigned char DDRC 0x0006;volatile unsigned char DDRD 0x0007;volatile unsigned char DDRE 0x000C;volatile unsigned char PTAPUE 0x000D; /* Port pull-up enables */volatile unsigned char PTCPUE 0x000E;volatile unsigned char PTDPUE 0x000F;25 Const變量關(guān)鍵字“const”,C語(yǔ)言中命名最差的關(guān)鍵字,并不表示恒量,而是代表“只讀”。在嵌入式系統(tǒng)中,有很大的不同,這一會(huì)應(yīng)會(huì)明白。Const聲明可用于任何變量,它告訴編譯器將其存貯在ROM代碼。編譯器保留了那個(gè)位置程序存貯器地址。由于位于ROM中,其值不能改變。 由于它作為常量工作,必須賦一初值。如:const double PI = 3.14159265;Const 變量與明顯的常數(shù)相對(duì),很多原文要求用const變量代替明顯的常數(shù)。例如:用const unsigned char channels = 8;代替#define CHANNELS 8 。本方法的基本原理是在調(diào)試器內(nèi)部,你能檢查一個(gè)const變量,然而一個(gè)明顯的常數(shù)不可訪問(wèn)。不幸的是,在很多8位機(jī)上你將為這一好處付出極大的代價(jià)。這兩個(gè)主要代價(jià)是: 一些編譯器在RAM中創(chuàng)建一個(gè)真實(shí)的變量來(lái)支持cost變量,這是一個(gè)極大的懲罰。 一些編譯器如CodeWarrior,知道變量為const,將把變量存貯在ROM中。無(wú)論怎樣,變量仍作為變量處理和訪問(wèn),典型地用某些變址尋址(16位)的方式。與直接尋址(8位)方式相比,這種方法通常很慢。Const的用法:const unsigned short a;unsigned short const a;const unsigned short *a;unsigned short * const a;26 Const volatile 變量現(xiàn)在討論一個(gè)深?yuàn)W的問(wèn)題,一個(gè)變量既能是常量,又能是可變量嗎?如果是這樣,這意味什么,怎樣使用?答案是“能”。這個(gè)修飾符應(yīng)該用于能出乎意料地改變的任何存貯器位置,因此需要volatile限定語(yǔ),由于const該變量是只讀的。最明顯的例子是硬件狀態(tài)寄存器,象SCI狀態(tài)寄存器SCS1。這個(gè)寄存器包含信號(hào)狀態(tài)標(biāo)志,如發(fā)送空、發(fā)送完成、接收滿以及其它。這是一個(gè)可變寄存器由于這些標(biāo)志的改變依賴于串行通信的狀態(tài),這也是只讀,由于標(biāo)志不能被程序直接改寫(xiě),它們只對(duì)模塊的狀態(tài)作出響應(yīng)。這個(gè)狀態(tài)寄存器最佳聲明方法是:const volatile unsigned char SCS1 0x0016 3、資源映射31 訪問(wèn)固定內(nèi)存位置嵌入式系統(tǒng)通常的特點(diǎn)是需要編程者訪問(wèn)一個(gè)指定的存貯器位置。練習(xí):在某個(gè)項(xiàng)目中需要將絕對(duì)地址0xFFA處整型變量的值設(shè)為0xAA55(編譯器為純粹的ANSI編譯器)。完成這個(gè)任務(wù)的代碼是:Int * ptr;ptr = (int *)0x2FFA;*ptr = 0xAA55;32 怎樣訪問(wèn)I/O寄存器在嵌入式領(lǐng)域,設(shè)備如微控制器有片上資源,應(yīng)當(dāng)被管理和訪問(wèn)。很多I/O和控制寄存器位于直接頁(yè),它們應(yīng)如此聲明,因此在可能時(shí)編譯器能直接尋址。它們有定位的地址,但問(wèn)題是它們不是存儲(chǔ)器,那么怎樣訪問(wèn)這些I/O寄存器呢?這是一個(gè)非常重要的問(wèn)題,答案比你想的簡(jiǎn)單或者復(fù)雜。一個(gè)普照通而有用的形式是使用如下的#define指示:#define PortA ( * ( volatile unsigned char * ) 0x0000 )這構(gòu)成了I/O寄存器,這種情況下,Port A為地址0x0000處字符型變量。#define實(shí)際做的是每次發(fā)現(xiàn)PortA時(shí)放置一個(gè)構(gòu)件。也就是說(shuō)在代碼中寫(xiě):PortA = 0x3F,實(shí)際做的就是告訴編譯器0x0000是一個(gè)volatile-unsigned-char類型的指針,它的內(nèi)容等于0x3F。糊涂嗎?有點(diǎn)讓我們看一些其它選擇:這樣做的一個(gè)容易的方法是在變量聲明中使用符號(hào)“”,創(chuàng)建一個(gè)語(yǔ)句讀作:在地址0x0000處創(chuàng)建一個(gè)volatile-unsigned-char型的變量PortA。這是一個(gè)編譯器特定的語(yǔ)法,它可讀性高,但失去了兼容性。無(wú)論什么時(shí)候我們決定使用一個(gè)不同的編譯器去編譯該代碼,也許會(huì)發(fā)現(xiàn)不被識(shí)別。CodeWarrior和Cosmic包含了這個(gè)特殊語(yǔ)法。CPU中的寄存器沒(méi)有內(nèi)存映射;指令集包含允許它們自修改的子集;C不提供直接訪問(wèn)寄存器的工具;C編譯器允許在C代碼中使用匯編指令,如:1)_asm AssemblyInstuction;2)asm (AssemblyInstruction);3)asm -修改CPU 中CCR的I位的內(nèi)容。使用匯編指示,I位被修改。33 位域在嵌入系統(tǒng)中,在一個(gè)給定的地址,一次能訪問(wèn)和修改一位或幾位。$0020 00001001完成這個(gè)任務(wù),在C語(yǔ)言中有不同的方法達(dá)到和實(shí)現(xiàn)。*位結(jié)構(gòu):效率隨編譯器的不同而改變;跨編譯器和目標(biāo)不能移植。*位類型:不能移植(標(biāo)準(zhǔn)C語(yǔ)言中沒(méi)有);如當(dāng)使用時(shí)可提高代碼的效率。*移位和掩??梢浦玻m當(dāng)?shù)男?;?jīng)常優(yōu)化為位操作。如果定義一個(gè)結(jié)構(gòu),但所有變量重疊在同一內(nèi)存的開(kāi)始位置,你應(yīng)該使用聯(lián)合體。聯(lián)合體允許引用在聯(lián)合體中定義的以任何形式描述的數(shù)據(jù)字節(jié)。聯(lián)合體在內(nèi)存中的尺寸大小為聯(lián)合體中所列的最大類型的大小。點(diǎn)操作符用于選擇需要的成員。打開(kāi)文件:Lab2-BitFields.mcp聯(lián)合體是一個(gè)變量,不同的時(shí)間持有對(duì)象不同的類型和大小,編譯器跟蹤變量的大小和決定需要。一條指令所寫(xiě)只有PS位被修改聯(lián)合體提供操作單一存貯區(qū)不同類型數(shù)據(jù)的方法,程序中沒(méi)有嵌入任何依賴于機(jī)器的信息。34 數(shù)組C允許程序員用幾種不同方法存取數(shù)組的內(nèi)容。Unsigned char Array=0xAA,0xBB,0xCC;依賴于執(zhí)行,選擇最適合于該應(yīng)用的需要,將產(chǎn)生快而小的代碼。數(shù)組訪問(wèn)方法:1)硬編碼:Array0=12*UNIT_VOLTS;編譯時(shí)決定地址,執(zhí)行速度快。2)變址增加Arrayindex+=12*UNIT_VOLTS;快速,比硬編碼靈活。3)數(shù)組指針*(ArrayPtr+)=12*UNIT_VOLTS;執(zhí)行速度快,可讀性差,可和循環(huán)一起使用。如下圖所示:打開(kāi)文件:Lab3-Arrays.mcp數(shù)組指針增量變址硬編碼每種訪問(wèn)類型都有各自的優(yōu)點(diǎn),使用不同的寄存器完成不同的操作。35 函數(shù)指針函數(shù)指針與數(shù)據(jù)指針一樣有用處,原因如下:當(dāng)你想要一個(gè)額外級(jí)別的間接時(shí);當(dāng)你想用同一段代碼依環(huán)境的不同調(diào)用不同的函數(shù)。下面的代碼定義了一個(gè)指向函數(shù)的指針,帶了一個(gè)整型參數(shù)并返回一整數(shù):int (*function)(int);(*function)周圍的圓括符是必須的,因?yàn)槎x中的優(yōu)先關(guān)系。沒(méi)有它們,我們則定義了一個(gè)函數(shù)返回一個(gè)整型指針。例如:函數(shù)指針現(xiàn)在指向一個(gè)不同的函數(shù)函數(shù)指針初始化下面舉一個(gè)HC08QL的例子:SLIC模塊僅有一個(gè)中斷;用戶必須讀SLIC中斷向量寄存器(SLCSV)來(lái)核實(shí)中斷源??赡艿慕鉀Q方案:switch 語(yǔ)句;嵌套的if語(yǔ)句;函數(shù)指針。打開(kāi)文件:Lab4-Pointers.mcp每次調(diào)用一個(gè)不同的函數(shù)定義了一個(gè)函數(shù)數(shù)組。調(diào)試(1):1、 在函數(shù)調(diào)用處下斷點(diǎn)。2、 跟蹤進(jìn)函數(shù)(F11)。調(diào)試(2):每次將執(zhí)行一個(gè)不同的函數(shù)。調(diào)試(3):打開(kāi)Component-Visuallization Tool打開(kāi)Display.vtl然后運(yùn)行:VarA在每個(gè)函數(shù)中被修改。什么時(shí)候使用指針:當(dāng)使用少量函數(shù)時(shí),嵌套的IF語(yǔ)句占用空間少;Switch語(yǔ)句可讀性好,但占空間大;當(dāng)很多函數(shù)被聲明時(shí),指針產(chǎn)生的代碼少,但它占用大量的RAM空間。36 棧指針與函數(shù)參數(shù)棧指針支持C的關(guān)鍵特性:在匯編程序和C編譯器中,堆棧通常用于給子程序傳遞變量;允許使用遞歸;是自動(dòng)變量的基礎(chǔ)。典型地子程序?qū)研枰牟僮鲾?shù)放入累加器。堆棧相對(duì)尋址允許訪問(wèn)堆棧上的數(shù)據(jù),提供直接訪問(wèn)操作數(shù),排除從堆棧壓入以及彈出數(shù)值所需要的代碼和時(shí)間。堆棧指針指令與等份的變址指令相比需要一個(gè)額外的字節(jié)和一個(gè)額外的執(zhí)行周期。例如:typedef struct unsigned char ID;unsigned short Time; ObjectType;void foo (unsigned char value) volatile ObjectType instance;instance.ID = value;編譯后得到:foo:B00B A7FB AIS #-3B00D 9EE701 STA 1,SPB010 A707 AIS #3B012 81 RTS 361 堆棧指針尋址堆棧指針相對(duì)尋址進(jìn)一步增強(qiáng)了C代碼的效率。有兩種類型:8位偏移的堆棧指針相對(duì)尋址和16位偏移的堆棧指針相對(duì)尋址。它們和間址建起方式工作相似,但使用堆棧指針代替H:X變址寄存器。注意當(dāng)中斷不允許時(shí)可用堆棧指針作為額外的變址寄存器。362 堆棧幀1)幀指針函數(shù)通常有一個(gè)包含其所有本地?cái)?shù)據(jù)的堆棧幀。編譯器并不設(shè)置一個(gè)明白的幀指針,但堆棧上的本地?cái)?shù)據(jù)和參數(shù)都根據(jù)SP寄存器訪問(wèn)。2)入口代碼 通常入口代碼是一系列為本地變量保留空間的指令: PSHA ;僅當(dāng)有寄存器參數(shù) PSHX ;僅當(dāng)有寄存器參數(shù) AIS #(-s) ;為本地變量保留空間 S是函數(shù)的本地?cái)?shù)據(jù)的大?。▎挝唬鹤止?jié))。沒(méi)有靜態(tài)鏈接,動(dòng)態(tài)鏈接并沒(méi)有明白地存儲(chǔ)。3)出口代碼 出口代碼從堆棧中移除本地變量,并返回到調(diào)用者:AIS #(t) ;移除本地棧空間,包括最終的寄存器參數(shù)RTS ;返回調(diào)用者363 HC08返回值除函數(shù)返回一對(duì)象大于二字節(jié),函數(shù)結(jié)果都返回到寄存器中。依據(jù)返回類型,使用不同的寄存器。如下表所示:返回類型寄存器Char(signed或unsigned)Aint(signed或unsigned)X:A指針/數(shù)組X:A函數(shù)指針X:A返回大對(duì)象:函數(shù)返回大于二字節(jié)的對(duì)象均與一個(gè)附加的參數(shù)一起調(diào)用,它被傳到H:X。這個(gè)參數(shù)是對(duì)象應(yīng)復(fù)制到的地址。打開(kāi)文件:Lab5-Arguments.mcp每個(gè)函數(shù)有一個(gè)不同類型的參數(shù)(void,byte,word)聲明了四個(gè)不同類型的函數(shù),每個(gè)函數(shù)返回一不同類型的變量。函數(shù)以RTS返回。全局變量賦值。被調(diào)用的函數(shù)跳轉(zhuǎn)到其源碼所在的內(nèi)存位置。 A-變量結(jié)果存貯在變量里堆棧中進(jìn)行的操作和返回值存貯在A中參數(shù)在A寄存器中A和X用作參數(shù)和返回寄存器A用作參數(shù)寄存器,也用作直接尋址數(shù)組中的字節(jié)。H:X用于返回指針.37 中斷好, 最后一個(gè)棘手的問(wèn)題深深地困擾嵌入式世界:怎樣處理中斷?答案是簡(jiǎn)單!CodeWarrior編譯器提供了一個(gè)非ANSI的變通的方法,在源碼中直接指定中斷向量號(hào)t。表達(dá)式以interrupt關(guān)鍵字開(kāi)始, 接著是中斷向量號(hào),最后是函數(shù)原型。interrupt 17 void TBM_ISR (void)/* Timebase Module Handler*/你應(yīng)查HC08手冊(cè),RESET和軟中斷向處在最高和相同的優(yōu)先級(jí)。這兩個(gè)是HC08的向量0,但CodeWarrior不得不給每個(gè)向量不同的號(hào),因此第一個(gè),RESET,將是向量0,然后SWI,向量1,依次類推直到最后TBM為向量17,以GP32為例。中斷向量表定位:向量號(hào)向量地址向量地址大小00xFFFE0xFFFF210xFFFC0xFFFD220xFFFA0xFFFB2n0xFFFF-(n*2)2打開(kāi)文件Lab6-Interrupts.mcp:使用中斷修飾符聲明一個(gè)中斷服務(wù)程序。中斷向量存貯了ISR開(kāi)始的地址函數(shù)指針使用RTI代替RTS38 疊代、跳轉(zhuǎn)、循環(huán)執(zhí)行無(wú)限循環(huán):While(1);For(;);Loop:goto Loop;對(duì)于嵌入式系統(tǒng):循環(huán)總是被基于MCU的應(yīng)用所需要。對(duì)于應(yīng)用程序第2種循環(huán)最好,因?yàn)樗粫?huì)導(dǎo)致“always true warning”的警告。39 標(biāo)準(zhǔn)C庫(kù)標(biāo)準(zhǔn)庫(kù)如stdio.h通常包含在編譯器中。Getchar()、gets()、printf()、putchar()、puts()、scanf()、sprintf()、sscanf()等,都是這些庫(kù)中的常用函數(shù)。 #include void main(void) printf(“Hello World!n”); while(1); 當(dāng)給PC機(jī)寫(xiě)這段代碼, printf()缺省的控制臺(tái)是顯示器,但HC08不需要顯示器作為片外外設(shè),如果有,哪個(gè)端口用于顯示?什么時(shí)候我們定義它?在哪兒?在嵌入式編程中,通常printf()調(diào)用putchar()執(zhí)行打印,這假定控制臺(tái)缺省為片上串行口(SCI)。在模擬時(shí),printf()訪問(wèn)片上“虛擬”IO調(diào)用一個(gè)模擬終端通過(guò)片上SCI輸出。建議修改基礎(chǔ)庫(kù)函數(shù)putchar()和getchar() t使用任何用戶需要的輸出/輸入控制臺(tái)。三、CodeWarrior介紹1、C編譯器對(duì)于現(xiàn)在的嵌入式應(yīng)用,沒(méi)必要花大量時(shí)間選擇一個(gè)C/C+交叉編譯器,但你應(yīng)記住詳細(xì)的難事。稍微詳細(xì)的資料讓我們使用一個(gè)特定的交叉編譯器容易一些,減少工程中受挫。理想情況下,應(yīng)從不考慮你的編譯器。它只是你用于將系統(tǒng)行為的算法和規(guī)則轉(zhuǎn)化為可執(zhí)行的程序。但是,世界不是理想的當(dāng)比較兩個(gè)或更多的交叉編譯器,以滿足你需要的硬件和軟件,你應(yīng)當(dāng)考慮些什么事情呢?有一些好的特性形成巨大的不同:在線匯編: 盡管C語(yǔ)言的發(fā)明已超過(guò)25年,當(dāng)開(kāi)發(fā)嵌入式系統(tǒng)時(shí),使用一定數(shù)量的匯編仍然是平常的事。中斷函數(shù):交叉編譯器另一個(gè)讓人滿意的特性是指定中斷類型。對(duì)PC平臺(tái),這一非標(biāo)準(zhǔn)關(guān)鍵字是C語(yǔ)言普遍增加的。當(dāng)用作函數(shù)聲明的一部份,它告訴編譯器這個(gè)函數(shù)是一個(gè)中斷服務(wù)程序(ISR)。編譯器能產(chǎn)生額外的堆棧信息和寄存器保存以及任何ISR需要的恢復(fù)。一個(gè)好的編譯器也會(huì)阻止這種方式定義的函數(shù)被程序的其它部分調(diào)用。應(yīng)該明白,C/C+中與進(jìn)出ISR相關(guān)的上層與匯編中是沒(méi)有差別的。 例如CodeWarrior,盡管進(jìn)一步深入理解一個(gè)處理器的中斷向表的結(jié)構(gòu)。這種情況,只需簡(jiǎn)單地向ISR 標(biāo)記添加中斷類型 (0x1E)。這使得中斷向量表自動(dòng)生成,并消除了編程人員潛在的誤解和錯(cuò)誤。 產(chǎn)生匯編語(yǔ)言:產(chǎn)生匯編語(yǔ)言清單的編譯器,作為匯編處理器的一部分是一個(gè)令人滿意的工具。這一特性對(duì)手工優(yōu)化代碼很有幫助,因?yàn)槟隳苋菀椎乜吹侥愀呒?jí)語(yǔ)言程序的每一行產(chǎn)生了什么代碼,如果一個(gè)特定的函數(shù)對(duì)于給定的應(yīng)用太慢,你將能夠容易地選擇函數(shù)最好的部分用匯編重寫(xiě)。 標(biāo)準(zhǔn)庫(kù):當(dāng)你為通用計(jì)算機(jī)開(kāi)發(fā)應(yīng)用軟件,你希望你的編譯器包含一套標(biāo)準(zhǔn)C函數(shù)庫(kù),數(shù)學(xué)庫(kù)和C+類。它們包含各種程序如memcpy()、sin()和cout等。但由于這些庫(kù)函數(shù)不嚴(yán)格地是C或C+語(yǔ)言標(biāo)準(zhǔn)的一部分(庫(kù)標(biāo)準(zhǔn)是分開(kāi)的),一個(gè)編譯器提供商可能省略它,這些省略在嵌入系統(tǒng)程序員使用的交叉編譯器提供商中是很普遍的。因些在某些情況下你不得不爭(zhēng)取得到標(biāo)準(zhǔn)庫(kù)的權(quán)利。想一下多少次你花時(shí)間重寫(xiě)那些自己的函數(shù)。因此花些時(shí)間堅(jiān)持將標(biāo)準(zhǔn)庫(kù)包含在你購(gòu)買的編譯器中。當(dāng)然不大可能在多數(shù)嵌入式系統(tǒng)應(yīng)用中使用printf(),但直到太遲了你才意識(shí)到你需要很多其它的函數(shù)。如果提供了標(biāo)準(zhǔn)庫(kù),確保它們能再進(jìn)去。換句話說(shuō),那些庫(kù)中的每個(gè)函數(shù)能同時(shí)執(zhí)行多次。重入函數(shù)能遞歸調(diào)用或多線程執(zhí)行。對(duì)于庫(kù)程序這意味著不應(yīng)使用全局變量。其內(nèi)部所有數(shù)據(jù)必須在棧上。 起動(dòng)代碼:這是在main()前先執(zhí)行的額外的一段程序。起動(dòng)代碼通常用匯編寫(xiě)成并和你建立的可執(zhí)行代碼連接在一起。它為用高級(jí)語(yǔ)言寫(xiě)的程序的執(zhí)行鋪路。顯然,一個(gè)編譯器缺少我們提到的一些特性,也仍可是一個(gè)好的編譯器。毫無(wú)疑問(wèn),人們會(huì)爭(zhēng)論非標(biāo)準(zhǔn)特性象 “asm”和interrupt關(guān)鍵字減少了代碼的兼容性。但若你在兩個(gè)或多個(gè)差不多的交叉編譯間選擇時(shí),你可能會(huì)考慮這些事情。正好你被要求完成這些任務(wù),它們會(huì)使你的工作容易。它們的確減少編程受挫。2、編譯器必要條件一個(gè)好的編譯必須提供的功能有:ROM定位代碼:例如,編譯器必須給出容易寫(xiě)入EPROM的的ROM定位代碼。優(yōu)化的代碼:代碼大小和執(zhí)行時(shí)間同樣必須優(yōu)化。分枝和窺孔優(yōu)化自動(dòng)激活。重入代碼:無(wú)全局變量用于存貯中間結(jié)果。由于結(jié)構(gòu)和或缺少棧操作(如HC05、ST7)并不是所有的目標(biāo)系統(tǒng)有重入代碼。HC08是允許重入代碼的一個(gè)好目標(biāo)系統(tǒng)。支持CPU家族的不同成員:對(duì)于M68K家族有用,允許激活68000、68020、68332或68881指令集。支持不同的存儲(chǔ)器模型:允許根據(jù)存貯器地圖的某些簡(jiǎn)單限制優(yōu)化產(chǎn)生的代碼。已有的存貯器模型與目標(biāo)處理器結(jié)果緊密相關(guān)。非明顯的優(yōu)化:盡管當(dāng)用匯編寫(xiě)代碼時(shí),能用于決定可能的復(fù)雜的優(yōu)化。編譯器工作過(guò)程示例:3、存貯器放置PRM文件看了前面的代碼,尤其是當(dāng)一個(gè)從桌面編程轉(zhuǎn)到嵌入式編程,腦子里會(huì)產(chǎn)生一些基本問(wèn)題我的代碼在哪兒?我的變量在哪兒?怎樣訪問(wèn)I/O寄存器?怎樣處理中斷?當(dāng)寫(xiě)桌面應(yīng)用程序時(shí),通常不用考慮代碼放在哪里。操作系統(tǒng)負(fù)責(zé)管理內(nèi)存分配。處理嵌入式設(shè)備,你不得不充當(dāng)OS決定將代碼放在何處,至少?zèng)Q定代碼開(kāi)始之處事實(shí)是連接器為我們作了大量工作,但并是所有的事情。為讓連接器知道我們的特定設(shè)備或目標(biāo)的存貯器分布,我們不得不指定它。定義的代碼的定位以及內(nèi)存尋址的數(shù)據(jù)段由連接器的參數(shù)文件控制。這個(gè)文件由后綴 “.prm”識(shí)別。連接器的參數(shù)文件是一個(gè)ASCII文本件。對(duì)每個(gè)程序你得寫(xiě)一個(gè)這樣的文件。它包含指導(dǎo)如何連接的命令。這個(gè)文件中,SECTIONS命令塊用于定義存貯器的物理區(qū)域。在SECTIONS命令塊中,每個(gè)單獨(dú)的物理存貯器段用一個(gè)名字、一個(gè)屬性和一個(gè)地址范圍描述。一旦定義了SECTIONS,代碼和數(shù)據(jù)段用PLACEMENT命令塊定位到存貯器中。PLACEMENT命令塊用于將代碼和數(shù)據(jù)段定位到存貯器段。參數(shù)文件中命令的順序沒(méi)有關(guān)系。你只應(yīng)確定SEGMENTS塊在PLACEMENT塊之前指定。若要詳細(xì)了解連接器的參數(shù)文件請(qǐng)參考Metrowerks的手冊(cè)文件“SmartLinker.pdf”。# pragma指示符#pragma 導(dǎo)致預(yù)處理器執(zhí)行一個(gè)依賴于執(zhí)行的動(dòng)作除非另規(guī)定一個(gè)PRAGMA聲明外,變量放在Default_RAM 的位置。地址范圍$0000至$00FF叫作直接頁(yè)、基本頁(yè)或零頁(yè)。在HC08微控制器家族,在直接頁(yè)的低地址部分包含I/O和控制寄存器,直接頁(yè)的高地址部分總是包含RAM。復(fù)位后,棧指針總是指向地址$00FF。直接頁(yè)非常重要,因?yàn)樵S多CPU08指令有一個(gè)直接尋址模式(8位尋址模式),其在直接頁(yè)中訪問(wèn)操作數(shù)比擴(kuò)展尋址模式(16位尋址模式)少一個(gè)時(shí)鐘周期。更有甚者,直接尋址模式指令需要的代碼少一字節(jié)。一些高效的指令只使用直接頁(yè)操作數(shù),它們是:BSET、BCLR、BRSET和BRCLR。MOV指令需要一個(gè)操作數(shù)在直接頁(yè)。只有變量明確地定義在直接頁(yè),編譯器才能利用直接尋址模式的效率高優(yōu)點(diǎn)。ANSI無(wú)標(biāo)準(zhǔn)方法做這些,編譯器通常提供不同的解決方案。CodeWarrior 使用#pragma聲明。PRAGMA是一個(gè)編譯器指示。你設(shè)置pragma為需要的狀態(tài)后,那一點(diǎn)以后的所有代碼用那個(gè)設(shè)置編譯,直到你改變?cè)O(shè)置或到達(dá)文件的末尾。在每個(gè)文件的開(kāi)頭,編譯器恢復(fù)到工程的設(shè)置或缺省設(shè)置。這個(gè)pragma將聲明的變量放在直接頁(yè)段,就如前面見(jiàn)到的,程序員必須記住修改PRM文件,使連接器把段放在直接頁(yè)或零頁(yè)的一個(gè)地址。直接頁(yè)RAM的數(shù)量總是有限的,因此只有頻繁使用的變量應(yīng)放在直接頁(yè)。如果能用到,要為全局變量釋放更多的直接頁(yè)RAM,堆棧被重定位在直接頁(yè)RAM之外,這不會(huì)影響堆棧指針尋址模式。請(qǐng)看下列例子:打開(kāi)文件Lab7-DataSeg.mcp:定義了一個(gè)新存貯段。變量定義在段中,它的位置由連接器決定。定義了一個(gè)數(shù)據(jù)段(VarA)位于指定的存貯位置。(即通信協(xié)議。)VarB在缺省段。VarA位于0x80打開(kāi)文件Lab8-CodeSeg.mcp定義了段,函數(shù)在該段內(nèi)執(zhí)行。定義一個(gè)代碼段,位于指定的存貯位置代碼段function1位于存貯器段FunctionsROM中,它定義在EF00與EFFF之間。打開(kāi)文件Lab9-ConstSeg.mcp在指定的存貯位置定義了一個(gè)常量段。存貯在數(shù)組中的常量值并沒(méi)存在內(nèi)存中,使用了直接放置其內(nèi)容的方法。若變量數(shù)組試圖在Fash中更新,將會(huì)得到錯(cuò)誤結(jié)果4、起動(dòng)程序你的程序是怎樣起動(dòng)的呢?在工作站或PC上操作系統(tǒng)從磁盤上裝入程序并建立環(huán)境。在嵌入式系統(tǒng)中沒(méi)有操作系統(tǒng)。基本上,程序員必須處理程序起動(dòng)的每個(gè)方面。嵌入式應(yīng)用,特別是用C或C+寫(xiě)的代碼,需要一個(gè)起動(dòng)模塊,在起動(dòng)main()之前配置硬件和代碼。通常不可避免地用匯編語(yǔ)言寫(xiě)成,這個(gè)模塊是處理器離開(kāi)復(fù)位狀態(tài)第一個(gè)執(zhí)行的代碼。C/C+起動(dòng)代碼通常執(zhí)行下列動(dòng)作: 1)關(guān)中斷;2)將初始化數(shù)據(jù)從ROM復(fù)制到RAM;3)將未初始化數(shù)據(jù)區(qū)清零;4)為堆棧定位空間以及初始化堆棧;5)創(chuàng)建并初始化堆;6)執(zhí)行構(gòu)造函數(shù)并初始化所有全局變量(僅C+);7)開(kāi)中斷;最后,起動(dòng)代碼調(diào)用main(),啟動(dòng)應(yīng)用的剩余部分。雙擊起動(dòng)程序是復(fù)位后第一個(gè)執(zhí)行的,復(fù)位向量存貯了_startup()所在位置。5、編譯器優(yōu)化CodeWarrior編譯器提供了幾種從C源代碼產(chǎn)生實(shí)際匯編代碼的優(yōu)化方法,這些代碼被編程到微控制器中?!癎lobal Optimizations”(全局優(yōu)化)設(shè)置面板設(shè)定編譯器怎樣優(yōu)化目標(biāo)代碼。所有優(yōu)化程序重新組織目標(biāo)代碼,不影響其邏輯執(zhí)行順序。1)強(qiáng)度減弱“Strength Reduction”(強(qiáng)度減弱)是一種優(yōu)化,力爭(zhēng)用開(kāi)銷小的操作代替開(kāi)銷大的操作,代價(jià)因素是執(zhí)行時(shí)間或代碼大小。在循環(huán)內(nèi),用加法指令代替乘法指令。下列例子將演示編譯器,基于應(yīng)用做什么,決定哪一種操作用最少代價(jià)達(dá)到同樣結(jié)果。打開(kāi)文件Lab10-Optimize1.mcp字節(jié)乘3用MUL指令執(zhí)行字節(jié)乘4用2個(gè)左移指令執(zhí)行。用H:X作為指向我們將要乘的值的指針。等同于:VarA=VarA*4;2)死代碼消除對(duì)于死代碼消除,編譯器優(yōu)化應(yīng)用程序并不為沒(méi)被使用的語(yǔ)句產(chǎn)生可執(zhí)行代碼。移除邏輯上從未執(zhí)行的語(yǔ)句或沒(méi)有被其他語(yǔ)句提到的語(yǔ)句。打開(kāi)文件:Lab11-Optimize2.mcp。循環(huán)結(jié)束后變量未被修改。異或指令=在循環(huán)后變量被修改。賦值被跳過(guò)3)死賦值消除死賦值,編譯器移去變量在再次賦值之前沒(méi)有被使用的賦值。在下面編譯器優(yōu)化的例子,我們將演示通過(guò)改變編譯器的優(yōu)化設(shè)置,達(dá)到改變CodeWarrior產(chǎn)生代碼的方式。打開(kāi)文件Lab12-Optimize3.mcp:這個(gè)循環(huán)定義了i的值,基于排列,但在循環(huán)后它將存貯值1。4)Codewarrior HC08 編譯器選項(xiàng)設(shè)置所有這些代碼被跳過(guò)循環(huán)中用到的變量是全局變量盡管優(yōu)化項(xiàng)打開(kāi),為循環(huán)產(chǎn)生的代碼沒(méi)被跳過(guò)。因?yàn)槿肿兞繒?huì)被硬件(中斷)動(dòng)作存取。5)循環(huán)解開(kāi)通過(guò)改變編譯器設(shè)置,我們可選擇不同的優(yōu)化項(xiàng),在生成代碼時(shí)將會(huì)有差異。循環(huán)體內(nèi)完全相同的代碼目的是展開(kāi)更多操作分支以完成上面的測(cè)試。下列例子演示“循環(huán)解開(kāi)”選項(xiàng)的工作,打開(kāi)文件Lab13-Optimize4.mcp:(沒(méi)有解開(kāi)循環(huán)的例子)編譯器產(chǎn)生與4次循環(huán)相關(guān)的代碼。循環(huán)解開(kāi)的例子:編譯器解開(kāi)循環(huán)for(i=0;i4;i+)Arrayi=i;Array0=0;Array1=1

溫馨提示

  • 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)論