對于某些對時間精度要求較高的程序,用c寫延時顯得有些力不從心,故需用到匯編程序。至于如何在c中嵌入匯編大家可以去網上查查,這方面的資料很多,且很簡單。以12MHz晶振為例,12MHz晶振的機器周期為1us,所以,執行一條單周期指令所用時間就是1us,如NOP指令。下面具體闡述一下。
1.若要延時1us,則可以調用_nop_();函數,此函數是一個c函數,其相當于一個NOP指令,使用時必須包含頭文件“intrins.h”。例如:
#include《intrins.h》
#include《reg52.h》
voidmain(void){
P1=0x0;
_nop_();//延時1us
P1=0xff;
}
2.延時5us,則可以寫一個delay_5us()函數:
delay_5us(){
#pragmaasm
nop
#pragma endasm
}
這就是一個延時5us的函數,只需要在需要延時5us時調用此函數即可。或許有人會問,只有一個NOP指令,怎么是延時5us呢?
答案是:在調用此函數時,需要一個調用指令,此指令消耗2個周期(即2us);函數執行完畢時要返回主調函數,需要一個返回指令,此指令消耗2個周期(2us)。調用和返回消耗了2us+2us=4us。然后再加上一個NOP指令消耗1us,不就是5us嗎。
3.延時10us。我們編寫一個delay_10us()函數:
delay_10us(){
#pragma asm
nop
nop
nop
nop
nop
nop
#pragma endasm
}
這就是延時10us的函數。同延時5us函數一樣,調用和返回消耗4us,加上函數中的6個NOP指令6us,正好是10us。
此時有人不禁要問那么,任意微秒時,函數應該怎么寫呢?
首先,延時任意微秒我暫時沒有想到,但是,我可以延時任意偶數微秒或延時任意奇數微秒,也就是說,需要兩個函數,一個函數專門實現任意偶數的微秒級延時,另一個函數專門實現任意奇數的微秒級延時。只要有了這兩個函數在,不就可以延時任意的微秒了嗎!
首先我們來實現任意偶數的微秒級延時:
voiddelay_even_us(unsignedchareven){ //任意偶數的微秒級延時
#pragmaasm
1 mova,r7 //為什么要用到r7呢,因為r7里面裝的是函數的參數!!!//^_^這句消耗1個周期
2 subb a,#10H//這句看完程序我再解釋這句消耗1個周期
3 movb,#02H//這句看完程序我再解釋這句消耗2個周期
4 divab//這句意思是a/b,商放在a里,余數放在b里稍 //后解釋這句消耗4個周期
5 movr0,a //這句消耗1個周期
6 nop //這句消耗1個周期
7 loop:
8 djnz r0,loop //不等于0跳轉指令,也就是說r0中的值若不為0的話,
//就跳轉到loop處這句消耗2個周期
#pragmaendasm
}
如下程序能實現ms毫秒級的比較精確的延時
void Delayms(unsigned int n)
{
unsigned int i,j;
for(j=n;j》0;j--)
for(i=112;i》0;i--);
}
用keil可以看出這個延時的時間,我們先延時1ms(Delayms(1))。
進入Delayms前,sec=0.00042209s
延時后,sec=0.00142253s
可以知道Delayms(1)實際延時0.00142253s—0.00042209s=0.00100044s≈1ms
同樣如果想延時15ms的話,用Delayms(15),實際延時0.01480903s≈15ms,延時還是挺精確的。
也可以用_nop_( )函數來實現微秒級的延時。
1_nop_(); // 直接當成一條語句使用,產生一條NOP指令
NOP指令為單周期指令,可由晶振頻率算出延時時間,對于12M晶振,延時1uS。
注:使用該函數時,需要將頭文件#include《intrins.h》包含進源文件中。
任意奇數的微秒級延時:
voiddelay_odd_us(unsignedcharodd){
#pragmaasm
1 mova,r7
2 subba,#0fH
3 movb,#02H
4 div ab
5 mov r0,a
6 loop1:
7 djnz r0,loop1
#pragmaendasm
}
此即為任意奇數微秒的延時,和偶數延時一樣的道理
評論