新聞中心

EEPW首頁 > 嵌入式系統(tǒng) > 設(shè)計(jì)應(yīng)用 > KEIL C51代碼優(yōu)化詳細(xì)分析

KEIL C51代碼優(yōu)化詳細(xì)分析

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

本文中對(duì)原文提到的問題,提出了三種不同于原文的解決方法。每種方法都比原文中提到的方法更直接和簡(jiǎn)單,設(shè)計(jì)也更規(guī)范。(無意批評(píng),請(qǐng)?jiān)淖髡咭娬?

本文引用地址:http://butianyuan.cn/article/201611/322090.htm

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

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編譯優(yōu)化產(chǎn)生的。因?yàn)樵谠某绦蛑袑⑼庠O(shè)地址直接按如下定義:
unsigned char xdata MAX197 _at_ 0x8000
采用_at_將變量MAX197定義到外部擴(kuò)展RAM指定地址0x8000。因此,Keil C51優(yōu)化編譯理所當(dāng)然認(rèn)為重復(fù)讀第二次是沒有用的,直接用第一次讀取的結(jié)果就可以了,因此編譯器跳過了第二條讀取語句。至此,問題就一目了然了。

2解決方法
由以上分析很容易就能提出很好的解決辦法。
2.1最簡(jiǎn)單最直接的辦法
程序一點(diǎn)都不用修改,將Keil C51的編譯優(yōu)化選擇設(shè)置為0(不優(yōu)化)就可以了。選擇project窗口的Target,然后打開“Options for Target”設(shè)置對(duì)話框,選擇“C51”選項(xiàng)卡,將“Code Optimiztaion”中的“Level”選擇為“0:Costant folding”。再次編譯后,大家會(huì)發(fā)現(xiàn)編譯結(jié)果為:
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,這個(gè)地址不是一般的擴(kuò)展RAM,而是連接的設(shè)備,具有“揮發(fā)”特性,每次讀取都是有意義的。可以修改變量定義,增加“volatile”關(guān)鍵字說明其特征:
unsigned char volatile xdata MAX197 _at_ 0x8000;
也可以在程序中包含系統(tǒng)頭文件;“#include”,然后在程序中修改變量,定義為直接地址:
#define MAX197 XBYTE[0x8000]
這樣,Keil C51的設(shè)置仍然可以保留高級(jí)優(yōu)化,且編譯結(jié)果中,同樣兩次讀取并不會(huì)被優(yōu)化跳過。

2 3硬件解決方法
原文中將MAX197的數(shù)據(jù)直接連接到數(shù)據(jù)總線,而對(duì)地址總線并未使用,采用一根端口線選擇操作高低字節(jié)。很簡(jiǎn)單的修改方法就是使用一根地址線選擇操作高低字節(jié)即可。比如:將P2.0(A8)連接到原來P1.0連接的HBEN腳(MAX197的5腳).在程序中分別定義高低字節(jié)的操作地址:
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小結(jié)
Keil C51經(jīng)過長期考驗(yàn)和改進(jìn)以及大量開發(fā)人員的實(shí)際使用,已經(jīng)克服了絕大多數(shù)的問題,并且其編譯效率也非常高。對(duì)于一般的使用.很難再發(fā)現(xiàn)什么問題。筆者曾經(jīng)粗略研究過一下Keil C51優(yōu)化編洋的結(jié)果.非常佩服Keil C51設(shè)計(jì)者的智慧,一些C程序編譯產(chǎn)生的匯編代碼.甚至比一般程序員直接用匯編編寫的代碼還要優(yōu)秀和簡(jiǎn)練通過研讀Kell C51編譯產(chǎn)生的匯編代碼.對(duì)提高匯編語言編寫程序的水平都是很有幫助的。
由本文中的問題可以看出:在設(shè)計(jì)中遇到問題時(shí).一定不要被表面現(xiàn)象蒙蔽,不要急于解決,應(yīng)該認(rèn)真分析,找出問題的原因.這樣才能從根本上徹底解決問題。

附表:Keil C51中的優(yōu)化級(jí)別及優(yōu)化作用

級(jí)別

說明

0

常數(shù)合并:編譯器預(yù)先計(jì)算結(jié)果,盡可能用常數(shù)代替表達(dá)式。包括運(yùn)行地址計(jì)算。
優(yōu)化簡(jiǎn)單訪問:編譯器優(yōu)化訪問8051系統(tǒng)的內(nèi)部數(shù)據(jù)和位地址。
跳轉(zhuǎn)優(yōu)化:編譯器總是擴(kuò)展跳轉(zhuǎn)到最終目標(biāo),多級(jí)跳轉(zhuǎn)指令被刪除。

1

死代碼刪除:沒用的代碼段被刪除。
拒絕跳轉(zhuǎn):嚴(yán)密的檢查條件跳轉(zhuǎn),以確定是否可以倒置測(cè)試邏輯來改進(jìn)或刪除。

2

數(shù)據(jù)覆蓋:適合靜態(tài)覆蓋的數(shù)據(jù)和位段被確定,并內(nèi)部標(biāo)識(shí)。BL51連接/定位器可以通過全局?jǐn)?shù)據(jù)流分析,選擇可被覆蓋的段。

3

窺孔優(yōu)化:清除多余的MOV指令。這包括不必要的從存儲(chǔ)區(qū)加載和常數(shù)加載操作。當(dāng)存儲(chǔ)空間或執(zhí)行時(shí)間可節(jié)省時(shí),用簡(jiǎn)單操作代替復(fù)雜操作。

4

寄存器變量:如有可能,自動(dòng)變量和函數(shù)參數(shù)分配到寄存器上。為這些變量保留的存儲(chǔ)區(qū)就省略了。
優(yōu)化擴(kuò)展訪問:IDATA、XDATA、PDATA和CODE的變量直接包含在操作中。在多數(shù)時(shí)間沒必要使用中間寄存器。
局部公共子表達(dá)式刪除:如果用一個(gè)表達(dá)式重復(fù)進(jìn)行相同的計(jì)算,則保存第一次計(jì)算結(jié)果,后面有可能就用這結(jié)果。多余的計(jì)算就被刪除。
Case/Switch優(yōu)化:包含SWITCH和CASE的代碼優(yōu)化為跳轉(zhuǎn)表或跳轉(zhuǎn)隊(duì)列。

5

全局公共子表達(dá)式刪除:一個(gè)函數(shù)內(nèi)相同的子表達(dá)式有可能就只計(jì)算一次。中間結(jié)果保存在寄存器中,在一個(gè)新的計(jì)算中使用。
簡(jiǎn)單循環(huán)優(yōu)化:用一個(gè)常數(shù)填充存儲(chǔ)區(qū)的循環(huán)程序被修改和優(yōu)化。

6

循環(huán)優(yōu)化:如果結(jié)果程序代碼更快和有效則程序?qū)ρh(huán)進(jìn)行優(yōu)化。

7

擴(kuò)展索引訪問優(yōu)化:適當(dāng)時(shí)對(duì)寄存器變量用DPTR。對(duì)指針和數(shù)組訪問進(jìn)行執(zhí)行速度和代碼大小優(yōu)化。

8

公共尾部合并:當(dāng)一個(gè)函數(shù)有多個(gè)調(diào)用,一些設(shè)置代碼可以復(fù)用,因此減少程序大小。

9

公共塊子程序:檢測(cè)循環(huán)指令序列,并轉(zhuǎn)換成子程序。Cx51甚至重排代碼以得到更大的循環(huán)序列。



關(guān)鍵詞: KEILC51代碼優(yōu)

評(píng)論


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

關(guān)閉