廣西民族大學物理與電子工程學院 白羽
眾所周知,相比于其他編程語言,C語言在編寫嵌入式編程中有著絕對的優勢。但它總也有缺點的:它的時序性比較差,不容易編寫精準的延時。而在編寫嵌入系統驅動程序時,常常需要比較精確的軟件延時,這使得C語言的“劣勢”暴露了出來,一般都只能通過嵌入匯編的方式實現。例如,在1MHZ工作頻率下需要延時10us,就需要嵌入10句“空操作”指令,顯然在書寫上比較難堪。本文提出一種簡化書寫的延時方案,使用帶參數的宏構來造微小時間片,可以實現完全精確的軟件延時,大大方便了驅動程序及軟件模擬通信協議的編寫。
說明:以下皆為ICC AVR平臺下的討論,對AVR系列所有型號的單片機皆有效。至于其他平臺,可據此方案自行修改和移值。
該方案的實現方法其實很簡單:
首先定義N個宏,分別調用 1 ~ N 個匯編“空操作”指令,如:
#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_40 NOP_40; asm("nop") //延時40個時鐘周期
然后利用“##”操作符,實現帶參數宏的延時:
#define NOP(N) NOP_##N //延時 N個時鐘周期
操作符的作用是把兩個部分的內容連成一個內容。就是說,NOP(3)展開后成為NOP_3,NOP(4)展開后成為NOP_4,等等。因此,定義上述宏之后,就可通過調用NOP(N)語句實現精確軟件延時。例如:
NOP(4); //延時4個時鐘周期
上述語句展開過程如下:
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");
正好延時4個時鐘周期
不過,上面的宏還不夠完善,如果試圖使用下面的語句,程序將會出現漏洞。
if(表達式)
NOP(3);
else
NOP(4);
這是因為NOP(N)宏展開之后,不是一個語句,而是變成N個語句。故必須用花括號括起來,程序才能運行正確。即應該改為:
if(表達式)
{
NOP(3);
}
else
{
NOP(4);
}
如果把NOP(N)宏的定義改為:
#define NOP(N) do{ NOP_##N ; }while(0)
則NOP(N)宏展開之后只形成一個語句,將不會出現上面的問題。
但是要注意,“##”操作符只能按照原樣把兩邊的內容連在一起。故NOP(N)的參數必須是具體的常量,即只能是數字,并且,與該數字相對應的宏NOP_N已必須已經定義。
例如:
“NOP(3+4);”語句展開之后,將將變成“NOP_3+4;”,出現語法錯誤;
又如:
“NOP(a);”語句展開之后,將將變成“NOP_a;”,而“NOP_a;”未定義。
只有這樣的語句才是正確的調用:
NOP(20); //延時20個時鐘周期
將上述方案整理成一個頭文件,以后就可以任意調用了。下面是整理好的頭文件:
注意:該文件不宜作長時間的延時。長時間的延時將會調用大量的“空操作”指令,占用大量的程序指令空間。這個問題將在V2.0版本中解決。
NOP.H
/*********************************************************************
單 位:廣西民族大學物理與電子工程學院
文件名稱:NOP.H
文件標識:_NOP_H_
摘 要:精密延時頭文件,可以精確延時40以內(包括40)的時鐘周期
當前版本:V1.0
作 者:白 羽
完成日期:2010年5月9日
特別聲明:您可以任意轉載、復制本文件,但不能隨便剔除本文件說明
*********************************************************************/
#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