C及汇编延时程序_第1页
C及汇编延时程序_第2页
C及汇编延时程序_第3页
C及汇编延时程序_第4页
C及汇编延时程序_第5页
已阅读5页,还剩11页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

有个好帖,从精度考虑,它得研究结果是:

void

delay2(unsigned

char

i)

{

while(--i);

}

为最佳方法。

分析:假设外挂12M(之后都是在这基础上讨论)

我编译了下,传了些参数,并看了汇编代码,观察记录了下面的数据:

delay2(0):延时518us

518-2*256=6

delay2(1):延时7us(原帖写“5us”是错的,^_^)

delay2(10):延时25us

25-20=5

delay2(20):延时45us

45-40=5

delay2(100):延时205us

205-200=5

delay2(200):延时405us

405-400=5

见上可得可调度为2us,而最大误差为6us。

精度是很高了!

但这个程序的最大延时是为518us

显然不

能满足实际需要,因为很多时候需要延迟比较长的时间。

那么,接下来讨论将t分配为两个字节,即uint型的时候,会出现什么情况。

void

delay8(uint

t)

{

while(--t);

}

我编译了下,传了些参数,并看了汇编代码,观察记录了下面的数据:

delay8(0):延时524551us

524551-8*65536=263

delay8(1):延时15us

delay8(10):延时85us

85-80=5

delay8(100):延时806us

806-800=6

delay8(1000):延时8009us

8009-8000=9

delay8(10000):延时80045us

80045-8000=45

delay8(65535):延时524542us

524542-524280=262

如果把这个程序的可调度看为8us,那么最大误差为263us,但这个延时程序还是不能满足要求的,因为延时最大为524.551ms。

那么用ulong

t呢?

一定很恐怖,不用看编译后的汇编代码了。。。

那么如何得到比较小的可调度,可调范围大,并占用比较少得RAM呢?请看下面的程序:

/*--------------------------------------------------------------------

程序名称:50us

延时

注意事项:基于1MIPS,AT89系列对应12M晶振,W77、W78系列对应3M晶振

例子提示:调用delay_50us(20),得到1ms延时

全局变量:无

返回:

--------------------------------------------------------------------*/

void

delay_50us(uint

t)

{

uchar

j;

for(;t>0;t--)

for(j=19;j>0;j--)

;

}

我编译了下,传了些参数,并看了汇编代码,观察记录了下面的数据:

delay_50us(1):延时63us

63-50=13

delay_50us(10):延时513us

503-500=13

delay_50us(100):延时5013us

5013-5000=13

delay_50us(1000):延时50022us

50022-50000=22

赫赫,延时50ms,误差仅仅22us,作为C语言已经是可以接受了。再说要求再精确的话,就算是用汇编也得改用定时器了。

/*--------------------------------------------------------------------

程序名称:50ms

延时

注意事项:基于1MIPS,AT89系列对应12M晶振,W77、W78系列对应3M晶振

例子提示:调用delay_50ms(20),得到1s延时

全局变量:无

返回:

--------------------------------------------------------------------*/

void

delay_50ms(uint

t)

{

uint

j;

/****

可以在此加少许延时补偿,以祢补大数值传递时(如delay_50ms(1000))造成的误差,

但付出的代价是造成传递小数值(delay_50ms(1))造成更大的误差。

因为实际应用更多时候是传递小数值,所以补建议加补偿!

****/

for(;t>0;t--)

for(j=6245;j>0;j--)

;

}

我编译了下,传了些参数,并看了汇编代码,观察记录了下面的数据:

delay_50ms(1):延时50

010

10us

delay_50ms(10):延时499

983

17us

delay_50ms(100):延时4

999

713

287us

delay_50ms(1000):延时4

997

022

2.978ms

赫赫,延时50s,误差仅仅2.978ms,可以接受!

上面程序没有才用long,也没采用3层以上的循环,而是将延时分拆为两个程序以提高精度。应该是比较好的做法了问题内容:怎样用c语言写延时程序原讨论链接:/expert/topicview1.asp?id=4760346所属论坛:单片机/工控

审核组:硬件/嵌入开发提问者:\o"zharrisl个人空间"zharrisl

解决者:\o"hiflower个人空间"hiflower感谢:\o"icesnows个人空间"icesnows\o"shimd0604个人空间"shimd0604\o"sclarkca810619个人空间"sclarkca810619\o"flowercity个人空间"flowercity\o"icesnows个人空间"icesnows\o"tony1976个人空间"tony1976\o"tony1976个人空间"tony1976\o"eastred个人空间"eastred\o"winp2003个人空间"winp2003\o"hu_an_xiong个人空间"hu_an_xiong\o"517517个人空间"517517\o"hiflower个人空间"hiflower\o"tyj_3个人空间"tyj_3关键字:函数语句硬件/嵌入开发单片机指令汇编void循环定时周期单片机/工控答案:要求是秒级的,同时说明下原理

---------------------------------------------------------------

空循环就行了

如while(i--);根据i的不同决定了延时长短

不过C的延时不是非常准确,你得根据反汇编,看汇编语句的数量和指令周期来计算时间

---------------------------------------------------------------

楼上的说得很对,用C语言编写单片机程序时,一般开发界面(如科尔KEILE)都提供了C

-

汇编的代码转换,参照转换后的汇编语言就可以精确延时了

---------------------------------------------------------------

你可以数指令,然后按着MCU的MIPS算时间,结果应该比较精确:)

---------------------------------------------------------------

void

mDelay(unsigned

int

Delay)

//Delay

=

1000

时间为1S

{

unsigned

int

i;

for(;Delay>0;Delay--)

{

for(i=0;i<124;i++)

{;}

}

}

---------------------------------------------------------------

一次循环的汇编指令,再乘以指令周期就知道一次循环的时间了啊,然后用1秒一除,不就知道循环次数了么

---------------------------------------------------------------

秒级的本身精度要求就不高嘛

很容易控制啊

多套用几个for语句

或者在for语句里引用n个更低量级的(如100ms级)的延时函数即可

要精确就计算汇编代码执行长度

---------------------------------------------------------------

to

flowercity(Love

Program,Love

Living):

你的函数没有什么参考价值

延时时间和指令周期以及编译出来的代码类型有关系的

不是所谓

//Delay

=

1000

时间为1S

就是一定的.

那只是针对你现在的系统.

用的晶振不同,执行CPU指令周期和时钟周期比率不同

结果都不同

---------------------------------------------------------------

秒级的,用定时器比较好吧。

---------------------------------------------------------------

void

waitms(int

i)

{

char

m;

for(

;

i

;i--)

{

for(m

=

203;

m

;

m--)

{

_nop_();

_nop_();

_nop_();

_nop_();

_nop_();

_nop_();

_nop_();

}

}

}

延时1ms的函数

时钟频率12MHz

---------------------------------------------------------------

空操作,不过不好做到很准确

---------------------------------------------------------------

秒级延时,用指令的话,你要求延时的精确度是多少,高的话最好用定时器,而且你延时这么长,你的CPU不是就一直占用了,浪费呀。。。

---------------------------------------------------------------

与定时器中断服务程序配合实现延时。

unsigned

int

sleepTime;

unsinged

char

inSleep

=

0;

void

sleepService(void)

{

if

(inSleep)

sleepTime--;

if

(sleepTime

==

0)

inSleep

=

0;

}

void

isr_timer(void)

//假定定时器中断1ms

中断一次。

{

...

sleepService();

...

}

void

sleep(unsigned

int

ms)

//延时子程序

{

sleepTime

=

ms;

inSleep

=

1;

while(inSleep);

}

void

main(void)

{

....

sleep(1000);

//延时

1秒

...

}

---------------------------------------------------------------

>>要求是秒级的

这么长的延时,单片机中一般采取不占CPU时间的延时,利用定时器来实现延时,

如果非得用循环延时,在C中也通常嵌入汇编实现,这样误差比较小在论坛上看到不少不错的延时程序,整理如下共同分享:精确延时计算公式:延时时间=[(2*第一层循环+3)*第二层循环+3]*第三层循环+5;延时5秒左右

DELAY5S:PUSH

04H

PUSH

05H

PUSH

06H

MOV

R4,#50

DELAY5S_0:MOV

R5,#200

DELAY5S_1:MOV

R6,#245

DJNZ

R6,$

DJNZ

R5,DELAY5S_1

DJNZ

R4,DELAY5S_0

POP

06H

POP

05H

POP

04H

RET

;513微秒延时程序

DELAY:

MOV

R2,#0FEH

DELAY1:DJNZ

R2,DELAY1

RET;10毫秒延时程序

DL10MS:MOV

R3,#14H

DL10MS1:LCALL

DELAY

DJNZ

R3,DL10MS1

RET;0.1s延时程序12mhz

DELAY:MOVR6,#250

DL1:MOVR7,#200

DL2:DJNZR6,DL2

DJNZR7,DL1

RET;延时1046549微秒(12mhz)

;具体的计算公式是:

;((((r7*2+1)+2)*r6+1)+2)*r5+1+4=((r7*2+3)*r6+3)*r5+5

DEL:MOV

R5,#08H

DEL1:MOV

R6,#0FFH

DEL2:MOV

R7,#0FFH

DJNZ

R7,$

DJNZ

R6,DEL2

DJNZ

R5,DEL1

RET;1秒延时子程序是以12MHz晶振

Delay1S:mov

r1,#50

del0:

movr2,#91

del1:

movr3,#100

djnzr3,$

djnzr2,del1

djnzr1,del0

Ret;1秒延时子程序是以12MHz晶振为例算指令周期耗时

KK:MOV

R5,#10

;1指令周期1

K1:MOV

R6,#0FFH

;1指令周期10

K2:MOV

R7,#80H

;1指令周期256*10=2560

K3:NOP

;1指令周期128*256*10=327680

DJNZ

R7,K3

;2指令周期2*128*256*10=655360

DJNZ

R6,K2

;2指令周期2*256*10=5120

DJNZ

R5,K1

;2指令周期2*10=20

RET

;2指令周期21+10+2560+327680+655360+5120+20+2=990753

;约等于1秒1秒=1000000微秒

;这个算下来也只有0.998抄

T_0:

MOV

R7,#10;

D1:

MOV

R6,#200;

D2:

MOV

R5,#248;

DJNZ

R5,$

DJNZ

R6,D2;

DJNZ

R7,D1;

RET;这样算下来应该是1.000011秒

T_0:

MOV

R7,#10;

D1:

MOV

R6,#200;

D2:

NOP

MOV

R5,#248;

DJNZ

R5,$

DJNZ

R6,D2;

DJNZ

R7,D1;

RETDELAY_2S:

;10MS(11.0592mhz)

MOVR3,#200

JMPDELAY10MS

DELAY_100MS:

;100MS(11.0592mhz)

MOVR3,#10

JMPDELAY10MS

DELAY_10MS:

MOVR3,#1

DELAY10MS:

;去抖动10MS(11.0592mhz)

MOVR4,#20

DELAY10MSA:

MOVR5,#247

DJNZR5,$

DJNZR4,DELAY10MSA

DJNZR3,DELAY10MS

RET

DELAY_500MS:

;500500MS

MOVR2,#208

JMPDELAY_MS

DELAY_175MS:

;175MS

MOVR2,#73

JMPDELAY_MS

delaY_120MS:

;120MS

MOVR2,#50

JMPDELAY_MS

delay_60ms:

;60ms

MOVR2,#25

JMPDELAY_MS

delay_30ms:

;30ms

MOVR2,#12

JMPDELAY_MS

DELAY_5MS:

;5MS

MOVR2,#2

;===================================

DELAY_MS:

CALLDELAY2400

DJNZR2,DELAY_MS

RET

;===================================

DELAY2400:

;10x244+4=2447/1.024=2390

MOV

R0,#244

;1

DELAY24001:

MULAB

;4

MULAB

;4

DJNZR0,DELAY24001;2

RETDELAY:;延时子程序(1秒)

MOVR0,#0AH

DELAY1:MOVR1,#00H

DELAY2:MOVR2,#0B2H

DJNZR2,$

DJNZR1,DELAY2

DJNZR0,DELAY1

RET

MOVR2,#10;延时1秒

LCALLDELAY

MOVR2,#50;延时5秒

LCALLDELAY

DELAY:;延时子程序

PUSHR2

PUSHR1

PUSHR0

DELAY1:MOVR1,#00H

DELAY2:MOVR0,#0B2H

DJNZR0,$

DJNZR1,DELAY2;延时100mS

DJNZR2,DELAY1

POPR0

POPR1

POPR2

RET

1:DEL:

MOV

R7,

#200

DEL1:

MOV

R6,

#123

NOP

DEL2:

DJNZ

R6,

DEL2

DJNZ

R7,

DEL1

RET是50.001ms算法是:

0.001ms+200*0.001ms+200*0.001ms+200*123*0.002ms+200*0.002ms;(123*2+4)*200+12:DEL:MOVR7,#200

DEL1:MOVR6,#123

DEL2:NOP

DJNZR6,DEL2

DJNZR7,DEL1RETD500MS:

PUSHPSW

SETBRS0

MOVR7,#200

D51:MOVR6,#250

D52:NOP

NOP

NOP

NOP

DJNZR6,D52

DJNZR7,D51

POPPSW

RET

DELAY:;延时1毫秒

PUSHPSW

SETBRS0

MOVR7,#50

D1:MOVR6,#10

D2:DJNZR6,$

DJNZR7,D1

POPPSW

RET

ORG

0

LJMP

MAIN

ORG

000BH

LJMP

CTC0

MAIN:

MOV

SP,#50H

CLR

EA

MOV

TMOD,#01H

MOV

TH0,#3CH

MOV

TL0,#0B0H

MOV

R4,

#10

SETB

ET0

SETB

EA

SETB

TR0

SJMP

$

;

CTC0:

MOV

TH0,#3CH

MOV

TL0,#0B0H

DJNZ

R4,LP

CPL

P1.0

MOV

R4,

#10

LP:

RETI

END汇编延时程序算法详解来源:嵌入式技术网作者:姜会敏时间:2008-01-01发布人:林逸摘要计算机反复执行一段程序以达到延时的目的称为软件延时,单片机应用程序中经常需要短时间延时,有时要求很高的精度,网上或书中虽然有现成的公式可以套用,但在部分算法讲解中发现有错误之处,而且延时的具体算法讲得并不清楚,相当一部分人对此仍很模糊,授人鱼,不如授之以渔,本文将以12MHZ晶振为例,详细讲解MCS-51单片机中汇编程序延时的精确算法。

关键词51单片机汇编延时算法

指令周期、机器周期与时钟周期

指令周期:CPU执行一条指令所需要的时间称为指令周期,它是以机器周期为单位的,指令不同,所需的机器周期也不同。

时钟周期:也称为振荡周期,一个时钟周期=晶振的倒数。

MCS-51单片机的一个机器周期=6个状态周期=12个时钟周期。

MCS-51单片机的指令有单字节、双字节和三字节的,它们的指令周期不尽相同,一个单周期指令包含一个机器周期,即12个时钟周期,所以一条单周期指令被执行所占时间为12*(1/12000000)=1µs。

程序分析

例150ms延时子程序:

DEL:MOVR7,#200①

DEL1:MOVR6,#125②

DEL2:DJNZR6,DEL2③

DJNZR7,DEL1④

RET⑤

精确延时时间为:1+(1*200)+(2*125*2

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论