如何寫(xiě)出高效的單片機(jī)C語(yǔ)言程序代碼
與之比較的。PC
對(duì)于單片機(jī)來(lái)說(shuō)就截然不同了,一般的單片機(jī)的Flash
機(jī)的資源是少得可憐,為此我們必須想法設(shè)法榨盡其所有資源,將它的性能發(fā)揮到最佳,程序設(shè)計(jì)時(shí)必須
遵循以下幾點(diǎn)進(jìn)行優(yōu)化:
1.
能夠使用字符型(char)定義的變量,就不要使用整型(int)變量來(lái)定義;能夠使用整型變量定義的變
量就不要用長(zhǎng)整型(long
量后不要超過(guò)變量的作用范圍,如果超過(guò)變量的范圍賦值,C
而且這樣的錯(cuò)誤很難發(fā)現(xiàn)。
2.
通常使用自加、自減指令和復(fù)合賦值表達(dá)式(如a-=1
程序代碼,編譯器通常都能夠生成inc
的指令,有很多C
3.
可以使用運(yùn)算量小但功能相同的表達(dá)式替換原來(lái)復(fù)雜的的表達(dá)式。
(1)
N=
說(shuō)明:位操作只需一個(gè)指令周期即可完成,而大部分的C
完成,代碼長(zhǎng)、執(zhí)行速度慢。通常,只要求是求2n
(2)
N=Pow(3,2)
說(shuō)明:在有內(nèi)置硬件乘法器的單片機(jī)中(如51
的求平方是通過(guò)調(diào)用子程序來(lái)實(shí)現(xiàn)的,乘法運(yùn)算的子程序比平方運(yùn)算的子程序代碼短,執(zhí)行速度快。
(3)
N=M*8
N=M/8
說(shuō)明:通常如果需要乘以或除以2n,都可以用移位的方法代替。如果乘以2n,都可以生成左移
的代碼,而乘以其它的整數(shù)或除以任何數(shù),均調(diào)用乘除法子程序。用移位的方法得到代碼比調(diào)用乘除法子
程序生成的代碼效率高。實(shí)際上,只要是乘以或除以一個(gè)整數(shù),均可以用移位的方法得到結(jié)果。如N=M*9
可以改為N=(M<<3)+M;
(4)
例如我們平時(shí)使用的延時(shí)函數(shù)都是通過(guò)采用自加的方式來(lái)實(shí)現(xiàn)。
void
{
UINT16
for(i=0;i
}
可以改為
void
{
UINT16
for(i=t;i>=0;i--)
for(j=1000;i>=0;j--)
}
說(shuō)明:兩個(gè)函數(shù)的延時(shí)效果相似,但幾乎所有的C
個(gè)字節(jié),因?yàn)閹缀跛械腗CU
4.
void
{
while(t--)
{
NOP();
}
}
可以改為
void
{
do
{
NOP();
}while(--t)
}
說(shuō)明:使用do…while
5.
void
{
while(*str
{
UARTSendByte(*str++)
}
}
可以改為
void
{
register
while(*pstr
{
UARTSendByte(*pstr++)
}
}
說(shuō)明:在聲明局部變量的時(shí)候可以使用register
器中,而不是在堆棧中,合理使用這種方法可以提高執(zhí)行速度。函數(shù)調(diào)用越是頻繁,越是可能提高代碼的
速度,注意register
6.
volatile
哪里使用、在哪里失效,分析結(jié)果可以用于常量合并,常量傳播等優(yōu)化,進(jìn)一步可以死代碼消除。一般來(lái)
說(shuō),volatile
a)
b)
c)
總之,volatile
更改,比如:操作系統(tǒng)、硬件或者其它線程等。遇到這個(gè)關(guān)鍵字聲明的變量,編譯器對(duì)訪問(wèn)該變量的代碼
就不再進(jìn)行優(yōu)化,從而可以提供對(duì)特殊地址的穩(wěn)定訪問(wèn)。
7.
在數(shù)據(jù)校驗(yàn)實(shí)戰(zhàn)當(dāng)中,CRC16
校驗(yàn)值,效率更高,當(dāng)校驗(yàn)數(shù)據(jù)量大的時(shí)候,使用查表法優(yōu)勢(shì)更加明顯,不過(guò)唯一的缺點(diǎn)是占用大量的空
間。
//查表法:
code
0x0000,
0x8108,
0x1231,
0x9339,
0x2462,
0xa56a,
0x3653,
0xb75b,
0x48c4,
0xc9cc,
0x5af5,
0xdbfd,
0x6ca6,
0xedae,
0x7e97,
0xff9f,
0x9188,
0x1080,
0x83b9,
0x02b1,
0xb5ea,
0x34e2,
0xa7db,
0x26d3,
0xd94c,
0x5844,
0xcb7d,
0x4a75,
0xfd2e,
0x7c26,
0xef1f,
0x6e17,
};
UINT16
{
UINT16
UINT16
for(i
{
uncrcReg
^
uncrcConst
}
return
}
如果系統(tǒng)要求實(shí)時(shí)性比較強(qiáng),在CRC16
8.
首先不推薦所有函數(shù)改為宏函數(shù),以免出現(xiàn)不必要的錯(cuò)誤。但是一些基本功能的函數(shù)很有必要使用宏
函數(shù)來(lái)代替。
UINT8
{
return
}
可以改為
#define
說(shuō)明:函數(shù)和宏函數(shù)的區(qū)別就在于,宏函數(shù)占用了大量的空間,而函數(shù)占用了時(shí)間。大家要知道的是,函
數(shù)調(diào)用是要使用系統(tǒng)的棧來(lái)保存數(shù)據(jù)的,如果編譯器里有棧檢查選項(xiàng),一般在函數(shù)的頭會(huì)嵌入一些匯編語(yǔ)
句對(duì)當(dāng)前棧進(jìn)行檢查;同時(shí),cpu
函數(shù)調(diào)用需要一些cpu
不會(huì)產(chǎn)生函數(shù)調(diào)用,所以僅僅是占用了空間,在頻繁調(diào)用同一個(gè)宏函數(shù)的時(shí)候,該現(xiàn)象尤其突出。
9.
作為程序員的我們會(huì)毫不猶豫地點(diǎn)擊鍵盤(pán)寫(xiě)出以下的計(jì)算方法:
UINT16
{
UINT8
for(i=1;i<=100;i++)
{
s+=i;
}
return
}
很明顯大家都會(huì)想到這種方法,但是效率方面并不如意,我們需要?jiǎng)幽X筋,就是采用數(shù)學(xué)算法解決問(wèn)題,
使計(jì)算效率提升一個(gè)級(jí)別。
UINT16
{
UINT16
s=(100
return
}
結(jié)果很明顯,同樣的結(jié)果不同的計(jì)算方法,運(yùn)行效率會(huì)有大大不同,所以我們需要最大限度地通過(guò)數(shù)
學(xué)的方法提高程序的執(zhí)行效率。
10.
在許多種情況下,可以用指針運(yùn)算代替數(shù)組索引,這樣做常常能產(chǎn)生又快又短的代碼。與數(shù)組索引相
比,指針一般能使代碼速度更快,占用空間更少。使用多維數(shù)組時(shí)差異更明顯。下面的代碼作用是相同的,
但是效率不一樣。
UINT8
UINT8
UINT8
UINT8
for(i=0;i<64;i++)szArrayB[i]=szArrayA[i];
for(i=0;i<64;i++)szArrayB[i]=*p++;
指針?lè)椒ǖ膬?yōu)點(diǎn)是,szArrayA
方法中,每次循環(huán)中都必須進(jìn)行基于i
11.
C
可以提供程序效率,而且使程序更加之簡(jiǎn)潔,由于強(qiáng)制轉(zhuǎn)換在C
個(gè)比較典型的例子作為講解。
例子1:將帶符號(hào)字節(jié)整型轉(zhuǎn)換為無(wú)符號(hào)字節(jié)整型
UINT8
INT8
a=(UINT8)b;
例子2:在大端模式下(8051
方法1:采用位移方法。
UINT8
UINT16
b=(a[0]<<8)|a[1];
結(jié)果:b=0x1234
方法2:強(qiáng)制類型轉(zhuǎn)換。
UINT8
UINT16
b=
結(jié)果:b=0x1234
例子3:保存結(jié)構(gòu)體數(shù)據(jù)內(nèi)容。
方法1:逐個(gè)保存。
typedef
{
UINT8
UINT8
UINT8
UINT8
UINT8
}ST;
ST
UINT8
s.a=1;
s.b=2;
s.c=3;
s.d=4;
s.e=5;
a[0]=s.a;
a[1]=s.b;
a[2]=s.c;
a[3]=s.d;
a[4]=s.e;
結(jié)果:數(shù)組a
方法2:強(qiáng)制類型轉(zhuǎn)換。
typedef
{
UINT8
UINT8
UINT8
UINT8
UINT8
}ST;
ST
UINT8
UINT8
UINT8
s.a=1;
s.b=2;
s.c=3;
s.d=4;
s.e=5;
for(i=0;i
a[i]=*p++;
}
評(píng)論