这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 综合技术 » 基础知识 » 基础知识每日一题——第四十四题

共13条 2/2 1 2 跳转至
院士
2014-08-09 10:14:05     打赏
11楼

想要得到精确的延时时间在硬件系统里必须采用定时器的方式。

上面有人提到的通过指令的方式,这种通过阻塞查询的方式,一旦有中断进入就会完全失效。


工程师
2014-08-10 16:02:15     打赏
12楼

硬件延时,使用定时器

实用软件延时NOP,或查使用for或while循环再看反汇编

推荐一篇博客,这里讲的相当详细

http://blog.sina.com.cn/s/blog_980e19e00101b5dh.html


高工
2014-08-11 11:33:56     打赏
13楼

  解答:

  有时候需要精确的延时,比如 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



共13条 2/2 1 2 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]