基于51单片机的精确延时(微秒级)

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

声明:
*此文章是基于51单片机的微秒级延时函数,采用12MHz晶振。

*此文章共包含4个方面,分别是延时1us,5us,10us和任意微秒。

前三个方面是作者学习过程中从书本或网络上面总结的,并非本人所作。

但是延时任意微秒函数乃作者原创且亲测无误。

欢迎转载。

*此篇文章是作者为方便初学者使用而写的,水平有限,有误之处还望大家多多指正。

*作者:Qtel
*2012.4.14
*QQ:97642651
----------------------------------------------------------------------------------------------------------------------序:
对于某些对时间精度要求较高的程序,用c写延时显得有些力不从心,故需用到汇编程序。

本人通过测试,总结了51的精确延时函数(在c语言中嵌入汇编)分享给大家。

至于如何在c 中嵌入汇编大家可以去网上查查,这方面的资料很多,且很简单。

以12MHz晶振为例,12MHz 晶振的机器周期为1us,所以,执行一条单周期指令所用时间就是1us,如NOP指令。

下面具体阐述一下。

----------------------------------------------------------------------------------------------------------------------1.若要延时1us,则可以调用_nop_();函数,此函数是一个c函数,其相当于一个NOP指令,使用时必须包含头文件“intrins.h”。

例如:
#include<intrins.h>
#include<reg52.h>
void main(void){
P1=0x0;
_nop_();//延时1us
P1=0xff;
}
----------------------------------------------------------------------------------------------------------------------2.延时5us,则可以写一个delay_5us()函数:
delay_5us(){
#pragma asm
nop
#pragma endasm
}
这就是一个延时5us的函数,只需要在需要延时5us时调用此函数即可。

或许有人会问,只有一个NOP指令,怎么是延时5us呢?
答案是:在调用此函数时,需要一个调用指令,此指令消耗2个周期(即2us);函数执行完毕时要返回主调函数,需要一个返回指令,此指令消耗2个周期(2us)。

调用和返回消耗了2us+2us=4us。

然后再加上一个NOP指令消耗1us,不就是5us吗。

----------------------------------------------------------------------------------------------------------------------3.延时10us。

我们编写一个delay_10us()函数:
delay_10us(){
#pragma asm
nop
nop
nop
nop
nop
nop
#pragma endasm
}
这就是延时10us的函数。

同延时5us函数一样,调用和返回消耗4us,加上函数中的6个NOP指令6us,正好是10us。

----------------------------------------------------------------------------------------------------------------------4.此时有人不禁要问那么,任意微秒时,函数应该怎么写呢?看我慢慢道来:
首先,延时任意微秒我暂时没有想到,但是,我可以延时任意偶数微秒或延时任意奇数微秒,也就是说,需要两个函数,一个函数专门实现任意偶数的微秒级延时,另一个函数专门实现任意奇数的微秒级延时。

只要有了这两个函数在,不就可以延时任意的微秒了吗!
首先我们来实现任意偶数的微秒级延时:
void delay_even_us(unsigned char even){//任意偶数的微秒级延时#pragma asm
1mov a,r7//为什么要用到r7呢,因为r7里面装的是函数的参数!!!
//^_^这句消耗1个周期
2subb a,#10H//这句看完程序我再解释这句消耗1个周期
3mov b,#02H//这句看完程序我再解释这句消耗2个周期
4div ab//这句意思是a/b,商放在a里,余数放在b里稍
//后解释这句消耗4个周期
5mov r0,a//这句消耗1个周期
6nop//这句消耗1个周期
7loop:
8djnz r0,loop//不等于0跳转指令,也就是说r0中的值若不为0的话,
//就跳转到loop处这句消耗2个周期
#pragma endasm
}
下面我们来分析一下为何这样写:为了方便分析,我给句子编上了序号。

我们以延时100us 为例(delay_even_us(100))。

首先减去调用和返回的4个周期(4us)。

再减去参数传递所消耗的
2个周期。

因为c函数参数传递到汇编是需要消耗周期的。

一共消耗了6个周期。

也就是消耗了6us,还剩下100us-6us=94us。

然后再看我再程序上面注释的各语句消耗时间:从1句到5句一共消耗了10个周期(不信你数数^_^)。

还剩下94us-10us=84us。

现在就看第8句了,这句应该消耗84个周期才能达到我们延时100us。

而这句每执行一次消耗2个周期,也就是说r0的值应该为84/2=42。

那么,怎样达到r0=42的呢?我们从第1句开始分析:
第1句中,r7为c传递过来的参数,此例子中为100.执行完此句后a的值为100;
第2句中,将a=a-16=100-16=84。

此句结束后a的值为84;
第3句中,给b赋值为2;
第4句中,用a来除以b。

结果商存入a中,余数存入b中,此句结束后a的值为a=a/b=84/2 =42;
第5句,将a值赋给r0,此句结束后r0的值为42。

于是乎,r0的值为42这个目的达到了。

结合前面的分析,此程序是不是延时了100us呢?答案当然是“是”了!
这个函数可以实现任意偶数微秒(>=18)的延时的,不信的话可以带一个值进去算的。

至于为什么值必须>=18us,用不着我解释了吧。

任意奇数的微秒级延时:
void delay_odd_us(unsigned char odd){
#pragma asm
1mov a,r7
2subb a,#0fH
3mov b,#02H
4div ab
5mov r0,a
6loop1:
7djnz r0,loop1
#pragma endasm
}
此即为任意奇数微秒的延时,和偶数延时一样的道理,不解释了。

^_^
此函数的参数必须大于等于17,请思考为什么?^_^。

相关文档
最新文档