STC89C52RC单片机额外篇 | 05 - 把NOP指令封装成微秒级延时函数
Posted Neutionwei
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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_();
}
以上是关于STC89C52RC单片机额外篇 | 05 - 把NOP指令封装成微秒级延时函数的主要内容,如果未能解决你的问题,请参考以下文章
STC89C52RC单片机额外篇 | 04 - 认识头文件<intrins.h>与_nop_函数
STC89C52RC单片机额外篇 | 02 - 认识串行通信波特率以及数据包
STC89C52RC单片机额外篇 | 06 - 认识高内聚低耦合的模块化编程
STC89C52RC单片机额外篇 | 03 - 认识C51编译器支持的数据类型