STC89C52RC单片机额外篇 | 05 - 把NOP指令封装成微秒级延时函数

延时函数是单片机开发中是必不可少的功能函数,在每个工程里都能找到它的踪影。虽然看起来不起眼,但在有些时序控制的场合,使用了一点点延时,往往能解决大问题。特别对于某些模块,往往需要微秒级的延时,例如超声波模块与红外接收器等。

以前我们使用延时函数的时候,基本上类似这样:

/*******************************************************************************
* 函 数 名         : delay
* 函数功能		   : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delay(u16 i)
{
	while(i--);	
}

我们看到函数体内部只有简单的一条语句while(i--);,看起来好像的确只是一条语句,多么简单!实际上从脑中跑一下逻辑,实际上是这样的:

/*******************************************************************************
* 函 数 名         : delay
* 函数功能		   : 延时函数,i=1时,大约延时10us
*******************************************************************************/
void delay(u16 i)
{
	if (i == 0) {
		return;
	} else {
		i--;
	}

	if (i == 0) {
		return;
	} else {
		i--;
	}

	if (i == 0) {
		return;
	} else {
		i--;
	}
	...
}

delay函数传递的i有多大,像这样的语句就有多少条:

	if (i == 0) {
		return;
	} else {
		i--;
	}

所以注释中说i=1,大约延时10us完全是有可能的,那我们想实现精确性稍微好点的微秒级延时函数怎么办?

其实这块有很多大神已经帮我们封装好了,我们直接使用即可:

  • 延时5us
void delay_5us(void)
{
#pragma ASM
	NOP
#pragma ENDASM
}

这就是一个延时5us的函数,只需要在需要延时5us时调用此函数即可。从前面博文《STC89C52RC单片机额外篇 | 04 - 认识头文件<intrins.h>与_nop_函数》可知,_nop_函数的执行需要消耗一个机器周期,对于12MHz晶振,就是1us,_nop_函数与NOP指令是一样的。那为啥函数delay_5us()只有一条NOP指令就需要5us?

答案是:在调用此函数时,需要一个调用指令,此指令消耗2个周期(即2us);函数执行完毕时要返回主调函数,需要一个返回指令,此指令消耗2个周期(2us)。调用和返回消耗了2us+2us=4us。然后再加上一个NOP指令消耗1us,就是5us了,所以说函数的调用本身也有一定的技术细节的。

  • 延时10us
void delay_10us(void)
{
#pragma ASM
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
#pragma ENDASM
}

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

  • 延时20us
void delay_20us(void)
{
#pragma ASM
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
#pragma ENDASM
}
  • 延时50us
void delay_50us(void)
{
#pragma ASM
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
	NOP
#pragma ENDASM
}

最后别忘了头文件<intrins.h>下的_nop_函数——延时1us!有了延时1us、5us、10us、20us、50us基本上就可以实现100us以内大部分的微秒级延时,这就像我们熟悉的纸币,有1元、2元、5元、10元、20元、50元,用它们进行组合,我们就可以买很多的一般商品了!

我们可以把这些函数放到delay.c文件中,然后在delay.h中声明函数即可,使用的时候直接调用即可!下一篇博文中,我会带领大家了解多文件编程,敬请期待!

这里注意一下:使用#pragma ASM#pragma ENDASM之前需要对相应的C源文件进行配置,否则会出现编译错误!具体参考这篇博文:《Keil4中嵌入汇编语句

如果不想使用嵌入汇编语句的这种方式,我们也可以使用_nop_函数代替NOP指令:

  • 延时10us
void delay_10us(void)
{
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
}
  • 延时20us
void delay_20us(void)
{
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
}
  • 延时50us
void delay_50us(void)
{
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	_nop_();
}
  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

嵌入式逍遥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值