廣西民族大學(xué)物理與電子工程學(xué)院 白羽
眾所周知,相比于其他編程語(yǔ)言,C語(yǔ)言在編寫嵌入式編程中有著絕對(duì)的優(yōu)勢(shì)。但它總也有缺點(diǎn)的:它的時(shí)序性比較差,不容易編寫精準(zhǔn)的延時(shí)。而在編寫嵌入系統(tǒng)驅(qū)動(dòng)程序時(shí),常常需要比較精確的軟件延時(shí),這使得C語(yǔ)言的“劣勢(shì)”暴露了出來(lái),一般都只能通過(guò)嵌入?yún)R編的方式實(shí)現(xiàn)。例如,在1MHZ工作頻率下需要延時(shí)10us,就需要嵌入10句“空操作”指令,顯然在書寫上比較難堪。本文提出一種簡(jiǎn)化書寫的延時(shí)方案,使用帶參數(shù)的宏構(gòu)來(lái)造微小時(shí)間片,可以實(shí)現(xiàn)完全精確的軟件延時(shí),大大方便了驅(qū)動(dòng)程序及軟件模擬通信協(xié)議的編寫。
說(shuō)明:以下皆為ICC AVR平臺(tái)下的討論,對(duì)AVR系列所有型號(hào)的單片機(jī)皆有效。至于其他平臺(tái),可據(jù)此方案自行修改和移值。
該方案的實(shí)現(xiàn)方法其實(shí)很簡(jiǎn)單:
首先定義N個(gè)宏,分別調(diào)用 1 ~ N 個(gè)匯編“空操作”指令,如:
#define NOP_1 asm("nop") //延時(shí)一個(gè)時(shí)鐘周期
#define NOP_2 NOP_1; asm("nop") //延時(shí)兩個(gè)時(shí)鐘周期
#define NOP_3 NOP_2; asm("nop") //延時(shí)三個(gè)時(shí)鐘周期
#define NOP_4 NOP_3; asm("nop") //延時(shí)四個(gè)時(shí)鐘周期
……
#define NOP_40 NOP_40; asm("nop") //延時(shí)40個(gè)時(shí)鐘周期
然后利用“##”操作符,實(shí)現(xiàn)帶參數(shù)宏的延時(shí):
#define NOP(N) NOP_##N //延時(shí) N個(gè)時(shí)鐘周期
操作符的作用是把兩個(gè)部分的內(nèi)容連成一個(gè)內(nèi)容。就是說(shuō),NOP(3)展開后成為NOP_3,NOP(4)展開后成為NOP_4,等等。因此,定義上述宏之后,就可通過(guò)調(diào)用NOP(N)語(yǔ)句實(shí)現(xiàn)精確軟件延時(shí)。例如:
NOP(4); //延時(shí)4個(gè)時(shí)鐘周期
上述語(yǔ)句展開過(guò)程如下:
NOP_3 ; asm("nop");
NOP_2; asm("nop"); asm("nop");
NOP_1; asm("nop"); asm("nop"); asm("nop");
asm("nop"); asm("nop"); asm("nop"); asm("nop");
正好延時(shí)4個(gè)時(shí)鐘周期
不過(guò),上面的宏還不夠完善,如果試圖使用下面的語(yǔ)句,程序?qū)?huì)出現(xiàn)漏洞。
if(表達(dá)式)
NOP(3);
else
NOP(4);
這是因?yàn)镹OP(N)宏展開之后,不是一個(gè)語(yǔ)句,而是變成N個(gè)語(yǔ)句。故必須用花括號(hào)括起來(lái),程序才能運(yùn)行正確。即應(yīng)該改為:
if(表達(dá)式)
{
NOP(3);
}
else
{
NOP(4);
}
如果把NOP(N)宏的定義改為:
#define NOP(N) do{ NOP_##N ; }while(0)
則NOP(N)宏展開之后只形成一個(gè)語(yǔ)句,將不會(huì)出現(xiàn)上面的問(wèn)題。
但是要注意,“##”操作符只能按照原樣把兩邊的內(nèi)容連在一起。故NOP(N)的參數(shù)必須是具體的常量,即只能是數(shù)字,并且,與該數(shù)字相對(duì)應(yīng)的宏NOP_N已必須已經(jīng)定義。
例如:
“NOP(3+4);”語(yǔ)句展開之后,將將變成“NOP_3+4;”,出現(xiàn)語(yǔ)法錯(cuò)誤;
又如:
“NOP(a);”語(yǔ)句展開之后,將將變成“NOP_a;”,而“NOP_a;”未定義。
只有這樣的語(yǔ)句才是正確的調(diào)用:
NOP(20); //延時(shí)20個(gè)時(shí)鐘周期
將上述方案整理成一個(gè)頭文件,以后就可以任意調(diào)用了。下面是整理好的頭文件:
注意:該文件不宜作長(zhǎng)時(shí)間的延時(shí)。長(zhǎng)時(shí)間的延時(shí)將會(huì)調(diào)用大量的“空操作”指令,占用大量的程序指令空間。這個(gè)問(wèn)題將在V2.0版本中解決。
NOP.H
/*********************************************************************
單 位:廣西民族大學(xué)物理與電子工程學(xué)院
文件名稱:NOP.H
文件標(biāo)識(shí):_NOP_H_
摘 要:精密延時(shí)頭文件,可以精確延時(shí)40以內(nèi)(包括40)的時(shí)鐘周期
當(dāng)前版本:V1.0
作 者:白 羽
完成日期:2010年5月9日
特別聲明:您可以任意轉(zhuǎn)載、復(fù)制本文件,但不能隨便剔除本文件說(shuō)明
*********************************************************************/
#ifndef _NOP_H_
#define _NOP_H_
#define NOP(N) do{ NOP_##N(); }while(0)
#define NOP_0()
#define NOP_1() asm("nop")
#define NOP_2() NOP_1();asm("nop")
#define NOP_3() NOP_2();asm("nop")
#define NOP_4() NOP_3();asm("nop")
#define NOP_5() NOP_4();asm("nop")
#define NOP_6() NOP_5();asm("nop")
#define NOP_7() NOP_6();asm("nop")
#define NOP_8() NOP_7();asm("nop")
#define NOP_9() NOP_8();asm("nop")
#define NOP_10() NOP_9();asm("nop")
#define NOP_11() NOP_10();asm("nop")
#define NOP_12() NOP_11();asm("nop")
#define NOP_13() NOP_12();asm("nop")
#define NOP_14() NOP_13();asm("nop")
#define NOP_15() NOP_14();asm("nop")
#define NOP_16() NOP_15();asm("nop")
#define NOP_17() NOP_16();asm("nop")
#define NOP_18() NOP_17();asm("nop")
#define NOP_19() NOP_18();asm("nop")
#define NOP_20() NOP_19();asm("nop")
#define NOP_21() NOP_20();asm("nop")
#define NOP_22() NOP_21();asm("nop")
#define NOP_23() NOP_22();asm("nop")
#define NOP_24() NOP_23();asm("nop")
#define NOP_25() NOP_24();asm("nop")
#define NOP_26() NOP_25();asm("nop")
#define NOP_27() NOP_26();asm("nop")
#define NOP_28() NOP_27();asm("nop")
#define NOP_29() NOP_28();asm("nop")
#define NOP_30() NOP_29();asm("nop")
#define NOP_31() NOP_30();asm("nop")
#define NOP_32() NOP_31();asm("nop")
#define NOP_33() NOP_32();asm("nop")
#define NOP_34() NOP_33();asm("nop")
#define NOP_35() NOP_34();asm("nop")
#define NOP_36() NOP_35();asm("nop")
#define NOP_37() NOP_36();asm("nop")
#define NOP_38() NOP_37();asm("nop")
#define NOP_39() NOP_38();asm("nop")
#define NOP_40() NOP_39();asm("nop")
#endif