关于对单片机延时时间的疑惑(谁来解释一下,解释的好追加50分)

_HOUT:
ROND:NOP
MOV 70H,#00H
DJNZ R7,ROND
RETI
END
上面这段汇编程序很简单,没有任何意义,只是用来进行延时的。
那么上面这段程序的延时时间是6μs+1us,(上面的程序加上RETI)
合计7US。

包含本身C语言做的传递值的语句,一共延时时间为 6+6*n
(n为C语言往R7中传递的基数,6*n指的是一次循环体执行时间是6US再乘以次数,前面的6指的是C语言本身传递值用的机器周期时间。这个时间是不变的。)

这是高电平的延时时间。。加上低电平的延时时间一共是 12+12*n
单片机用C语言调用这段延时程序,其值传递利用R7传递。

那么我请问,R7值如果是1的时候,延时时间符合逻辑,是24US。.

那么,R7值是2的时候,延时时间是多少?为什么不是 2*12+12=36US?

而是34US?

我要声明,我电路中没有什么特别的东西,直接从单片机口线输出频率

只是用C语言调用这段汇编,并且传递值在R7位,但是我输出的频率是逐步衰 减的!我用的是12M晶振

比如我送值为2,就衰减2

送值为3,输出频率就衰减4

送值为4,输出频率就衰减6US

很有规律,以此类推。

这是什么原因?附带我的 C语言调用程序

do
{
P1_1=1;
hout(hzoutnum);
P1_1=0;
hout(hzoutnum);
}

有高人来给我解释一下。。我下午调程序无意中调出来的。为什么会衰减?
回复2楼的,这是中断子程序。在KEIL里用C调用汇编,如果用RET就报错。

R7的值通过变量 HZOUTNUM进行传递,我仿真了一下,传递过程是正常的,最大取值范围是FF,也就是255

确实是正常的

你知道R7如果变成0下面 就会是多少么?FF!这误差就一个天上一个地下了。。不是这样的,因为用示波器检查

了,输出周期只是平均每执行一遍循环体,周期就衰减2US

"那段循环程序无论R7值为多少,只循环一遍的话,输出正常,如果第二遍就不正常了"

楼下给我的解释有点牵强。我需要更加合理的说法。我要知道原因

仿照楼主的问题,进行了程序调试,C调用汇编的时间,可以看插图。

实验证明了三个问题。

1. 使用 RETI 是不必要的,使用 RET 并不报错。

2. C调用这个汇编函数的时间,是 (5 + 5 * n)us。(假设机器周期T=1us)。

3. 从仿真调试过程中,没有看到楼主所说“衰减”的现象。

分析说明如下:

主函数传值到R7:1us;

主函数调用汇编:2us;

汇编返回值(无):0us;

汇编返回(RET):2us;

以上就是公式中的“5us”。

汇编函数体各指令的耗时:

ROND:NOP      ;1us

     MOV 70H,#00H   ;2us

     DJNZ R7,ROND   ;2us

执行一遍共5us,以R7的值,控制循环次数,故有“5*n(us)”。

条件所限,没有使用示波器进行测试,等以后找个机会吧。

温馨提示:答案为网友推荐,仅供参考
第1个回答  2010-03-20
系统频率:6MHz
Delay: MOV R5,#25 ;5ms延时——MOV指令占用1机器周期时间

Delay1: MOV R6,#200 ;200ms延时

Delay2: MOV R7,#166 ;1ms延时常数

Delay3: NOP ;空指令,什么都不做,停留1机器周期时间

DJNZ R7,Delay3 ;R7减1赋值给R7,如果此时R7不等于零,转到Delay3执行。——2机器周期时间

DJNZ R6,Delay2

DJNZ R5,Delay1

解析如下:
1、首先计算机器周期T=12*1/f=2μs。
2、注意DJNZ R7,Delay3每执行1次需要占用NOP的时间和DJNZ本身的时间共3个机器周期。6μs。那么1ms的时间需要1ms*1000/6μs=166.67,取166。
3、注意DJNZ R6,Delay2是在166次循环后执行1次的(时间为MOV机器周期+本身机器周期,3*2=6μs),直到166*200次后,R6=0,才执行DJNZ R5,Delay1。
4、DJNZ R5,Delay1是在R5不为0的时候循环回去。时间也为6μs。
5、时间总计:166*200*25*6μs+200*25*6μs+25*6μs=5010150μs,合计5.01015ms(编程的人都遇到过类似的潜逃循环,此程序忽略了执行MOV的时间,只计算了循环所用时间,即166*200*25*6/1000000=4.98ms,近似5ms)。

程序改进:
去掉NOP命令,整数化1ms需要的延时常数。
Delay: MOV R5,#25 ;5ms延时——MOV指令占用1机器周期时间

Delay1: MOV R6,#200 ;200ms延时

Delay2: MOV R7,#250 ;1ms延时常数

Delay3: ;NOP ;空指令,什么都不做,停留1机器周期时间

DJNZ R7,Delay3 ;R7减1赋值给R7,如果此时R7不等于零,转到Delay3执行。——2机器周期时间

DJNZ R6,Delay2

DJNZ R5,Delay1

此时时间总计:250*200*25*4μs+200*25*6μs+25*6μs=5030150μs。时间占用误差反而比未改进的时候大,可修正,将R7-30150/(25*200*4)=248(因为R7=250循环1次占用2个机器周期,4μs,计算等于R7-1.5075,将时间减小到小于5ms,剩余时间另补,取248)。则:时间总计:248*200*25*4μs+200*25*6μs+25*6μs=4990150μs,需要补:5000000-4990150=9850μs,9850/2=4925机器周期。补一个MOV R4,#200,4个NOP,还需4920机器周期,将其约分,得到24*205=4920。如何建立函数根据实际代码调整,如下:

Delay: MOV R5,#25 ;5ms延时——MOV指令占用1机器周期时间

Delay1: MOV R6,#200 ;200ms延时

Delay2: MOV R7,#250 ;1ms延时常数

Delay3: ;NOP ;空指令,什么都不做,停留1机器周期时间

DJNZ R7,Delay3 ;R7减1赋值给R7,如果此时R7不等于零,转到Delay3执行。——2机器周期时间

DJNZ R6,Delay2

DJNZ R5,Delay1

NOP
NOP
NOP
NOP
MOV R3,#6

Delayadd: MOV R4,#205
MOV R2,#0H
DJNZ R3,Delayadd
解析205*24调整为205*6——这是因为Delay循环为4机器周期代码,因此将24/4=6。请计算:205*6*4=4920;4920+5=4925。时间补充正好。此时时间计算:248*200*25*4μs+200*25*6μs+25*6μs=4990150μs+4925*2μs=5000000μs合计5ms。
理论上1μs都不差(仅为科学探讨,具体晶振频率的误差多大作者并不明确)。怎么样?
行吗?
第2个回答  2010-03-20
直接回答你最后一个问题,当R7值为0时,执行DJNZ时先减1,变成0xFF,这时直比较,条件不为零,继续执行,当然相差很大了.

关于你执行时间有变少的问题,单从你给的程序来看,不能完全确定,即然你用的是C语言调用汇编,汇编可以直接算出执行的机器周期,但是C语言编译后的汇编是不确定的,这要看编译器有没有优化及优化的程度.keil C51里面是有这个选项的.

建议你看下编译器生成的汇编代码,虽然难懂些,但是那个最能说明问题.

顺便说下,RETI是伪指令,编译时直接放下步要去的地址,本身不占用时间的.因为上面的中断子程序执行完,就直接执行要跳转到的地方的代码.所以你上面计算也不太准确.

有什么不懂的可以直接给我邮件或发消息.
第3个回答  2010-03-20
HOUT:
ROND:NOP
MOV 70H,#00H
DJNZ R7,ROND
RETI
END
你那单片机是什么型号的呀,为什么要加reti返回呢,如果是51单片机不是中断子程序的话reti是错的,RET就行,还有就是r7的值都不清楚,它怎么进行条件跳转,可能第一次R7你上面赋值了,但循环经过DJNZ R7,ROND,这条指令后他会变到0去,你下面如果没给R7再赋值的话有可能就与第一次不相同了。
第4个回答  2010-03-19
你用的晶振是不是11.059MHz的?
另外一个理由就是示波器的值可能不准!