色偷偷偷久久伊人大杳蕉,色爽交视频免费观看,欧美扒开腿做爽爽爽a片,欧美孕交alscan巨交xxx,日日碰狠狠躁久久躁蜜桃

TMS320F240學(xué)習(xí)及uCOS II移植心得(轉(zhuǎn))

發(fā)布時(shí)間:2010-1-5 10:15    發(fā)布者:李寬
關(guān)鍵詞: ucos , 心得 , 學(xué)習(xí) , 移植
20世紀(jì)30年代,英國送奶公司送奶到訂戶門口,沒蓋子也沒封口,麻雀和紅襟鳥可以很容易的喝到上層的奶皮。后來,牛奶公司把瓶口用錫箔紙封裝起來防止鳥的偷食。20年后,英國的麻雀都學(xué)會(huì)了用嘴把奶瓶的錫箔紙啄開,繼續(xù)偷吃它們喜歡的奶皮。然而,同樣是20年,紅襟鳥卻一直沒學(xué)會(huì)這種方法。生物學(xué)家對這兩種鳥進(jìn)行了研究,從生理角度看它們沒多大區(qū)別,但在進(jìn)化上卻如此的不同。后來發(fā)現(xiàn)這于它們的生活習(xí)性有關(guān),麻雀是群居的鳥類,當(dāng)某只發(fā)現(xiàn)了啄破錫箔紙的方法,就可以教會(huì)別的麻雀。而紅襟鳥則喜歡獨(dú)居,它們?nèi)Φ貫橹,溝通僅止于求偶和對侵犯者的驅(qū)逐,因此,就是有某只發(fā)現(xiàn)了那個(gè)方法,別的鳥也無法知曉。對于人類也是如此,進(jìn)步需要交流和行動(dòng),這樣,新技能才可以發(fā)揚(yáng)光大。于是,我寫了一下這些學(xué)習(xí)硬件編程中的感受。

      一、 初學(xué)匯編
  
       研究生課程結(jié)束時(shí),我知道畢設(shè)應(yīng)該是硬件相關(guān)的方向,當(dāng)時(shí)對硬件的認(rèn)識是一片空白?粗瑢W(xué)們早就投入到自己的課題中,自己很著急。忙著去圖書館借了很多關(guān)于硬件的書,和電子、電路單片機(jī)等相關(guān)的,五花八門,只要覺得里面有想知道的,就拿回來啃,像一只忙碌的沒頭的蒼蠅一樣亂撞。對單片機(jī)類的,沒有"型號"的概念,天書一般,只好理解一些硬件基本知識,很多東西覺得很好,下功夫理解記憶,但沒多久就忘了一干二凈,F(xiàn)在想想很正常,因?yàn)槟男〇|西是需要實(shí)踐的。那個(gè)學(xué)期前后借了幾十本書,但看懂的很少。當(dāng)時(shí)做的筆記,只限于對三態(tài)門、總線驅(qū)動(dòng)器、鎖存器、計(jì)數(shù)器之類的概念了解,很是低級的東西。后來就看DSP的書,實(shí)驗(yàn)室的書不管是寫什么系列的,都被我瀏覽了一番,好像朦朧的明白了什么。腦袋里裝了一堆不知前因后果的片斷就到了新學(xué)期,DSP和操作系統(tǒng)更是沒有頭緒,好在當(dāng)時(shí)有了確定的目標(biāo)——TMS320F240。寫開題報(bào)告前,努力的看了ucOS-II操作系統(tǒng),仔細(xì)的讀了有關(guān)240的原理的書。但仍然對這兩者怎么聯(lián)系起來的概念很模糊。在開題報(bào)告里,寫了很多怎樣在ucOS 里編程的問題,在當(dāng)時(shí)的理解下,覺得寫了很"充分"的東西,想象著以后編程就是那個(gè)樣子的。但實(shí)踐以后知道那時(shí)的理解有些本末倒置了。

       開題后已是四月上旬了,"嵌入式"、"操作系統(tǒng)"、"移植"、"DSP"這些東西一直在腦子了盤旋,看書上網(wǎng)查資料都要朝著這些目標(biāo)。比較蠢的做法是,像我一樣只是努力的找書,企圖把這些底層的東西都理解了,甚至想把匯編的指令都記住。直到五月中旬的一天,覺得這樣埋頭讀書不能前進(jìn)了,就準(zhǔn)備動(dòng)手。當(dāng)時(shí)已經(jīng)是非典隔離期了,大家都在拼命的運(yùn)動(dòng)發(fā)泄各種心情,沒有學(xué)習(xí)的氣氛。我也很怕,沒心情學(xué)習(xí),但不敢消沉下去。于是我拿過來板子、仿真器、電源這些很陌生的東西,試著把它們裝起來,接著就是裝軟件、仿真器驅(qū)動(dòng),因?yàn)橛邪惭b步驟的說明,我很順利的完成了。但測試軟件時(shí)卻顯示沒有成功,仿真器不能用,安裝軟件的能力我還是比較自信的,但就是找不到問題,請有經(jīng)驗(yàn)的同學(xué)幫忙結(jié)果一樣。忙了兩天還沒搞定仿真器,嚴(yán)重的打擊了我本來就很迷茫的自信。正當(dāng)我無所適從時(shí),很幸運(yùn)的突然發(fā)現(xiàn)了電腦CMOS設(shè)置里有并口設(shè)置的選項(xiàng),我發(fā)現(xiàn)了"EPP"模式,我當(dāng)時(shí)就知道了這次成功了。這個(gè)開頭很難,但困難有多大,解決困難后就有多興奮,興奮之余渾身充滿了前進(jìn)的動(dòng)力。

        接下來就可以編程了,第一步要熟悉軟件編程環(huán)境,我的第一個(gè)疑問就是"Simulator"和"Emulator"的區(qū)別。我上網(wǎng)到清華的BBS上發(fā)現(xiàn)有很多人在討論DSP,我在別人的貼子中隱約知道了我用仿真器就是"Emulator"(Simulator是在軟件中模擬,開始我還想試試,但有仿真器,最終沒去理會(huì))。論壇人氣很旺,很多問題我都不知所云,大開眼界,原來問題有這么多!我的第一個(gè)程序是最簡單的加法。由于我之前還是努力的看了書,所以用到的簡單指令不用很費(fèi)力就可以寫出來,但一個(gè)完整的程序不止這些,要知道cmd文件怎么寫,知道它的作用(當(dāng)時(shí)不能完全理解,按照大家一貫的寫法寫),還有中斷向量表、頭文件等。這些文件的作用開始是我不能完全理解的,不太明白為什么那么寫。大多書中只是稍微提一下,不能足以幫一個(gè)初學(xué)者建立一個(gè)很明確的概念和編程框架。因?yàn)槌绦蚝芎唵,我仿照師姐留下的一個(gè)加法程序?qū)懥顺鰜。這個(gè)加法程序用了三天時(shí)間,其中大部分時(shí)間花費(fèi)在一個(gè)小問題上:第一次寫程序太隨意,可能是寫高級語言程序的毛病,一個(gè)標(biāo)號的第一個(gè)字母我沒有寫在第一列,而是隨意的打了個(gè)空格(當(dāng)時(shí)沒有意識到后果),這個(gè)空格害我找了調(diào)試了一天時(shí)間!找出錯(cuò)誤以后,我又總結(jié)了一下,哪些格式可以隨意寫,哪些要嚴(yán)格遵守,這樣再寫程序就不那么不自在了。這樣簡單的"1+1=2",畢竟不能解決我的大部分疑問,只是稍微了解了編程環(huán)境,還有很多個(gè)疑問不能找到答案,所以就把CC'C2000的幫助文件很仔細(xì)的看了一遍,很費(fèi)勁,當(dāng)時(shí)覺得沒有很大收獲,但從此對幫助文件的內(nèi)容有了大致的了解,在以后的編程過程中,很習(xí)慣的查看幫助。

       完成了第一個(gè)程序,以后的就按照這個(gè)結(jié)構(gòu)寫其他一些簡單的程序,逐漸的用到了寄存器、中斷等。這樣就熟悉了以前看書時(shí)想努力記住但沒有成功的一些指令和寄存器的配置,還逐步的有了一些調(diào)試經(jīng)驗(yàn)。逐漸的我不像以前那樣急切,很多問題是要細(xì)心的體會(huì),試驗(yàn)一次不能反映全部問題,經(jīng)驗(yàn)是在不斷更正錯(cuò)誤的基礎(chǔ)上積累起來的。我的一個(gè)體會(huì)是:不要試圖在最初知道所有問題的答案,即使找到的答案也只是紙上談兵,還要在實(shí)踐中深化理解,大部分答案都在實(shí)踐中自然浮出水面。最初編程很死,不敢越雷池半步,這是因?yàn)楹芏鄸|西不完全理解,只有按部就班的把它做出來,不敢加以隨意的變化,變了就不知道對不對。我把這些不理解的東西就當(dāng)作學(xué)習(xí)的目標(biāo),帶著這些問題從練習(xí)中逐漸找出答案。這個(gè)過程中,我養(yǎng)成了一個(gè)習(xí)慣:因?yàn)閱栴}很多,我隨時(shí)都有可能明白了一些,也可能又有了一個(gè)新的疑問,我就把這些想法隨時(shí)記下來,等待以后驗(yàn)證或?qū)ふ掖鸢。寫下來對我加深印象真的很有用。后來,如果有了什么重要的?jīng)驗(yàn),等一個(gè)程序成功后,都會(huì)把它們總結(jié)出來,算是對自己的一種肯定,很有成就感?偨Y(jié)的多了,就了解了很多細(xì)節(jié)的東西,哪怕是以前看起來很簡單的指令,也有運(yùn)用是很巧妙的地方。舉幾個(gè)例子:

       1.對形如:y=a1*x1+a2*x2+a3*x3的多項(xiàng)式編程,240指令的裝載臨時(shí)寄存器的指令有LT、LTD、LTP、LTA、LTS,乘法指令有MPY、MPYS、MPYA、MPYU,這些指令中有很多可以同時(shí)執(zhí)行幾步,如果能巧妙的結(jié)合利用,程序很簡潔、效率很高,但要很好的運(yùn)用,不是很容易(這些是最能體現(xiàn)DSP特點(diǎn)的指令,還有塊移動(dòng)指令,它們和流水線有關(guān),所以效率很高)。自己寫程序不要求很高,但知道它們之間有區(qū)別即使不用、記不大清楚,看別人的程序也能充分的領(lǐng)會(huì)其中的巧妙。有一條指令BANZ,我的程序中最初肯定不會(huì)利用它,偶爾一次看到有人用,仔細(xì)的體會(huì)了它的用法,發(fā)現(xiàn)用在循環(huán)中真是個(gè)不錯(cuò)的選擇。

       2.有一次看一個(gè)程序,涉及到了定標(biāo)問題,我?guī)缀跏强粗绦虺聛淼脑囼?yàn)的。其中有幾條非常常見的指令MPY、MPYA、ADD、OR在編譯時(shí)提示有錯(cuò)誤,程序中有這么兩句:

MPY #7FFBH
MPYA #0H

       我看不出有問題,而且和書上是一模一樣的呀。我就查軟件中的幫助,發(fā)現(xiàn)原來書上用錯(cuò)了!那個(gè)錯(cuò)誤實(shí)在是非常容易犯的!對MPY #k指令,操作數(shù)為立即數(shù)時(shí)為只能是 "13-bit short immediate value"。對MPYA指令根本就沒有立即數(shù)尋址方式,只有直接或間接尋址方式。還有ADD和OR的用法都是類似的想當(dāng)然地用,而不注意它地特殊之處。比較幸運(yùn)的是,這種錯(cuò)誤編譯器可以發(fā)現(xiàn)的,但有些隱含的錯(cuò)誤它可能發(fā)現(xiàn)不了,自己又覺得不可能會(huì)錯(cuò),結(jié)果出來后錯(cuò)誤很難排除。

        3.最初面對240眾多的寄存器,初始化時(shí)總覺得多寫了沒有用到,不然就是少了一些配置,這些要和240內(nèi)部結(jié)構(gòu)結(jié)合起來記憶理解。開始是對CPU寄存器、系統(tǒng)配置寄存器、時(shí)鐘模塊寄存器熟悉,其次熟悉了定時(shí)器、比較模塊的寄存器配置,上手后就慢慢熟悉其他的,比較麻煩的就是EV模塊。大多寄存器只要在程序的最初配置一次,就可以不用管了,個(gè)別的比較特殊。如等待狀態(tài)發(fā)生寄存器WSGR在IO空間中,對它賦值就要用out指令而不是常用的splk。還有如 COMCON,要配置為PWM模式,為保證全比較單元的正確操作,需要對它連續(xù)兩次寫操作。還有時(shí)鐘控制寄存器CKCR0、CKCR1,編程時(shí),必須先使 CKCR0的CLKMD1=0,禁止PLL,然后根據(jù)要求設(shè)置CKCR1設(shè)置其他位,最后使CLKMD1=1,允許PLL工作(如果使用PLL的話)。還有定時(shí)器的控制寄存器TxCON有時(shí)也需要寫兩次,第一次配置,第二次啟動(dòng)。總之,對一些需要比較"特殊"的做法,如果注意總結(jié)會(huì)對整體有個(gè)清晰的把握。

       二、 移植系統(tǒng)
   
      練習(xí)多了,就有點(diǎn)柳暗花明的感覺。于是躍躍欲試,開始試著做我的重要任務(wù)——移植uCOS II,看了紹貝貝的書,明白了我要做的是什么,雖然這時(shí)還是霧里看花,理解也很朦朧,但已經(jīng)有了前所未有的自信。最簡單的方法是去www.ucos.com網(wǎng)站下載已經(jīng)移植的代碼,當(dāng)時(shí)我查的時(shí)候,對TI的DSP,只有C31和C54的移植代碼下載(不知現(xiàn)在有沒有更新)。我試著從從這兩個(gè)例程中學(xué)習(xí)我需要的東西。首先是要明白這么多文件的組織關(guān)系,最初面對一大堆文件,根本不知它們是何種關(guān)系,為什么存在?大多文獻(xiàn)里的都是對幾個(gè)移植文件做了詳細(xì)的說明,而對怎樣組織的好像是不言而瑜的事情,對一個(gè)資深的程序員確實(shí)沒有必要教怎么做,可是我沒有開發(fā)大程序的經(jīng)驗(yàn),沒有清晰的把握,因?yàn)樽约鹤龅膮R編程序都是十幾行的小程序,而且還是對cmd文件、向量表、頭文件這些不是程序"核心"的東西沒有深刻的認(rèn)識,我對這些零散的文件研究了很久,才意識到我不止要改幾個(gè)函數(shù)那么簡單,還要要寫一個(gè)有main.c的文件、一個(gè) cmd文件、中斷向量表、一些必要的頭文件,還要象寫其他簡單的程序一樣做一個(gè)框架,操作系統(tǒng)當(dāng)成普通的用戶程序一樣和這個(gè)框架結(jié)合起來,然后再寫程序和普通的不同的是我有這么多別人都已經(jīng)做了的東西,我要實(shí)現(xiàn)那樣的機(jī)制不用自己去寫,只需拿來用。

       明白這些算是思想上的重大突破,不然連 DSP程序和操作系統(tǒng)的關(guān)系都不知道。這樣就動(dòng)手寫移植部分代碼,代碼中的一些是參照一個(gè)例子,那個(gè)應(yīng)該是240的移植,也只是移植部分的代碼,不是一個(gè)完整的代碼。最初我對ucos認(rèn)識不深的時(shí)候,借鑒了那個(gè)程序中的一些做法,如任務(wù)切換函數(shù)是用軟件中斷INT31,當(dāng)時(shí)對中斷的認(rèn)識都很淺,不用說軟件中斷了。對于什么是硬件中斷什么是軟件中斷的問題也困擾我很長時(shí)間,曾經(jīng)問過一個(gè)比我早入手的同學(xué),在他的編程中也沒有用過軟件中斷,可以說沒有意識到這兩種中斷只是匯編中普通的中斷。至于為什么用INT31就不知道了,現(xiàn)在知道了可以用任何一個(gè)軟中斷的。還有一個(gè)就是調(diào)用庫函數(shù)I$$SAVE和I$$ REST用于移植,最初我在傻傻的想,我是不是可以直接用這兩個(gè)函數(shù)?可是它們在什么地方?我怎樣找到它們看看代碼?還有很多別的疑問,但我還是建立了一個(gè).mak把那些覺得需要的文件加了進(jìn)去并按照以前的做法把它們"歸位"。然后編譯,當(dāng)然有很多很多錯(cuò)誤,除了語法錯(cuò)誤,當(dāng)然有我不懂的錯(cuò)誤。我盡可能的改了一些,但不能完全正確。問題是出在用C編程上,所以我還要熟悉用C編程的方法。

     (一) 用C編程
   
       最初用C寫沒有什么可以參考的書,我還是從最簡單的加法開始,寫一個(gè)純粹的C程序,同學(xué)說可以用輸出語句輸出結(jié)果,我的即使運(yùn)行正確也不能輸出,找了人幫忙看,還是于事無補(bǔ)。畢竟用C的人很少,于是我自己開始仔細(xì)的找原因。看生成的map文件找結(jié)果所在的地址,有結(jié)果而且正確,看交*列表,C語句對應(yīng)的匯編語句,沒什么錯(cuò)誤,就是不明白為什么有錯(cuò),和別人的不一樣。這當(dāng)然影響我的自信心,覺得為什么倒霉的總是我?抱怨當(dāng)然不是辦法,還是要繼續(xù)找錯(cuò)了。于是我拿起了放了很久都沒看的TI的C編譯器文檔,雖是全英文的,還是堅(jiān)持了三天看完了,好像沒有找到答案,但更堅(jiān)定了我的想法,錯(cuò)誤是肯定有的,因?yàn)槲臋n上有printf函數(shù),但好像不影響程序的運(yùn)行結(jié)果,于是在以后的編程中只好暫時(shí)放棄用輸出語句(后來調(diào)試基本成功后換了板子就可以輸出了),這對調(diào)試當(dāng)然很不方便,要在映射的地址中看結(jié)果。看文檔的好處是,更清楚的知道了用C和匯編編程的不同,如cmd文件、中斷向量表的寫法。因?yàn)橐婕暗交旌暇幊,就要對在C中和匯編中的函數(shù)、變量互相調(diào)用問題弄明白,這是個(gè)難點(diǎn),那個(gè)文檔看了很多遍,有的問題還是不能完全明白,最終在老師的幫助下對它有了比較清晰的理解,理解后就用編程來驗(yàn)證,結(jié)果是我們的理解是正確的(后來看到有些書上也有對此的討論,我甚至能判斷作者的理解是否完全正確)。下面是幾點(diǎn)總結(jié):

       cmd文件寫法可以參照CC‘C2000幫助文件中的例子,還可以查閱TI文檔spru024D的2.8.3。

       寄存器映射地址頭文件,和匯編中的不同,要重新定義,定義方法如下:
#define CKCR0 (volatile unsigned int *) 0x702B
使用方法: *CKCR0=0x0041;
中斷向量表的第一條語句應(yīng)該跳轉(zhuǎn)到_c_int0對于這點(diǎn)我最初不是很明白,因?yàn)槲铱吹降某绦蚨际且詍ain開始的。后來逐漸明白了,_c_int0是程序真正開始的地方,只是這個(gè)開始不是開發(fā)者寫出來的,而是編譯器自動(dòng)為我們做好的,你要配合它做的是就是在Build Option中對linker的C Initialization的選項(xiàng)選擇ROM Autoinitialization Model或RAM Autoinitialization Model,而不是匯編中的No Autoinitialization,開發(fā)者的程序要以main函數(shù)開始,初始化結(jié)束后會(huì)跳轉(zhuǎn)到main函數(shù)。在反匯編代碼中可以看到這些過程。兩種初始化的方式詳見上面文檔的同一節(jié)。

       匯編代碼中要用到的C的變量或符號,都要在前面加"_ ",即C中的fun要用在匯編中寫為"_fun"。當(dāng)然互調(diào)前要聲明為全局變量或外部函數(shù)。詳細(xì)的說明見spru024D的4.2.2。在C中要嵌入?yún)R編的格式為:
asm(" clrc INTM");

       這個(gè)地方要注意的是引號里面第一個(gè)字符為空格或Tab鍵(還可以是別的記不大清了),不能直接寫指令。為什么會(huì)有上面的一些規(guī)定,看看反匯編的代碼就很清楚了,編譯后編譯器會(huì)為C中的符號都加以下劃線,所以在匯編中用當(dāng)然要寫成"一樣"的了,第二條規(guī)則也是和編譯以后的程序格式有關(guān),可以在你的程序中故意不正確的寫,看看顯示的錯(cuò)誤就明白了。

       比較難的是C調(diào)用匯編函數(shù),匯編函數(shù)的寫法。這時(shí)要在匯編函數(shù)的開始和結(jié)束加入一些語句。C中用三個(gè)寄存器管理堆棧和局部幀:AR1作為堆棧指針 SP,AR0作為幀指針FP,AR2最為局部變量指針LVP。調(diào)用函數(shù)時(shí)當(dāng)前指針必須為AR1,首先要在軟件堆棧中保存函數(shù)返回地址、FP,分配局部幀空間,空間的大小是局部變量的個(gè)數(shù)加1,如果被調(diào)函數(shù)中可能修改寄存AR6、AR7,也要保存(當(dāng)編譯器優(yōu)化時(shí)它們被用作保存寄存器變量)。函數(shù)實(shí)現(xiàn)過程中注意調(diào)用它的函數(shù)傳遞的參數(shù)的存放次序:從右到左按照堆棧增長的方向放置。函數(shù)退出時(shí)和進(jìn)入函數(shù)時(shí)的操作相反。這個(gè)規(guī)則的原因也可以從生成的交*列表中找到答案,和上面的原因大同小異,C語句編譯后的匯編代碼可以看出在任何一個(gè)函數(shù)調(diào)用前都會(huì)有這樣的"保存 "工作,結(jié)束時(shí)做相應(yīng)的恢復(fù)。詳見spru024D的4.2.2,4.2.4和4.3節(jié)。

       用C時(shí)需要.lib庫函數(shù),這個(gè)格式的不能用文本的形式看,在它的同一目錄下有rts.scr文件可以以文本形式打開。用一個(gè)命令可以提取某個(gè)庫函數(shù)可以對它查看或是修改。我知道這個(gè)過程,但沒有用過,所以不多說了。詳見spru024D的4.1.3。

    (二)系統(tǒng)調(diào)試及總結(jié)
   
       明白了以上的規(guī)則就可以大膽的用C編程了,確實(shí)要比匯編方便了很多,F(xiàn)在還回到我的移植程序中,弄懂上面的東西后又修改了一些錯(cuò)誤,到了六月上旬,整個(gè)程序編譯通過了。我很興奮,終于有了進(jìn)展。接下來就是調(diào)試,調(diào)試是比編寫程序痛苦的事,對那些隱藏的錯(cuò)誤要能順利的找出來實(shí)在是困難。系統(tǒng)不能正常工作,首先懷疑的就是移植代碼部分,移植代碼是按照ucOS提供的步驟寫的,寫的時(shí)候由于借鑒了別的例子并沒有深刻理解,調(diào)試時(shí)就必須有個(gè)深刻地認(rèn)識。

       難點(diǎn)一:對任務(wù)堆棧初始初始化函數(shù)OSTaskStkInit()的作用的理解,方法是模擬TI公司的I$$SAVE庫函數(shù)對任務(wù)堆棧初始化,按照庫函數(shù)地保存順序開辟?臻g,得到堆棧指針。這個(gè)函數(shù)的編寫要充分理解"堆棧"的概念。芯片本身的堆棧只有 8 級,無法作為系統(tǒng)堆棧使用,這8級堆棧用來保存函數(shù)調(diào)用和中斷的返回地址。C 編譯器將寄存器AR0、AR1作為SP和FP管理系統(tǒng)堆棧和局部幀(上面有說明)。編譯器使保存在硬件堆棧里的返回地址彈出保存在系統(tǒng)堆棧里,并保存其他寄存器,即保存了任務(wù)運(yùn)行的現(xiàn)場,這些工作都由I$$SAVE來做。有了任務(wù)堆棧初始化函數(shù)OSTaskStkInit(),系統(tǒng)在進(jìn)行初始化時(shí),這個(gè)函數(shù)將任務(wù)地址放在堆棧中,然后用中斷返回也就是I$$REST函數(shù)將寄存器和TOS初始化,將任務(wù)的起始地址彈回到TOS中,這樣就能從中斷的任務(wù)開始運(yùn)行了。

       難點(diǎn)二:時(shí)鐘節(jié)拍。對節(jié)拍地作用是在看了操作系統(tǒng)的內(nèi)核代碼后有了深刻認(rèn)識的,雖然移植是可能不太了解具體的代碼,但沒有操作系統(tǒng)的概念最好把這個(gè)比較易學(xué)的操作系統(tǒng)的代碼看看,有個(gè)結(jié)構(gòu)和原理的認(rèn)識,我大概花了一周仔細(xì)的看了書和代碼,這次和以前看不同,了解了代碼實(shí)現(xiàn)地細(xì)節(jié),看完會(huì)更加頭腦清醒。最初地時(shí)鐘節(jié)拍中斷是用實(shí)時(shí)時(shí)鐘中斷RTI,看完代碼知道了應(yīng)該不可以用它來實(shí)現(xiàn)節(jié)拍,因?yàn)橄到y(tǒng)時(shí)鐘地啟動(dòng)是在初始化結(jié)束后第一個(gè)任務(wù)開始前啟動(dòng)的,實(shí)時(shí)時(shí)鐘不能這樣控制,它在板子上電是就啟動(dòng)了,所以我改用定時(shí)器1實(shí)現(xiàn)。時(shí)鐘節(jié)拍函數(shù)OSTickISR()的實(shí)現(xiàn)是定時(shí)器的硬件中斷,因?yàn)樵谖倚薷倪^程中不斷地出錯(cuò),這使我熟練掌握了F240的中斷編程方法。我對中斷編程做了總結(jié),包括用C編寫中斷,對初學(xué)者應(yīng)該有幫助:

      在UCOS中的中斷編程和一般的中斷編程稍有不同。共同的是:

      1.中斷矢量表。中斷矢量表一定要定位在程序空間的地址0開始的地方,0000h~003Fh為中斷矢量表。第0行跳轉(zhuǎn)到代碼開始的地方、第1到第6行是硬件中斷跳轉(zhuǎn)指令,除NMI中斷其他是軟件中斷指令(INTk最大為INT31)。發(fā)生硬件中斷后,處理器自動(dòng)到前面查表跳轉(zhuǎn)到相應(yīng)位置。軟件中斷是在程序中執(zhí)行了INTk指令才會(huì)發(fā)生,然后根據(jù)x查中斷矢量表跳轉(zhuǎn)到相應(yīng)的ISR(移植系統(tǒng)時(shí)用到了軟件中斷指令,即任務(wù)切換函數(shù))。

      2.硬件中斷系統(tǒng)。其中的可屏蔽中斷INTk(k=1~6)對應(yīng)了多個(gè)中斷源,有系統(tǒng)中斷和EV中斷,它們都通過INTk和CPU相關(guān)(將INTk稱為內(nèi)核中斷)。寫系統(tǒng)中斷或EV中斷必須知道對應(yīng)哪個(gè)內(nèi)核中斷。因?yàn)槊總(gè)內(nèi)核中斷對應(yīng)了幾個(gè)中斷源(具體對應(yīng)查閱書籍)。有中斷源復(fù)用問題,當(dāng)一個(gè)內(nèi)核中斷中有多于一個(gè)的外部中斷發(fā)生時(shí),就要查外部中斷矢量表,它是根據(jù)中斷標(biāo)識排列的。注意每條跳轉(zhuǎn)指令占兩個(gè)字節(jié)。外部中斷矢量表的位置可以在程序空間的任何位置(表中有一個(gè)代表表的起始位置的符號)。對它的查表方式為基址+變址;窞楸淼钠鹗嫉刂,變址為中斷源的標(biāo)識×2。

      3.中斷編程。本程序的 INT1有中斷復(fù)用,如果用匯編編寫,需要外部中斷矢量表。但在ucOS中編寫串口通訊時(shí),發(fā)送任務(wù)沒有采用中斷方式,它要和接收任務(wù)通訊而有相應(yīng)的動(dòng)作(沒有操作系統(tǒng)時(shí)就是查詢方式)。即接收中斷發(fā)生后要調(diào)用發(fā)送信號量函數(shù)(也可以使用別的通訊機(jī)制),在匯編中調(diào)用較麻煩,所以采用了C編程,這樣在 INT1的ISR中用了switch語句,就不用外部中斷矢量表。其他中斷源沒有復(fù)用問題。所以整個(gè)程序也不需要外部中斷矢量表。

       在ucOS中的中斷編程要注意的是進(jìn)入中斷調(diào)用庫函數(shù)I$$SAVE(C編寫自動(dòng)調(diào)用),而程序結(jié)束是調(diào)用OSINTExit()(最后調(diào)用了I$$REST)。

       看了操作系統(tǒng)的源代碼再加上對F240編程方法進(jìn)一步掌握,感覺對這個(gè)系統(tǒng)的整體有很清晰的認(rèn)識,很高興自己在無數(shù)的錯(cuò)誤中摸索出來了。不幸的是我的程序仍然不能成功地運(yùn)行,但我相信應(yīng)該問題不太大,應(yīng)該不是在關(guān)鍵處。因?yàn)橄到y(tǒng)可以單步運(yùn)行且結(jié)果正確。我很幸運(yùn)的在網(wǎng)上遇到了一位做過在2407移植的人,網(wǎng)上還有完整地源碼下載。我對比了程序,仍然不知錯(cuò)在哪里,然后我向他討教,他給了一個(gè)建議是,查看map文件,找到兩個(gè)常量表OSMapTbl和 OSUnMapTbl的映射地址,看看它們的值是否正確。我查看了一下沒錯(cuò),但偶然發(fā)現(xiàn)一個(gè)寄存器的映射地址是錯(cuò)的,再看其他寄存器也是錯(cuò)的,因?yàn)橛肅編程寄存器的映射頭文件要重新定義,我采用的是賦值語句,定義指針,程序中用指針尋址,這種方法應(yīng)該是沒有問題的,但我知道有它的不方便的地方,不利于我的程序中在每個(gè)需要的文件中包含這個(gè)頭文件,于是就改成宏定義寄存器,這樣改過之后地址映射就正確了。我把程序從頭到尾的看了很多遍,包括反匯編的代碼都仔細(xì)去找錯(cuò),倒是有點(diǎn)小bug被找出來,但都不是致命的那個(gè)。在我身心俱憊時(shí),我決定放松一下。放風(fēng)了兩天,仍然心有不甘,就又著手我的程序。這次我把所有的寄存器配置從操作系統(tǒng)中拿開,在匯編中檢驗(yàn),終于找到了那個(gè)bug:SYSCR的配置錯(cuò)誤,這個(gè)常用的寄存器不用看幫助就知道怎樣配置,但我寫錯(cuò)了,可能是最初的筆誤,直接導(dǎo)致了系統(tǒng)的復(fù)位。系統(tǒng)終于可以運(yùn)行了!從我的第一個(gè)程序到這時(shí)有兩個(gè)多月的時(shí)間,我學(xué)業(yè)生涯中最不平坦的兩個(gè)多月。

       我換了一塊板子,以前不能顯示輸出語句結(jié)果的問題也解決了,于是我又寫了比較復(fù)雜的測試程序測試系統(tǒng)運(yùn)行情況,雖然不是一次就可以寫成功的,但這次調(diào)試用了很短的時(shí)間。還有下面的總結(jié),是C語言幾個(gè)關(guān)鍵字有關(guān)的內(nèi)容,雖然較為基礎(chǔ),在操作系統(tǒng)中可能用到的,對透徹把握程序很有幫助。

      1.volatile類型限定符。用它修飾的對象叫易變對象,用于告訴編譯程序它所修飾的對象(可以是變量或常量)的值可能會(huì)以程序中未顯式指定的方式發(fā)生變化,即不是由程序中的賦值、初始化等顯式指定的方式發(fā)生變化。如,其變化可能式由中斷程序或IO端口所施加的。再如,在程序中可能會(huì)把某個(gè)全局變量的地址傳送給操作系統(tǒng)的時(shí)鐘并用于存放系統(tǒng)的實(shí)際時(shí)間,盡管程序中沒有對這個(gè)變量使用賦值語句賦值,但它的內(nèi)容還是變了。舉個(gè)例子:

volatile int ticks;
interrupt timer( )
{
ticks++;
}
wait (int time)
{
ticks = 0;
while (ticks < time ) ;
}

       如果ticks沒有聲明為易失變量,編譯程序可能會(huì)把它當(dāng)作寄存器變量分配,從而wait函數(shù)執(zhí)行永遠(yuǎn)不會(huì)中止。上例中的interrupt 關(guān)鍵字是修飾中斷函數(shù)的,表示改函數(shù)與中斷相聯(lián)系。

      2.typedef 定義新的數(shù)據(jù)類型。例:

typedef unsigned int INT16U;

       定義了類型INT16U,這樣做可以提高程序的可移植性。例如,有些C編譯系統(tǒng)沒有提供無符號短整數(shù)unsigned short int類型,這樣,在其他編譯系統(tǒng)整運(yùn)行的使用了這種類型的編譯器就要把程序中出現(xiàn)的unsigned short int都換成另一種合適的類型如unsigned int,這樣改動(dòng)比較大。使用類型定義可以解決這個(gè)問題,這時(shí),在允許使用unsigned short int 的編譯系統(tǒng)中編寫程序時(shí),先使用一個(gè)類型定義:

typedef unsigned short int USINT ;

以后在其他編譯系統(tǒng)運(yùn)行時(shí),只要把改類型定義改成:

typedef unsigned int USINT ;

其他地方不動(dòng)就可以了。

       還有一點(diǎn)就是可以避免因不同編譯系統(tǒng)實(shí)現(xiàn)上的差別而帶來的可移植性問題。例在某些編譯系統(tǒng)中char、short(有無符號)用8位表示,而在 TMS320C2xx的系統(tǒng)中,都用16位表示,為使在前者系統(tǒng)中運(yùn)行的程序在C2xx中運(yùn)行,必須把char、short改成int,這時(shí),使用類型定義可以減少修改。

       3.register存儲類區(qū)分符。用它修飾說明的變量叫寄存器變量,它的用途一是與auto一樣,使它所修飾的對象成為自動(dòng)的,二是建議編譯程序在存儲分配使盡可能的把它分配到機(jī)器存儲器中,以便用時(shí)能快速存取。使用寄存器變量最常見的情況時(shí)把循環(huán)控制變量說明成寄存器變量,因?yàn)檫@個(gè)變量在每次循環(huán)時(shí)都要至少訪問一次,例:

register int I ;
fun( )
{
for ( I =0 ;I <1000;I ++)
{ ...... }
}

        理論上,一個(gè)程序中可說明任意多個(gè)寄存器變量,實(shí)際上,由于寄存器數(shù)目的物理限制,編譯系統(tǒng)只把最前面的有限數(shù)目的寄存器變量分配在寄存器中,而把其余的當(dāng)作普通自動(dòng)變量處理。在F240中,編譯系統(tǒng)允許把AR6、AR7用了存儲寄存器變量,使用優(yōu)化選項(xiàng)是還允許使用AR5(見 spru024D4.2.4)。

       以上是我學(xué)習(xí)中的一些總結(jié)。我相信有很多像我這樣從零開始的后來者,希望能給他們一點(diǎn)信心和勇氣,讓他們知道有我這樣一個(gè)人也經(jīng)歷許多郁悶的日子,最終解決了當(dāng)時(shí)覺得解決不了的問題。如果看到我用了"幸運(yùn)"這個(gè)詞,不要羨慕我的運(yùn)氣,不要怪自己得問題為什么不能"幸運(yùn)"的解決(我就曾這樣痛苦的想過),因?yàn)榭赡苣愀疫\(yùn),根本就不會(huì)像我這么"倒霉"遇到它。但總會(huì)有問題發(fā)生,如果解決了,你更幸運(yùn)的獲得了一個(gè)寶貴的經(jīng)驗(yàn)、非常難得的財(cái)富。萬事開頭難,入了門腳下的路就就會(huì)逐步平坦了。
本文地址:http://m.54549.cn/thread-7255-1-1.html     【打印本頁】

本站部分文章為轉(zhuǎn)載或網(wǎng)友發(fā)布,目的在于傳遞和分享信息,并不代表本網(wǎng)贊同其觀點(diǎn)和對其真實(shí)性負(fù)責(zé);文章版權(quán)歸原作者及原出處所有,如涉及作品內(nèi)容、版權(quán)和其它問題,我們將根據(jù)著作權(quán)人的要求,第一時(shí)間更正或刪除。
您需要登錄后才可以發(fā)表評論 登錄 | 立即注冊

相關(guān)視頻

關(guān)于我們  -  服務(wù)條款  -  使用指南  -  站點(diǎn)地圖  -  友情鏈接  -  聯(lián)系我們
電子工程網(wǎng) © 版權(quán)所有   京ICP備16069177號 | 京公網(wǎng)安備11010502021702
快速回復(fù) 返回頂部 返回列表