新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > KEIL C51代碼優化詳細分析

        KEIL C51代碼優化詳細分析

        作者: 時間:2016-11-27 來源:網絡 收藏
        閱讀了《單片機嵌入式系統應用》2005年第10期雜志《經驗交流》欄目的一篇文章《Keil C51對同一端口的連續讀取方法》(原文)后,筆者認為該文并未就此問題進行深入準確的分析文章中提到的兩種解決方法并不直接和簡單。筆者認為這并非是Keil C51中不能處理對一個端口進行連續讀寫的問題,而是對Kei1 C51的使用不夠熟悉和設計不夠細致的問題,因此特撰寫本文。

        本文中對原文提到的問題,提出了三種不同于原文的解決方法。每種方法都比原文中提到的方法更直接和簡單,設計也更規范。(無意批評,請原文作者見諒)

        本文引用地址:http://www.104case.com/article/201611/322090.htm

        1問題回顧和分析
        原文中提到:在實際工作中遇到對同一端口反復連續讀取,Keil C51編譯并未達到預期的結果。原文作者對C編譯出來的匯編程序進行分析發現,對同一端口的第二次讀取語句并未被編譯。但可惜原文作者并未分析沒有被編譯的原因,而是匆忙地采用一些不太規范的方法試驗出了兩種解決辦法。
        對此問題,翻閱Keil C51的手冊很容易發現:KeilC51的編譯器有一個優化設置,不同的優化設置,會產生不同的編譯結果。一般情況缺省編譯優化設置被設定為8級優化,實際最高可設定為9級優化:

        1. Dead code elimination。
        2.Data overlaying。
        3.Peephole optimization。
        4.Register variables。
        5.Common subexpression elimination。
        6.Loop rotation。
        7.Extended Index Access Optimizing。
        8.Reuse Common Entry Code。
        9.Common Block Subroutines。
        而以上的問題,正是由于Keil C51編譯優化產生的。因為在原文程序中將外設地址直接按如下定義:
        unsigned char xdata MAX197 _at_ 0x8000
        采用_at_將變量MAX197定義到外部擴展RAM指定地址0x8000。因此,Keil C51優化編譯理所當然認為重復讀第二次是沒有用的,直接用第一次讀取的結果就可以了,因此編譯器跳過了第二條讀取語句。至此,問題就一目了然了。

        2解決方法
        由以上分析很容易就能提出很好的解決辦法。
        2.1最簡單最直接的辦法
        程序一點都不用修改,將Keil C51的編譯優化選擇設置為0(不優化)就可以了。選擇project窗口的Target,然后打開“Options for Target”設置對話框,選擇“C51”選項卡,將“Code Optimiztaion”中的“Level”選擇為“0:Costant folding”。再次編譯后,大家會發現編譯結果為:
        CLR MAXHBEN
        MOV DPTR,#MAX197
        MOVX A,@DPTR
        MOV R7,A
        MOV down8,R7
        SETB MAXHBEN
        MOV DPTR,#MAX197
        MOVX A,@DPTR
        MOV R7,A
        MOV up4,R7
        兩次讀取操作都被編譯出來了。

        2.2最好的方法
        告訴Keil C51,這個地址不是一般的擴展RAM,而是連接的設備,具有“揮發”特性,每次讀取都是有意義的。可以修改變量定義,增加“volatile”關鍵字說明其特征:
        unsigned char volatile xdata MAX197 _at_ 0x8000;
        也可以在程序中包含系統頭文件;“#include”,然后在程序中修改變量,定義為直接地址:
        #define MAX197 XBYTE[0x8000]
        這樣,Keil C51的設置仍然可以保留高級優化,且編譯結果中,同樣兩次讀取并不會被優化跳過。

        2 3硬件解決方法
        原文中將MAX197的數據直接連接到數據總線,而對地址總線并未使用,采用一根端口線選擇操作高低字節。很簡單的修改方法就是使用一根地址線選擇操作高低字節即可。比如:將P2.0(A8)連接到原來P1.0連接的HBEN腳(MAX197的5腳).在程序中分別定義高低字節的操作地址:
        unsigned char volatile xdata MAX197_L _at_ 0x8000;
        unsigned char volatile xdata MAX197_H _at_ 0x8100;
        將原來的程序:
        MAXHBEN =0;
        down8=MAX197;//讀取低8位
        MAXHBEN =1;
        up4=MAX197;//讀取高4位
        改為以下兩句即可
        down8= MAX197_L;//讀取低8位
        up4=MAX197_H;//讀取高4位

        3小結
        Keil C51經過長期考驗和改進以及大量開發人員的實際使用,已經克服了絕大多數的問題,并且其編譯效率也非常高。對于一般的使用.很難再發現什么問題。筆者曾經粗略研究過一下Keil C51優化編洋的結果.非常佩服Keil C51設計者的智慧,一些C程序編譯產生的匯編代碼.甚至比一般程序員直接用匯編編寫的代碼還要優秀和簡練通過研讀Kell C51編譯產生的匯編代碼.對提高匯編語言編寫程序的水平都是很有幫助的。
        由本文中的問題可以看出:在設計中遇到問題時.一定不要被表面現象蒙蔽,不要急于解決,應該認真分析,找出問題的原因.這樣才能從根本上徹底解決問題。

        附表:Keil C51中的優化級別及優化作用

        級別

        說明

        0

        常數合并:編譯器預先計算結果,盡可能用常數代替表達式。包括運行地址計算。
        優化簡單訪問:編譯器優化訪問8051系統的內部數據和位地址。
        跳轉優化:編譯器總是擴展跳轉到最終目標,多級跳轉指令被刪除。

        1

        死代碼刪除:沒用的代碼段被刪除。
        拒絕跳轉:嚴密的檢查條件跳轉,以確定是否可以倒置測試邏輯來改進或刪除。

        2

        數據覆蓋:適合靜態覆蓋的數據和位段被確定,并內部標識。BL51連接/定位器可以通過全局數據流分析,選擇可被覆蓋的段。

        3

        窺孔優化:清除多余的MOV指令。這包括不必要的從存儲區加載和常數加載操作。當存儲空間或執行時間可節省時,用簡單操作代替復雜操作。

        4

        寄存器變量:如有可能,自動變量和函數參數分配到寄存器上。為這些變量保留的存儲區就省略了。
        優化擴展訪問:IDATA、XDATA、PDATA和CODE的變量直接包含在操作中。在多數時間沒必要使用中間寄存器。
        局部公共子表達式刪除:如果用一個表達式重復進行相同的計算,則保存第一次計算結果,后面有可能就用這結果。多余的計算就被刪除。
        Case/Switch優化:包含SWITCH和CASE的代碼優化為跳轉表或跳轉隊列。

        5

        全局公共子表達式刪除:一個函數內相同的子表達式有可能就只計算一次。中間結果保存在寄存器中,在一個新的計算中使用。
        簡單循環優化:用一個常數填充存儲區的循環程序被修改和優化。

        6

        循環優化:如果結果程序代碼更快和有效則程序對循環進行優化。

        7

        擴展索引訪問優化:適當時對寄存器變量用DPTR。對指針和數組訪問進行執行速度和代碼大小優化。

        8

        公共尾部合并:當一個函數有多個調用,一些設置代碼可以復用,因此減少程序大小。

        9

        公共塊子程序:檢測循環指令序列,并轉換成子程序。Cx51甚至重排代碼以得到更大的循環序列。



        關鍵詞: KEILC51代碼優

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 赤城县| 富平县| 宜州市| 东乌珠穆沁旗| 宝坻区| 台山市| 苏尼特左旗| 扶绥县| 城步| 库伦旗| 兴业县| 台山市| 峨眉山市| 仲巴县| 静宁县| 山西省| 泾源县| 深水埗区| 华宁县| 遂溪县| 四子王旗| 巴林左旗| 杂多县| 金寨县| 正镶白旗| 班戈县| 潜山县| 两当县| 上杭县| 留坝县| 东台市| 临桂县| 华亭县| 奈曼旗| 图们市| 平邑县| 云霄县| 闽清县| 普兰店市| 睢宁县| 黎城县|