你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

51 的精确延时函数

[复制链接]
gaosmile 发布时间:2020-11-11 20:16
前言

对于某些对时间精度要求较高的程序,用 c 写延时显得有些力不从心,故需用到汇编程序。

本人通过测试,总结了 51 的精确延时函数(在 c 语言中嵌入汇编)分享给大家。至于如何在 c 中嵌入汇编大家可以去网上查查,这方面的资料很多,且很简单。

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

若要延时 1us,则可以调用_nop_();函数,此函数是一个 c 函数,其相当于一个 NOP 指令

使用时必须包含头文件 intrins.h

例如:

#include <intrins.h>
#include <reg52.h>
void main(void)
{
  P1 = 0x0;
  _nop_(); //延时 1us
  P1 = 0xff;
}
延时 5us,则可以写一个delay_5us()函数delay_5us()
{
  #pragma asm
  nop
  #pragma endasm
}

这就是一个延时 5us 的函数,只需要在需要延时 5us 时调用此函数即可。或许有人会问,只有一个 NOP 指令,怎么是延时 5us 呢?

答案是:

在调用此函数时,需要一个调用指令,此指令消耗 2个周期(即 2us);函数执行完 毕时要返回主调函数,需要一个返回指令,此指令消耗 2 个周期(2us)。调用和返回消耗了

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

延时 10us。

我们编写一个 delay_10us()函数

delay_10us(){
#pragma asm
nop
nop
nop
nop
nop
nop
#pragma endasm
}

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

此时有人不禁要问那么,任意微秒时,函数应该怎么写呢?

看我慢慢道来:首先,延时任意微秒我暂时没有想到,但是,我可以延时任意偶数微秒或延时任意奇数微秒, 也就是说,需要两个函数,一个函数专门实现任意偶数的微秒级延时,另一个函数专门实现 任意奇数的微秒级延时。只要有了这两个函数在,不就可以延时任意的微秒了吗!

首先我们来实现任意偶数的微秒级延时:

void delay_even_us(unsigned char even){ //任意偶数的微秒级延时
#pragma asm
1 mov a, r7 //为什么要用到 r7 呢,因为 r7 里面装的是函数的参数!!!
// ^_^ 这句消耗 1 个周期
2 subb a, #10H //这句看完程序我再解释 这句消耗 1 个周期
3 mov b, #02H //这句看完程序我再解释 这句消耗 2 个周期
4 div ab // 这句意思是 a/b ,商放在 a 里,余数放在 b 里 稍
//后解释 这句消耗 4 个周期
5 mov r0, a //这句消耗 1 个周期
6 nop //这句消耗 1 个周期
7 loop:
8 djnz 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
1 mov a, r7
2 subb a, #0fH
3 mov b, #02H
4 div ab
5 mov r0, a
6 loop1:
7 djnz r0, loop1
#pragma endasm
}

此即为任意奇数微秒的延时,和偶数延时一样的道理,不解释了。^_^

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


收藏 评论0 发布时间:2020-11-11 20:16

举报

0个回答

所属标签

STM32团队

意法半导体微控制器和微处理器拥有广泛的产品线,包含低成本的8位单片机和基于ARM® Cortex®-M0、M0+、M3、M4、M33、M7及A7内核并具备丰富外设选择的32位微控制器及微处理器


最新内容

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
微信公众号二维码 微信公众号
手机版二维码 手机版