51单片机延时程序探讨

一 单片机周期简介

首先,先从51单片机的周期说起,在单片机上面,有这么几种周期,分别为:振周时钟周期机器周期指令周期,它们的关系如下图

204141_4mSE_999412.jpg

一个机器周期一般由12个晶振周期组成,比如对于晶振周期为12Mhz的单片机而言,其机器周期为1s/12Mhz * 12 = 1us。计算公式是1s/(晶振频率) * (12个晶振周期)

单片机执行不同指令时,消耗的机器周期因指令的复杂度而变化,范围在1~4个机器周期之间。此处的指令指汇编的指令,像MOV A,#data这类的语句执行时会消耗一个机器周期。

二 示例程序和分析

以下为延时子程序,实现的是5ms的延时

void delay(){
	unsigned char i,j,k;
	for(i = 1;i > 0; i--)
	for(j = 98; j > 0; j--)
	for(k = 24; k > 0; k--);
}

从keil中可以获得该延时子程序的汇编语句

C:0x0810    120833   LCALL    delay(C:0833)

3:         for(i = 1;i > 0; i--)
C:0x0833    7FC8     MOV      R7,#T2CON(0xC8)
4:         for(j = 98; j > 0; j--)
C:0x0835    7E62     MOV      R6,#0x62
5:         for(k = 24; k > 0; k--);
C:0x0837    7D18     MOV      R5,#0x18
C:0x0839    DDFE     DJNZ     R5,C:0839
C:0x083B    DEFA     DJNZ     R6,C:0837
C:0x083D    DFF6     DJNZ     R7,C:0835
6: }
C:0x083F    22       RET

LCALL调用延时子程序,然后跳到子程序。三个for循环语句被解释成DJNZ 不为0转移指令,以上汇编语句执行过程如下

213548_HKwu_999412.png

进入延时子程序后,语句一路执行到第5条,然后自循环k次,接着执行第6句,判断R6此时是否为0,不为0,跳转到语句4,这个过程执行j次,接着执行第7句,判断R7是否为0,不为0,跳转到语句3,这个过程执行i次,最后RET跳转回主程序,从以上过程可以获得上述示例程序的执行时间为

{ 2 + 1 + (1 + (1 + 2k + 2)j + 2)i + 2 } * T (T为机器周期)

化简一下得到  { [(3 + 2k)j + 3 ]*i + 5 } * T

示例程序中 i =1, j = 98, k = 24 , 计算可得延时时间为5001 个机器周期,对于12MHZ的单片机而言即为5001us,即5ms,误差为 6us,将 i 的值进行替换,即可获得变换不同的延时时间,例如当 i = 200 时,计算得到时间为 1000205 us,亦即 1 s, 误差为 205us。

三 关于延时程序的实用代码

通过上文的公式,我遍历了一些i,j,k的值(晶振12Mhz),形成了几个较为常用的延时程序,如下

/*延时50ms,误差大于0us*/
void delay_50ms(){
	unsigned char i,j,k;
	for(i = 101;i > 0; i--)
	for(j = 12; j > 0; j--)
	for(k = 19; k > 0; k--);
}

/*延时200ms,误差大于3us*/
void delay_200ms(){
	unsigned char i,j,k;
	for(i = 78;i > 0; i--)
	for(j = 13; j > 0; j--)
	for(k = 97; k > 0; k--);
}

/*延时250ms,误差大于1us*/
void delay_250ms(){
	unsigned char i,j,k;
	for(i = 249;i > 0; i--)
	for(j = 143; j > 0; j--)
	for(k = 2; k > 0; k--);
}

/*延时333ms,误差大于2us*/
void delay_333ms(){
	unsigned char i,j,k;
	for(i = 203;i > 0; i--)
	for(j = 11; j > 0; j--)
	for(k = 73; k > 0; k--);
}


/*延时500ms,误差大于1us*/
void delay_500ms(){
	unsigned char i,j,k;
	for(i = 49;i > 0; i--)
	for(j = 101; j > 0; j--)
	for(k = 49; k > 0; k--);
}

/*延时1s,误差大于3us*/
void delay_1s(){
	unsigned char i,j,k;
	for(i = 98;i > 0; i--)
	for(j = 101; j > 0; j--)
	for(k = 49; k > 0; k--);
}

虽然延时误差仍然存在,而且采用的都是3层for循环(延时有限制范围),不过以上程序对于普通程序,对时间精度要求不严谨的应用场合还是可以得。




转载于:https://my.oschina.net/idaren/blog/614123

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值