<meter id="pryje"><nav id="pryje"><delect id="pryje"></delect></nav></meter>
          <label id="pryje"></label>

          新聞中心

          EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計應(yīng)用 > 關(guān)于Keil C51中using關(guān)鍵字的使用心得

          關(guān)于Keil C51中using關(guān)鍵字的使用心得

          作者: 時間:2012-11-06 來源:網(wǎng)絡(luò) 收藏
          剛才看到一位很牛的師兄寫的一篇日志中提到了 這個的用法,粗心的我本來一直都沒有留意它是用來干嘛的(因為我一般看見它都是在中斷服務(wù)函數(shù)的定義開頭處,好像沒有了它也可以中斷呀,所以才沒怎么管),然而在日志中有看到這個,所以也考究了一下,突然發(fā)現(xiàn),原來這個東東和我最近在幫一個同學(xué)調(diào)的一個程序的時候突然遇到一個很怪的問題是有關(guān)系的,而且就是因為它才搞得程序莫明奇妙的出錯(因為編譯通過了,看起來也沒什么錯誤,按C語言的邏輯分析也分析不出個什么所以然來,所以才怪)。

          后來調(diào)試了好久,甚至到http://www.51hei.com/keil%CF%C2%D4%D8.html這里下載了好幾個版本的keil,反匯編代碼看了N次,基本各個版本出來的結(jié)果都差不多,不知情的情況下,推斷出是 的編譯器問題,以為 的編譯器的變量空間分配出問題了,R7本來是用來作參數(shù)傳遞的,卻也被編譯器分配用來在主函數(shù)中被用來作循環(huán)變量,結(jié)果就是循環(huán)變量的匯編判斷指令CJNE指令執(zhí)行前,R7的值(也就是循環(huán)變量)被改變了,導(dǎo)致判斷R7總是不能達到循環(huán)設(shè)置的值,就不斷地在循環(huán),也就致使按鍵掃描去抖動這個延時循環(huán)無法完成,就導(dǎo)致延時后的第二次判斷無法進行,自然按鍵下來也就沒反應(yīng)了。后來嘗試著關(guān)了定時器中斷,又可以了,那就可以肯定是在執(zhí)行CJNE前,R7的值被改變了,就是因為跳到了中斷,然后中斷函數(shù)執(zhí)行的過程中,R7值被改變了(因為中斷函數(shù)中還調(diào)用了其它的函數(shù),而R7后來被分析反匯編代碼時發(fā)現(xiàn)是被用作參數(shù)傳遞的),中斷執(zhí)行完后R7的值當(dāng)然不正確啦!

          得出推斷后我的解決辦法就是:讓C51編譯好之后手動修改匯編的指令,不要直接使用寄存器來作循環(huán)變量,而是使用能實現(xiàn)間接尋地址的R1進行間接尋址(指向0x77)的方式,終于把問題解決了,因為0x77在執(zhí)行中斷函數(shù)的過程中沒被修改,CJNE語句能正常判斷了,循環(huán)能完成了,按鍵也能掃下來了,問題也可以解決了。后來我又想到用_at_直接指定循環(huán)變量的分配地址,這樣的話就不用手動改匯編指令了,編譯器直接就是編譯成使用間接尋址的,這也算解決了。但還是有個疑問,為什么編譯器會不夠聰明地把R7的空間分配錯了呢?一直在疑問。。。。。。奇怪,怎么編譯器會出這種問題?

          直到我剛才考究過了的用法之后,才發(fā)現(xiàn)原來自己的推斷是錯的,結(jié)論的總方向還是對的,只是問題并不在編譯器身上,真正的問題根源如下:

          1.我的同學(xué)寫的那個程序,用到了定時器0,它的中斷服務(wù)函數(shù)定義是這樣寫的:

          void t0(void) interrupt 1 0

          {

          ........//一大串大代碼,其中包括調(diào)用了其他函數(shù),用到了R7作參數(shù)傳遞

          }

          這里就是加了個using 0,而問題就出在加了這個using 0,為什么?且聽我的理解:

          using關(guān)鍵字的作用就是指定某個函數(shù)在執(zhí)行時切換寄存器組的:

          51中有四個寄存器組,每個組有R0-R7這8個寄存器,用于CPU的數(shù)據(jù)處理,一般主函數(shù)main()默認(rèn)使用第0組,因為PSW寄存器的初始值的第3、4位是00嘛,即默認(rèn)指定了第0組。using 0就是指定在執(zhí)行函數(shù)時切換為使用第0組,不加using關(guān)鍵字的話,一般都默認(rèn)使用第0組,但這樣的話在調(diào)用其他函數(shù)(包括中斷服務(wù)函數(shù))的時候,就會加入一些壓棧指令以保護原來的R0-R7寄存器的(這樣的話,程序執(zhí)行會效率會低一點,因為會產(chǎn)生很多個指令是用來壓棧出棧的),照這樣說,只是加了using 0,使用的也是第0組又不是其它的組,程序就不應(yīng)該有問題了吧,但是就是因為加了using 0,編譯了一次,才發(fā)現(xiàn)在定時器中斷函數(shù)t0()的入口中并沒有發(fā)現(xiàn)把R0-R7的代碼壓入棧呀,就是說沒有保護好R7呀,那當(dāng)然就是在執(zhí)行完之后回來R7不能回復(fù)原來的值啦,接下來的事情。。。。我就不說啦,這就是問題的根源,去掉using 0就可以了,編譯器就自動幫你將R0-R7壓棧,手動加了using 0,就是讓編譯器以為之前用的并不是第0組,而現(xiàn)在執(zhí)行這個中斷函數(shù)時就切換到第0組,而省去了將R0-R7這8個寄存器壓入棧的指令了,這樣雖然看起來是快了,然而對于這個程序來說卻是致命的問題?。?!因為根本沒有保護好R0-R7,而沒有保護R7并不是我預(yù)期發(fā)生的?。?!這不是編譯器的問題,是自己沒有了解好、用好using的問題??!還有,其實也可以在編譯器選項里有選項來硬性規(guī)定編譯器統(tǒng)一不直接使用寄存器而是使用間接尋址的辦法來改變循環(huán)變量分配的地址的,或者使用

          #pragma NOAREGS

          定義函數(shù)
          #pragma AREGS

          來規(guī)定某個函數(shù)的是這樣子。

          當(dāng)然,這樣的規(guī)定和使用using本身并不沖突,只是使用了這個關(guān)鍵字后就可能會間接地產(chǎn)生一系列的問題,讓人郁悶了這么久,其實本來如果有詳細(xì)地看整個程序的反匯編代碼,或許當(dāng)時就會發(fā)現(xiàn)發(fā)現(xiàn)少了那段壓棧指令了,而不是說推斷為編譯器分配空間的問題了。。。。。。。。希望我的這次教訓(xùn)對各位有所幫助?。?!

          另外,using的用法,其實就是手動指定函數(shù)使用的寄存器組,用得不好,如果在中斷里還有調(diào)用其它函數(shù),用得不好會出現(xiàn)函數(shù)傳遞出錯的,不信可以反匯編看看,建議如果對這個關(guān)鍵字用法和C51的結(jié)構(gòu)及匯編不熟的話,請還是讓C51編譯器幫你好了,不要胡亂使用,因為會比較容易出錯的,要切記哦?。?!其實用using關(guān)鍵到底對在編譯后會造成什么影響,建議自己親自去查看匯編程序。。。



          關(guān)鍵詞: Keil C51 using 關(guān)鍵字

          評論


          相關(guān)推薦

          技術(shù)專區(qū)

          關(guān)閉
          看屁屁www成人影院,亚洲人妻成人图片,亚洲精品成人午夜在线,日韩在线 欧美成人 (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })();