欢迎使用Markdown编辑器写博客
产生精确的延迟是许多嵌入式系统的关键要求:
- 硬件延迟:通过使用一个片内定时器产生精确地延迟,特别适合产生大约0.1ms或更长的延迟。
软件延迟:不需要硬件资源,灵活方便,适用于产生较短的延迟(以微秒为单位)
早期的8051定时器每12个振荡周期加1.当(16)位定时器溢出时,即从65535加1,定时器标志(TF0)将被置1。这个溢出还可以产生中断。
硬件延迟通常按照以下形式计算:- 计算定时器所需的初始值
- 将这个值加载到定时器0或定时器1中。
- 启动定时器
- 定时器将按照由振荡器频率确定的速度增加,而不需要软件的干预。等待定时器到达它的最大值后“翻转”
- 定时器的翻转将改变标志变量的值,从而标志延迟的结束。
- 对于一个运行在12MHz,12个振荡周期/指令的8051,使用16位定时器能够产生最大延迟是65ms。如果需要更长的延迟,可以重复这个过程。
对于早期的12MHz的8051,理论上最小的时间增量是1微秒(即振荡器频率的1/12)。然而延迟往往小于调用延迟函数、设置,以及启动定时器的时间。比如如果定时器采用中断方式,则10微秒到了之后,进入中断服务程序,而进入中断服务程序的时间本身就有几微秒。同时其他单条语句的执行时间也是微秒级别。
一般说来,小于10微秒的延迟最好由软件来实现。
调用延迟函数以及为定时器人工重装初始计数值需要时间。如果没有仔细地将这些因素考虑在内,就无法产生精确的时间延迟。例如:当试图通过调用20次50ms的延迟来产生1s的延迟时,需要特别关注这种误差,因为将不可能做到精确。不要试图使用硬件延迟来实现实时时钟。
一般来说,串口波特率的产生通常采用定时器T1。
//定义用于1ms延迟的定时器0/定时器1的重装值,已考虑到函数调用等等开销而做出调整
#define PRELOAD01 (65536-OSC_FREQ/(OSC_PER_INST *1063))
#define PRELOAD01H (PRELOAD01 / 256)
#define PRELOAD01L (PRELOAD01 % 256)
//大约延迟N毫秒
void Hardware_Delay_T0(const tWord N)
{
tWord i;
TMOD &= 0XF0; //清除所有有关T0的位(T1不变)
TMOD |= OXO1; //设置所需的T0的位(T1不变)
ET0 = 0; //不使用中断
//每个循环的延迟值“大约”是1ms.
for ( i = 0; i< N; i++)
{
TH0 = PRELOAD01H ;
Tl0 = PRELOAD01L ;
TF0 = 0; //清除溢出标志
TR0 = 1;
while ( TF0 == 0); //循环直到定时器0溢出(TF0 = 1)
TRO = 0;
}
}