keil優化等級設置

優化級別說明(僅供參考):
則其中的 Code Optimization? ? 欄就是用來設置C51的優化級別。共有9個優化級別(書上這么寫的),高優化級別中包含了前面所有的優化級別。現將各個級別說明如下:

0級優化:
1、 常數折疊:只要有可能,編譯器就執行將表達式化為常數數字的計算,其中包括運行地址的計算。
2、 簡單訪問優化:對8051系統的內部數據和位地址進行訪問優化。
3、 跳轉優化:編譯器總是將跳轉延至最終目標上,因此跳轉到跳轉之間的命令被刪除。
1級優化:
1、 死碼消除:無用的代碼段被消除。
2、 跳轉否決:根據一個測試回溯,條件跳轉被仔細檢查,以決定是否能夠簡化或刪除。
2級優化:
1、 數據覆蓋:適于靜態覆蓋的數據和位段被鑒別并標記出來。連接定位器BL51通過對全局數據流的分析,選擇可靜態覆蓋的段。
3級優化:
1、“窺孔”優化:將冗余的MOV命令去掉,包括不必要的從存儲器裝入對象及裝入常數的操作。另外如果能節省存儲空間或者程序執行時間,復雜操作將由簡單操作所代替。
4級優化:
1、 寄存器變量:使自動變量和函數參數盡可能位于工作寄存器中,只要有可能,將不為這些變量保留數據存儲器空間。
2、擴展訪問優化:來自IDATA、XDATA、PDATA和CODE區域的變量直接包含在操作之中,因此大多數時候沒有必要將其裝入中間寄存器。
3、局部公共子式消除:如果表達式中有一個重復執行的計算,第一次計算的結果被保存,只要有可能,將被用作后續的計算,因此可從代碼中消除繁雜的計算。
4、 CASE/SWITCH語句優化:將CASE/SWITCH語句作為跳轉表或跳轉串優化。
5級優化:
1、 全局公共子式消除:只要有可能,函數內部相同的子表達式只計算一次。中間結果存入一個寄存器以代替新的計算。
2、 簡單循環優化:以常量占據一段內存的循環再運行時被優化。
6級優化:
1、 回路循環:如果程序代碼能更快更有效地執行,程序回路將進行循環。
7級優化:
1、 擴展入口優化:在適合時對寄存器變量使用DPTR數據指針,指針和數組訪問被優化以減小程序代碼和提高執行速度。
8級優化:
1、 公共尾部合并:對同一個函數有多處調用時,一些設置代碼可被重復使用,從而減小程序代碼長度。
9級優化:
1、 公共子程序塊:檢測重復使用的指令序列,并將它們轉換為子程序。C51甚至會重新安排代碼以獲得更多的重復使用指令序列。
當然,優化級別并非越高越好,應該根據具體要求適當選擇。?




Keil C51總線外設操作問題的深入分析
? ? 閱讀了《單片機與嵌入式系統應用》2005年第10期雜志《經驗交流》欄目的一篇文章《Keil C51對同一端口的連續讀取方法》(原文)后,筆者認為該文并未就此問題進行深入準確的分析 文章中提到的兩種解決方法并不直接和簡單。筆者認為這并非是Keil C51中不能處理對一個端口進行連續讀寫的問題,而是對Kei1 C51的使用不夠熟悉和設計不夠細致的問題,因此特撰寫本文。
? ? 本文中對原文提到的問題,提出了三種不同于原文的解決方法。每種方法都比原文中提到的方法更直接和簡單,設計也更規范。(無意批評,請原文作者見諒)

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<absacc.h>”,然后在程序中修改變量,定義為直接地址:
#define MAX197 XBYTE
? ? 這樣,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甚至重排代碼以得到更大的循環序列。




優化論

談到優化,其實很多人都哭笑不得,因為在一個C51軟件工程師的生涯中,總要被KEIL的優化耍那么一次到幾次。我被耍過,想必看著文章的你也被耍過,如果你回答說不,那只能說你寫的C51程序不多!
看看KEILC的優化級別選項吧:


0-9共10個級別的優化,0是最低,9最高,一個普通的程序,設置最高級別和最低級別,編譯后代碼量有時會相差很遠,以DX板DEMO程序為例,0級優化后是14K的CODE,9級優化后是10K的CODE,前后相差了4K。可見這個差別是多么的大。
事實上我們不需要知道對應的各個級別KEIL會如何優化你的程序或優化了些什么,我們只需要以一種嚴謹的態度去編寫和對待你的程序就可以了。在我個人的觀念中,程序在9級優化后依然能保持完美無誤的運行,你才算了解KEIL的脾氣。
好了,還是說點正點的:
有些人習慣整體程序都選擇同一個優化級,事實上每個C文件都可以有獨立的優化級別的:

在工作區右鍵選擇你的模塊(.C)然后選取Options for File xxx就會出現如下界面:


在C51選項中就可以選擇優化級別和警告級別等東西了,被獨立設置過的C文件會有特殊的標記的:


用以提醒你這個文件的編譯處理并非默認設置!
如果你覺得模塊優化都不夠細的話,你可以考慮局部優化,也就是說對某個函數實行某個級別的優化。當你發現9級優化的時候某個函數總是變的不正常,但你又希望其它函數和程序段保持最高的簡潔度,那么局部優化可以說是相當有用的了。在KEIL手冊中有介紹這個功能:
#pragma OPTIMIZE(x) x就是你希望的優化級別,一般應用如下:

#pragma OPTIMIZE(6)
void FunA()
{
}
......
......

#pragma OPTIMIZE(9)
void FunB()
{
}

上面的意思就是說,在void FunA()到void FunB()之前的所有函數,包括FunA在內,都采用6級的優化,而從FunB開始直到之后,只要沒碰上#pragma OPTIMIZE,都采用9級優化了。
OPTIMIZE還可以多一個參數,就是speed和size,
用法: #pragma OPTIMIZE(9,speed)或#pragma OPTIMIZE(5,size)
對應的就是9級優化,以速度為主,或5級優化,以空間最小為主。

4.StartUp.a51
在之前第一節的建立工程中就曾經提到過StartUp.a51這個東西了,就是在工程初建的時候有個對話框用于選擇是否為工程添加這個a51文件。


其實這個文件給大家最最深刻的感覺就是:開機清空RAM。事實上它還有其他特別的用途的,例如初始化堆棧(很多人不知道KEILC一開始把堆棧設定為多少,事實上可以通過軟件仿真的時候從這個文件找到答案),然后是再入函數的虛擬堆棧的設置,還有更高級一點的,BANK的初始化。
舊版本KEIL自動為每個工程默認添加相同的StartUp文件,后期的KEIL就有了上圖的選擇,如果選擇添加,則會為每個工程添加一個獨立的StartUp。用戶可以通過手工改寫StartUp.a51實現某些必要的上電初始化。例如最通常的:取消單片機開機清RAM功能!!
關于STARTUP的介紹,我建議大家看看以下的文章,它的解釋非常詳盡。

##################################

在實際使用時發現仿真時有寫程序是白色的無法進行斷點設置

搜索到的答案是優化等級過高,一些普通的程序被優化。

只得把優化程序等級降低。

轉載于:https://www.cnblogs.com/shirishiqi/p/5552539.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/257080.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/257080.shtml
英文地址,請注明出處:http://en.pswp.cn/news/257080.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

SVN命令使用詳解

1、檢出svn co http://路徑(目錄或文件的全路徑) [本地目錄全路徑] --username 用戶名 --password 密碼svn co svn://路徑(目錄或文件的全路徑) [本地目錄全路徑] --username 用戶名 --password 密碼svn checkout http://路徑(目錄或文件的全路徑) [本地目錄全路徑]…

服務器排障 之 nginx 499 錯誤的解決

問題描述&#xff1a; Nginx 服務器大量499報錯 220.181.165.136 - - [18/May/2015:10:31:02 0800] "POST /v1/jobsHTTP/1.1" 499 0 "" "bdHttpRequest/1.0.0"115.239.212.7 - - [18/May/2015:10:31:03 0800] "GET /v1/job/643309e3-dc73-4…

二叉查找樹的先序遍歷,中序遍歷,后序遍歷

1、有一個二叉查找樹&#xff0c;存儲者字符A,B,C,D,E,F,G,H,下面哪個結果是后序樹遍歷結果 A. ADBCEGFH B. BCAGEHFD C. BCAEFDHG D. BDACEFHG 我的結題思路是將每個答案按照后序的遍歷方法把二叉樹存儲數據的結構還原&#xff0c;看是否滿足二叉樹的性質。 二叉樹的性…

學習筆記(13):Python網絡編程并發編程-解決粘包問題-終極版本

立即學習:https://edu.csdn.net/course/play/24458/296244?utm_sourceblogtoedu 粘包現象解決&#xff08;終極版&#xff09; 1.簡單版的問題所在 1&#xff09;報頭信息不一定只是包含著命令執行結果的字節數長度&#xff0c;在文件傳輸的時候也可能包含文件名等&#xff0c…

C#多態

C#多態 多態性&#xff08;C# 編程指南&#xff09;轉自MSDN通過繼承&#xff0c;一個類可以用作多種類型&#xff1a;可以用作它自己的類型、任何基類型&#xff0c;或者在實現接口時用作任何接口類型。這稱為多態性。C# 中的每種類型都是多態的。類型可用作它們自己的類型或用…

Ubuntu 14.04.02 安裝openvswitch-2.3.1

Open vSwitch安裝 安裝好操作系統 # lsb_release -a LSB Version: core-2.0-amd64:core-2.0-noarch:core-3.0-amd64:core-3.0-noarch:core-3.1-amd64:core-3.1-noarch:core-3.2-amd64:core-3.2-noarch:core-4.0-amd64:core-4.0-noarch:core-4.1-amd64:core-4.1-noarch:security…

struts-上傳

一、創建項目項目名稱&#xff1a;demoupload二、添加jar包commons-fileupload-1.2.2.jarcommons-io-2.0.1.jarcommons-lang3-3.1.jarfreemarker-2.3.19.jarjavassist-3.11.0.GA.jarognl-3.0.5.jarstruts2-core-2.3.4.1.jarxwork-core-2.3.4.1.jar三、在web.xml文件中配置過濾器…

將數組作為參數,調用該函數時候給的是數組地址還是整個數組

1、在實際的應用中&#xff0c;數組經常作為函數參數&#xff0c;將數組中的數據傳遞到另外一個函數中&#xff0c;一般來說&#xff0c;傳遞可以采用兩種方法&#xff1a; 1>、數組元素作為函數的實參時&#xff0c;用法跟普通變量作參數相同&#xff0c;將數組元素的值傳遞…

C#項目中常用到的設計模式

C#項目中常用到的設計模式 1. 引言 一個項目的通常都是從Demo開始&#xff0c;不斷為項目添加新的功能以及重構&#xff0c;也許剛開始的時候代碼顯得非常凌亂&#xff0c;毫無設計可言。但是隨著項目的迭代&#xff0c;往往需要將很多相同功能的代碼抽取出來&#xff0c;這也是…

學習筆記(14):Python網絡編程并發編程-文件傳輸功能實現

立即學習:https://edu.csdn.net/course/play/24458/296245?utm_sourceblogtoedu 1.課程目的&#xff1a; 實現客戶端輸入下載文件的命令&#xff0c;然后將命令發送給服務端&#xff0c;服務端再執行下載文件的命令&#xff0c;最后將執行下載文件命令后的結果返回給客戶端&a…

NFS精簡版配置方法

此實驗的前提是防火墻需關閉。 1.關閉iptables /etc/init.d/iptables stop /etc/init.d/iptables status 2.關閉selinux setenforce 0 getenforce Permissive ---出現這個單詞即代表selinux臨時關閉&#xff0c;如需永久關閉則需修改/etc/sysconfig/selinux配置文件 …

Serializable接口中serialVersionUID字段的作用

序列化運行時使用一個稱為 serialVersionUID 的版本號與每個可序列化類相關聯&#xff0c;該序列號在反序列化過程中用于驗證序列化對象的發送者和接收者是否為該對象加載了與序列化兼容的類。 如果接收者加載的該對象的類的 serialVersionUID 與對應的發送者的類的版本號不同&…

重新認知指針

1、把指針指向的變量的數據類型稱為指針的數據類型&#xff1b;而任何一個指針變量本身數據值的類型都是unsigned long int 2.、指針變量名前的符號“*”表示的是指向運算。 3、不要認為“ *p" 是指針變量&#xff0c;指針變量是p而不是*p 4、

分布式數據庫 HBase

原文地址&#xff1a;http://www.oschina.net/p/hbase/ HBase 概念 HBase – Hadoop Database&#xff0c;是一個高可靠性、高性能、面向列、可伸縮的分布式存儲系統&#xff0c;利用HBase技術可在廉價PC Server上搭建起大規模結構化存儲集群。 HBase是Google Bigtable的開源實…

學習筆記(15):Python網絡編程并發編程-進程理論

立即學習:https://edu.csdn.net/course/play/24458/296423?utm_sourceblogtoedu 1.進程&#xff1a;正在運行的一個過程或者一個任務&#xff1b; 2.進程與程序的區別&#xff1a;程序是一堆代碼&#xff0c;程序運行起來就是進程了&#xff0c;一個程序運行兩次&#xff0c;算…

【翻譯】Designing Websites for iPhone X

讓網站適配 iphone X 英文原文地址&#xff1a;https://webkit.org/blog/7929/...本文原文地址&#xff1a;https://github.com/cnsnake11/... The section below about safe area insets was updated on Oct 31, 2017 to reflect changes in the iOS 11.2 beta. 以下關于safe …

指針作為函數參數引用數組的任意元素

void swap(int *a,int*b) {*a*a^*b;*b*a^*b;*a*a^*b; } swap(data[j],data[j1]&#xff09;; int data[10]{13,55,48,13,62,45,754,0,10};以上是我遇到的問題&#xff0c;我覺得調用這個swap函數是不能這樣直接把數組的某個元素直接丟給swap數據 在程序中參加數據處理的量不是指…

使用 Log4Net 記錄日志

第一步&#xff1a;下載Log4Net 下載地址&#xff1a;http://logging.apache.org/log4net/download_log4net.cgi 把下載的 log4net-1.2.11-bin-newkey解壓后&#xff0c;如下圖所示&#xff1a; 雙擊bin文件夾 雙擊net文件夾&#xff0c;選擇針對.NET FramerWork的不同版本 找…

Xcode常用快捷鍵

1. 文件CMD N: 新文件CMD SHIFT N: 新項目CMD O: 打開CMD S: 保存CMDOPtS&#xff1a;保存所有文件CMD SHIFT S: 另存為CMD W: 關閉窗口CMD Q :退出XcodeCMD SHIFT W: 關閉文件2. 編輯CMD [: 左縮進CMD ]: 右縮進CMDshiftF:項目中查找CMDG:查找下一個CMDshiftG:查…

學習筆記(16):Python網絡編程并發編程-開啟子進程的兩種方式

立即學習:https://edu.csdn.net/course/play/24458/296424?utm_sourceblogtoedu #方式一&#xff1a;使用python內置模塊multiprocessing下的process類 from multiprocessing import Process import time#定義進程函數 def task(name):print(%s is running&#xff01;%name)t…