Keil C使用經(jīng)驗(yàn)小結(jié)_第1頁(yè)
Keil C使用經(jīng)驗(yàn)小結(jié)_第2頁(yè)
Keil C使用經(jīng)驗(yàn)小結(jié)_第3頁(yè)
Keil C使用經(jīng)驗(yàn)小結(jié)_第4頁(yè)
Keil C使用經(jīng)驗(yàn)小結(jié)_第5頁(yè)
已閱讀5頁(yè),還剩14頁(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、keil c使用經(jīng)驗(yàn)小結(jié)秦建勛2005/7/29目錄引言1語(yǔ)言擴(kuò)展1數(shù)據(jù)存儲(chǔ)器區(qū)域1存儲(chǔ)器模型2指針3函數(shù)3參數(shù)傳遞3自動(dòng)變量分配8c51的陷阱9運(yùn)算溢出9編譯與鏈接控制10編譯時(shí)控制10定制文件10startup.a5110init.a5110l51_bank.a5111鏈接時(shí)控制11代碼或常數(shù)的絕對(duì)定位11和_at_關(guān)鍵字的比較11overlay12如何控制overlay15overlay相關(guān)的其它問(wèn)題15可重入函數(shù)16vision ide使用簡(jiǎn)介16簡(jiǎn)單的代碼習(xí)慣17頭文件(.h文件)習(xí)慣17c模塊的習(xí)慣18cvs的使用18引言2004年6月以來(lái)開(kāi)始接觸keil c,原因是muse項(xiàng)目控

2、制器采用了目前8位微控制器領(lǐng)域最經(jīng)典、使用最廣泛的8051 mcu。從一年多來(lái)的使用實(shí)踐看,我們的8051 ip還是比較可靠的,那么以后可能有更多的產(chǎn)品需要用到該ip,因此看起來(lái)還是需要在相當(dāng)長(zhǎng)一段時(shí)間需要與keil c打交道。本文就簡(jiǎn)單小結(jié)我對(duì)keil c的一些理解以及使用過(guò)程中的一些經(jīng)驗(yàn)、教訓(xùn),試圖起到拋磚引玉的作用,為大家總結(jié)keil c使用經(jīng)驗(yàn)提供一個(gè)討論的起點(diǎn)。語(yǔ)言擴(kuò)展所謂語(yǔ)言擴(kuò)展是指相對(duì)標(biāo)準(zhǔn)c(如ansi c嚴(yán)格說(shuō)來(lái),主要是針對(duì)ansi c,因?yàn)閗eil c顯然不支持c+,一些語(yǔ)言特性,如“/”注釋是c 99標(biāo)準(zhǔn)引入的)進(jìn)行的針對(duì)8051硬件平臺(tái)進(jìn)行的擴(kuò)展,這樣的c編譯器才是真正為

3、8051量身訂做的:資源的使用是緊湊的、編譯出來(lái)的代碼是高效的,另外,keil 公司好象也出了針對(duì)arm的c編譯器,所以,從命名來(lái)說(shuō),看起來(lái)c51更準(zhǔn)確些,實(shí)際上vision也是這么做的。數(shù)據(jù)存儲(chǔ)器區(qū)域8051的數(shù)據(jù)存儲(chǔ)器分為片內(nèi)和片外存儲(chǔ)器兩大類,片內(nèi)ram分為直接訪問(wèn)和間接訪問(wèn)兩部分,片外ram由可有頁(yè)尋址和普通區(qū)域兩部分,總是讓人混淆,下面我結(jié)合c51的數(shù)據(jù)存儲(chǔ)器區(qū)域給一個(gè)圖示解釋ff007f80ff只能間接訪問(wèn),idata直接訪問(wèn):data間接訪問(wèn):idatasfrs,只能直接訪問(wèn),sfrffff00ff0000pdata, movx rnxdatamovx dptr片內(nèi)數(shù)據(jù)存儲(chǔ)器片外

4、數(shù)據(jù)存儲(chǔ)器,dmbdataregister banks1f2f圖1 8051數(shù)據(jù)存儲(chǔ)器對(duì)應(yīng)的c51存儲(chǔ)器模型我們可以看到,data作為可存放數(shù)據(jù)的空間只有128字節(jié),還要排除掉32字節(jié)的寄存器組和16字節(jié)的可位尋址空間,實(shí)際只有80字節(jié)的變量可分配空間,所以有時(shí)候會(huì)出現(xiàn)鏈接時(shí)報(bào)告片內(nèi)數(shù)據(jù)只使用100字節(jié)卻數(shù)據(jù)空間溢出的情況(使用small存儲(chǔ)器編譯模型),原因就在于程序引入的附加data型的數(shù)據(jù)量已經(jīng)超過(guò)了80字節(jié),此時(shí),把data型變量改為idata就可以通過(guò)鏈接,只要變量總量不超過(guò)片內(nèi)的256字節(jié)(還應(yīng)該考慮運(yùn)行時(shí)堆棧大小 j)。存儲(chǔ)器模型c51的存儲(chǔ)器模型用于確定:函數(shù)參數(shù)、自動(dòng)變量以及

5、不帶顯式存儲(chǔ)器類型說(shuō)明變量聲明的缺省存儲(chǔ)器類型,有如下幾種模型:小模型(small model),在該模型下,所有變量缺省都駐留在8051片內(nèi)存儲(chǔ)器中(如同聲明為data類型),變量的訪問(wèn)效率非常高。然而,所有對(duì)象,包括堆棧(運(yùn)行時(shí)的最大堆棧容量)必須都放在片內(nèi)ram中,一般來(lái)說(shuō)在程序規(guī)模小且使用overlay技術(shù)(后面會(huì)講到)、沒(méi)有聲明可重入函數(shù)并多次嵌套調(diào)用情況下是最佳的。緊湊模型(compact model),該模型下,所有變量,缺省駐留在外部dm的一個(gè)page之內(nèi),(通過(guò)movx ri指令訪問(wèn),見(jiàn)圖說(shuō)明),緊湊模型的效率遜于小模型、優(yōu)于打模型。這里自然產(chǎn)生一個(gè)問(wèn)題問(wèn)題,當(dāng)緊湊模型下使用

6、的變量超過(guò)一個(gè)頁(yè)大?。?56字節(jié))怎么辦?多余的部分,keil c手冊(cè)說(shuō),使用p2的設(shè)置以使用另外的page,但實(shí)際情況是我們的8051只支持0頁(yè),我向徐國(guó)柱核實(shí)過(guò),這體現(xiàn)在movx ri的時(shí)候,16為dm地址總線的高8位(我們的8051與經(jīng)典的不一樣,經(jīng)典的由于考慮到封裝的要求,使用p0和p2,p0還是地址、數(shù)據(jù)復(fù)用,我們的8051和dm都是集成在片內(nèi)的,沒(méi)有封裝帶來(lái)的限制)始終為0,可否搞一個(gè)sfr來(lái)產(chǎn)生movx ri指令執(zhí)行時(shí)候的高8位地址,復(fù)位地址為0。我們現(xiàn)在的程序規(guī)模就采用了這種模式。大模型(large model),該模型下,所有變量缺省情況下都駐留在dm中,就象使用xdata存

7、儲(chǔ)器類型修飾符聲明一樣(通過(guò)movx dptr指令訪問(wèn),尋址采用dptr),這種方式速度慢,產(chǎn)生的代碼也最多,而且對(duì)于需要頻繁運(yùn)算的變量,效率更低。指針通用指針以標(biāo)準(zhǔn)c指針的方式聲明,如:char *s; /* string ptr */int*numptr; /* int ptr */long*state; /* texas */ 通用指針總是以三字節(jié)進(jìn)行存儲(chǔ),第一個(gè)字節(jié)是存儲(chǔ)器類型,第二字節(jié)是指針代表的地址的高字節(jié),第三字節(jié)是地址的低字節(jié)。通用指針的好處就是可以訪問(wèn)8051存儲(chǔ)器空間中任何存儲(chǔ)器區(qū)域中的變量,因?yàn)檫@個(gè)原因,很多cx51庫(kù)例程使用這種指針類型。存儲(chǔ)器專用指針就是在指針聲明的時(shí)

8、候,指定對(duì)應(yīng)存儲(chǔ)器類型,如:char data*str; /* ptr to string in data */int xdata*numtab; /* ptr to int(s) in xdata */long code*powtab; /* ptr to long(s) in code */由于存儲(chǔ)器類型在編譯期指定了,通用指針需要的存儲(chǔ)器類型字節(jié)就不再需要了,而且,通用指針的指針地址部分必須取所有指針類型中最長(zhǎng)的,2個(gè)字節(jié),而存儲(chǔ)器專用指針則根據(jù)實(shí)際的指針類型確定指針大小,對(duì)于idata, data, bdata, 和 pdata是一個(gè)字節(jié),對(duì)于code和xdata是兩字節(jié),這樣可以加快

9、速度和減少代碼,用于函數(shù)參數(shù)的傳遞時(shí)候效果更佳。這里需要澄清兩個(gè)概念:存儲(chǔ)器專用指針,和位于特定存儲(chǔ)區(qū)中的指針變量,前著是指指針的值(地址)指向的特定存儲(chǔ)區(qū)的,后者是指指針本身(指針本身也是一個(gè)變量,只不過(guò)其值是個(gè)地址)存放在特定的存儲(chǔ)區(qū)域,看下面的例子char data *str; /* 指向位于data空間的字符類型,指針本身的位置沒(méi)說(shuō)明,依據(jù)編譯采用的存儲(chǔ)器模型 */char data * xdata str; /* 指向位于data空間的字符類型,指針本身位于xdata中 */函數(shù)參數(shù)傳遞經(jīng)典8051的堆棧指針只是以間接方式訪問(wèn)片內(nèi)數(shù)據(jù)存儲(chǔ)器,因此可以使用整個(gè)片內(nèi)256字節(jié)的存儲(chǔ)器。8

10、051的堆棧指針是向上增長(zhǎng)的(即push指令執(zhí)行時(shí)是先增加棧指針sp,與x86相反),c51編譯器把堆棧指針初始化到緊鄰片內(nèi)存儲(chǔ)器所有變量之后的位置。由于堆??臻g最多為256字節(jié),實(shí)際上還遠(yuǎn)小于這個(gè)值,因此c51編譯器并不使用堆棧傳遞參數(shù),而是為函數(shù)參數(shù)分配一個(gè)固定的存儲(chǔ)器位置,函數(shù)調(diào)用發(fā)生時(shí),調(diào)用者先把參數(shù)拷貝到該位置,然后被調(diào)用需要參數(shù)時(shí)就從該固定位置抽取參數(shù),只有返回值是存儲(chǔ)在堆棧上的(位返回值放在cf中)。這個(gè)固定存儲(chǔ)器位置是怎么確定的呢?第一種情況,當(dāng)參數(shù)滿足下列條件的時(shí)候,采用寄存器傳遞參數(shù)這里特別需要注意的是,如果函數(shù)第一參數(shù)是bit類型,則后面的其它參數(shù)不能通過(guò)寄存器傳遞,因?yàn)?/p>

11、這種情況下破壞了上面的編號(hào)方案,因此,bit型的變量應(yīng)盡量作為參數(shù)列表的末尾。那么,當(dāng)2字節(jié)大小參數(shù)多于3個(gè),或包含4字節(jié)大小的參數(shù)多于一個(gè)時(shí),c51怎么傳遞參數(shù)呢?對(duì)于需要接收寄存器方式以外傳遞參數(shù)的函數(shù),c51會(huì)自動(dòng)產(chǎn)生一個(gè)參數(shù)傳遞數(shù)據(jù)段,命名方式是 “?函數(shù)名?byte”和“?函數(shù)名?bit”,位參數(shù)在調(diào)用參數(shù)前先拷貝到?函數(shù)名?bit段,所有其它參數(shù)拷貝到?函數(shù)名?byte段,在這些段中所有參數(shù)都分配空間,即使有些參數(shù)通過(guò)寄存器傳遞(是否效率低?),參數(shù)傳遞以它們聲明的順序存儲(chǔ)在這些參數(shù)傳遞段中。需要說(shuō)明的是,這些用于參數(shù)傳遞的固定存儲(chǔ)器可能位于內(nèi)部數(shù)據(jù)存儲(chǔ)器或外部數(shù)據(jù)存儲(chǔ)器,具體情況

12、依賴于使用的編譯存儲(chǔ)器模型:small使用片內(nèi)ram,compact使用dm的pdata,large使用普通dm。特別需要注意的是,對(duì)于4字節(jié)(32位)大小、非寄存器、位于xdata(compact和large模型編譯)參數(shù)的傳遞,c51是調(diào)用一個(gè)內(nèi)部例程?c?lstkxdata來(lái)實(shí)現(xiàn)參數(shù)的拷貝(到對(duì)應(yīng)參數(shù)數(shù)據(jù)段)的,效率相當(dāng)?shù)停晕乙ㄗh諸如32位的運(yùn)算都傳地址,地址最多16位。#include bastype.hint32 testf(int16 arg1, int16 arg2, int16 arg3, int16 arg4, int32 arg5)return (arg1 + arg

13、2 + arg3 + arg4 + arg5);void main()testf(11, 22, 33, 44, 55);搞清楚參數(shù)是怎么傳遞后,我們就可以消除一個(gè)警告,因?yàn)橐郧厥侠斫猓琧語(yǔ)言的參數(shù)永遠(yuǎn)是傳值的(即使對(duì)于傳指針,從指針作為變量這個(gè)意義上仍舊就傳遞的是值,c+由于引用的引入,從形式上改變了這一情況,盡管編譯器實(shí)現(xiàn)仍舊使用指針),而且這個(gè)值還是在固定的存儲(chǔ)位置,所以我們不能對(duì)實(shí)參(值)本身指定存儲(chǔ)區(qū)位置int16 testf(int16 xdata arg, int16 xdata * arg1, int16 * data arg2);在上例中,第一個(gè)形參聲明指定arg放在xdat

14、a空間,這違背了編譯器選擇固定存儲(chǔ)器位置傳遞參數(shù)的原則;第二個(gè)形參聲明是正確的,因?yàn)樗皇钦f(shuō)指針arg1指向的地址(即把指針視為一個(gè)變量的話,變量的值是一個(gè)指向xdata的地址);第三個(gè)形參對(duì)指針本身的位置進(jìn)行限定,本質(zhì)上犯了形參1聲明的錯(cuò)誤。?pr?_testf?test segment code ?xd?_testf?test segment xdata overlayable ?pr?main?test segment code extrncode (?c_startup)extrncode (?c?lstkxdata)publicmainpublic?_testf?bytepublic

15、_testfrseg ?xd?_testf?test?_testf?byte: arg1?040: ds 2 arg2?041: ds 2 arg3?042: ds 2 arg4?043: ds 2 arg5?044: ds 4; #include bastype.h; ; int32 testf(int16 arg1, int16 arg2, int16 arg3, int16 arg4, int32 arg5)rseg ?pr?_testf?test_testf:using0; source line # 3;- variable arg1?040 assigned to register

16、 r6/r7 -;- variable arg3?042 assigned to register r2/r3 -;- variable arg2?041 assigned to register r4/r5 -; ; source line # 4; return (arg1 + arg2 + arg3 + arg4 + arg5); source line # 5mov a,r7add a,r5mov r7,amov r7,amov a,r6addc a,r2mov r6,amov dptr,#arg4?043+01hmovx a,dptraddc a,r4mov r4,a; ; sour

17、ce line # 6?c0001:ret ; end of _testf; ; void main()rseg ?pr?main?testmain:using0; source line # 8; ; source line # 9; testf(11, 22, 33, 44, 55); source line # 10mov dptr,#?_testf?byte+06hclr amovx dptr,ainc dptrmov a,#02ch;44movx dptr,ainc dptrlcall?c?lstkxdatadb 00hdb 00hdb 00hdb 037h;55mov r3,#02

18、1h;33mov r2,#00hmov r5,#016h;22mov r4,#00hmov r7,#0bh;11mov r6,#00hljmp _testf; end of main自動(dòng)變量 自動(dòng)變量在標(biāo)準(zhǔn)c里是自動(dòng)分配和釋放的變量,一般對(duì)應(yīng)函數(shù)棧幀上分配的、函數(shù)調(diào)用期間存在返回后消失的變量,從這個(gè)意義上說(shuō)c51幾乎沒(méi)有自動(dòng)變量(可重入函數(shù)除外),這里的自動(dòng)變量可理解為函數(shù)內(nèi)部的非靜態(tài)存儲(chǔ)局部變量。分配前面已經(jīng)提到“c51 把函數(shù)的自動(dòng)變量放在固定的存儲(chǔ)器位置”,那么這個(gè)固定存儲(chǔ)器位置是哪里呢?首先,速度最快、訪問(wèn)最簡(jiǎn)單的當(dāng)推當(dāng)前的寄存器組了,int8 test(int16 arg)/ lin

19、e 18int8 temp = 0;/ line 20temp = 2;/ line 22if ( arg = 0 )return temp;elsereturn 0; function _test (begin) ; source line # 18;- variable arg assigned to register r6/r7 - ; source line # 19 ; source line # 20;- variable temp assigned to register r5 -0000 e4 clr a ; source line # 220001 25e0 add a,ac

20、c0003 25e0 add a,acc0005 fd mov r5,a自動(dòng)變量采用寄存器進(jìn)行分配的原則是什么?視是否能容納。超過(guò)的自動(dòng)變量會(huì)在前面討論參數(shù)傳遞超過(guò)寄存器部分一樣,在固定存儲(chǔ)器位置創(chuàng)建一個(gè)數(shù)據(jù)段來(lái)容納這些自動(dòng)變量,而不是放在棧上,這些數(shù)據(jù)段屬性具有overlayable的,所以進(jìn)行overlay,怎么overlay,請(qǐng)參閱文檔后部分。創(chuàng)建的數(shù)據(jù)段視當(dāng)前的編譯采用的存儲(chǔ)器模型來(lái)確定,small是data,compact是pdata,large是普通xdatac51的陷阱運(yùn)算溢出看下面例子uint32 testf(uint16 a, uint16 b)return a * b; ;

21、 function _testmul (begin) ; source line # 3;- variable b assigned to register r4/r5 -;- variable a assigned to register r6/r7 - ; source line # 4 ; source line # 50000 120000 e lcall ?c?imul0003 e4 clr a0004 fc mov r4,a0005 fd mov r5,a ; source line # 60006 ?c0001:0006 22 ret可以看到,c51在執(zhí)行上述乘法的時(shí)候,盡管存放

22、結(jié)果的變量是32位的,并沒(méi)有對(duì)兩個(gè)乘數(shù)進(jìn)行整數(shù)提升(到32位),而是直接進(jìn)行16位乘,得到16位結(jié)果后符號(hào)擴(kuò)展(這里是無(wú)符號(hào)數(shù),符號(hào)為0)到32位,如果testf(257, 258)就會(huì)溢出,結(jié)果非我們所愿??朔椒ㄊ菍?duì)乘數(shù)預(yù)先強(qiáng)制整型提升:uint32 testf(uint16 a, uint16 b)return (uint32)a * (uint32)b;編譯與鏈接控制編譯時(shí)控制主要時(shí)指定c源碼編譯的優(yōu)化級(jí)別,需要注意的各優(yōu)化級(jí)別是一個(gè)遞進(jìn)的關(guān)系而不是“或”的關(guān)系。中斷向量的基地址,缺省條件下,c51會(huì)根據(jù)經(jīng)典8051的中斷向量基地址0進(jìn)行編譯,看下例子:isr_ext0() inter

23、rupt 0 using 1/ external interrupt 0產(chǎn)生如下匯編代碼:csegat00003hljmpisr_ext0;使用跳轉(zhuǎn),這樣代碼可以做到最大可浮動(dòng)rseg ?pr?isr_ext0?isr;可浮動(dòng)段using1isr_ext0:push accpush b如果指定intvector(0x1000),則上述的中斷入口地址語(yǔ)句變?yōu)椤癱seg at 01003h”,這主要用在和bootloader代碼的中斷向量的銜接。定制文件startup.a51指定復(fù)位后執(zhí)行點(diǎn)cseg at 0x6000init.a51初始化c靜態(tài)數(shù)據(jù)l51_bank.a51bank切換配置文件鏈接

24、時(shí)控制代碼或常數(shù)的絕對(duì)定位代碼的全部定位很簡(jiǎn)單,如全部定位在0x1000(如我們的2a01、2b01)以后,使用code (0x1000)即可,但這只是把可重定位的代碼放在0x1000以后,中斷向量(起始點(diǎn)),復(fù)位后的執(zhí)行點(diǎn)這些代碼缺省的基地址都是0x0000,也需要配合使用:cseg at 0x1000intvector(0x1000)和_at_關(guān)鍵字的比較_at_關(guān)鍵字是在源代碼中使用,比較直觀,缺點(diǎn)是不能對(duì)該絕對(duì)定位變量進(jìn)行初始化,而且只能用于變量,不能用于函數(shù)。uint8xdata _run_mode_at_ 0x0100;uint32xdata _rsvcdlbnum_at_ 0x0

25、101;* * * * * * * x d a t a m e m o r y * * * * * * * xdata 0000h 0001h inpage _pdata_group_ xdata 0001h 00ffh absolute xdata 0100h 0001h absolute xdata 0101h 0004h absolute函數(shù)在鏈接時(shí)絕對(duì)定位要使用它們的段名(segment name)形式,使用相對(duì)稍微不方便。對(duì)于作為數(shù)據(jù)的變量,由于在鏈接階段變量都只是符號(hào),沒(méi)有單個(gè)變量實(shí)體存在,鏈接操縱的實(shí)體是段,所以絕對(duì)定位只能以段進(jìn)行,這種情況下需要單獨(dú)為需要絕對(duì)定位的變量單獨(dú)創(chuàng)建

26、一個(gè).c文件,最后對(duì)這個(gè).c基名命名的段進(jìn)行鏈接時(shí)絕對(duì)定位。下面的例子給出如何利用鏈接產(chǎn)生的.m51文件,查找對(duì)應(yīng)函數(shù)的對(duì)應(yīng)的段名,然后添加鏈接選項(xiàng)來(lái)控制函數(shù)的絕對(duì)定位。其實(shí)常數(shù)、函數(shù)的命名是有規(guī)律可尋的,在熟練的情況下,完全可以不用查閱.m51文件就可以猜處內(nèi)部的段名,具體可參考鏈接有關(guān)的幫助void bot_init(void)p_rbc_parms = rbc_init( &(botblk.bot_cmdblock.cdbrbc) );code 4914h 001ch unit ?pr?bot_init?bot.code(?pr?bot_init?bot(0x1000), )overla

27、y由于x51可用的堆??臻g相當(dāng)有限,c51的自動(dòng)變量和函數(shù)參數(shù)存放在固定存儲(chǔ)器位置而不是堆棧上。通常,鏈接器分析程序的結(jié)構(gòu),創(chuàng)建調(diào)用樹(shù)并對(duì)包含自動(dòng)變量和函數(shù)參數(shù)的數(shù)據(jù)段做overlay(覆蓋)處理。該技術(shù)通常情況下工作得相當(dāng)不錯(cuò),提供一個(gè)和常規(guī)基于堆棧幀相同得性能,從而該技術(shù)也被稱為編譯時(shí)堆棧,因?yàn)槎褩5牟季衷诰幾g器和鏈接器運(yùn)行的時(shí)候是固定的。缺省情況下,只要函數(shù)彼此不相互調(diào)用,鏈接器會(huì)把這些函數(shù)的自動(dòng)變量和參數(shù)進(jìn)行overlay。因此,鏈接器需要分析程序的結(jié)構(gòu),創(chuàng)建函數(shù)調(diào)用樹(shù),互不調(diào)用(包括間接調(diào)用,a調(diào)b,b調(diào)c,則a間接調(diào)用c)的函數(shù)就會(huì)在不同的調(diào)用樹(shù)上,不同樹(shù)上的函數(shù)內(nèi)的自動(dòng)變量、非寄

28、存器方式傳遞的參數(shù)所在固定存儲(chǔ)器段都可以相互overlay,在某些直接調(diào)用情況下,鏈接器也會(huì)智能地進(jìn)行overlay,看下圖:int funca(void)long temp;funcb(10);temp = 20;temp = 1;temp = funcc();return temp;void funcb(int a)long temp;funcd(a);temp = funcc();funcd(temp);temp += func();funcd(temp);但是,在下面幾種情況下,鏈接器就不會(huì)智能地分析出函數(shù)之間地依賴關(guān)系,從而產(chǎn)生overlay,導(dǎo)致程序運(yùn)行時(shí)錯(cuò)誤。1、中斷處理例程情況

29、,看下面例子timer0_isr() interrupt 1 / timer0 interruptfunca();void main()while (1) funcb();overlay(funca !*)在這種情況下,鏈接器會(huì)認(rèn)為funca和funcb互不調(diào)用,完全可以overlay,甚至不會(huì)產(chǎn)生l15警告(多重調(diào)用),因?yàn)椴皇窃谥餮h(huán)和isr中調(diào)用同一函數(shù)。但實(shí)踐表明,還是有可能出錯(cuò),設(shè)想funcb執(zhí)行了一半,timer0_isr開(kāi)始執(zhí)行的情形.,所以安全的做法是isr中調(diào)用的例程不能在主循環(huán)中被調(diào)用,另起爐灶!解決辦法:鏈接時(shí)關(guān)閉中斷調(diào)用例程的overlay,最好不要讓例程同時(shí)被isr、

30、main調(diào)用,除非聲明為reentrant。2、函數(shù)指針作為參數(shù)情況:bit indirectfunc1 (void) /* indirect function 1 */unsigned char n1, n2;return (n1 n2);bit indirectfunc2 (void) /* indirect function 2 */unsigned char a1, a2;return (a1 - 0x41) (a2 - 0x41);void execute (bit (*fct) () /* sort routine */unsigned char i;for (i = 0; i 1

31、0; i+) if (fct () i = 10;void main (void) if (switch) /* switch: defines function */execute (indirectfunc1);elseexecute (indirectfunc2);:overlay (main (indirectfunc1, indirectfunc2),execute ! (indirectfunc1, indirectfunc2)這種情況下,鏈接器依據(jù)函數(shù)名稱認(rèn)為main函數(shù)依賴indirectfunc1和indirectfunc2,而execute不依賴上述兩個(gè)函數(shù),實(shí)際情況恰相反

32、,從而有可能i和n1、n2以及a1、a2產(chǎn)生錯(cuò)誤的overlay。解決辦法:消除錯(cuò)誤的依賴,建立正確的依賴3、函數(shù)指針數(shù)組static code pf_generic_func romfunctablemax_func_entry_num = flashinit, /*0*/(pf_generic_func)startudisk,initftl,#definepfe_loc_initftl(rom_function_table_loc + pfe_size * 2)#defineinitftl_rom()(*(pf_generic_func)*(ppf_generic_func)pfe_loc

33、_initftl)()main () initftl_rom();overlay(?co?mod_name (flashinit, startudisk , ), main !(initftl, ), )在這種情況下,main函數(shù)實(shí)際調(diào)用(依賴)initftl,但鏈接器分析不出來(lái),因?yàn)閙ain函數(shù)實(shí)際使用的是一個(gè)函數(shù)指針數(shù)組中的一個(gè)元素而已。反而在某些情況下會(huì)產(chǎn)生一個(gè)“recursive call to segment”調(diào)用警告,可以看實(shí)際工程chap9的一個(gè)例子。解決辦法:消除錯(cuò)誤的依賴,建立正確的依賴。如何控制overlayoverlay (sfname ! | sfname, )over

34、lay (sfname ! | (sfname, sfname, ), )overlay (sfname ! *)overlay (* ! sfname)幸運(yùn)的是,overlay使用c代碼的函數(shù)名,而不是內(nèi)部段名!overlay相關(guān)的其它問(wèn)題神秘問(wèn)題,引起大家注意,特征:ftl的兩個(gè)例程,eraseflash和initlist都用到了data型的自動(dòng)變量,在非erase_flash情形(即erase_flash宏定義不啟用情形)下,上述兩個(gè)例程并不被調(diào)用,于是是產(chǎn)生下面的警告:* warning l16: uncalled segment, ignored for overlay proces

35、s segment: ?pr?initlist?flashlist* warning l16: uncalled segment, ignored for overlay process segment: ?pr?checkpmsig?ftl該警告的意思是,該代碼段并沒(méi)有被調(diào)用,于是排除在overlay過(guò)程之外(即并不對(duì)該代碼使用自動(dòng)變量和參數(shù)數(shù)據(jù)段進(jìn)行overlay),按keil c手冊(cè)言,這種情況只是浪費(fèi)一些存儲(chǔ)器空間,并沒(méi)有副作用,但實(shí)際上產(chǎn)生了一個(gè)神秘問(wèn)題:就是閃存寫(xiě)的時(shí)候會(huì)出錯(cuò),而且8051運(yùn)行到非有效程序區(qū)域,我想應(yīng)該是函數(shù)調(diào)用的時(shí)候堆棧出錯(cuò),導(dǎo)致無(wú)效返回地址(或者鏈接器出錯(cuò),可能

36、性較小),更為奇怪的是,這個(gè)問(wèn)題會(huì)隨工程規(guī)模的擴(kuò)大而消失。目前的幾種解決辦法:1把上述兩個(gè)函數(shù)放入到條件編譯中,2把上述兩個(gè)函數(shù)中的局部data型變量聲明改為xdata或使用缺省(pdata)??芍厝牒瘮?shù)常??梢钥吹较旅娴逆溄泳? warning l15: multiple call to segment segment: ?pr?_usbt_synreadep?usbt caller1: ?pr?isr_ext0?isr caller2: ?c_c51startup因?yàn)?c_c51startup是main函數(shù)的祖先,所以上述警告實(shí)際上提示我們,main函數(shù)直接或間接調(diào)用了usbt_synr

37、eadep,中斷處理例程isr_ext0也調(diào)用了usbt_synreadep,c51鏈接器會(huì)比較智能地檢查isr和其它根(單任務(wù)是main,多任務(wù)是rtx的_task_)是否調(diào)用同一例程。本質(zhì)上是c51不使用堆棧傳遞參數(shù)和分配自動(dòng)變量引起的,從這個(gè)意義上來(lái)說(shuō),函數(shù)遞規(guī)調(diào)用也會(huì)有問(wèn)題,不過(guò)產(chǎn)生的警告號(hào)是l13* warning l13: recursive call to segment segment: ?co?chap9 caller: ?pr?chap9_getdescriptor?chap9聲明可重入函數(shù)采用c51擴(kuò)展關(guān)鍵字reentrant。vision ide使用簡(jiǎn)介1、 創(chuàng)建project,關(guān)鍵是選擇device,device的選取最主要參考指標(biāo)是device的ramsize,其它主要是一些特殊廠家的器件擴(kuò)展(如支持雙dptr),實(shí)質(zhì)也是選用這些device后,編譯器自動(dòng)加入一些特殊編譯選項(xiàng)而已;2、 設(shè)置project:target:存儲(chǔ)器模型(small/compact/large)output:指定是否創(chuàng)建hex文件,還可以指定make之后做后續(xù)動(dòng)作(如轉(zhuǎn)換成asc文件、bin文件

溫馨提示

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