時間:2018-09-11 10:44:08來源:網(wǎng)絡(luò)轉(zhuǎn)載
本文主要是關(guān)于ucos-II的相關(guān)介紹,并著重對ucos-II移植到51單片機進行了詳盡的闡述。
ucos-II
μC/OS-II由Micrium公司提供,是一個可移植、可固化的、可裁剪的、占先式多任務(wù)實時內(nèi)核,它適用于多種微處理器,微控制器和數(shù)字處理芯片(已經(jīng)移植到超過100種以上的微處理器應(yīng)用中)。同時,該系統(tǒng)源代碼開放、整潔、一致,注釋詳盡,適合系統(tǒng)開發(fā)。μC/OS-II已經(jīng)通過聯(lián)邦航空局(FAA)商用航行器認(rèn)證,符合航空無線電技術(shù)委員會(RTCA)DO-178B標(biāo)準(zhǔn)。
μC/OS-II被廣泛應(yīng)用于微處理器、微控制器和數(shù)字信號處理器。
μC/OS-II的前身是μC/OS,最早出自于1992年美國嵌入式系統(tǒng)專家JeanJ.Labrosse在《嵌入式系統(tǒng)編程》雜志的5月和6月刊上刊登的文章連載,并把μC/OS的源碼發(fā)布在該雜志的BBS上。
μC/OS和μC/OS-II是專門為計算機的嵌入式應(yīng)用設(shè)計的,絕大部分代碼是用C語言編寫的。CPU硬件相關(guān)部分是用匯編語言編寫的、總量約200行的匯編語言部分被壓縮到最低限度,為的是便于移植到任何一種其它的CPU上。用戶只要有標(biāo)準(zhǔn)的ANSI的C交叉編譯器,有匯編器、連接器等軟件工具,就可以將μC/OS-II嵌入到開發(fā)的產(chǎn)品中。μC/OS-II具有執(zhí)行效率高、占用空間小、實時性能優(yōu)良和可擴展性強等特點,最小內(nèi)核可編譯至2KB。μC/OS-II已經(jīng)移植到了幾乎所有知名的CPU上。
嚴(yán)格地說uC/OS-II只是一個實時操作系統(tǒng)內(nèi)核,它僅僅包含了任務(wù)調(diào)度,任務(wù)管理,時間管理,內(nèi)存管理和任務(wù)間的通信和同步等基本功能。沒有提供輸入輸出管理,文件系統(tǒng),網(wǎng)絡(luò)等額外的服務(wù)。但由于uC/OS-II良好的可擴展性和源碼開放,這些非必須的功能完全可以由用戶自己根據(jù)需要分別實現(xiàn)。
uC/OS-II目標(biāo)是實現(xiàn)一個基于優(yōu)先級調(diào)度的搶占式的實時內(nèi)核,并在這個內(nèi)核之上提供最基本的系統(tǒng)服務(wù),如信號量,郵箱,消息隊列,內(nèi)存管理,中斷管理等。
uC/OS-II以源代碼的形式發(fā)布,是開源軟件,但并不意味著它是免費軟件。你可以將其用于教學(xué)和私下研究(peacefulresearch);但是如果你將其用于商業(yè)用途,那么你必須通過Micrium獲得商用許可。
uCOSII移植的一點心得
uCOS-II是一種十分優(yōu)秀實時操作系統(tǒng),其在NASA的認(rèn)證通過直接說明了其優(yōu)秀及穩(wěn)健的性能,同時由于其完全open,所以受到廣大開源愛好者的喜愛。uCOS-II簡單明了,同時絕大部分代碼都采用ANSIC編寫(除了與CPU相關(guān)代碼外),所以學(xué)習(xí)起來十分容易,是嵌入式學(xué)習(xí)乃至操作系統(tǒng)學(xué)習(xí)最好的入門OS之一。
我主要想講一下自己最近移植uCOS-II的心得,因為最近也在學(xué)習(xí)操作系統(tǒng),所以這段日子對于uCOS-II的學(xué)習(xí)的確也讓我對于操作系統(tǒng)有了一個實際深刻的認(rèn)識。
uCOS-II移植其實十分簡單。對于一個處理器,需要做的工作只有:修改三個文件――os_cpu_c.c、os_cpu.h、os_cpu_a.asm(ASM文件根據(jù)編譯器不同而又有一些不同)。
用另一種方式說,需要做的工作就是修改五個函數(shù):
1、os_cpu_c.c:OSTaskStkInit;
2、os_cpu_a.asm:OSStartHighRdy、OSCtxSw、OSIntCtxSw、OSTickISR;
OSTaskStkInit函數(shù)是針對CPU壓棧的函數(shù),需要模仿出CPU初始化后的寄存器狀況。也使需要修改的唯一一個C語言函數(shù)。其他的都是匯編函數(shù)。
如果我們可以從uCOS-II官方網(wǎng)站上找到相同CPU或是相似的同一家族的CPU移植代碼,那么我們的移植工作將會簡單得多。因為至少我們可以只用了解這個處理器的內(nèi)部結(jié)構(gòu),而不用細致的了解其匯編指令等很多繁瑣而沒有意義的事情(有的處理器你可能一輩子不再用它,了解得太細致只是在浪費時間)。
譬如,此次我要做的是將uCOS-II移植到瑞薩M16C/62A上,而官方網(wǎng)站上只有其62P的移植代碼,于是乎我就將二者的datasheet在CPU的寄存器、中斷部分仔細比對,發(fā)現(xiàn)二者區(qū)別很小。最大的區(qū)別恐怕就在CPU內(nèi)部寄存器中的INTBL和PC寄存器二者順序相反吧,這只要在相關(guān)部分注意就可以了,所以很容易就搞定了CPU相關(guān)代碼部分。
總結(jié)一下移植中浪費我時間的幾個小錯誤吧,這完全是個人粗心導(dǎo)致的失誤:
1、在os_cpu.h文件中需要用宏定義將OS_TASK_SW指向OSCtxSw函數(shù),而我開始像以前一樣直接將OSCtxSw函數(shù)與0號軟終端鏈接起來,結(jié)果發(fā)現(xiàn)函數(shù)調(diào)用不成功。后來直接用宏定義將OS_TASK_SWdefine為OSCtxSw函數(shù),初步調(diào)試通過,即驗證OSCtxSw函數(shù)正確,但是到后來調(diào)用任務(wù)的時候卻發(fā)現(xiàn)任務(wù)切換不正常,不得不重新將函數(shù)與中斷結(jié)合起來,當(dāng)然就不能還是0號中斷了,而是改為一個比較保險的軟終端,這個問題糾結(jié)了很長時間。
2、在看書的時候不仔細直接導(dǎo)致我犯了一個大錯誤。起初以為task只要是能夠達到功能的死循環(huán)即可。所以每個task函數(shù)都是while(1)或者for(;;;),但是我沒有注意到一點就是每個task里面都應(yīng)該有OSTimeDly()函數(shù),否則將導(dǎo)致任務(wù)之間不能跳轉(zhuǎn)。所以最初的實驗現(xiàn)象是永遠只有一個任務(wù)在運行,但是任務(wù)不能切換……
3、未注意到版本之間的區(qū)別。我們知道在新版本的uCOS-II中,添加了一個文件os_tmr.c,主要是在timer上面做了很大的調(diào)整,但是我沒有注意到這一點,仍舊按照老版本的方法調(diào)試,導(dǎo)致函數(shù)調(diào)用讓我完全不知所措。最后注意到os的源代碼的不同,仔細閱讀源代碼之后知道了其用法,其實如果不需要timer太強大的功能,只要在os_cfg.h文件中將OS_TMR_EN設(shè)置為0即可。這在習(xí)慣老版本調(diào)試方法的同學(xué)而言是很好的方法。
ucos-II移植到51單片機的解決辦法
先來了解和51移植相關(guān)的三個概念:
第一,移植UCOS必須要了解編譯器,我們一般使用的51編譯器都是KEIL。值得一提的是KEIL對可重入函數(shù)的處理。由于51單片機的堆棧指針是8位的,所以硬件堆棧只能設(shè)置在內(nèi)部RAM的DATA區(qū)和IDATA區(qū)(DATA、IDATA、PDATA、XDATA、CODE這些概念相關(guān)資料很多,我不想在此處滋述),所以51的堆棧是很緊張的。于是,KEIL將函數(shù)內(nèi)的動態(tài)變量和函數(shù)傳遞的參數(shù)(當(dāng)然有一部分參數(shù)是用寄存器直接傳送的),放在分配的固定數(shù)據(jù)段中,函數(shù)執(zhí)行時在固定的數(shù)據(jù)段中去取得相關(guān)的數(shù)據(jù),而不是像傳統(tǒng)的CPU都用堆棧來處理,這就導(dǎo)致了函數(shù)不可重入,因為當(dāng)一個函數(shù)沒執(zhí)行完成時再次執(zhí)行會把數(shù)據(jù)段里的內(nèi)容覆蓋掉。為了使函數(shù)可重入KEIL引入了仿真堆棧的概念(重入函數(shù)需在函數(shù)定義后面加上reentrant關(guān)鍵字),用仿真堆棧來傳遞參數(shù)及分配動態(tài)變量,就好像傳統(tǒng)堆棧的入棧、出棧操作一般,如此函數(shù)第二次進入執(zhí)行時,就不會覆蓋掉上一次的變量和參數(shù),仿真堆棧實現(xiàn)原理詳見http://hi.baidu.com/lyb1900/blog/item/99b6313defc2b40abaa167fe.html。但是,KEIL的這一機制會給我們移植造成了麻煩,任務(wù)切換時不僅要保存好硬件堆棧內(nèi)容,還要保存好仿真堆棧的內(nèi)容。(建議先理解仿真堆棧的概念)
第二,其他類型的CPU可以在任務(wù)切換時先將SP指針保存到被中斷任務(wù)的OSTCBCur-》OSTCBStkPtr中,再將高優(yōu)先級任務(wù)的OSTCBCur-》OSTCBStkPtr恢復(fù)到SP中就可以了,各個任務(wù)使用各自的堆??臻g,互不干擾,切換也很方便。而51的堆棧指針是8位的,SP只能指向內(nèi)部RAM空間,但是內(nèi)部RAM很小,根本不可能將所有任務(wù)堆棧都設(shè)置在內(nèi)部RAM中(DATA和IDATA區(qū))。所以,51只能設(shè)置一個固定的硬件堆棧,每個任務(wù)可以在外部RAM中設(shè)置各自的任務(wù)堆棧,任務(wù)切換時,將本任務(wù)所使用到的硬件堆棧的長度和內(nèi)容保存到任務(wù)堆棧中,然后將高優(yōu)先級任務(wù)的用戶堆棧里的內(nèi)容恢復(fù)到硬件堆棧中。所以51切換任務(wù)會比較慢。
第三,在KEIL的工程配置Target選項中會有一個MemoryModel選項。用鼠標(biāo)點擊MemoryModel的下拉箭頭,會有3個選項。
Small:變量存儲在內(nèi)部ram里。
Compact:變量存儲在外部ram里,使用頁8位間接尋址
Large:變量存儲在外部Ram里,使用16位間接尋址。
這三個變量決定了定義的變量在不加存儲類型關(guān)鍵字時,變量存放的位置。這一點很多網(wǎng)站、資料都說的很明白。但是其實還有一點很多資料都是沒說的。它還默認(rèn)決定了上述仿真堆棧的位置。這一點在51的啟動代碼STARTUP.asm中能體現(xiàn)出來。其中有一段如下:
;StackSpaceforreentrantfunctionsintheSMALLmodel.
IBPSTACKEQU1;setto1ifsmallreentrantisused.
IBPSTACKTOPEQU0FFH+1;settopofstacktohighestlocation+1.
;
;StackSpaceforreentrantfunctionsintheLARGEmodel.
XBPSTACKEQU0;setto1iflargereentrantisused.
XBPSTACKTOPEQU7FFFH+1;settopofstacktohighestlocation+1.
;
;StackSpaceforreentrantfunctionsintheCOMPACTmodel.
PBPSTACKEQU0;setto1ifcompactreentrantisused.
PBPSTACKTOPEQU7FFFH+1;settopofstacktohighestlocation+1.
IFIBPSTACK《》0
EXTRNDATA(?C_IBP)
MOV?C_IBP,#LOWIBPSTACKTOP
ENDIF
IFXBPSTACK《》0
EXTRNDATA(?C_XBP)
MOV?C_XBP,#HIGHXBPSTACKTOP
MOV?C_XBP+1,#LOWXBPSTACKTOP
ENDIF
IFPBPSTACK《》0
EXTRNDATA(?C_PBP)
MOV?C_PBP,#LOWPBPSTACKTOP
ENDIF
注釋講的很清楚,根據(jù)所選模式,編譯器會將IBPSTACK、PBPSTACK或者XBPSTACK設(shè)置為1,就決定了仿真堆棧在IDATA區(qū)、PDAIA區(qū)還是XDATA區(qū)。對應(yīng)的,KEIL會自動分配一個仿真堆棧指針,分別是?C_IBP、?C_PBP和(?C_XBP、?C_XBP+1),由于尋址XDATA區(qū)需要16位地址,所以需要兩個字節(jié)。這三個指針是KEIL根據(jù)選擇的MemoryModel選項自動分配的。
注意:不要試圖在選擇好模式后將仿真堆棧設(shè)置在另一模式的空間中。比如,我用的小模式編譯,仿真堆棧在IDATA區(qū),用的仿真堆棧指針是?C_IBP,但是我現(xiàn)在在啟動代碼中將IBPSTACK定義為0,將XBPSTACK設(shè)置為1,看起來我們先把仿真堆棧設(shè)置在XDATA區(qū)了,但實際上其它代碼段中使用的仿真堆棧指針任然是?C_IBP。有趣的是,KEIL還為我們的啟動代碼做了一個很友好的列表框選擇界面。但實際上選擇好編譯模式后,仿真堆棧使用空間是不能更改的,不知道KEIL為什么這么做?但是我們有時候要根據(jù)單片機的型號選擇仿真堆棧的起始地址。
講了那么多,應(yīng)該來看看關(guān)于堆棧的組織了,首先是不知道哪位前輩移植的,用的小模式編譯的堆棧結(jié)構(gòu):
每個任務(wù)分都需要配一個任務(wù)堆棧,OSTCBCur-》OSTCBStkPtr指向任務(wù)堆棧的棧底,任務(wù)堆棧的首字節(jié)是仿真堆棧指針?C_IBP(由于是小模式編譯,所以使用的仿真堆棧設(shè)置在IDAIA區(qū))。用戶堆棧中緊接著存放的是該任務(wù)的仿真堆棧中的內(nèi)容。再接著是系統(tǒng)堆棧(就是SP指針?biāo)傅亩褩#┑拈L度,最后是系統(tǒng)堆棧的內(nèi)容。
任務(wù)在切換時,首先將當(dāng)前的?C_IBP的值保存到本任務(wù)堆棧的首地址中,然后將仿真堆棧的全部內(nèi)容復(fù)制到任務(wù)堆棧中(仿真堆棧棧底固定在IDATA區(qū)的最高字節(jié)0xff,可以根據(jù)(0xff-?C_IBP+1)的值來確定所使用的仿真堆棧的長度),接著保存系統(tǒng)堆棧的長度(系統(tǒng)堆棧設(shè)置在DATA或IDATA區(qū)中,系統(tǒng)堆棧的棧底的地址我們可以在啟動代碼中設(shè)置,長度可以用(SP-Stack+1)來計算得到)最后將所用的系統(tǒng)堆棧中的內(nèi)容復(fù)制到任務(wù)堆棧中。
然后得到高優(yōu)先級的任務(wù)堆棧,首先恢復(fù)高優(yōu)先級任務(wù)的?C_IBP,然后計算出高優(yōu)先級任務(wù)所用仿真堆棧的長度,將保存的仿真堆棧的內(nèi)容一一恢復(fù)到仿真堆棧中,然后得到系統(tǒng)棧的長度,再將保存的系統(tǒng)堆棧的內(nèi)容恢復(fù)到系統(tǒng)堆棧中,最后恢復(fù)SP指針并執(zhí)行RETI返回指令,便實現(xiàn)了任務(wù)切換。
任務(wù)被打斷時將仿真堆棧和系統(tǒng)堆棧的內(nèi)容全都備份到任務(wù)堆棧中,在恢復(fù)運行時將相應(yīng)的內(nèi)容還原到系統(tǒng)堆棧和仿真堆棧中。
這種方法的缺點是,任務(wù)切換將會變的很慢,因為要分別拷貝和恢復(fù)仿真堆棧和系統(tǒng)堆棧的全部內(nèi)容。完全可以將仿真堆棧設(shè)置在XDATA區(qū)中,任務(wù)切換時,只需保存和恢復(fù)?C_XBP指針就行了,而不必每次都拷貝和恢復(fù)仿真堆棧的全部內(nèi)容。由于SP指針只有8位,系統(tǒng)堆棧只能設(shè)置在內(nèi)部RAM中。
再來看看楊屹大俠大模式編譯下的堆棧結(jié)構(gòu):
同樣,每個任務(wù)分配一個任務(wù)堆棧,OSTCBCur-》OSTCBStkPtr指向任務(wù)堆棧的棧底,任務(wù)堆棧的首字節(jié)是系統(tǒng)堆棧的長度,接著是系統(tǒng)堆棧的全部內(nèi)容。再接著是仿真堆棧指針?C_XBP的高低字節(jié)(因為是大模式編譯,所以仿真堆棧在XDATA區(qū)),任務(wù)堆棧再高的字節(jié)是作為仿真堆棧用的,用戶堆棧的棧頂就是仿真堆棧的棧底。
任務(wù)切換時,首先計算任務(wù)使用的系統(tǒng)堆棧的長度,將長度保存在任務(wù)堆棧棧底,然后將使用的系統(tǒng)堆棧的內(nèi)容全部復(fù)制到任務(wù)堆棧中,最后保存當(dāng)前的?C_XBP仿真堆棧指針的高低字節(jié)。
接著恢復(fù)高優(yōu)先級任務(wù)的信息,先得到堆棧長度,將備份的堆棧內(nèi)容恢復(fù)到系統(tǒng)堆棧中,并恢復(fù)SP指針(根據(jù)長度和系統(tǒng)堆棧的棧底可以計算出SP指針的值)。最后恢復(fù)?C_XBP的高低字節(jié)。便實現(xiàn)了任務(wù)的切換。
任務(wù)切換時將系統(tǒng)堆棧的內(nèi)容和仿真堆棧指針保存起來,再將高優(yōu)先級任務(wù)的仿真堆棧指針和系統(tǒng)堆棧的內(nèi)容恢復(fù)。
和上述的小模式下的切換過程相比,仿真堆棧的內(nèi)容在任務(wù)切換時不需要保存和恢復(fù)了,任務(wù)切換速度會提高不少。但是讀過楊屹大俠代碼的朋友肯定知道,每個任務(wù)堆棧的大小都要設(shè)置成相同。這對于有些堆棧使用很少的任務(wù)來說是很浪費的,而且51的RAM本來就那么緊張?仿真堆棧被設(shè)置在任務(wù)堆棧的最高地址處,細心的朋友會發(fā)現(xiàn),堆棧檢測函數(shù)肯定是無法運行了。
正是意識到這些缺陷,我對楊屹大俠移植的代碼進行了一些改動,堆棧結(jié)構(gòu)也有較大改變,使用的也是大模式編譯:
先來了解和51移植相關(guān)的三個概念:
第一,移植UCOS必須要了解編譯器,我們一般使用的51編譯器都是KEIL。值得一提的是KEIL對可重入函數(shù)的處理。由于51單片機的堆棧指針是8位的,所以硬件堆棧只能設(shè)置在內(nèi)部RAM的DATA區(qū)和IDATA區(qū)(DATA、IDATA、PDATA、XDATA、CODE這些概念相關(guān)資料很多,我不想在此處滋述),所以51的堆棧是很緊張的。于是,KEIL將函數(shù)內(nèi)的動態(tài)變量和函數(shù)傳遞的參數(shù)(當(dāng)然有一部分參數(shù)是用寄存器直接傳送的),放在分配的固定數(shù)據(jù)段中,函數(shù)執(zhí)行時在固定的數(shù)據(jù)段中去取得相關(guān)的數(shù)據(jù),而不是像傳統(tǒng)的CPU都用堆棧來處理,這就導(dǎo)致了函數(shù)不可重入,因為當(dāng)一個函數(shù)沒執(zhí)行完成時再次執(zhí)行會把數(shù)據(jù)段里的內(nèi)容覆蓋掉。為了使函數(shù)可重入KEIL引入了仿真堆棧的概念(重入函數(shù)需在函數(shù)定義后面加上reentrant關(guān)鍵字),用仿真堆棧來傳遞參數(shù)及分配動態(tài)變量,就好像傳統(tǒng)堆棧的入棧、出棧操作一般,如此函數(shù)第二次進入執(zhí)行時,就不會覆蓋掉上一次的變量和參數(shù),仿真堆棧實現(xiàn)原理詳見http://hi.baidu.com/lyb1900/blog/item/99b6313defc2b40abaa167fe.html。但是,KEIL的這一機制會給我們移植造成了麻煩,任務(wù)切換時不僅要保存好硬件堆棧內(nèi)容,還要保存好仿真堆棧的內(nèi)容。(建議先理解仿真堆棧的概念)
第二,其他類型的CPU可以在任務(wù)切換時先將SP指針保存到被中斷任務(wù)的OSTCBCur-》OSTCBStkPtr中,再將高優(yōu)先級任務(wù)的OSTCBCur-》OSTCBStkPtr恢復(fù)到SP中就可以了,各個任務(wù)使用各自的堆??臻g,互不干擾,切換也很方便。而51的堆棧指針是8位的,SP只能指向內(nèi)部RAM空間,但是內(nèi)部RAM很小,根本不可能將所有任務(wù)堆棧都設(shè)置在內(nèi)部RAM中(DATA和IDATA區(qū))。所以,51只能設(shè)置一個固定的硬件堆棧,每個任務(wù)可以在外部RAM中設(shè)置各自的任務(wù)堆棧,任務(wù)切換時,將本任務(wù)所使用到的硬件堆棧的長度和內(nèi)容保存到任務(wù)堆棧中,然后將高優(yōu)先級任務(wù)的用戶堆棧里的內(nèi)容恢復(fù)到硬件堆棧中。所以51切換任務(wù)會比較慢。
第三,在KEIL的工程配置Target選項中會有一個MemoryModel選項。用鼠標(biāo)點擊MemoryModel的下拉箭頭,會有3個選項。
Small:變量存儲在內(nèi)部ram里。
Compact:變量存儲在外部ram里,使用頁8位間接尋址
Large:變量存儲在外部Ram里,使用16位間接尋址。
這三個變量決定了定義的變量在不加存儲類型關(guān)鍵字時,變量存放的位置。這一點很多網(wǎng)站、資料都說的很明白。但是其實還有一點很多資料都是沒說的。它還默認(rèn)決定了上述仿真堆棧的位置。這一點在51的啟動代碼STARTUP.asm中能體現(xiàn)出來。其中有一段如下:
;StackSpaceforreentrantfunctionsintheSMALLmodel.
IBPSTACKEQU1;setto1ifsmallreentrantisused.
IBPSTACKTOPEQU0FFH+1;settopofstacktohighestlocation+1.
;
;StackSpaceforreentrantfunctionsintheLARGEmodel.
XBPSTACKEQU0;setto1iflargereentrantisused.
XBPSTACKTOPEQU7FFFH+1;settopofstacktohighestlocation+1.
;
;StackSpaceforreentrantfunctionsintheCOMPACTmodel.
PBPSTACKEQU0;setto1ifcompactreentrantisused.
PBPSTACKTOPEQU7FFFH+1;settopofstacktohighestlocation+1.
IFIBPSTACK《》0
EXTRNDATA(?C_IBP)
MOV?C_IBP,#LOWIBPSTACKTOP
ENDIF
IFXBPSTACK《》0
EXTRNDATA(?C_XBP)
MOV?C_XBP,#HIGHXBPSTACKTOP
MOV?C_XBP+1,#LOWXBPSTACKTOP
ENDIF
IFPBPSTACK《》0
EXTRNDATA(?C_PBP)
MOV?C_PBP,#LOWPBPSTACKTOP
ENDIF
注釋講的很清楚,根據(jù)所選模式,編譯器會將IBPSTACK、PBPSTACK或者XBPSTACK設(shè)置為1,就決定了仿真堆棧在IDATA區(qū)、PDAIA區(qū)還是XDATA區(qū)。對應(yīng)的,KEIL會自動分配一個仿真堆棧指針,分別是?C_IBP、?C_PBP和(?C_XBP、?C_XBP+1),由于尋址XDATA區(qū)需要16位地址,所以需要兩個字節(jié)。這三個指針是KEIL根據(jù)選擇的MemoryModel選項自動分配的。
注意:不要試圖在選擇好模式后將仿真堆棧設(shè)置在另一模式的空間中。比如,我用的小模式編譯,仿真堆棧在IDATA區(qū),用的仿真堆棧指針是?C_IBP,但是我現(xiàn)在在啟動代碼中將IBPSTACK定義為0,將XBPSTACK設(shè)置為1,看起來我們先把仿真堆棧設(shè)置在XDATA區(qū)了,但實際上其它代碼段中使用的仿真堆棧指針任然是?C_IBP。有趣的是,KEIL還為我們的啟動代碼做了一個很友好的列表框選擇界面。但實際上選擇好編譯模式后,仿真堆棧使用空間是不能更改的,不知道KEIL為什么這么做?但是我們有時候要根據(jù)單片機的型號選擇仿真堆棧的起始地址。
標(biāo)簽:
中國傳動網(wǎng)版權(quán)與免責(zé)聲明:凡本網(wǎng)注明[來源:中國傳動網(wǎng)]的所有文字、圖片、音視和視頻文件,版權(quán)均為中國傳動網(wǎng)(www.wangxinlc.cn)獨家所有。如需轉(zhuǎn)載請與0755-82949061聯(lián)系。任何媒體、網(wǎng)站或個人轉(zhuǎn)載使用時須注明來源“中國傳動網(wǎng)”,違反者本網(wǎng)將追究其法律責(zé)任。
本網(wǎng)轉(zhuǎn)載并注明其他來源的稿件,均來自互聯(lián)網(wǎng)或業(yè)內(nèi)投稿人士,版權(quán)屬于原版權(quán)人。轉(zhuǎn)載請保留稿件來源及作者,禁止擅自篡改,違者自負版權(quán)法律責(zé)任。
產(chǎn)品新聞
更多>2025-04-30
性能躍升20%!維宏NK300CX Plus數(shù)控系統(tǒng)...
2025-04-11
rpi-image-gen:樹莓派軟件鏡像構(gòu)建的終...
2025-04-08
【產(chǎn)品解讀】全面提升精密制造檢測節(jié)拍...
2025-03-31
激光閃耀 智慧引領(lǐng) | WISE MASER 黑武士...
2025-03-20