最近经常用到SysCtlDelay()函数,觉得这函数不错,可以做到精确延时。不久前,做NRF905模块的时候,有一处要精确到610us。
TI的资料中,此函数在Sysctl.c中是这样定义的:
#if defined(ewarm) || defined(DOXYGEN) //定义在IAR的编译环境中
void
SysCtlDelay(unsigned long ulCount)
{
__asm(" subs r0, #1\n"
" bne.n SysCtlDelay\n"
" bx lr");
}
#endif
#if defined(codered) || defined(gcc) || defined(sourcerygxx) //定义在codered、gcc、sourcerygcc编译环境下
void __attribute__((naked))
SysCtlDelay(unsigned long ulCount)
{
__asm(" subs r0, #1\n"
" bne SysCtlDelay\n"
" bx lr");
}
#endif
#if defined(rvmdk) || defined(__ARMCC_VERSION) //在KEIL MDK的编译环境下
__asm void
SysCtlDelay(unsigned long ulCount)
{
subs r0, #1;
bne SysCtlDelay;
bx lr;
}
#endif
不管哪种环境下,发现用了三条汇编指令。我用的是KEIL MDK。
subs r0,#1; // 使用了16位的Thumb指令,无条件更新标志位。S后缀的使用要担心,16位的Thunb指令有可能会无条件更新标志位,也有可能不会。所以,但你需要更新标志位时,一定不要忘了加上S后缀。
bne SysCtlDelay; // 无条件跳转指令有两条,B和BX, BNE中的NE即NotEqual,对应于标志位Z==0;
表示不等的时候无条件转移到SysCtlDelay处对应的地址;
bx lr; //执行这条指令后,把返回地址存储到LR(R14)中;
关于SysCtlDelay()延时函数:
TI LM3S8962 默认的设置为采用主晶振6M, 所以,一个周期的时间是1/6us。
SysCtlDelay()函数里执行了三条指令。
1.微妙级的延时:
SysCtlDelay(2); // 延时1us;
SysCtlDelay(2*x); 延时x us;x=1000时,延时1ms;
另一种写法
#defined TheSysClock 6000000
SysCtlDelay(1*(TheSysClock/3000000)) //延时 1us
2.毫秒级的延时:
SysCtlDelay(SysCtlClockGet( ) / 3000); // 延时1ms
SysCtlDelay(10 * (SysCtlClockGet( ) / 3000)); // 延时10ms
SysCtlClockGet( )=6000000 ;
另一种种写法
// 定义系统时钟 6M
#define TheSysClock 6000000
SysCtlDelay(10 * (TheSysClock / 3000)); 延时10ms
// 定义系统时钟 8M
#define TheSysClock 8000000
SysCtlDelay(10 * (TheSysClock / 3000)); 延时10ms