写一个延迟子程序?

时间:2011-02-27 17:55:38

标签: assembly microcontroller 8051

我需要写一个延迟子程序。它应该延迟大约1秒钟。它必须适用于8051环境,DS89C430微控制器(11.0592 MHz XTAL)。我该如何编写这个子程序?

Delay1sec: ...
....
...
....
...

3 个答案:

答案 0 :(得分:3)

要获得在中断期间也能正常工作的1秒延迟,您需要使用硬件定时器,而不是软件定时器。我建议你使用一个可用的机载定时器as suggested by Jerry Coffin

这是一种涉及内置定时器和计数定时器溢出的方法。由于运行定时器默认每12个时钟周期更新一次,以保持与8051的兼容性,因此每秒更新921,600次。一点乘法告诉我们从0到46080计数需要50 ms,这也告诉我们我们可以在19456启动一个16位定时器并等待它溢出20次延迟1秒 *

代码看起来像这样:

        CLR     T0M          ; set timer 0 to use a divide-by-12 of
                             ; the crystal frequency (default)

        MOV     R0,TMOD      ; set timer 0 to 16-bit mode without
        ORL     R0,#01h      ; affecting the setup of timer 1
        MOV     TMOD,R0

        LCALL   Delay1sec    ; call the delay subroutine

Delay1sec:
        MOV     R0,#20d      ; set loop count to 20

loop:   CLR     TR0          ; start each loop with the timer stopped
        CLR     TF0          ; and the overflow flag clear. setup
        MOV     TH0,#4Ch     ; timer 0 to overflow in 50 ms, start the
        MOV     TL0,#00h     ; timer, wait for overflow, then repeat
        SETB    TR0          ; until the loop count is exhausted
        JNB     TF0,$
        DJNZ    R0,loop
        RET   

注意:从示例中排除了指令执行时间的开销。
*数学如何分解:
11059200/12 = 921600
0.05 * 921600 = 46080
65536 - 46080 = 19456 = 0x4C00


软件延迟循环会浪费处理器时间并受到中断的干扰。话虽这么说,你可以用硬编码的方式做到这一点。

一种方法涉及了解每个机器周期的时钟周期数以及各种指令执行所需的机器周期数。根据{{​​3}},DS89C430通常对每个指令字节使用一个机器周期,并且需要一个周期来执行。每条指令的周期数在data sheet

中提供

由于您的晶振频率为11.0592 MHz,因此您的例程需要延迟11,059,200个时钟周期。这通常通过已知长度的嵌套循环完成,然后包括任何额外的循环设置以及可能的子程序调用和返回指令 *

该功能可能如下所示:

Delay1sec:                   ; <------------------------------+
;       LCALL   Delay1sec    ; 3 cycles                       |
        MOV     R2,#42d      ; 2 cycles                       |
        MOV     R1,#00d      ; 2 cycles                       |
        MOV     R0,#00d      ; 2 cycles                       |
loop:   DJNZ    R0,loop      ; 4 cycles <-- l1 <- l2 <- l3    Delay1sec
        DJNZ    R1,loop      ; 4 cycles <---------+     |     |
        DJNZ    R2,loop      ; 4 cycles <---------------+     |
        RET                  ; 3 cycles <---------------------+

让我们看看数学如何分解 **

l1 = 4 * 256 = 1024个周期
l2 =(1024 + 4)* 256 = 263168个周期
l3 =(263168 + 4)* 42 = 11053224个周期
Delay1sec = 11072668 + 3 + 2 + 2 + 2 + 3 = 11053236周期

11053236周期* 1/11059200秒/周期= 999.461 ms

*必要时可省略子程序调用和返回指令。
**我使用Microsoft Excel来协助与确定循环计数器相关的计算。

答案 1 :(得分:2)

这个微控制器有三个板载定时器(参见User's Manual的第11节)连接到系统时钟(除以12),因此编程它们以在时间到期时产生中断。由于分频输入仅低于1 MHz,最大计数器为16位,因此您需要计算14次中断才能达到1秒(至少如果我已正确完成数学运算)。

答案 2 :(得分:0)

A)参考硬件计时器。

B)参考CPU计时器。有些处理器有一个非常宽的定时器,即64位宽,在时钟周期运行。

C)软件循环。为获得最佳结果,代码和所有数据应驻留在具有可预测时序的内部存储器中。从SDRAM运行会导致计时问题。

您无需计算装配周期。相反,您可以在引脚上“绘制”脉冲(在环路前拉高,在环路后拉低),使用逻辑延迟器测量脉冲宽度,然后更改环路计数以调整您的时序。为了获得最佳效果,您应该通过使用频率计来测量它来补偿外部CPU时钟/晶体,然后补偿远离中心频率,因为大多数廉价的晶体都没有死机。

您可以使用计时器自我校准来计算循环时间。