找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 129308|回复: 150
收起左侧

编写延时函数的简单方法

  [复制链接]
ID:1 发表于 2010-6-21 00:26 | 显示全部楼层 |阅读模式

   在本站51hei-5板子上做315兆无线解码和红外解码试验的时候,延时函数的精度很重要,要做到相当精确才可以成功,所以大家一定要掌握.

 

  这也是大家最常在QQ里问我的一个问题,如果从keil里看了c语言的反汇编代码然后根据晶振和指令计算延时的时间这样虽然非常的准确但是相当的麻烦而且容易搞错,我这里介绍一个最简单的方法.可以验证你的延时函数

 

   这里用一个例程详细介绍一下。
    过程参考如下:
    在编译器下建立一个新项目,也可以利用已有项目。此过程中需要注意,单片机晶振的选择,因为for循环里指令的执行时间和晶振有直接关系,本例中晶振使用11.0592M。

20090oc1.jpg

 
    编写一段关于延时的函数,主要利用for循环,代码如下:
void delay_ms(unsigned int ms)
{
unsigned int i;
unsigned char j;
    for(i=0;i<ms;i++)
    {
        for(j=0;j<200;j++);
        for(j=0;j<102;j++);
    }

}
其中ms是输入参数,如果输入1,就是要求程序延时1ms。
j变量是调整程序运行的时间参数。调整j的数值,使1次循环的时间在1ms。
    将此程序编译通过,然后利用软件仿真,调整时间。

  20090oc2.jpg

下面这个sec就是程序运行到现在的这一行所用的时间。

20090oc3.jpg
 

  两次时间差就是延时函数使用的时间,如果与1ms相差比较多,用户可以调整j参数的值,使延时时间尽量接近1ms。如增大j的值for(j=0;j<105;j++);
    此方法得出延时函数,在晶振不同的情况下,延时时间会不准。软件调试结果,这个程序的延时时间为:1.01779ms,一般的单片机系统中都可以应用。

 

下面来说说汇编的传统计算方法:

 

指令周期、机器周期与时钟周期
       指令周期:CPU执行一条指令所需要的时间称为指令周期,它是以机器周期为单位的,指令不同,所需的机器周期也不同。
       时钟周期:也称为振荡周期,一个时钟周期 =晶振的倒数。
       MCS-51单片机的一个机器周期=6个状态周期=12个时钟周期。
       MCS-单片机的指令有单字节、双字节和三字节的,它们的指令周期不尽相同,一个单周期指令包含一个机器周期,即12个时钟周期,所以一条单周期指令被执行所占时间为12*(1/12000000)=1us。

了解了上面这些我们来看一个例子

;============延时1秒子程序========================
DELAY_1S:         ;延时子程序,12M晶振延时1.002035秒
MOV R4,#10
L3: MOV R2 ,#200  ;1指令周期
L1: MOV R3 ,#249  ;1指令周期
L2: DJNZ R3 ,L2     ;2指令周期
DJNZ R2 ,L1          ;2指令周期
DJNZ R4 ,L3          ;2指令周期
RET                      ;2指令周期
;循环体延时时间: [(249*2+1+2)*200+1+2]*10*12/12000000=1.002030s
;加上ACALL指令和第一条mov指令以及最后一条RET指令算出来整个函数的时间为1.002035s
;===================================================
通常选用的是11.0592MHZ的晶振:
[(249*2+1+2)*200+1+2]*10*12/11059200=1.08727213541666666...S

汇编延时子程序的延时计算问题
对于程序
DELAY:  MOV R0,#00H
DELAY1: MOV R1,#0B3H
DJNZ R1,$
DJNZ R0,DELAY1

  查指令表可知 MOV一个机器周期,DJNZ 指令需用两个机器周期,而一个机器周期时间长度为12/11.0592MHz,所以该段程序执行时间为:

((0B3×2+1+2)×256+1)×12÷11059200=100.2789mS

  第一层:DJNZ R1,$:执行了B3H次,一次两个周期,所以为0B3×2;

  第二层:MOV R1,#0B3H为一个周期,DJNZ R0,DELAY1为两个周期,这样循环一次就是0B3×2+1+2个周期;第二层的执行次数本来是255次,但因为赋首值为0,而DJNZ是先减1,再比较的,所以就应该是256次。

  这样的话,整个循环执行完应该是(0B3×2+1+2)×256+1次。再加上开始赋值这一句,就是((0B3×2+1+2)×256+1)了

 

 

还说明一下:

nop指令或者_nop_(); 函数占一个机器周期,
   在stc单片机的12T模式下一个机器周期是一个振荡周期的12分频,如果你的晶振是12MHZ,那你的一个机器周期就是1微秒.一个nop指令的执行时间也就是1US

   当在6T模式(下载的时候可选择模式)下12M晶振的时候,一个nop就是0.5US了.

[此贴子已经被作者于2010-7-4 2:51:54编辑过]

评分

参与人数 3黑币 +17 收起 理由
ko44 + 2
YANG122331 + 5 赞一个!
qjzyx + 10 很给力!

查看全部评分

回复

使用道具 举报

ID:23004 发表于 2010-6-21 14:34 | 显示全部楼层

支持。。。。。

回复

使用道具 举报

ID:24515 发表于 2010-6-21 15:23 | 显示全部楼层

admin 斑竹 不愧为强人一个,受教了

回复

使用道具 举报

ID:17294 发表于 2010-6-22 22:58 | 显示全部楼层

要求精确的话用汇编

回复

使用道具 举报

ID:24661 发表于 2010-6-23 12:31 | 显示全部楼层
嗯,确实要延时就是循环做空操作。具体循环次数要在实践中修正,不同器件的振荡周期可能不同
回复

使用道具 举报

ID:24747 发表于 2010-6-27 13:37 | 显示全部楼层

是可以 比较直观

 

回复

使用道具 举报

ID:19313 发表于 2010-6-28 23:51 | 显示全部楼层

学习了。。。。。。。。。。。。。。

回复

使用道具 举报

ID:24818 发表于 2010-7-14 10:14 | 显示全部楼层
空操作是延时常采用的手段
回复

使用道具 举报

ID:25784 发表于 2010-8-29 10:09 | 显示全部楼层
讨教了
回复

使用道具 举报

ID:9767 发表于 2010-9-23 11:02 | 显示全部楼层
才学多指教
回复

使用道具 举报

ID:26252 发表于 2010-10-16 18:59 | 显示全部楼层
在图书馆一边打瞌睡一边把您的帖子看完了,真是不错,让我又明白了很多,我QQ是451647703,能加我吗,还有问题讨教
回复

使用道具 举报

ID:26542 发表于 2010-10-25 10:11 | 显示全部楼层
不错哦,值得借鉴
回复

使用道具 举报

ID:26529 发表于 2010-10-27 09:43 | 显示全部楼层
现在有单片机小精灵了,可以直接获取延时程序
回复

使用道具 举报

ID:26542 发表于 2010-10-27 20:05 | 显示全部楼层

哎 我学得是 一塌糊涂啊

学着学着都不知道从何学起了

回复

使用道具 举报

ID:26651 发表于 2010-11-6 23:24 | 显示全部楼层

用C编程的方法解释不够祥细

回复

使用道具 举报

ID:26754 发表于 2010-11-8 14:08 | 显示全部楼层

延时的初值可以借助软件工具那样比较快

回复

使用道具 举报

ID:26890 发表于 2010-11-16 13:32 | 显示全部楼层
学习!
回复

使用道具 举报

ID:26942 发表于 2010-12-12 20:44 | 显示全部楼层

好!有用,实用!

回复

使用道具 举报

ID:9542 发表于 2010-12-13 21:15 | 显示全部楼层
可以用定时器来做延时!
回复

使用道具 举报

ID:17308 发表于 2011-1-11 11:48 | 显示全部楼层

延时时间精确计算哦 ,看看。。。。

回复

使用道具 举报

ID:27793 发表于 2011-1-13 11:31 | 显示全部楼层
牛人就是牛!!
回复

使用道具 举报

ID:27884 发表于 2011-1-20 12:37 | 显示全部楼层
小弟刚来,学习了
回复

使用道具 举报

ID:27985 发表于 2011-1-27 22:15 | 显示全部楼层
绝对支持
回复

使用道具 举报

ID:28159 发表于 2011-2-24 13:29 | 显示全部楼层

学习学习,谢谢楼主!

回复

使用道具 举报

ID:28355 发表于 2011-3-6 02:33 | 显示全部楼层

其实用汇编写也蛮简单的   1S的延时: 

   DELAY:MOV R4,,#50

        D1:MOV R5,,#50

        D2:MOV R6,,#50

              DJNZ R6,,$

              DJNZ R5,D2

              DJNZ R4,D1

               RET

回复

使用道具 举报

ID:28362 发表于 2011-3-6 15:53 | 显示全部楼层

楼主这个方法真是太好了,这样的话即使是c语言延时也能精确到us级别了

 

回复

使用道具 举报

ID:27793 发表于 2011-3-10 09:05 | 显示全部楼层
就是来学习的,呵呵
回复

使用道具 举报

ID:27563 发表于 2011-3-25 10:51 | 显示全部楼层

版主啊,这个程序中,j的循环次数是(200+102)*ms 还是200*102*ms啊 如果是第一种的话,为什么不直接写成j=302 呢 然后最里面的括号直接一个循环语句呢?求回答~

回复

使用道具 举报

ID:29254 发表于 2011-6-8 17:29 | 显示全部楼层
恩,老师教的也是这样
回复

使用道具 举报

ID:24040 发表于 2011-6-10 14:50 | 显示全部楼层

谢谢,很不错的,很经典

回复

使用道具 举报

ID:30369 发表于 2011-8-15 14:51 | 显示全部楼层
其实用定时器更准啊
回复

使用道具 举报

ID:31227 发表于 2011-9-11 09:36 | 显示全部楼层
仁兄,请问红色标志的那些字怎么弄上去的,讨教了
回复

使用道具 举报

ID:31466 发表于 2011-9-17 16:41 | 显示全部楼层

学习了,谢谢

回复

使用道具 举报

ID:31466 发表于 2011-9-21 07:20 | 显示全部楼层

学习了,谢谢

回复

使用道具 举报

ID:32673 发表于 2011-10-22 19:24 | 显示全部楼层
非常有用哈。学习了。
回复

使用道具 举报

ID:24977 发表于 2011-11-10 16:50 | 显示全部楼层
温习了一遍  汇编精准定时
回复

使用道具 举报

ID:7485 发表于 2012-1-27 13:21 | 显示全部楼层

其实要想真正的准确,还要加上调用和结束语句的耗时。

要求严格时,还要禁止其他中断,否则一旦被中断,延时时间准确就无从谈起了。

回复

使用道具 举报

ID:34086 发表于 2012-2-6 22:50 | 显示全部楼层
正学习中,刚好有这种疑惑,受教了!
回复

使用道具 举报

ID:9542 发表于 2012-2-11 14:59 | 显示全部楼层
使用前后台系统,可以使用定时器精确延时!
回复

使用道具 举报

ID:34245 发表于 2012-2-13 19:35 | 显示全部楼层

好东西!!

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表