找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 144104|回复: 150
打印 上一主题 下一主题
收起左侧

编写延时函数的简单方法

  [复制链接]
跳转到指定楼层
#
ID:1 发表于 2010-6-21 00:26 | 只看该作者 回帖奖励 |正序浏览 |阅读模式

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

 

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

 

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



 
    编写一段关于延时的函数,主要利用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。
    将此程序编译通过,然后利用软件仿真,调整时间。

 

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


 

  两次时间差就是延时函数使用的时间,如果与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 很给力!

查看全部评分

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏15 分享淘帖 顶14 踩
回复

使用道具 举报

150#
ID:1085441 发表于 2023-7-28 00:08 | 只看该作者
我是做个脉冲标记,用数字示波器直接测量
回复

使用道具 举报

149#
ID:137736 发表于 2022-7-26 16:29 | 只看该作者
有软件可直接生产需要的延时程序。
回复

使用道具 举报

148#
ID:866313 发表于 2021-11-1 20:59 | 只看该作者
可以,很详细,感谢分享
回复

使用道具 举报

147#
ID:694299 发表于 2020-3-16 21:33 | 只看该作者
小白 想问个问题 这个是不是多编译几次那个延时就不一样
回复

使用道具 举报

146#
ID:560110 发表于 2020-1-31 22:21 | 只看该作者
值得学习值得学习
回复

使用道具 举报

145#
ID:634141 发表于 2019-12-21 23:38 | 只看该作者
有些地方还是没看懂,还得多看啊
回复

使用道具 举报

144#
ID:71883 发表于 2019-8-25 09:34 | 只看该作者
空操作是延时常采用的手段
回复

使用道具 举报

143#
ID:591456 发表于 2019-8-13 02:34 | 只看该作者
赞一个
回复

使用道具 举报

142#
ID:505864 发表于 2019-4-6 18:02 | 只看该作者
感谢大佬  学会了很多东西
回复

使用道具 举报

141#
ID:461428 发表于 2019-3-10 19:49 | 只看该作者
学习了,,谢
回复

使用道具 举报

140#
ID:479009 发表于 2019-2-24 00:20 | 只看该作者
看汇编代码有多少行就知道循环体有几个指令,占多少个周期了
回复

使用道具 举报

139#
ID:445393 发表于 2018-12-13 09:24 | 只看该作者
支持。。。
回复

使用道具 举报

138#
ID:444851 发表于 2018-12-12 15:03 | 只看该作者
非常受用,谢,谢
回复

使用道具 举报

137#
ID:439930 发表于 2018-12-5 15:29 | 只看该作者
我新手  学习了  谢谢
回复

使用道具 举报

136#
ID:429158 发表于 2018-11-19 13:51 | 只看该作者
比较实用
回复

使用道具 举报

135#
ID:383273 发表于 2018-8-6 01:44 | 只看该作者
谢谢分享,顶起
回复

使用道具 举报

134#
ID:363038 发表于 2018-8-5 17:36 | 只看该作者
非常棒的方法,感谢
回复

使用道具 举报

133#
ID:289276 发表于 2018-3-8 16:39 | 只看该作者

支持。。。。。
回复

使用道具 举报

132#
ID:228186 发表于 2017-12-19 19:27 | 只看该作者
受教了,楼主大神也
回复

使用道具 举报

131#
ID:217754 发表于 2017-7-10 22:31 | 只看该作者
厉害,我就来看看。没记住。留个印,回头再来多看几遍。希望能懂
回复

使用道具 举报

130#
ID:198331 发表于 2017-5-10 00:18 | 只看该作者
老实说,用空循环来做延时的项目对实时系统要求高的项目是一个很坏的做法,因为可能有一些中断恰好会在这个空循环的时候发生,但是我们必须等待这个空循环完成。所以有一些事件就检测不到。
所以建议用定时器来精确延时比较好,当然也要修正一下延时时代码的执行时间。
回复

使用道具 举报

129#
ID:187614 发表于 2017-4-17 22:56 | 只看该作者
楼主分析的不错。用C编程调试时可看到汇编代码,然后用各指令的周期进行计算。
回复

使用道具 举报

128#
ID:62289 发表于 2017-3-5 21:04 | 只看该作者

谢谢,很不错的,很经典
回复

使用道具 举报

127#
ID:153199 发表于 2016-12-31 11:34 | 只看该作者
感谢分享
回复

使用道具 举报

126#
ID:147803 发表于 2016-11-14 15:49 | 只看该作者
初来乍到,看着感觉蛮厉害
回复

使用道具 举报

125#
ID:142326 发表于 2016-10-11 15:46 | 只看该作者
白开水 发表于 2010-11-8 14:08
延时的初值可以借助软件工具那样比较快

怎么获取?
回复

使用道具 举报

124#
ID:142326 发表于 2016-10-11 15:45 | 只看该作者
优游鸢123 发表于 2010-10-27 09:43
**** 作者被禁止或删除 内容自动屏蔽 ****

什么单片机小精灵?除了51系列的单片机其他的带系统的单片机也可以获取到延程序吗?
吗?
回复

使用道具 举报

123#
ID:116662 发表于 2016-6-11 01:03 来自触屏版 | 只看该作者
看了这些帖子感觉楼主的知识太深了,高手
回复

使用道具 举报

122#
ID:103211 发表于 2016-1-14 15:30 | 只看该作者
呵呵,常规方法
回复

使用道具 举报

121#
ID:92785 发表于 2015-10-18 00:47 | 只看该作者
不错,值得参考一下!
回复

使用道具 举报

120#
ID:66287 发表于 2015-9-10 19:58 | 只看该作者
很好的方法
回复

使用道具 举报

119#
ID:75468 发表于 2015-3-31 14:48 | 只看该作者
受教了
回复

使用道具 举报

118#
ID:70525 发表于 2014-12-17 18:25 | 只看该作者
回复

使用道具 举报

117#
ID:70003 发表于 2014-12-5 21:10 | 只看该作者
支持楼主,感谢分享
回复

使用道具 举报

116#
ID:69706 发表于 2014-12-1 12:41 | 只看该作者
学习啦!!!!!!!!!
回复

使用道具 举报

115#
ID:69115 发表于 2014-11-20 17:08 | 只看该作者
学习了,这个经验很重要,记下了
回复

使用道具 举报

114#
ID:67844 发表于 2014-10-26 12:13 | 只看该作者
支持啊
回复

使用道具 举报

113#
ID:66419 发表于 2014-9-20 17:28 | 只看该作者
这种方法我也曾用到过,写起来方便简单。
回复

使用道具 举报

112#
ID:66004 发表于 2014-9-15 11:37 | 只看该作者
第二层的执行次数本来是255次  這個看不出來 ?
回复

使用道具 举报

111#
ID:65779 发表于 2014-9-4 14:36 | 只看该作者
感谢分享!受教啦
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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