想要得到精确的延时时间在硬件系统里必须采用定时器的方式。
上面有人提到的通过指令的方式,这种通过阻塞查询的方式,一旦有中断进入就会完全失效。
解答:
有时候需要精确的延时,比如 18B20 温度传感器对时序要求非常严格,
必须精确到微秒级别
一、用 NOP 函数
在 keil C51 中,直接调用库函数:
#include // 声明了 void _nop_(void);
_nop_(); // 产生一条 NOP 指令
作用:对于延时很短的,要求在 us 级的,采用“_nop_”函数,这个函
数相当汇编 NOP 指令,延时几微秒。NOP 指令为单周期指令,可由晶振频率
算出延时时间,对于 12M 晶振,延时 1uS。(若为 11.0592MHz,延时为
12*(1/11.0592)=1.085uS)。对于延时比较长的,要求在大于 10us,采用 C51
中的循环语句来实现。
二、用 for 和 while 实现
在选择 C51 中循环语句时,要注意以下几个问题
第一、定义的 C51 中循环变量,尽量采用无符号字符型变量。
第二、在 FOR 循环语句中,尽量采用变量减减来做循环。
第三、在 do…while,while 语句中,循环体内变量也采用减减方法。
这因为在 C51 编译器中,对不同的循环方法,采用不同的指令来完成的。
下面举例说明:
unsigned char i;
for(i=0;i<255;i++);
unsigned char i;
for(i=255;i>0;i--);
其中,第二个循环语句 C51 编译后,就用 DJNZ 指令来完成,相当于如
下指令:
MOV
09H,#0FFH
LOOP: DJNZ
09H,LOOP
指令相当简洁,也很好计算精确的延时时间。
同样对 do…while,while 循环语句中,也是如此
例:
unsigned char n;
n=255;
do{n--}
while(n);
或
n=255;
while(n)
{n--};
这两个循环语句经过 C51 编译之后,形成 DJNZ 来完成的方法,
故其精确时间的计算也很方便。
其三:对于要求精确延时时间更长,这时就要采用循环嵌套的方法来实
现,因此,循环嵌套的方法常用于达到 ms 级的延时。对于循环语句同样可
以采用 for,do…while,while 结构来完成,每个循环体内的变量仍然采用
无符号字符变量。
unsigned char i,j
for(i=255;i>0;i--)
for(j=255;j>0;j--);
或
unsigned char i,j
i=255;
do{j=255;
do{j--}
while(j);
i--;
}
while(i);
或
unsigned char i,j
i=255;
while(i)
{j=255;
while(j)
{j--};
i--;
}
这三种方法都是用 DJNZ 指令嵌套实现循环的,由 C51 编译器用下面的
指令组合来完成的
MOV
R7,#0FFH
LOOP2: MOV
R6,#0FFH
LOOP1: DJNZ
R6,LOOP1
DJNZ
R7,LOOP2
这些指令的组合在汇编语言中采用 DJNZ 指令来做延时用,因此它的时
间精确计算也是很简单,假上面变量 i 的初值为 m,变量 j 的初值为 n,则
总延时时间为:m×(n×T+T),其中 T 为 DJNZ 指令执行时间(DJNZ 指令为双
周期指令)。这里的+T 为 MOV 这条指令所使用的时间。同样对于更长时间的
延时,可以采用多重循环来完成。
只要在程序设计循环语句时注意以上几个问题。
下面给出有关在 C51 中延时子程序设计时要注意的问题
1、在 C51 中进行精确的延时子程序设计时,尽量不要或少在延时子程
序中定义局部变量,所有的延时子程序中变量通过有参函数传递。
2、在延时子程序设计时,采用 do…while,结构做循环体要比 for 结构
做循环体好。
3、在延时子程序设计时,要进行循环体嵌套时,采用先内循环,再减
减比先减减,再内循环要好。
unsigned char delay(unsigned char i,unsigned char j,unsigned char
k)
{unsigned char b,c;
b="j";
c="k";
do{
do{
do{k--};
while(k);
k="c";
j--;};
while(j);
j=b;
i--;};
while(i);
}
这精确延时子程序就被 C51 编译为有下面的指令组合完成
delay 延时子程序如下:
MOV R6,05H
MOV R4,03H
C0012: DJNZ R3, C0012
MOV R3,04H
DJNZ R5, C0012
MOV R5,06H
DJNZ R7, C0012
RET
假设参数变量 i 的初值为 m,参数变量 j 的初值为 n,参数变量 k 的初
值为 l,则总延时时间为:l×(n×(m×T+2T)+2T)+3T,其中 T 为 DJNZ 和 MOV
指令执行的时间。当 m=n=l 时,精确延时为 9T,最短;当 m=n=l=256 时,精
确延时到 16908803T,最长。
以上参考
http://wenku.baidu.com/view/e79d80c40c22590102029da1.html
三、下面介绍一下如何用 keil 仿真延时时间
测试函数:
void TempDelay (unsigned char idata us)
{
while(us--);
}
测试用例:
TempDelay(80); //530uS
TempDelay(14); //100uS
NOP; //1.085uS
操作:
1、打开调试
2、起始时间为 0.00059136s
3、执行了 TempDelay(80)后时间为 0.00112413s,用时
0.00053277s=532.77uS
4、到这里起始时间为 0.00112630s
5、执行了 TempDelay(14)后,变为 0.00122938s,用时
0.00010308s=103.08uS
6、这是执行了一次 NOP 指令(晶振为 11.0592MHz,单片机为 STC89C52),
时间为 0.00123047s,用时 0.00000109s=1.09uS
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |
打赏帖 | |
---|---|
与电子爱好者谈读图二被打赏50分 | |
【FRDM-MCXN947评测】Core1适配运行FreeRtos被打赏50分 | |
【FRDM-MCXN947评测】双核调试被打赏50分 | |
【CPKCORRA8D1B评测】---移植CoreMark被打赏50分 | |
【CPKCORRA8D1B评测】---打开硬件定时器被打赏50分 | |
【FRDM-MCXA156评测】4、CAN loopback模式测试被打赏50分 | |
【CPKcorRA8D1评测】--搭建初始环境被打赏50分 | |
【FRDM-MCXA156评测】3、使用FlexIO模拟UART被打赏50分 | |
【FRDM-MCXA156评测】2、rt-thread MCXA156 BSP制作被打赏50分 | |
【FRDM-MCXN947评测】核间通信MUTEX被打赏50分 |