以文本方式查看主題 - 曙海教育集團論壇 (http://m.scb-ycwb.com/bbs/index.asp) -- 單片機初中級 (http://m.scb-ycwb.com/bbs/list.asp?boardid=55) ---- 單片機代碼優(yōu)化深入討論 (http://m.scb-ycwb.com/bbs/dispbbs.asp?boardid=55&id=2204) |
-- 作者:wangxinxin -- 發(fā)布時間:2010-12-7 13:56:33 -- 單片機代碼優(yōu)化深入討論 本人在優(yōu)化定時器和計數(shù)器的中斷處理函數(shù)中總結(jié)了一下經(jīng)驗,才有自言自語格式: ![]() 1、優(yōu)化代碼采用匯編就是啦,何必在用C語言呢? 答:代碼的優(yōu)化是建立在于程序結(jié)構(gòu)最優(yōu)化之上的,好的程序結(jié)構(gòu),代碼優(yōu)化才有價值,是優(yōu)中優(yōu);反之糟糕的程序結(jié)構(gòu),代碼優(yōu)化只能在最差的程序結(jié)構(gòu)中得到最好代碼,是差中優(yōu)。所以優(yōu)中優(yōu)>差中優(yōu)。C語言是一種高級語言(有的叫中級語言)在描述程序結(jié)構(gòu)的與匯編沒有區(qū)別,更直觀。 2、現(xiàn)在單片機速度很快,為什么要優(yōu)化的程序結(jié)構(gòu)呢? 答:比如我在編寫定時器和計數(shù)器的程序的時候,由于這個函數(shù)使用頻繁,這個中斷以后還要加入類似PLC的IO數(shù)據(jù)刷新程序(把PLC程序的結(jié)果送入單片機的IO端口,或從IO端口中讀入數(shù)據(jù))和系統(tǒng)變量數(shù)據(jù)函數(shù)(如秒脈沖,100ms秒脈沖,等),所以這個中斷函數(shù)負擔(dān)很重。所以每個算法必須最優(yōu)化。現(xiàn)在單片機速度很快,但是具體某一個固定功能的函數(shù)優(yōu)化一下,可以把單片機資源更多的用于用戶程序。比如PLC的單片機必須解釋用戶程序。必須在定期完成。比如PLC周期是100ms,比如12M的8051,1/10的振蕩周期內(nèi)完成。1.2M/12=100kHZ,平均下來,10萬指令條不到,還是比較緊張的。稍微好一點的PLC,周期數(shù)可以達到10ms。即使采用AVR這種RISC的,在10ms完成一個PLC掃描周期,也是很吃緊的。 3、怎么才能得到最優(yōu)的程序結(jié)構(gòu)? 答:這個問題很廣,算法=程序+數(shù)據(jù)結(jié)構(gòu)。數(shù)據(jù)結(jié)構(gòu)優(yōu)化,可以學(xué)習(xí)數(shù)據(jù)結(jié)構(gòu)的書籍,里面全是最優(yōu)的結(jié)構(gòu),依賴于計算機。程序的優(yōu)化,一般獨立于計算機,要自己有一個好的思路。 比如我在處理定時器和計數(shù)器函數(shù)是,畫了狀態(tài)圖,根據(jù)狀態(tài)圖,編程序一目了然,基本是最優(yōu)結(jié)構(gòu)了。除非開發(fā)專用硬件或查表法。請參看我的另一個帖子:http://www.stmfans.com/bbs/viewt ... &extra=page%3D1 4、你的那個帖子,首先發(fā)的效率不是還可以嗎? C語言精簡不等于編譯出來的東西會精簡。 5、為什么呀? 我首先貼出來的的C程序,沒有跟我畫出來的狀態(tài)圖一一對應(yīng)。沒有充分利用各bit量的信息。 比如,定時器從S1轉(zhuǎn)到S2,只需判斷T_EN=1;維持狀態(tài):T_EN=0 S2轉(zhuǎn)到S1,只需判斷T_EN=0。S2維持,須判斷T_ACC<T_SET=1。S2轉(zhuǎn)到S3,須判斷T_ACC<T_SET=0; S3轉(zhuǎn)到S1,T_EN=0;S3維持,T_EN=1;這個時候T_ACC<T_SET是個無關(guān)量,不需要重復(fù)運算了。 我還設(shè)置tmp中間量,其實T_OUT的狀態(tài)已經(jīng)表明T_ACC<T_SET=0,tmp是畫蛇添足的,浪費空間。 6、條件表達式不是比if else要好嗎? 在大多情況下,進行簡單的運算,要好一點(微弱),語句復(fù)雜的話,編譯出來的東西不一定高效。況且條件表達式中, 無法加入break等語句。 7、我看了關(guān)于編程優(yōu)化的書籍,要減少跳轉(zhuǎn)的,你后面的程序跳轉(zhuǎn)很多呀?尤其是那個計數(shù)器,嵌套了好幾層呀? 由于很多編程優(yōu)化的書籍是針對PC機的:減少跳轉(zhuǎn),可以提高CPU緩存的命中率。由于緩存速度很快,與CPU同步的。如intel的扣肉 分一級緩存,二級緩存。當(dāng)跳轉(zhuǎn)的時候如果跳出了二級緩存的范圍,會到內(nèi)存中讀取數(shù)據(jù),由于內(nèi)存的速度比CPU慢一個數(shù)量級。 所以效率不高。 而我們的單片機編程的時候,flash與RAM都是與CPU同步的。單片機的RAM全部是SRAM(緩存也是SRAM),跳轉(zhuǎn)只能在單片機的資源以內(nèi),相當(dāng)于PC的CPU中只能在緩存空間內(nèi)跳。所以單片機的命中率是100%,除非出錯。 ![]() 8、你后面發(fā)的程序,為什么是最優(yōu)呢? 我把后面的程序由編譯器編譯出來的指令貼出來: ; d:\\MYDOCU~1\\51_proj\\timer.c:28: if(T0_EN) jnb _T0_EN,00105$ ;對應(yīng)狀態(tài)圖S2 t2 ; d:\\MYDOCU~1\\51_proj\\timer.c:30: if(T0_OUT); jb _T0_OUT,00106$ ;對應(yīng)狀態(tài)圖S2 t2 ; d:\\MYDOCU~1\\51_proj\\timer.c:32: {T0_OUT=++T0_ACC>=T0_SET;} inc _T0_ACC ;對應(yīng)狀態(tài)圖S2 t1 clr c t1 mov a,_T0_ACC t2 subb a,#0x14 t2 mov b0,c t2 cpl c t1 mov _T0_OUT,c ;對應(yīng)狀態(tài)圖S3 t2 sjmp 00106$ t2 00105$: ; d:\\MYDOCU~1\\51_proj\\timer.c:36: T0_OUT=0;T0_ACC=0; clr _T0_OUT ;對應(yīng)狀態(tài)圖S1 t1 mov _T0_ACC,#0x00 t2 00106$: 即使沒采用匯編語言,C編譯器已經(jīng)為我們產(chǎn)生出來很精簡的語句,當(dāng)然32至36之間的代碼還可以采用匯編優(yōu)化。 所以首先程序優(yōu)化,然后在進行匯編,難度降低了很多。因為程序優(yōu)化后,C編譯出來的匯編,在進行優(yōu)化工作量很小了。 其中計數(shù)器的代碼變化最大,優(yōu)化了10行之多。給我可以自己用編譯器試驗一下。 9、這個是最快的嗎? 不是,最快的應(yīng)該是查表法。對這個定時器來說: 方案一: 輸入:T_EN,T_ACC,T_SET 輸出:T_OUT,T_ACC 建立一個數(shù)據(jù)表格,然后在中斷函數(shù)中用查表法,大概兩條指令搞定。不過占用的空間也是嚇人。 ![]() 10、在使用if else語句注意什么? 采用if else語句避免()中進行多目運算。也不要進行取反運算,因為這樣代碼會增加好幾行。 如果直接用bit量,這樣編譯器會用 jnb或jb, 由于本人水平有限,舉例采用的是8051(因為我的電腦是P3 800,運行proteus正好)。希望對大家有參考作用 |